diff --git a/src/openprocurement/tender/belowthreshold/tests/award.py b/src/openprocurement/tender/belowthreshold/tests/award.py index 5e4aff11f8..87ebb94e2c 100644 --- a/src/openprocurement/tender/belowthreshold/tests/award.py +++ b/src/openprocurement/tender/belowthreshold/tests/award.py @@ -64,6 +64,7 @@ # TenderAwardDocumentResourceTest not_found_award_document, create_tender_award_document, + put_tender_json_award_document_of_document, put_tender_award_document, patch_tender_award_document, create_award_document_bot, @@ -96,6 +97,7 @@ class TenderAwardDocumentResourceTestMixin(object): test_not_found_award_document = snitch(not_found_award_document) test_create_tender_award_document = snitch(create_tender_award_document) test_put_tender_award_document = snitch(put_tender_award_document) + test_put_tender_json_award_document_of_document = snitch(put_tender_json_award_document_of_document) test_patch_tender_award_document = snitch(patch_tender_award_document) test_create_award_document_bot = snitch(create_award_document_bot) test_patch_not_author = snitch(patch_not_author) diff --git a/src/openprocurement/tender/belowthreshold/tests/award_blanks.py b/src/openprocurement/tender/belowthreshold/tests/award_blanks.py index 2edb1ee75b..e4ff987c53 100644 --- a/src/openprocurement/tender/belowthreshold/tests/award_blanks.py +++ b/src/openprocurement/tender/belowthreshold/tests/award_blanks.py @@ -593,6 +593,42 @@ def create_tender_award_no_scale(self): self.assertNotIn("scale", response.json["data"]["suppliers"][0]) +def put_tender_json_award_document_of_document(self): + response = self.app.post( + "/tenders/{}/awards/{}/documents?acc_token={}".format(self.tender_id, self.award_id, self.tender_token), + upload_files=[("file", "name.doc", "content")], + ) + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + document_id = response.json["data"]["id"] + response = self.app.patch_json( + "/tenders/{}/awards/{}/documents/{}?acc_token={}".format(self.tender_id, self.award_id,document_id, self.tender_token), + {"data": { + "title": u"укр.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": "0"*32, + }}, status=422 + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + + u'relatedItem should be one of documents' + ] + } + ] + ) + + # TenderLotAwardResourceTest diff --git a/src/openprocurement/tender/belowthreshold/tests/base.py b/src/openprocurement/tender/belowthreshold/tests/base.py index c0718ba5b6..1fe9c37c0b 100644 --- a/src/openprocurement/tender/belowthreshold/tests/base.py +++ b/src/openprocurement/tender/belowthreshold/tests/base.py @@ -91,6 +91,26 @@ "procurementMethodType": "belowThreshold", "milestones": test_milestones, } + +test_tender_document_data = { + "url": "http://ds.prozorro.local/get/b97562e3f33c493297fd14dd6d8c50f0?KeyID=a8968c46&Signature=3OV7QC7f%2ByfcGTvpy0tf%2FaM%2BFRI6kkg1ImfEJlfAx5qi%2FLY7IIj7TFqtxgaPrzdd%2BWIOCe3O5Q7WhXkOdCB9CQ%3D%3D", + "documentType":"tenderNotice", + "title": "Notice.pdf", + "hash": "md5:00000000000000000000000000000000", + "format": "application/pdf" +} + +test_tender_full_document_data = { + "hash": "md5:00000000000000000000000000000000", + "author": "tender_owner", + "format": "application/msword", + "title": "tender_document.doc", + "documentOf": "tender", + "datePublished": "2020-04-23T14:31:34.217330+03:00", + "dateModified": "2020-04-23T14:31:34.217368+03:00", + "id": uuid4().hex +} + if SANDBOX_MODE: test_tender_data["procurementMethodDetails"] = "quick, accelerator=1440" test_features_tender_data = test_tender_data.copy() diff --git a/src/openprocurement/tender/belowthreshold/tests/contract.py b/src/openprocurement/tender/belowthreshold/tests/contract.py index f88314ff51..008cceb7b0 100644 --- a/src/openprocurement/tender/belowthreshold/tests/contract.py +++ b/src/openprocurement/tender/belowthreshold/tests/contract.py @@ -175,7 +175,8 @@ def setUp(self): class TenderContractDocumentResourceTest(TenderContentWebTest, TenderContractDocumentResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids - + docservice = True + def setUp(self): super(TenderContractDocumentResourceTest, self).setUp() # Create award @@ -218,6 +219,7 @@ class Tender2LotContractDocumentResourceTest(TenderContentWebTest): initial_status = "active.qualification" initial_bids = test_bids initial_lots = 2 * test_lots + docservice = True def setUp(self): super(Tender2LotContractDocumentResourceTest, self).setUp() diff --git a/src/openprocurement/tender/belowthreshold/tests/contract_blanks.py b/src/openprocurement/tender/belowthreshold/tests/contract_blanks.py index 28e2e419cc..ae0c7759a9 100644 --- a/src/openprocurement/tender/belowthreshold/tests/contract_blanks.py +++ b/src/openprocurement/tender/belowthreshold/tests/contract_blanks.py @@ -4,7 +4,7 @@ from copy import deepcopy from openprocurement.api.utils import get_now -from openprocurement.tender.belowthreshold.tests.base import test_claim, test_cancellation +from openprocurement.tender.belowthreshold.tests.base import test_claim, test_cancellation, test_tender_data, test_organization, test_tender_full_document_data from openprocurement.tender.core.tests.cancellation import activate_cancellation_after_2020_04_19 # TenderContractResourceTest @@ -1010,14 +1010,29 @@ def create_tender_contract_document(self): response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] ) - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 7) - self.assertEqual(response.body, "content") - + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 7) + self.assertEqual(response.body, "content") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") @@ -1046,6 +1061,7 @@ def create_tender_contract_document(self): ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") + self.assertEqual( response.json["errors"][0]["description"], "Can't add document in current ({}) tender status".format( @@ -1058,10 +1074,10 @@ def create_tender_contract_document_by_supplier(self): response = self.app.get("/tenders/{}/contracts/{}".format(self.tender_id, self.contract_id)) contract = response.json["data"] self.assertEqual(response.json["data"]["status"], "pending") + doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] - for bid in doc.get("bids", []): if bid["id"] == bid_id and bid["status"] == "pending": bid["status"] = "active" @@ -1070,76 +1086,215 @@ def create_tender_contract_document_by_supplier(self): i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"] if 'value' in doc['contracts'][0] and doc['contracts'][0]['value']['valueAddedTaxIncluded']: doc['contracts'][0]['value']['amountNet'] = str(float(doc['contracts'][0]['value']['amount']) - 1) + + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] self.db.save(doc) - # Supplier + #Tender owner response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], - status=403, + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.json["errors"], [{u'description': u"Supplier can't add document in current contract status", u'location': u'body', - u'name': u'data'}]) - + u'name': u'data'}]) # Tender owner response = self.app.patch_json( "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), {"data": {"status": "pending.winner-signing"}} ) self.assertEqual(response.status, "200 OK") - self.assertEqual(response.json["data"]["status"], "pending.winner-signing") + self.assertEqual(response.json["data"]["status"], "pending.winner-signing") # Supplier response = self.app.post( "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + upload_files=[("file", "contract_first_document.doc", "content")], + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add contract documents", + u'location': u'body', + u'name': u'data'}]) + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add tender documents", + u'location': u'body', + u'name': u'data'}]) + + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": "0"*32, + } + }, + status=422, + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + + u'relatedItem should be one of documents' + ] + } + ] + ) + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can add only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) - self.assertEqual("name.doc", response.json["data"]["title"]) - key = response.json["data"]["url"].split("?")[-1] - + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"]["title"]) + key = response.json["data"]["url"].split("/")[-1].split("?")[0] + response = self.app.get("/tenders/{}/contracts/{}/documents".format(self.tender_id, self.contract_id)) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") - self.assertEqual(doc_id, response.json["data"][0]["id"]) - self.assertEqual("name.doc", response.json["data"][0]["title"]) + self.assertEqual(doc_id, response.json["data"][-1]["id"]) + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"][-1]["title"]) response = self.app.get("/tenders/{}/contracts/{}/documents?all=true".format(self.tender_id, self.contract_id)) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") - self.assertEqual(doc_id, response.json["data"][0]["id"]) - self.assertEqual("name.doc", response.json["data"][0]["title"]) - - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), - status=404, - ) - self.assertEqual(response.status, "404 Not Found") - self.assertEqual(response.content_type, "application/json") - self.assertEqual(response.json["status"], "error") - self.assertEqual( - response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] - ) - - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 7) - self.assertEqual(response.body, "content") + self.assertEqual(doc_id, response.json["data"][-1]["id"]) + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"][-1]["title"]) + + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 7) + self.assertEqual(response.body, "content") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) - self.assertEqual("name.doc", response.json["data"]["title"]) + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"]["title"]) tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" @@ -1292,14 +1447,30 @@ def put_tender_contract_document(self): self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content2") + + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content2") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") @@ -1318,15 +1489,21 @@ def put_tender_contract_document(self): self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content3") - + + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content3") + tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" self.db.save(tender) @@ -1368,7 +1545,6 @@ def put_tender_contract_document_by_supplier(self): doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] - for bid in doc.get("bids", []): if bid["id"] == bid_id and bid["status"] == "pending": bid["status"] = "active" @@ -1377,12 +1553,36 @@ def put_tender_contract_document_by_supplier(self): i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"] if 'value' in doc['contracts'][0] and doc['contracts'][0]['value']['valueAddedTaxIncluded']: doc['contracts'][0]['value']['amountNet'] = str(float(doc['contracts'][0]['value']['amount']) - 1) + + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] self.db.save(doc) - # Supplier + #Tender owner response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, status=403 ) self.assertEqual(response.status, "403 Forbidden") @@ -1396,53 +1596,178 @@ def put_tender_contract_document_by_supplier(self): ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "pending.winner-signing") - + # Supplier - response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) + # Supplier response = self.app.put( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( - self.tender_id, self.contract_id, doc_id, bid_token - ), - status=404, - upload_files=[("invalid_name", "name.doc", "content")], + self.tender_id, self.contract_id, doc_id, bid_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=403, ) - self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update contract documents", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update tender documents", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can update only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": "0"*32, + } + }, + status=422, + ) + self.assertEqual(response.status, "422 Unprocessable Entity") self.assertEqual(response.content_type, "application/json") - self.assertEqual(response.json["status"], "error") - self.assertEqual(response.json["errors"], [{u"description": u"Not Found", u"location": u"body", u"name": u"file"}]) + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u'description': [u'relatedItem should be one of documents'] + } + ] + ) + # Supplier + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) - response = self.app.put( + response = self.app.put_json( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( - self.tender_id, self.contract_id, doc_id, bid_token - ), - upload_files=[("file", "name.doc", "content2")], + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=200 ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content2") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content2") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) - self.assertEqual("name.doc", response.json["data"]["title"]) + self.assertEqual("supplier_first_document_sign_updated.pkcs7", response.json["data"]["title"]) response = self.app.put( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( @@ -1450,19 +1775,39 @@ def put_tender_contract_document_by_supplier(self): ), "content3", content_type="application/msword", + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can update only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.put( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token + ), + "content3", + content_type="application/pkcs7-signature", ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content3") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/pkcs7-signature") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content3") tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" @@ -1480,14 +1825,22 @@ def put_tender_contract_document_by_supplier(self): self.assertEqual(response.json["errors"][0]["description"], "Supplier can't update document in current contract status") - self.set_status("{}".format(self.forbidden_contract_document_modification_actions_status)) - - response = self.app.put( + self.set_status(self.forbidden_document_modification_actions_status) + + response = self.app.put_json( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( - self.tender_id, self.contract_id, doc_id, bid_token - ), - upload_files=[("file", "name.doc", "content3")], - status=403, + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated1.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") @@ -1627,10 +1980,10 @@ def patch_tender_contract_document_by_supplier(self): response = self.app.get("/tenders/{}/contracts/{}".format(self.tender_id, self.contract_id)) contract = response.json["data"] self.assertEqual(response.json["data"]["status"], "pending") + doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] - for bid in doc.get("bids", []): if bid["id"] == bid_id and bid["status"] == "pending": bid["status"] = "active" @@ -1639,39 +1992,159 @@ def patch_tender_contract_document_by_supplier(self): i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"] if 'value' in doc['contracts'][0] and doc['contracts'][0]['value']['valueAddedTaxIncluded']: doc['contracts'][0]['value']['amountNet'] = str(float(doc['contracts'][0]['value']['amount']) - 1) + + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] self.db.save(doc) - + + #Tender owner response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, status=403 ) self.assertEqual(response.status, "403 Forbidden") - self.assertEqual(response.json["errors"][0]["description"], - "Supplier can't add document in current contract status") - + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add document in current contract status", + u'location': u'body', + u'name': u'data'}]) + + # Tender owner response = self.app.patch_json( "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), {"data": {"status": "pending.winner-signing"}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "pending.winner-signing") - - response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"]["title"]) + key = response.json["data"]["url"].split("/")[-1].split("?")[0] + # Supplier response = self.app.patch_json( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( self.tender_id, self.contract_id, doc_id, bid_token ), - {"data": {"description": "document description"}}, + {"data": {"format": "application/msword"}}, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can update only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "tender", + "relatedItem": self.tender_id + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update tender documents", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token + ), + {"data": {"relatedItem": "0"*32}}, + status=422, ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + u'relatedItem should be one of documents' + ] + } + ] + ) + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token + ), + {"data": {"description": "description"}}, + status=200 + ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) @@ -1680,7 +2153,7 @@ def patch_tender_contract_document_by_supplier(self): self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) - self.assertEqual("document description", response.json["data"]["description"]) + self.assertEqual("description", response.json["data"]["description"]) tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" @@ -1782,20 +2255,48 @@ def lot2_create_tender_contract_document_by_supplier(self): response = self.app.get("/tenders/{}/contracts/{}".format(self.tender_id, self.contract_id)) contract = response.json["data"] self.assertEqual(response.json["data"]["status"], "pending") + doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] - # Supplier + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] + self.db.save(doc) + + #Tender owner response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], - status=403 + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first1.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status = 403 ) self.assertEqual(response.status, "403 Forbidden") - self.assertEqual(response.json["errors"][0]["description"], - "Supplier can't add document in current contract status") - + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add document in current contract status", + u'location': u'body', + u'name': u'data'}]) + # Tender owner response = self.app.patch_json( "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), @@ -1803,18 +2304,129 @@ def lot2_create_tender_contract_document_by_supplier(self): ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "pending.winner-signing") - + # Supplier response = self.app.post( "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + upload_files=[("file", "contract_first_document.doc", "content")], + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add contract documents", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add tender documents", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": "0"*32, + } + }, + status=422, + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + + u'relatedItem should be one of documents' + ] + } + ] + ) + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can add only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) - self.assertEqual("name.doc", response.json["data"]["title"]) - key = response.json["data"]["url"].split("?")[-1] + self.assertEqual("supplier_first_document_sign.pkcs7", response.json["data"]["title"]) + key = response.json["data"]["url"].split("/")[-1].split("?")[0] cancellation = dict(**test_cancellation) cancellation.update({ @@ -1831,10 +2443,19 @@ def lot2_create_tender_contract_document_by_supplier(self): activate_cancellation_after_2020_04_19(self, response.json['data']['id']) # Supplier - response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], - status=403, + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") @@ -1966,14 +2587,39 @@ def lot2_put_tender_contract_document_by_supplier(self): response = self.app.get("/tenders/{}/contracts/{}".format(self.tender_id, self.contract_id)) contract = response.json["data"] self.assertEqual(response.json["data"]["status"], "pending") + doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] + + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] + self.db.save(doc) - # Supplier + #Tender owner response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, status=403 ) self.assertEqual(response.status, "403 Forbidden") @@ -1989,32 +2635,147 @@ def lot2_put_tender_contract_document_by_supplier(self): self.assertEqual(response.json["data"]["status"], "pending.winner-signing") # Supplier - response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) + # Supplier response = self.app.put( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( - self.tender_id, self.contract_id, doc_id, bid_token - ), - status=404, - upload_files=[("invalid_name", "name.doc", "content")], + self.tender_id, self.contract_id, doc_id, bid_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=403, ) - self.assertEqual(response.status, "404 Not Found") - self.assertEqual(response.content_type, "application/json") - self.assertEqual(response.json["status"], "error") - self.assertEqual(response.json["errors"], [{u"description": u"Not Found", u"location": u"body", u"name": u"file"}]) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update contract documents", + u'location': u'body', + u'name': u'data'}]) + + + # Supplier + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update tender documents", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) - response = self.app.put( + response = self.app.put_json( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( - self.tender_id, self.contract_id, doc_id, bid_token - ), - upload_files=[("file", "name.doc", "content2")], + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can update only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": "0"*32, + } + }, + status=422, + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + u'relatedItem should be one of documents' + ] + + } + ] + ) + + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=200 ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") @@ -2044,6 +2805,22 @@ def lot2_put_tender_contract_document_by_supplier(self): upload_files=[("file", "name.doc", "content3")], status=403, ) + response = self.app.put_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign_updated.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["errors"][0]["description"], "Can update document only in active lot status") @@ -2125,10 +2902,56 @@ def lot2_patch_tender_contract_document_by_supplier(self): response = self.app.get("/tenders/{}/contracts/{}".format(self.tender_id, self.contract_id)) contract = response.json["data"] self.assertEqual(response.json["data"]["status"], "pending") + doc = self.db.get(self.tender_id) bid_id = jmespath.search("awards[?id=='{}'].bid_id".format(contract["awardID"]), doc)[0] bid_token = jmespath.search("bids[?id=='{}'].owner_token".format(bid_id), doc)[0] + for bid in doc.get("bids", []): + if bid["id"] == bid_id and bid["status"] == "pending": + bid["status"] = "active" + for i in doc.get("awards", []): + if 'complaintPeriod' in i: + i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"] + if 'value' in doc['contracts'][0] and doc['contracts'][0]['value']['valueAddedTaxIncluded']: + doc['contracts'][0]['value']['amountNet'] = str(float(doc['contracts'][0]['value']['amount']) - 1) + + tender_document = deepcopy(test_tender_full_document_data) + tender_document["url"] = self.generate_docservice_url() + doc["documents"] = [tender_document] + tender_document_id = doc["documents"][0]["id"] + self.db.save(doc) + #Tender owner + response = self.app.post( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), + upload_files=[("file", "contract_first_document.doc", "content")], + status=201, + ) + contract_doc_id = response.json["data"]["id"] + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't add document in current contract status", + u'location': u'body', + u'name': u'data'}]) + # Tender owner response = self.app.patch_json( "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id, self.contract_id, self.tender_token), @@ -2136,23 +2959,135 @@ def lot2_patch_tender_contract_document_by_supplier(self): ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "pending.winner-signing") - - # Supplier - response = self.app.post( - "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), - upload_files=[("file", "name.doc", "content")], + + # Supplier + response = self.app.post_json( + "/tenders/{}/contracts/{}/documents?acc_token={}".format(self.tender_id, self.contract_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": contract_doc_id, + } + }, + status=201 ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") doc_id = response.json["data"]["id"] self.assertIn(doc_id, response.headers["Location"]) - + + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "tender", + "relatedItem": self.tender_id + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update tender documents", + u'location': u'body', + u'name': u'data'}]) + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.pkcs7", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/pkcs7-signature", + "documentOf": "document", + "relatedItem": tender_document_id, + } + }, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"relatedItem should be one of contract documents", + u'location': u'body', + u'name': u'data'}]) + # Supplier response = self.app.patch_json( "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( self.tender_id, self.contract_id, doc_id, bid_token ), - {"data": {"description": "document description"}}, + {"data": {"format": "application/msword"}}, + status=403 + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can update only 'application/pkcs7-signature' document format files", + u'location': u'body', + u'name': u'data'}]) + + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token + ), + {"data": {"relatedItem": "0"*32}}, + status=422, ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + u'relatedItem should be one of documents' + ] + } + ] + ) + + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token), + { + "data": { + "title": u"supplier_first_document_sign.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "tender", + "relatedItem": self.tender_id + } + }, + status=403, + ) + self.assertEqual(response.status, "403 Forbidden") + self.assertEqual(response.json["errors"], + [{u'description': u"Supplier can't update tender documents", + u'location': u'body', + u'name': u'data'}]) + # Supplier + response = self.app.patch_json( + "/tenders/{}/contracts/{}/documents/{}?acc_token={}".format( + self.tender_id, self.contract_id, doc_id, bid_token + ), + {"data": {"description": "document description"}}, + status=200 + ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) diff --git a/src/openprocurement/tender/belowthreshold/tests/document.py b/src/openprocurement/tender/belowthreshold/tests/document.py index 9f6960bae1..ace1991594 100644 --- a/src/openprocurement/tender/belowthreshold/tests/document.py +++ b/src/openprocurement/tender/belowthreshold/tests/document.py @@ -11,6 +11,7 @@ create_tender_document, put_tender_document, patch_tender_document, + put_tender_json_document_of_document, # TenderDocumentWithDSResourceTest create_tender_document_error, create_tender_document_json_invalid, @@ -33,6 +34,7 @@ class TenderDocumentWithDSResourceTestMixin(object): test_create_tender_document_json_invalid = snitch(create_tender_document_json_invalid) test_create_tender_document_json = snitch(create_tender_document_json) test_put_tender_document_json = snitch(put_tender_document_json) + test_put_tender_json_document_of_document = snitch(put_tender_json_document_of_document) class TenderDocumentResourceTest(TenderContentWebTest, TenderDocumentResourceTestMixin): diff --git a/src/openprocurement/tender/belowthreshold/tests/document_blanks.py b/src/openprocurement/tender/belowthreshold/tests/document_blanks.py index ae12c06efb..37c0e0ade2 100644 --- a/src/openprocurement/tender/belowthreshold/tests/document_blanks.py +++ b/src/openprocurement/tender/belowthreshold/tests/document_blanks.py @@ -3,7 +3,9 @@ # TenderDocumentResourceTest from mock import patch +from copy import deepcopy from openprocurement.tender.core.tests.base import bad_rs_request, srequest +from openprocurement.tender.belowthreshold.tests.base import test_tender_document_data def not_found(self): @@ -888,3 +890,60 @@ def lot_patch_tender_document_json_items_none(self): errors = {error["name"]: error["description"] for error in response.json["errors"]} self.assertEqual(errors["documents"][0], {"relatedItem": ["relatedItem should be one of items"]}) + + +def put_tender_json_document_of_document(self): + document_data = deepcopy(test_tender_document_data) + document_data["url"] = self.generate_docservice_url() + document_data["hash"] = "md5:" + "0" * 32 + document_data["documentType"] = "tenderNotice" + + response = self.app.post_json("/tenders/{}/documents?acc_token={}".format( + self.tender_id, self.tender_token),{"data":document_data}, status=201) + + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + document_id = response.json["data"]["id"] + + response = self.app.post_json( + "/tenders/{}/documents?acc_token={}".format(self.tender_id, self.tender_token), + { + "data": { + "title": u"укр.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": document_id, + } + }, + ) + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + + response = self.app.post_json( + "/tenders/{}/documents?acc_token={}".format(self.tender_id, self.tender_token), + {"data": { + "title": u"укр.doc", + "url": self.generate_docservice_url(), + "hash": "md5:" + "0" * 32, + "format": "application/msword", + "documentOf": "document", + "relatedItem": "0"*32, + }}, status=422 + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + + u'relatedItem should be one of documents' + ] + } + ] + ) \ No newline at end of file diff --git a/src/openprocurement/tender/belowthreshold/views/contract_document.py b/src/openprocurement/tender/belowthreshold/views/contract_document.py index 82d7aaccd9..eb486927b3 100644 --- a/src/openprocurement/tender/belowthreshold/views/contract_document.py +++ b/src/openprocurement/tender/belowthreshold/views/contract_document.py @@ -11,7 +11,11 @@ from openprocurement.api.validation import validate_file_update, validate_file_upload, validate_patch_document_data from openprocurement.tender.core.utils import save_tender, optendersresource, apply_patch -from openprocurement.tender.core.validation import validate_role_for_contract_document_operation +from openprocurement.tender.core.validation import ( + validate_role_for_contract_document_operation, + validate_relatedItem_for_contract_document_uploading, + validate_contract_supplier_role_for_contract_document_uploading, +) @optendersresource( @@ -64,13 +68,16 @@ def collection_get(self): return {"data": collection_data} @json_view(permission="upload_contract_documents", validators=(validate_file_upload, - validate_role_for_contract_document_operation,)) + validate_role_for_contract_document_operation, + validate_contract_supplier_role_for_contract_document_uploading, + validate_relatedItem_for_contract_document_uploading)) def collection_post(self): """Tender Contract Document Upload """ if not self.validate_contract_document("add"): return document = upload_file(self.request) + document.author = self.request.authenticated_role self.context.documents.append(document) if save_tender(self.request): self.LOGGER.info( @@ -98,9 +105,14 @@ def get(self): ] return {"data": document_data} - @json_view(validators=(validate_file_update, validate_role_for_contract_document_operation,), + @json_view(validators=(validate_file_update, + validate_role_for_contract_document_operation, + validate_contract_supplier_role_for_contract_document_uploading, + validate_relatedItem_for_contract_document_uploading, + ), permission="upload_contract_documents") def put(self): + """Tender Contract Document Update""" if not self.validate_contract_document("update"): return @@ -114,7 +126,11 @@ def put(self): return {"data": document.serialize("view")} @json_view(content_type="application/json", - validators=(validate_patch_document_data, validate_role_for_contract_document_operation,), + validators=(validate_patch_document_data, + validate_role_for_contract_document_operation, + validate_contract_supplier_role_for_contract_document_uploading, + validate_relatedItem_for_contract_document_uploading, + ), permission="upload_contract_documents") def patch(self): """Tender Contract Document Update""" diff --git a/src/openprocurement/tender/cfaselectionua/models/submodels/contract.py b/src/openprocurement/tender/cfaselectionua/models/submodels/contract.py index 9e5f9f3663..78cd0318a3 100644 --- a/src/openprocurement/tender/cfaselectionua/models/submodels/contract.py +++ b/src/openprocurement/tender/cfaselectionua/models/submodels/contract.py @@ -1,12 +1,28 @@ # -*- coding: utf-8 -*- +import jmespath from openprocurement.api.roles import RolesFromCsv from schematics.exceptions import ValidationError from schematics.types.compound import ModelType from schematics.types import StringType from openprocurement.tender.core.models import ContractValue -from openprocurement.tender.core.utils import get_contract_supplier_roles, get_contract_supplier_permissions +from openprocurement.tender.core.utils import get_contract_supplier_roles, get_contract_supplier_permissions, flatten_multidimensional_list, get_all_nested_from_the_object from openprocurement.api.utils import get_now from openprocurement.api.models import Model, ListType, Contract as BaseContract, Document +from openprocurement.tender.core.models import get_tender + + +class ContractDocument(Document): + documentOf = StringType(required=True, choices=["tender","document"], default="tender") + + def validate_relatedItem(self, data, relatedItem): + if not relatedItem and data.get("documentOf") in ["document"]: + raise ValidationError(u"This field is required.") + parent = data["__parent__"] + tender = get_tender(parent) + if data.get("documentOf") == "document": + documents = get_all_nested_from_the_object("documents",tender) + get_all_nested_from_the_object("documents",parent) + if relatedItem not in [i.id for i in documents]: + raise ValidationError(u"relatedItem should be one of documents") class Contract(BaseContract): @@ -15,7 +31,7 @@ class Options: value = ModelType(ContractValue) awardID = StringType(required=True) - documents = ListType(ModelType(Document, required=True), default=list()) + documents = ListType(ModelType(ContractDocument, required=True), default=list()) def __acl__(self): return get_contract_supplier_permissions(self) diff --git a/src/openprocurement/tender/cfaselectionua/tests/award.py b/src/openprocurement/tender/cfaselectionua/tests/award.py index 094debba84..23d5bef734 100644 --- a/src/openprocurement/tender/cfaselectionua/tests/award.py +++ b/src/openprocurement/tender/cfaselectionua/tests/award.py @@ -3,7 +3,10 @@ from copy import deepcopy from openprocurement.api.tests.base import snitch -from openprocurement.tender.belowthreshold.tests.award_blanks import patch_tender_lot_award_lots_none +from openprocurement.tender.belowthreshold.tests.award_blanks import ( + patch_tender_lot_award_lots_none, + put_tender_json_award_document_of_document, +) from openprocurement.tender.cfaselectionua.adapters.configurator import TenderCfaSelectionUAConfigurator from openprocurement.tender.cfaselectionua.tests.base import ( TenderContentWebTest, @@ -53,6 +56,7 @@ class TenderAwardResourceTestMixin(object): class TenderAwardDocumentResourceTestMixin(object): test_not_found_award_document = snitch(not_found_award_document) test_create_tender_award_document = snitch(create_tender_award_document) + test_put_tender_json_award_document_of_document = snitch(put_tender_json_award_document_of_document) test_put_tender_award_document = snitch(put_tender_award_document) test_patch_tender_award_document = snitch(patch_tender_award_document) test_create_award_document_bot = snitch(create_award_document_bot) diff --git a/src/openprocurement/tender/cfaselectionua/tests/contract.py b/src/openprocurement/tender/cfaselectionua/tests/contract.py index 80e5f23d75..7152c0f9c4 100644 --- a/src/openprocurement/tender/cfaselectionua/tests/contract.py +++ b/src/openprocurement/tender/cfaselectionua/tests/contract.py @@ -143,7 +143,8 @@ class TenderContractDocumentResourceTest(TenderContentWebTest, TenderContractDoc initial_status = "active.awarded" initial_bids = test_bids initial_lots = test_lots - + docservice = True + test_create_tender_contract_document_by_supplier = snitch(create_tender_contract_document_by_supplier) test_create_tender_contract_document_by_others = snitch(create_tender_contract_document_by_others) test_put_tender_contract_document_by_supplier = snitch(put_tender_contract_document_by_supplier) diff --git a/src/openprocurement/tender/cfaselectionua/tests/contract_blanks.py b/src/openprocurement/tender/cfaselectionua/tests/contract_blanks.py index f984ed3f5c..8abaf48329 100644 --- a/src/openprocurement/tender/cfaselectionua/tests/contract_blanks.py +++ b/src/openprocurement/tender/cfaselectionua/tests/contract_blanks.py @@ -642,13 +642,31 @@ def create_tender_contract_document(self): response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] ) - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 7) - self.assertEqual(response.body, "content") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 7) + self.assertEqual(response.body, "content") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") @@ -752,13 +770,31 @@ def put_tender_contract_document(self): self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content2") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content2") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") @@ -778,13 +814,31 @@ def put_tender_contract_document(self): self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content3") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content3") tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" diff --git a/src/openprocurement/tender/cfaselectionua/tests/document.py b/src/openprocurement/tender/cfaselectionua/tests/document.py index d247628e5e..2dba08efff 100644 --- a/src/openprocurement/tender/cfaselectionua/tests/document.py +++ b/src/openprocurement/tender/cfaselectionua/tests/document.py @@ -10,6 +10,7 @@ create_tender_document_json_invalid, create_tender_document_json, put_tender_document_json, + put_tender_json_document_of_document, ) from openprocurement.tender.cfaselectionua.tests.document_blanks import ( @@ -34,6 +35,7 @@ class TenderDocumentWithDSResourceTestMixin(object): test_create_tender_document_json_invalid = snitch(create_tender_document_json_invalid) test_create_tender_document_json = snitch(create_tender_document_json) test_put_tender_document_json = snitch(put_tender_document_json) + test_put_tender_json_document_of_document = snitch(put_tender_json_document_of_document) class TenderDocumentResourceTest(TenderContentWebTest, TenderDocumentResourceTestMixin): diff --git a/src/openprocurement/tender/cfaselectionua/views/contract_document.py b/src/openprocurement/tender/cfaselectionua/views/contract_document.py index ff14b3c0e6..a4a26b977f 100644 --- a/src/openprocurement/tender/cfaselectionua/views/contract_document.py +++ b/src/openprocurement/tender/cfaselectionua/views/contract_document.py @@ -11,7 +11,11 @@ from openprocurement.api.validation import validate_file_update, validate_file_upload, validate_patch_document_data from openprocurement.tender.core.utils import save_tender, optendersresource, apply_patch -from openprocurement.tender.core.validation import validate_role_for_contract_document_operation +from openprocurement.tender.core.validation import( + validate_role_for_contract_document_operation, + validate_relatedItem_for_contract_document_uploading, + validate_contract_supplier_role_for_contract_document_uploading, +) @optendersresource( @@ -64,7 +68,9 @@ def collection_get(self): return {"data": collection_data} @json_view(permission="upload_contract_documents", validators=(validate_file_upload, - validate_role_for_contract_document_operation,)) + validate_role_for_contract_document_operation, + validate_relatedItem_for_contract_document_uploading, + validate_contract_supplier_role_for_contract_document_uploading,)) def collection_post(self): """Tender Contract Document Upload """ @@ -98,8 +104,11 @@ def get(self): ] return {"data": document_data} - @json_view(validators=(validate_file_update, validate_role_for_contract_document_operation,), - permission="upload_contract_documents") + @json_view(permission="upload_contract_documents", validators=(validate_file_update, + validate_role_for_contract_document_operation, + validate_relatedItem_for_contract_document_uploading, + validate_contract_supplier_role_for_contract_document_uploading, + )) def put(self): """Tender Contract Document Update""" if not self.validate_contract_document("update"): @@ -114,8 +123,12 @@ def put(self): return {"data": document.serialize("view")} @json_view(content_type="application/json", - validators=(validate_patch_document_data, validate_role_for_contract_document_operation,), - permission="upload_contract_documents") + permission="upload_contract_documents", + validators=(validate_patch_document_data, + validate_role_for_contract_document_operation, + validate_relatedItem_for_contract_document_uploading, + validate_contract_supplier_role_for_contract_document_uploading, + )) def patch(self): """Tender Contract Document Update""" if not self.validate_contract_document("update"): diff --git a/src/openprocurement/tender/competitivedialogue/tests/stage1/document.py b/src/openprocurement/tender/competitivedialogue/tests/stage1/document.py index 1845a6349f..cd99fb31b8 100644 --- a/src/openprocurement/tender/competitivedialogue/tests/stage1/document.py +++ b/src/openprocurement/tender/competitivedialogue/tests/stage1/document.py @@ -12,6 +12,7 @@ from openprocurement.tender.competitivedialogue.tests.stage1.document_blanks import ( put_tender_document, patch_tender_document, + put_tender_json_document_of_document, ) # _____________________________________________________________________ @@ -61,7 +62,7 @@ class DialogUADocumentResourceTest(BaseCompetitiveDialogUAContentWebTest, Tender test_put_tender_document = snitch(put_tender_document) test_patch_tender_document = snitch(patch_tender_document) - + test_put_tender_json_document_of_document =snitch(put_tender_json_document_of_document) class DialogUADocumentWithDSResourceTest(DialogUADocumentResourceTest): docservice = True diff --git a/src/openprocurement/tender/competitivedialogue/tests/stage1/document_blanks.py b/src/openprocurement/tender/competitivedialogue/tests/stage1/document_blanks.py index 0d21682b24..1ca8ab6e4c 100644 --- a/src/openprocurement/tender/competitivedialogue/tests/stage1/document_blanks.py +++ b/src/openprocurement/tender/competitivedialogue/tests/stage1/document_blanks.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from email.header import Header +from openprocurement.tender.belowthreshold.tests.base import test_tender_document_data # DialogEUDocumentResourceTest @@ -244,3 +245,51 @@ def patch_tender_document(self): self.assertEqual(response.content_type, "application/json") self.assertEqual(doc_id, response.json["data"]["id"]) self.assertEqual("document description", response.json["data"]["description"]) + + +def put_tender_json_document_of_document(self): + response = self.app.post( + "/tenders/{}/documents?acc_token={}".format(self.tender_id, self.tender_token), + upload_files=[("file", str(Header(u"укр.doc", "utf-8")), "content")], + ) + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + old_doc_id = response.json["data"]["id"] + + response = self.app.post( + "/tenders/{}/documents?acc_token={}".format(self.tender_id, self.tender_token), + upload_files=[("file", str(Header(u"укр.doc", "utf-8")), "content")], + ) + self.assertEqual(response.status, "201 Created") + self.assertEqual(response.content_type, "application/json") + doc_id = response.json["data"]["id"] + self.assertIn(doc_id, response.headers["Location"]) + self.assertEqual(u"укр.doc", response.json["data"]["title"]) + + response = self.app.patch_json( + "/tenders/{}/documents/{}?acc_token={}".format(self.tender_id, doc_id, self.tender_token), + {"data": {"documentOf": "document", "relatedItem": doc_id}}, + status=200, + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/json") + response = self.app.patch_json( + "/tenders/{}/documents/{}?acc_token={}".format(self.tender_id, doc_id, self.tender_token), + {"data": {"documentOf": "document", "relatedItem": "0"*32,}}, + status=422, + ) + self.assertEqual(response.status, "422 Unprocessable Entity") + self.assertEqual(response.content_type, "application/json") + self.assertEqual( + response.json["errors"], + [ + { + u"location": u"body", + u"name": u"relatedItem", + u"description": [ + + u'relatedItem should be one of documents' + ] + } + ] + ) diff --git a/src/openprocurement/tender/competitivedialogue/tests/stage2/contract.py b/src/openprocurement/tender/competitivedialogue/tests/stage2/contract.py index 91ced82f82..fd2dd93367 100644 --- a/src/openprocurement/tender/competitivedialogue/tests/stage2/contract.py +++ b/src/openprocurement/tender/competitivedialogue/tests/stage2/contract.py @@ -52,6 +52,7 @@ class TenderStage2EUContractResourceTest(BaseCompetitiveDialogEUStage2ContentWeb initial_bids = test_tender_bids initial_auth = ("Basic", ("broker", "")) author_data = test_author + docservice = True def setUp(self): super(TenderStage2EUContractResourceTest, self).setUp() @@ -97,6 +98,7 @@ class TenderStage2EUContractDocumentResourceTest( initial_status = "active.qualification" initial_bids = test_tender_bids initial_auth = ("Basic", ("broker", "")) + docservice = True def setUp(self): super(TenderStage2EUContractDocumentResourceTest, self).setUp() @@ -132,6 +134,7 @@ def setUp(self): class TenderStage2UAContractResourceTest(BaseCompetitiveDialogUAStage2ContentWebTest): initial_status = "active.qualification" initial_bids = test_tender_bids + docservice = True def setUp(self): super(TenderStage2UAContractResourceTest, self).setUp() @@ -172,6 +175,7 @@ def setUp(self): class TenderContractVATNotIncludedResourceTest(BaseCompetitiveDialogUAStage2ContentWebTest): initial_status = "active.qualification" initial_bids = test_tender_bids + docservice = True def create_award(self): auth = self.app.authorization @@ -213,7 +217,8 @@ class TenderStage2UAContractDocumentResourceTest( ): initial_status = "active.qualification" initial_bids = test_tender_bids - + docservice = True + def setUp(self): super(TenderStage2UAContractDocumentResourceTest, self).setUp() # Create award diff --git a/src/openprocurement/tender/competitivedialogue/tests/stage2/document.py b/src/openprocurement/tender/competitivedialogue/tests/stage2/document.py index c808b634a3..f0184fded9 100644 --- a/src/openprocurement/tender/competitivedialogue/tests/stage2/document.py +++ b/src/openprocurement/tender/competitivedialogue/tests/stage2/document.py @@ -12,6 +12,7 @@ from openprocurement.tender.competitivedialogue.tests.stage1.document_blanks import ( put_tender_document, patch_tender_document, + put_tender_json_document_of_document, ) # _____________________________________________________________________ @@ -49,7 +50,6 @@ class TenderStage2EUDocumentResourceTest(BaseCompetitiveDialogEUStage2ContentWeb test_put_tender_document = snitch(put_tender_document) test_patch_tender_document = snitch(patch_tender_document) - class TenderStage2DocumentWithDSResourceTest(TenderStage2EUDocumentResourceTest, TenderDocumentResourceTestMixin): docservice = True @@ -65,7 +65,7 @@ class TenderStage2UADocumentResourceTest(BaseCompetitiveDialogUAStage2ContentWeb test_put_tender_document = snitch(put_tender_document) test_patch_tender_document = snitch(patch_tender_document) - + test_put_tender_json_document_of_document = snitch(put_tender_json_document_of_document) class TenderStage2UADocumentWithDSResourceTest(TenderStage2UADocumentResourceTest, TenderDocumentResourceTestMixin): docservice = True diff --git a/src/openprocurement/tender/core/models.py b/src/openprocurement/tender/core/models.py index 778afdb2b1..b947ec084a 100644 --- a/src/openprocurement/tender/core/models.py +++ b/src/openprocurement/tender/core/models.py @@ -56,10 +56,13 @@ COMPLAINT_ENHANCED_AMOUNT_RATE, COMPLAINT_ENHANCED_MIN_AMOUNT, COMPLAINT_ENHANCED_MAX_AMOUNT, ) from openprocurement.tender.core.utils import ( - calc_auction_end_time, rounding_shouldStartAfter, - restrict_value_to_bounds, round_up_to_ten, - get_contract_supplier_roles, get_contract_supplier_permissions, - calculate_tender_business_date, + calc_auction_end_time, + rounding_shouldStartAfter, + restrict_value_to_bounds, + round_up_to_ten, + get_contract_supplier_roles, + get_contract_supplier_permissions, + get_all_nested_from_the_object, ) from openprocurement.tender.core.validation import ( validate_lotvalue_value, @@ -158,10 +161,12 @@ def export_loop(self, model_instance, field_converter, role=None, print_none=Fal class Document(BaseDocument): - documentOf = StringType(required=True, choices=["tender", "item", "lot"], default="tender") + documentOf = StringType(required=True, choices=[ + "tender", "item", "lot", "document"], default="tender") + def validate_relatedItem(self, data, relatedItem): - if not relatedItem and data.get("documentOf") in ["item", "lot"]: + if not relatedItem and data.get("documentOf") in ["item", "lot", "document"]: raise ValidationError(u"This field is required.") parent = data["__parent__"] if relatedItem and isinstance(parent, Model): @@ -170,6 +175,10 @@ def validate_relatedItem(self, data, relatedItem): raise ValidationError(u"relatedItem should be one of lots") if data.get("documentOf") == "item" and relatedItem not in [i.id for i in tender.items if i]: raise ValidationError(u"relatedItem should be one of items") + if data.get("documentOf") == "document": + documents = get_all_nested_from_the_object("documents",tender) + get_all_nested_from_the_object("documents",parent) + if relatedItem not in [i.id for i in documents]: + raise ValidationError(u"relatedItem should be one of documents") class ConfidentialDocumentModelType(ModelType): diff --git a/src/openprocurement/tender/core/utils.py b/src/openprocurement/tender/core/utils.py index 1f1b632afc..f4bd25aa79 100644 --- a/src/openprocurement/tender/core/utils.py +++ b/src/openprocurement/tender/core/utils.py @@ -599,3 +599,20 @@ def get_contract_supplier_roles(contract): bid_data = jmespath.search("bids[?id=='{}'].[owner,owner_token]".format(bid_id), contract.__parent__)[0] roles['_'.join(bid_data)] = 'contract_supplier' return roles + + +def flatten_multidimensional_list(list_to_flatten): + for element in list_to_flatten: + if isinstance(element,(list, tuple)): + for x in flatten_multidimensional_list(element): + yield x + else: + yield element + + +def get_all_nested_from_the_object(objects_to_find, obj): + nested_regex = ["", "*.", "*[*]."] + search_query = ' || '.join([item + objects_to_find for item in nested_regex]) + nested_objects = jmespath.search(search_query, obj) + nested_objects = list(flatten_multidimensional_list(nested_objects)) + return nested_objects \ No newline at end of file diff --git a/src/openprocurement/tender/core/validation.py b/src/openprocurement/tender/core/validation.py index 71b1e76aa2..971deaf594 100644 --- a/src/openprocurement/tender/core/validation.py +++ b/src/openprocurement/tender/core/validation.py @@ -1587,3 +1587,44 @@ def validate_role_for_contract_document_operation(request): raise_operation_error( request, "Tender onwer can't {} document in current contract status".format(OPERATIONS.get(request.method)) ) + + +def validate_contract_supplier_role_for_contract_document_uploading(request): + if request.authenticated_role in ("contract_supplier"): + if 'file' in request.validated: + raise_operation_error( + request, "Supplier can't {} contract documents".format( + OPERATIONS.get(request.method)) + ) + elif "data" in request.validated: + data = request.validated["data"] + if data["documentOf"] == "document": + if data["format"] != "application/pkcs7-signature": + raise_operation_error( + request, "Supplier can {} only 'application/pkcs7-signature' document format files".format( + OPERATIONS.get(request.method)) + ) + else: + raise_operation_error( + request, "Supplier can't {} {} documents".format( + OPERATIONS.get(request.method), data["documentOf"]) + ) + elif request.content_type != "application/pkcs7-signature": + raise_operation_error( + request, "Supplier can {} only 'application/pkcs7-signature' document format files".format( + OPERATIONS.get(request.method)) + ) + + +def validate_relatedItem_for_contract_document_uploading(request): + if "data" in request.validated: + data = request.validated["data"] + parent = data["__parent__"] + documents = [] + if hasattr(parent, "documents"): + documents = parent.documents + elif hasattr(parent["__parent__"], "documents"): + documents = parent["__parent__"].documents + if data.get("documentOf") == "document" and data.get('relatedItem') not in [i.id for i in documents]: + raise_operation_error( + request, "relatedItem should be one of contract documents") diff --git a/src/openprocurement/tender/esco/tests/contract.py b/src/openprocurement/tender/esco/tests/contract.py index a680e5edb4..3affe20b35 100644 --- a/src/openprocurement/tender/esco/tests/contract.py +++ b/src/openprocurement/tender/esco/tests/contract.py @@ -121,7 +121,8 @@ class TenderContractDocumentResourceTest(BaseESCOContentWebTest, TenderContractD initial_status = "active.qualification" initial_bids = test_bids initial_auth = ("Basic", ("broker", "")) - + docservice = True + def setUp(self): super(TenderContractDocumentResourceTest, self).setUp() # Create award diff --git a/src/openprocurement/tender/limited/tests/contract.py b/src/openprocurement/tender/limited/tests/contract.py index 1a54565143..9633c4d4dd 100644 --- a/src/openprocurement/tender/limited/tests/contract.py +++ b/src/openprocurement/tender/limited/tests/contract.py @@ -50,7 +50,8 @@ class TenderContractResourceTest(BaseTenderContentWebTest, TenderContractResourc initial_status = "active" initial_data = test_tender_data initial_bids = None # test_bids - + docservice = True + def create_award(self): # Create award response = self.app.post_json( @@ -364,6 +365,7 @@ class TenderNegotiationAccelerationTest(TenderNegotiationQuickAccelerationTest): class TenderContractDocumentResourceTest(BaseTenderContentWebTest, TenderContractDocumentResourceTestMixin): initial_status = "active" initial_bids = None + docservice = True def create_award(self): # Create award diff --git a/src/openprocurement/tender/limited/tests/contract_blanks.py b/src/openprocurement/tender/limited/tests/contract_blanks.py index 8fd8852846..d9a03ffbe5 100644 --- a/src/openprocurement/tender/limited/tests/contract_blanks.py +++ b/src/openprocurement/tender/limited/tests/contract_blanks.py @@ -955,13 +955,35 @@ def create_tender_contract_document(self): response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] ) - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id)) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 7) + self.assertEqual(response.body, "content") + + response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 7) - self.assertEqual(response.body, "content") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(doc_id, response.json["data"]["id"]) + self.assertEqual("name.doc", response.json["data"]["title"]) response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") @@ -1032,13 +1054,31 @@ def put_tender_contract_document(self): self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content2") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content2") response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id)) self.assertEqual(response.status, "200 OK") @@ -1058,13 +1098,31 @@ def put_tender_contract_document(self): self.assertEqual(doc_id, response.json["data"]["id"]) key = response.json["data"]["url"].split("?")[-1] - response = self.app.get( - "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) - ) - self.assertEqual(response.status, "200 OK") - self.assertEqual(response.content_type, "application/msword") - self.assertEqual(response.content_length, 8) - self.assertEqual(response.body, "content3") + if self.docservice: + response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key)) + self.assertEqual(response.status, "302 Moved Temporarily") + self.assertIn("http://localhost/get/", response.location) + self.assertIn("Signature=", response.location) + self.assertIn("KeyID=", response.location) + self.assertNotIn("Expires=", response.location) + else: + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id), + status=404, + ) + self.assertEqual(response.status, "404 Not Found") + self.assertEqual(response.content_type, "application/json") + self.assertEqual(response.json["status"], "error") + self.assertEqual( + response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}] + ) + response = self.app.get( + "/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key) + ) + self.assertEqual(response.status, "200 OK") + self.assertEqual(response.content_type, "application/msword") + self.assertEqual(response.content_length, 8) + self.assertEqual(response.body, "content3") tender = self.db.get(self.tender_id) tender["contracts"][-1]["status"] = "cancelled" diff --git a/src/openprocurement/tender/openeu/tests/contract.py b/src/openprocurement/tender/openeu/tests/contract.py index 40650d08d9..d719b7b454 100644 --- a/src/openprocurement/tender/openeu/tests/contract.py +++ b/src/openprocurement/tender/openeu/tests/contract.py @@ -82,7 +82,8 @@ class TenderContractDocumentResourceTest(BaseTenderContentWebTest, TenderContrac initial_status = "active.qualification" initial_bids = test_bids initial_auth = ("Basic", ("broker", "")) - + docservice = True + def setUp(self): super(TenderContractDocumentResourceTest, self).setUp() # Create award diff --git a/src/openprocurement/tender/openua/tests/contract.py b/src/openprocurement/tender/openua/tests/contract.py index 2d54dcc3f9..26e88264d1 100644 --- a/src/openprocurement/tender/openua/tests/contract.py +++ b/src/openprocurement/tender/openua/tests/contract.py @@ -71,7 +71,7 @@ def setUp(self): class TenderContractVATNotIncludedResourceTest(BaseTenderUAContentWebTest, TenderContractResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids - + docservice = True def create_award(self): auth = self.app.authorization self.app.authorization = ("Basic", ("token", "")) @@ -111,7 +111,8 @@ def setUp(self): class TenderContractDocumentResourceTest(BaseTenderUAContentWebTest, TenderContractDocumentResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids - + docservice = True + def setUp(self): super(TenderContractDocumentResourceTest, self).setUp() # Create award @@ -142,7 +143,6 @@ def setUp(self): test_put_tender_contract_document_by_others = snitch(put_tender_contract_document_by_others) test_patch_tender_contract_document_by_supplier = snitch(patch_tender_contract_document_by_supplier) - def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TenderContractResourceTest)) diff --git a/src/openprocurement/tender/openuadefense/tests/contract.py b/src/openprocurement/tender/openuadefense/tests/contract.py index 60826cf057..899eb25ac0 100644 --- a/src/openprocurement/tender/openuadefense/tests/contract.py +++ b/src/openprocurement/tender/openuadefense/tests/contract.py @@ -35,6 +35,7 @@ class TenderContractResourceTest(BaseTenderUAContentWebTest, TenderContractResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids + docservice = True def setUp(self): super(TenderContractResourceTest, self).setUp() @@ -72,6 +73,7 @@ def setUp(self): class TenderContractVATNotIncludedResourceTest(BaseTenderUAContentWebTest, TenderContractResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids + docservice = True def create_award(self): authorization = self.app.authorization @@ -113,7 +115,8 @@ def setUp(self): class TenderContractDocumentResourceTest(BaseTenderUAContentWebTest, TenderContractDocumentResourceTestMixin): initial_status = "active.qualification" initial_bids = test_bids - + docservice = True + def setUp(self): super(TenderContractDocumentResourceTest, self).setUp() # Create award