Skip to content

Commit

Permalink
Added complaints for limited negotiation
Browse files Browse the repository at this point in the history
  • Loading branch information
kroman0 committed Mar 3, 2016
1 parent 78f04e7 commit cf31c12
Show file tree
Hide file tree
Showing 26 changed files with 2,048 additions and 20 deletions.
5 changes: 4 additions & 1 deletion buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ newest = false
parts = test
develop = .
find-links = http://op:x9W3jZ@dist.quintagroup.com/op/
auto-checkout = openprocurement.api
auto-checkout =
openprocurement.api
openprocurement.tender.openua

[sources]
openprocurement.api = git https://github.com/openprocurement/openprocurement.api.git
openprocurement.tender.openua = git https://github.com/openprocurement/openprocurement.tender.openua.git

[test]
recipe = zc.recipe.egg:scripts
Expand Down
140 changes: 138 additions & 2 deletions docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,34 @@
}
}

complaint = {
"data": {
"author": {
"address": {
"countryName": "Україна",
"locality": "м. Вінниця",
"postalCode": "21100",
"region": "м. Вінниця",
"streetAddress": "вул. Островського, 33"
},
"contactPoint": {
"email": "soleksuk@gmail.com",
"name": "Сергій Олексюк",
"telephone": "+380 (432) 21-69-30"
},
"identifier": {
"id": "13313462",
"legalName": "Державне комунальне підприємство громадського харчування «Школяр»",
"scheme": "UA-EDR",
"uri": "http://sch10.edu.vn.ua/"
},
"name": "ДКП «Школяр»"
},
"description": "Умови виставлені замовником не містять достатньо інформації, щоб заявка мала сенс.",
"title": "Недостатньо інформації"
}
}

test_tender_negotiation_data = deepcopy(test_tender_data)
test_tender_negotiation_data['procurementMethodType'] = "negotiation"

Expand All @@ -114,7 +142,7 @@ class DumpsTestAppwebtest(TestApp):

def do_request(self, req, status=None, expect_errors=None):
req.headers.environ["HTTP_HOST"] = "api-sandbox.openprocurement.org"
if not self.file_obj.closed:
if hasattr(self, 'file_obj') and not self.file_obj.closed:
self.file_obj.write(req.as_bytes(True))
self.file_obj.write("\n")
if req.body:
Expand All @@ -126,7 +154,7 @@ def do_request(self, req, status=None, expect_errors=None):
pass
self.file_obj.write("\n")
resp = super(DumpsTestAppwebtest, self).do_request(req, status=status, expect_errors=expect_errors)
if not self.file_obj.closed:
if hasattr(self, 'file_obj') and not self.file_obj.closed:
headers = [(n.title(), v)
for n, v in resp.headerlist
if n.lower() != 'content-length']
Expand Down Expand Up @@ -447,3 +475,111 @@ def test_docs(self):
self.tender_id, self.contract_id, owner_token), {'data': {'status': 'active'}})
self.assertEqual(response.status, '200 OK')

def test_award_complaints(self):
self.app.authorization = ('Basic', ('broker', ''))

response = self.app.post_json('/tenders?opt_pretty=1', {"data": self.initial_data})
self.assertEqual(response.status, '201 Created')

tender = response.json['data']
owner_token = response.json['access']['token']
self.tender_id = tender['id']

response = self.app.post_json('/tenders/{}/awards?acc_token={}'.format(self.tender_id, owner_token), supplier)
self.assertEqual(response.status, '201 Created')
award_id = response.json['data']['id']

self.app.patch_json('/tenders/{}/awards/{}?acc_token={}'.format(self.tender_id, award_id, owner_token), {"data": {"status": "active"}})

with open('docs/source/tutorial/award-complaint-submission.http', 'w') as self.app.file_obj:
response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(self.tender_id, award_id), complaint)
self.assertEqual(response.status, '201 Created')

complaint1_token = response.json['access']['token']
complaint1_id = response.json['data']['id']

with open('docs/source/tutorial/award-complaint-submission-upload.http', 'w') as self.app.file_obj:
response = self.app.post('/tenders/{}/awards/{}/complaints/{}/documents?acc_token={}'.format(self.tender_id, award_id, complaint1_id, complaint1_token),
upload_files=[('file', u'Complaint_Attachement.pdf', 'content')])
self.assertEqual(response.status, '201 Created')

with open('docs/source/tutorial/award-complaint-complaint.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}?acc_token={}'.format(self.tender_id, award_id, complaint1_id, complaint1_token), {"data": {"status": "pending"}})
self.assertEqual(response.status, '200 OK')

complaint_data = {'data': complaint['data'].copy()}
complaint_data['data']['status'] = 'pending'
with open('docs/source/tutorial/award-complaint-submission-complaint.http', 'w') as self.app.file_obj:
response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(self.tender_id, award_id), complaint_data)
self.assertEqual(response.status, '201 Created')

complaint2_token = response.json['access']['token']
complaint2_id = response.json['data']['id']

response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(self.tender_id, award_id), complaint_data)
self.assertEqual(response.status, '201 Created')
complaint3_token = response.json['access']['token']
complaint3_id = response.json['data']['id']

self.app.authorization = ('Basic', ('reviewer', ''))
with open('docs/source/tutorial/award-complaint-reject.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint2_id), {"data": {
"status": "invalid"
}})
self.assertEqual(response.status, '200 OK')

with open('docs/source/tutorial/award-complaint-accept.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint1_id), {"data": {
"status": "accepted"
}})
self.assertEqual(response.status, '200 OK')

response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint3_id), {"data": {
"status": "accepted"
}})
self.assertEqual(response.status, '200 OK')

with open('docs/source/tutorial/award-complaint-resolution-upload.http', 'w') as self.app.file_obj:
response = self.app.post('/tenders/{}/awards/{}/complaints/{}/documents'.format(self.tender_id, award_id, complaint1_id),
upload_files=[('file', u'ComplaintResolution.pdf', 'content')])
self.assertEqual(response.status, '201 Created')

with open('docs/source/tutorial/award-complaint-resolve.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint1_id), {"data": {
"status": "satisfied"
}})
self.assertEqual(response.status, '200 OK')

with open('docs/source/tutorial/award-complaint-decline.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint3_id), {"data": {
"status": "declined"
}})
self.assertEqual(response.status, '200 OK')

self.app.authorization = ('Basic', ('broker', ''))
with open('docs/source/tutorial/award-complaint-resolved.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}?acc_token={}'.format(self.tender_id, award_id, complaint1_id, owner_token), {"data": {
"tendererAction": "Умови виправлено",
"status": "resolved"
}})
self.assertEqual(response.status, '200 OK')

response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(self.tender_id, award_id), complaint_data)
self.assertEqual(response.status, '201 Created')

with open('docs/source/tutorial/award-complaint-cancel.http', 'w') as self.app.file_obj:
response = self.app.patch_json('/tenders/{}/awards/{}/complaints/{}?acc_token={}'.format(self.tender_id, award_id, response.json['data']['id'], response.json['access']['token']), {"data": {
"cancellationReason": "Умови виправлено",
"status": "cancelled"
}})
self.assertEqual(response.status, '200 OK')

with open('docs/source/tutorial/award-complaints-list.http', 'w') as self.app.file_obj:
self.app.authorization = None
response = self.app.get('/tenders/{}/awards/{}/complaints'.format(self.tender_id, award_id))
self.assertEqual(response.status, '200 OK')

with open('docs/source/tutorial/award-complaint.http', 'w') as self.app.file_obj:
self.app.authorization = None
response = self.app.get('/tenders/{}/awards/{}/complaints/{}'.format(self.tender_id, award_id, complaint1_id))
self.assertEqual(response.status, '200 OK')
95 changes: 95 additions & 0 deletions docs/source/complaints-award.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
.. Kicking page rebuild 2014-10-30 17:00:08
Complaint Retrieval
=========================

Tender Award Complaint Retrieval
-------------------------------------------

You can list all Tender Award Complaints:

.. include:: tutorial/award-complaints-list.http
:code:

And check individual complaint:

.. include:: tutorial/award-complaint.http
:code:

Complaint Submission
====================

If tender award is favoriting certain supplier, or in any other viable case, one can submit Tender Award Complaint.

Tender Award Complaint Submission (with documents)
---------------------------------------------------

At first create a complaint. Send POST request with bidder's access token.

.. include:: tutorial/award-complaint-submission.http
:code:

Then upload necessary documents:

.. include:: tutorial/award-complaint-submission-upload.http
:code:

Submit tender award complaint:

.. include:: tutorial/award-complaint-complaint.http
:code:

Tender Award Complaint Submission (without documents)
-----------------------------------------------------

You can submit complaint that does not need additional documents:

.. include:: tutorial/award-complaint-submission-complaint.http
:code:

Complaint Resolution
====================

Rejecting Tender Award Complaint
-------------------------------------

.. include:: tutorial/award-complaint-reject.http
:code:


Accepting Tender Award Complaint
-------------------------------------

.. include:: tutorial/award-complaint-accept.http
:code:


Submitting Tender Award Complaint Resolution
-------------------------------------------------

The Complaint Review Body uploads the resolution document:

.. include:: tutorial/award-complaint-resolution-upload.http
:code:

And either resolves complaint:

.. include:: tutorial/award-complaint-resolve.http
:code:

Or declines it:

.. include:: tutorial/award-complaint-decline.http
:code:

Submitting Resolution Confirmation
----------------------------------

.. include:: tutorial/award-complaint-resolved.http
:code:

Cancelling Tender Award Complaint
=================================

.. include:: tutorial/award-complaint-cancel.http
:code:
93 changes: 93 additions & 0 deletions docs/source/complaints.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.. Kicking page rebuild 2014-10-30 17:00:08
..
contents:: Table of Contents
:depth: 2
:local:
.. _complaint_workflow:

Complaint Workflow
==================

For more detailed information read `Complaints <http://openprocurement.org/en/complaints.html>`_.

Tender Award Complaints
-----------------------

.. graphviz::

digraph G {
subgraph cluster_complaint {
label = "complaint";
pending; satisfied; accepted;
}
satisfied -> resolved;
edge[style=dashed];
draft -> pending;
{accepted,draft,pending} -> cancelled;
edge[style=bold];
pending -> {accepted,invalid};
accepted -> {declined,satisfied};
}

.. toctree::
:maxdepth: 1

complaints-award

Roles
-----

:Complainant:
dashed

:Procuring entity:
plain

:Reviewer:
bold

:Chronograph:
dotted

Statuses
--------

:draft:
Initial status

Complainant can submit claim, upload documents, cancel claim, and re-submit it.

:claim:
Procuring entity can upload documents and answer to claim.

Complainant can cancel claim.

:answered:
Complainant can cancel claim, upload documents, accept solution or escalate claim to complaint.

:pending:
Reviewer can upload documents and review complaint.

Complainant can cancel claim.

:invalid:
Terminal status

Complaint recognized as invalid.

:declined:
Terminal status

Complaint recognized as declined.

:resolved:
Terminal status

Complaint recognized as resolved.

:cancelled:
Terminal status

Complaint cancelled by complainant.
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
extensions = [
'cornice.ext.sphinxext',
'sphinx.ext.intersphinx',
'sphinx.ext.graphviz',
'sphinxcontrib.httpdomain',
]

Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Contents:
overview
tutorial
standard/index
complaints
reference

Indices and tables
Expand Down

0 comments on commit cf31c12

Please sign in to comment.