def validate_operation_submission_in_not_allowed_period(request, **kwargs): framework = request.validated["framework"] enquiryPeriod = framework.get("enquiryPeriod") operation = OPERATIONS.get(request.method) period = framework.get("period") if ( not enquiryPeriod or "endDate" not in enquiryPeriod or not period or "endDate" not in period ): raise_operation_error( request, "Submission cannot be {} without framework enquiryPeriod or period".format(operation) ) enquiryPeriod_endDate = parse_date(enquiryPeriod["endDate"]) period_endDate = parse_date(period["endDate"]) now = get_now() if now < enquiryPeriod_endDate or now > period_endDate: raise_operation_error( request, "Submission can be {} only during the period: from ({}) to ({}).".format( operation, enquiryPeriod_endDate, period_endDate), )
def validate_agreement_signing(request, **kwargs): tender = request.validated["tender"] data = request.validated["data"] config = getAdapter(tender, IContentConfigurator) if request.context.status != "active" and "status" in data and data[ "status"] == "active": if "period" not in data or not data["period"]: raise_operation_error(request, "Period is required for agreement signing.") if not data["period"]["startDate"] or not data["period"]["endDate"]: raise_operation_error( request, "startDate and endDate are required in agreement.period.") agreement_start_date = parse_date(data["period"]["startDate"]) agreement_end_date = parse_date(data["period"]["endDate"]) calculated_end_date = agreement_start_date + config.max_agreement_period if calculated_end_date < agreement_end_date: raise_operation_error( request, "Agreement period can't be greater than {}.".format( duration_isoformat(config.max_agreement_period)), ) awards = [ a for a in tender.awards if a.id in request.context.get_awards_id() ] lots_id = set([a.lotID for a in awards] + [None]) pending_complaints = [ i for i in tender.complaints if i.status in tender.block_complaint_status and i.relatedLot in lots_id ] pending_awards_complaints = [ i for a in tender.awards for i in a.complaints if i.status in tender.block_complaint_status and a.lotID in lots_id ] if pending_complaints or pending_awards_complaints: raise_operation_error( request, "Can't sign agreement before reviewing all complaints") empty_unitprices = [] active_contracts = [] for contract in request.context.contracts: if contract.status == "active": active_contracts.append(contract.id) for unit_price in contract.unitPrices: empty_unitprices.append(unit_price.value.amount is None) if any(empty_unitprices): raise_operation_error( request, "Can't sign agreement without all contracts.unitPrices.value.amount" ) if len(active_contracts) < config.min_bids_number: raise_operation_error( request, "Agreement don't reach minimum active contracts.")
def test_tender_award_complaint_period(self, name, date_str, mock_normalized_date_str, mock_midnight_date_str, expected_date_str, expected_sb_date_str): tender_award_complaint_period( self, parse_date(date_str), parse_date(mock_normalized_date_str), parse_date(mock_midnight_date_str), parse_date(expected_date_str), parse_date(expected_sb_date_str), )
def next_check_value_with_unanswered_question(self): response = self.app.post_json( "/tenders/{}/questions".format(self.tender_id), { "data": { "title": "question title", "description": "question description", "questionOf": "lot", "relatedItem": self.initial_lots[0]["id"], "author": test_author, } }, ) question = response.json["data"] self.assertEqual(question["questionOf"], "lot") self.assertEqual(question["relatedItem"], self.initial_lots[0]["id"]) self.set_status("active.auction", extra={"status": "active.tendering"}) response = self.check_chronograph() self.assertEqual(response.json["data"]["status"], "active.tendering") self.assertNotIn("next_check", response.json["data"]) cancellation = dict(**test_cancellation) cancellation.update({ "status": "active", "cancellationOf": "lot", "relatedLot": self.initial_lots[0]["id"], }) response = self.app.post_json( "/tenders/{}/cancellations?acc_token={}".format( self.tender_id, self.tender_token), {"data": cancellation}, ) cancellation_id = response.json["data"]["id"] if RELEASE_2020_04_19 < get_now(): activate_cancellation_with_complaints_after_2020_04_19( self, cancellation_id) else: response = self.app.get("/tenders/{}".format(self.tender_id)) self.assertIn("next_check", response.json["data"]) self.assertEqual( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"])) response = self.check_chronograph() self.assertEqual(response.json["data"]["status"], "active.auction") self.assertIn("next_check", response.json["data"]) self.assertGreater( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"]))
def recalculate_tender_periods(self): tender = self.request.validated["tender"] cancellation = self.request.validated["cancellation"] tenderer_action_date = self.context.tendererActionDate enquiry_period = tender.enquiryPeriod complaint_period = tender.complaintPeriod tender_period = tender.tenderPeriod auction_period = tender.auctionPeriod date = cancellation.complaintPeriod.startDate diff = calculate_date_diff(tenderer_action_date, date) delta = diff.days delta_plus = 1 if diff.seconds > 3599 else 0 delta += delta_plus delta = timedelta(days=1 if not delta else delta) if tender.status == "active.tendering" and tender.enquiryPeriod: if enquiry_period.startDate < date <= tender_period.endDate: enquiry_period.endDate = calculate_tender_business_date( enquiry_period.endDate, delta, tender, True) enquiry_period.clarificationsUntil = calculate_tender_business_date( enquiry_period.clarificationsUntil, delta, tender, True) tender_period.endDate = calculate_tender_business_date( tender_period.endDate, delta, tender, True) complaint_period.endDate = calculate_tender_business_date( complaint_period.endDate, delta, tender, True) if auction_period.shouldStartAfter: auction_period.shouldStartAfter = calculate_tender_business_date( parse_date(auction_period.shouldStartAfter), delta, tender, True).isoformat() if auction_period.startDate: auction_period.startDate = calculate_tender_business_date( auction_period.startDate, delta, tender, True) elif auction_period and tender_period.endDate and auction_period.shouldStartAfter\ and tender_period.endDate < date <= parse_date(auction_period.shouldStartAfter): auction_period.shouldStartAfter = calculate_tender_business_date( auction_period.shouldStartAfter, delta, tender, True) auction_period.startDate = calculate_tender_business_date( auction_period.startDate, delta, tender, True)
def get_version_from_date(request, doc, revisions): version_date = parse_date(request.headers.get(VERSION_BY_DATE, pytz.utc)) if version_date > parse_date( doc["dateModified"]) or version_date < parse_date( revisions[1]["date"]): return return404(request, "header", "version") for version, revision in reversed(list(enumerate(revisions))): doc = get_valid_apply_patch_doc(doc, request, revision) if version_date < parse_date(find_dateModified(revisions[:version])): continue else: doc["dateModified"] = find_dateModified(revisions[:version + 1]) return (doc, parse_hash(revision["rev"]), parse_hash(revisions[version - 1].get("rev", ""))) return404(request, "header", "version")
def next_check_value_with_unanswered_claim(self): claim = deepcopy(test_claim) claim["relatedLot"] = self.initial_lots[0]["id"] response = self.app.post_json( "/tenders/{}/complaints".format(self.tender_id), {"data": claim}, ) self.assertEqual(response.status, "201 Created") complaint = response.json["data"] self.assertEqual(complaint["relatedLot"], self.initial_lots[0]["id"]) self.set_status("active.auction", extra={"status": "active.tendering"}) orig_auth = self.app.authorization response = self.check_chronograph() self.assertEqual(response.json["data"]["status"], "active.tendering") self.assertNotIn("next_check", response.json["data"]) self.app.authorization = orig_auth cancellation = dict(**test_cancellation) cancellation.update({ "status": "active", "cancellationOf": "lot", "relatedLot": self.initial_lots[0]["id"], }) response = self.app.post_json( "/tenders/{}/cancellations?acc_token={}".format( self.tender_id, self.tender_token), {"data": cancellation}, ) cancellation_id = response.json["data"]["id"] if RELEASE_2020_04_19 < get_now(): activate_cancellation_with_complaints_after_2020_04_19( self, cancellation_id) else: response = self.app.get("/tenders/{}".format(self.tender_id)) self.assertIn("next_check", response.json["data"]) self.assertEqual( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"])) response = self.check_chronograph() self.assertEqual(response.json["data"]["status"], "active.auction") self.assertIn("next_check", response.json["data"]) self.assertGreater( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"]))
def switch_tender_cancellation_complaints_draft(self): # first we post a cancellation tender = self.db.get(self.tender_id) cancellation = deepcopy(test_cancellation) cancellation["status"] = "pending" cancellation["complaintPeriod"] = dict( startDate=get_now(), endDate=get_now() + timedelta(days=10), ) cancellation = Cancellation(cancellation) cancellation_data = cancellation.serialize("embedded") tender.update(cancellations=[cancellation_data]) self.db.save(tender) # let's post a draft complaint response = self.app.post_json( "/tenders/{}/cancellations/{}/complaints".format( self.tender_id, cancellation.id), {"data": test_draft_complaint}, ) self.assertEqual(response.json["data"]["status"], "draft") # get tender and check next_check response = self.app.get("/tenders/{}".format(self.tender_id)) self.assertEqual( parse_date(response.json["data"].get("next_check")), parse_date(cancellation_data["complaintPeriod"]["endDate"]), ) # and once the date passed tender = self.db.get(self.tender_id) tender["cancellations"][0]["complaintPeriod"] = dict( startDate=(get_now() - timedelta(days=30)).isoformat(), endDate=(get_now() - timedelta(days=20)).isoformat()) self.db.save(tender) # switch response = self.check_chronograph() self.assertNotEqual(response.json["data"].get("next_check"), cancellation_data["complaintPeriod"]["endDate"]) # check complaint status response = self.app.get("/tenders/{}/cancellations/{}/complaints".format( self.tender_id, cancellation.id)) complaint = response.json["data"][0] self.assertEqual(complaint["status"], "mistaken") self.assertEqual(complaint["rejectReason"], "complaintPeriodEnded")
def to_native(self, value, context=None): if isinstance(value, datetime): return value try: return parse_date(value, default_timezone=TZ) except ValueError: raise ConversionError(self.messages["parse"].format(value)) except OverflowError as e: raise ConversionError(str(e))
def set_auction_period(self): def check_chronograph(auction_period_data=None): if self.initial_lots: data = { "data": { "lots": [{ "auctionPeriod": auction_period_data }] } } if auction_period_data else None ch_response = self.check_chronograph(data) ch_response_item = ch_response.json["data"]["lots"][0] else: data = { "data": { "auctionPeriod": auction_period_data } } if auction_period_data else None ch_response = self.check_chronograph(data) ch_response_item = ch_response.json["data"] return ch_response, ch_response_item self.set_status("active.tendering", {"status": "active.enquiries"}) response, item = check_chronograph() self.assertEqual(response.json["data"]["status"], "active.tendering") self.assertIn("auctionPeriod", item) self.assertIn("shouldStartAfter", item["auctionPeriod"]) self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn("T00:00:00+", item["auctionPeriod"]["shouldStartAfter"]) self.assertEqual( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"])) response, item = check_chronograph( auction_period_data={"startDate": "9999-01-01T00:00:00"}) self.assertEqual(response.status, "200 OK") self.assertEqual(item["auctionPeriod"]["startDate"], "9999-01-01T00:00:00+02:00") response, item = check_chronograph(auction_period_data={"startDate": None}) self.assertEqual(response.status, "200 OK") self.assertNotIn("startDate", item["auctionPeriod"])
def switch_award_complaints_draft(self): response = self.app.patch_json( "/tenders/{}/awards/{}?acc_token={}".format(self.tender_id, self.award_id, self.tender_token), {"data": { "status": "active" }}, ) self.assertEqual(response.json["data"]["status"], "active") award_data = response.json["data"] # let's post a draft complaint token = list(self.initial_bids_tokens.values())[0] response = self.app.post_json( "/tenders/{}/awards/{}/complaints?acc_token={}".format( self.tender_id, self.award_id, token), {"data": test_draft_complaint}, ) self.assertEqual(response.json["data"]["status"], "draft") # get tender and check next_check response = self.app.get("/tenders/{}".format(self.tender_id)) self.assertEqual( parse_date(response.json["data"].get("next_check")), parse_date(award_data["complaintPeriod"]["endDate"]), ) # and once the date passed tender = self.db.get(self.tender_id) tender["awards"][0]["complaintPeriod"] = dict( startDate=(get_now() - timedelta(days=20)).isoformat(), endDate=(get_now() - timedelta(days=10)).isoformat()) self.db.save(tender) # switch response = self.check_chronograph() data = response.json["data"] complaint = data["awards"][0]["complaints"][0] self.assertEqual(complaint["status"], "mistaken") self.assertEqual(complaint["rejectReason"], "complaintPeriodEnded") self.assertNotEqual(data.get("next_check"), award_data["complaintPeriod"]["endDate"])
def setUp(self): super(BaseSubmissionContentWebTest, self).setUp() self.initial_submission_data["frameworkID"] = self.framework_id response = self.app.patch_json( "/frameworks/{}?acc_token={}".format(self.framework_id, self.framework_token), {"data": {"status": "active"}} ) submission_date = parse_date(response.json["data"]["enquiryPeriod"]["endDate"]) self.freezer = freeze_time((submission_date + timedelta(hours=1)).isoformat(), tick=True) self.freezer.start()
def validate_header(request): version = request.validated[VERSION] = request.headers.get(VERSION, "") request.validated[HASH] = request.headers.get(HASH, "") if request.headers.get(VERSION_BY_DATE, "") != "": try: request.validated[VERSION_BY_DATE] = parse_date( request.headers.get(VERSION_BY_DATE, ""), pytz.utc) except: if (version and (not version.isdigit() or int(version) < 1)) or version == "": return404(request, "header", "version") else: request.validated[VERSION_BY_DATE] = "" return if (version and (not version.isdigit() or int(version) < 1)) and request.headers.get( VERSION_BY_DATE, "") == "": return404(request, "header", "version")
def test_post_milestone(app, centralized_plan): plan, access_token = centralized_plan app.authorization = ("Basic", ("broker", "broker")) response = app.post_json( "/plans/{}/milestones".format(plan["id"]), {"data": test_milestone_data(app)} ) assert response.status_code == 201 milestone = response.json["data"] assert set(milestone.keys()) == {"status", "description", "title", "author", "id", "owner", "type", "dateModified", "dueDate", "documents"} assert milestone["description"] == MILESTONE_APPROVAL_DESCRIPTION assert milestone["status"] == Milestone.STATUS_SCHEDULED date_modified = parse_date(milestone["dateModified"]) assert get_now() - date_modified < timedelta(seconds=1) assert "documents" in milestone assert "access" in response.json assert "token" in response.json["access"] response = app.get("/plans/{}".format(plan["id"])) assert response.json["data"]["dateModified"] == milestone["dateModified"]
def test_parse_date_invalid_format(self): dt_str = "test" with self.assertRaises(ValueError) as e: parse_date(dt_str)
def test_parse_date_with_no_time_and_tz(self): dt_str = "2020-01-01" dt_result = parse_date(dt_str) dt_expected = utc.localize(datetime(2020, 1, 1)) self.assertEqual(dt_result, dt_expected)
def test_parse_date(self): dt_str = "2020-01-01T12:00:00+02:00" dt_result = parse_date(dt_str) dt_expected = timezone("Europe/Kiev").localize( datetime(2020, 1, 1, 12, 0, 0)) self.assertEqual(dt_result, dt_expected)
def check_auction_period(period, tender): if period and period.startDate and period.shouldStartAfter: start = parse_date(period.shouldStartAfter) date = calculate_tender_date(start, AUCTION_PERIOD_TIME, tender, True) return period.startDate > date return False
def test_milestone(self): """ test alp milestone is created in two cases 1. amount less by >=40% than mean of amount before auction 2. amount less by >=30% than the next amount :return: """ # sending auction results auction_results = deepcopy(self.initial_bids) if "lotValues" in self.initial_bids[0]: lot_id = auction_results[0]["lotValues"][0]["relatedLot"] auction_results[0]["lotValues"][0]["value"]["amount"] = 29 # only 1 case auction_results[1]["lotValues"][0]["value"]["amount"] = 30 # both 1 and 2 case auction_results[2]["lotValues"][0]["value"]["amount"] = 350 # only 2 case auction_results[3]["lotValues"][0]["value"]["amount"] = 500 # no milestones else: lot_id = None auction_results[0]["value"]["amount"] = 29 # only 1 case auction_results[1]["value"]["amount"] = 30 # both 1 and 2 case auction_results[2]["value"]["amount"] = 350 # only 2 case auction_results[3]["value"]["amount"] = 500 # no milestones with change_auth(self.app, ("Basic", ("auction", ""))): url = "/tenders/{}/auction".format(self.tender_id) if lot_id: url += "/" + lot_id response = self.app.post_json( url, {"data": {"bids": auction_results}}, status=200 ) tender = response.json["data"] self.assertEqual("active.qualification", tender["status"]) self.assertGreater(len(tender["awards"]), 0) award = tender["awards"][0] bid_id = award["bid_id"] self.assertEqual(bid_id, auction_results[0]["id"]) if get_now() < RELEASE_2020_04_19: return self.assertEqual(len(award.get("milestones", [])), 0) # check that a milestone's been created self.assertEqual(len(award.get("milestones", [])), 1) milestone = award["milestones"][0] self.assertEqual(milestone["code"], "alp") self.assertEqual(milestone["description"], ALP_MILESTONE_REASONS[0]) # try to change award status unsuccessful_data = {"status": "unsuccessful"} response = self.app.patch_json( "/tenders/{}/awards/{}?acc_token={}".format( self.tender_id, award["id"], self.tender_token ), {"data": unsuccessful_data}, status=403 ) expected_due_date = calculate_complaint_business_date( parse_date(milestone["date"]), timedelta(days=1), tender, working_days=True, ) self.assertEqual( response.json, { u'status': u'error', u'errors': [{ u'description': u"Can't change status to 'unsuccessful' until milestone.dueDate: {}".format( expected_due_date.isoformat() ), u'location': u'body', u'name': u'data' }] } ) # try to post/put/patch docs for doc_type in ["evidence", None]: self._test_doc_upload( tender["procurementMethodType"], doc_type, bid_id, self.initial_bids_tokens[bid_id], expected_due_date ) # setting "dueDate" to now self.wait_until_award_milestone_due_date(award_index=0) # after milestone dueDate tender owner can change award status response = self.app.patch_json( "/tenders/{}/awards/{}?acc_token={}".format( self.tender_id, award["id"], self.tender_token ), {"data": unsuccessful_data}, status=200 ) self.assertEqual(response.json["data"]["status"], "unsuccessful") # check second award response = self.app.get( "/tenders/{}/awards?acc_token={}".format(self.tender_id, self.tender_token), status=200 ) self.assertGreater(len(response.json["data"]), 1) second_award = response.json["data"][1] self.assertEqual(len(second_award.get("milestones", [])), 1) self.assertEqual(second_award["milestones"][0]["description"], u" / ".join(ALP_MILESTONE_REASONS)) # proceed to the third award self.wait_until_award_milestone_due_date(award_index=1) response = self.app.patch_json( "/tenders/{}/awards/{}?acc_token={}".format( self.tender_id, second_award["id"], self.tender_token ), {"data": unsuccessful_data}, status=200 ) self.assertEqual(response.json["data"]["status"], "unsuccessful") # checking 3rd award response = self.app.get( "/tenders/{}/awards?acc_token={}".format(self.tender_id, self.tender_token), status=200 ) self.assertGreater(len(response.json["data"]), 2) third_award = response.json["data"][2] self.assertEqual(len(third_award.get("milestones", [])), 1) self.assertEqual(third_award["milestones"][0]["description"], ALP_MILESTONE_REASONS[1]) # proceed to the last award self.wait_until_award_milestone_due_date(award_index=2) response = self.app.patch_json( "/tenders/{}/awards/{}?acc_token={}".format( self.tender_id, third_award["id"], self.tender_token ), {"data": unsuccessful_data}, status=200 ) self.assertEqual(response.json["data"]["status"], "unsuccessful") # checking last award response = self.app.get( "/tenders/{}/awards?acc_token={}".format(self.tender_id, self.tender_token), status=200 ) self.assertGreater(len(response.json["data"]), 3) last_award = response.json["data"][3] self.assertNotIn("milestones", last_award)
test_tender_ua_data = deepcopy(tender_defense) bid = deepcopy(bid) bid2 = deepcopy(bid2) bid.update(subcontracting) bid.update(qualified) bid2.update(qualified) bid.update({"selfEligible": True}) bid2.update({"selfEligible": True}) TARGET_DIR = 'docs/source/tendering/defense/http/' @mock.patch("openprocurement.tender.core.validation.RELEASE_SIMPLE_DEFENSE_FROM", parse_date(MOCK_DATETIME) + timedelta(days=365)) class TenderUAResourceTest(BaseTenderUAWebTest, MockWebTestMixin): AppClass = DumpsWebTestApp relative_to = os.path.dirname(__file__) initial_data = test_tender_ua_data docservice = True docservice_url = DOCS_URL auctions_url = AUCTIONS_URL def setUp(self): super(TenderUAResourceTest, self).setUp() self.setUpMock() def tearDown(self): self.tearDownMock()
def patch_tender(self): response = self.app.get("/tenders") self.assertEqual(response.status, "200 OK") self.assertEqual(len(response.json["data"]), 0) response = self.app.post_json("/tenders", {"data": self.initial_data}) self.assertEqual(response.status, "201 Created") tender = response.json["data"] self.tender_id = response.json["data"]["id"] owner_token = response.json["access"]["token"] dateModified = tender.pop("dateModified") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"status": "cancelled"}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertNotEqual(response.json["data"]["status"], "cancelled") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"procuringEntity": {"kind": "general"}}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertNotEqual(response.json["data"]["procuringEntity"]["kind"], "general") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"tenderPeriod": {"startDate": tender["enquiryPeriod"]["endDate"]}}}, status=422, ) self.assertEqual(response.status, "422 Unprocessable Entity") self.assertEqual(response.content_type, "application/json") self.assertEqual( response.json["errors"], [ { "location": "body", "name": "tenderPeriod", "description": ["tenderPeriod must be at least 6 full business days long"], } ], ) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"procurementMethodRationale": "Open"}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertIn("invalidationDate", response.json["data"]["enquiryPeriod"]) new_tender = response.json["data"] new_enquiryPeriod = new_tender.pop("enquiryPeriod") new_dateModified = new_tender.pop("dateModified") tender.pop("enquiryPeriod") tender["procurementMethodRationale"] = "Open" self.assertEqual(tender, new_tender) self.assertNotEqual(dateModified, new_dateModified) revisions = self.db.get(tender["id"]).get("revisions") self.assertTrue( any( [ i for i in revisions[-1]["changes"] if i["op"] == "remove" and i["path"] == "/procurementMethodRationale" ] ) ) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"dateModified": new_dateModified}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") new_tender2 = response.json["data"] new_enquiryPeriod2 = new_tender2.pop("enquiryPeriod") new_dateModified2 = new_tender2.pop("dateModified") self.assertEqual(new_tender, new_tender2) self.assertNotEqual(new_enquiryPeriod, new_enquiryPeriod2) self.assertNotEqual(new_dateModified, new_dateModified2) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"items": [self.initial_data["items"][0]]}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"items": [{}, self.initial_data["items"][0]]}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") item0 = response.json["data"]["items"][0] item1 = response.json["data"]["items"][1] self.assertNotEqual(item0.pop("id"), item1.pop("id")) self.assertEqual(item0, item1) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"items": [{}]}} ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(len(response.json["data"]["items"]), 1) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"items": [{"classification": {"scheme": "ДК021", "id": "44620000-2", "description": "Cartons 2"}}]}}, status=200, ) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), { "data": { "items": [ { "classification": { "scheme": "ДК021", "id": "55523100-3", "description": "Послуги з харчування у школах", } } ] } }, status=403, ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["errors"][0]["description"], "Can't change classification") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), { "data": { "items": [ { "additionalClassifications": [ tender["items"][0]["additionalClassifications"][0] for i in range(3) ] } ] } }, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"items": [{"additionalClassifications": tender["items"][0]["additionalClassifications"]}]}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"enquiryPeriod": { "startDate": calculate_tender_business_date( parse_date(new_dateModified2), -timedelta(3), None, True ).isoformat(), "endDate": new_dateModified2 }}}, status=403, ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["errors"][0]["description"], "Can't change enquiryPeriod") self.set_status("complete") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(tender["id"], owner_token), {"data": {"status": "active.auction"}}, status=403 ) self.assertEqual(response.status, "403 Forbidden") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["errors"][0]["description"], "Can't update tender in current (complete) status")
def test_24hours_milestone(self): self.app.authorization = ("Basic", ("broker", "")) # try upload documents response = self.app.get("/tenders/{}".format(self.tender_id)) context = response.json["data"]["{}s".format(self.context_name)][0] bid_id = context.get("bid_id") or context.get("bidID") # awards and qualifications developed on different days winner_token = self.initial_bids_tokens[bid_id] upload_allowed_by_default = response.json["data"]["procurementMethodType"] in \ ("aboveThresholdUA.defense", "simple.defense") self.assert_upload_docs_status(bid_id, winner_token, success=upload_allowed_by_default) # invalid creation response = self.app.post_json( "/tenders/{}/{}s/{}/milestones".format(self.tender_id, self.context_name, self.context_id), { "data": {} }, status=403 ) self.assertEqual( response.json, {"status": "error", "errors": [{"location": "url", "name": "permission", "description": "Forbidden"}]} ) response = self.app.post_json( "/tenders/{}/{}s/{}/milestones?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), { "data": { "code": "alp" } }, status=403 ) if get_now() > RELEASE_2020_04_19: self.assertEqual( response.json, {"status": "error", "errors": [{"description": "The only allowed milestone code is '24h'", "location": "body", "name": "data"}]} ) else: self.assertEqual( response.json, {"status": "error", "errors": [{"location": "body", "name": "data", "description": "Forbidden"}]} ) return # valid creation request_data = { "code": "24h", "description": "One ring to bring them all and in the darkness bind them", "dueDate": (get_now() + timedelta(days=10)).isoformat() } response = self.app.post_json( "/tenders/{}/{}s/{}/milestones?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), {"data": request_data}, ) self.assertEqual(response.status, "201 Created") created_milestone = response.json["data"] # get milestone from tender response = self.app.get("/tenders/{}".format(self.tender_id)) tender_data = response.json["data"] context = tender_data["{}s".format(self.context_name)][0] public_milestone = context["milestones"][0] self.assertEqual(created_milestone, public_milestone) self.assertEqual( set(created_milestone.keys()), { "id", "date", "code", "description", "dueDate", } ) self.assertEqual(created_milestone["code"], request_data["code"]) self.assertEqual(created_milestone["description"], request_data["description"]) self.assertNotEqual(created_milestone["dueDate"], request_data["dueDate"]) expected_date = calculate_tender_date( parse_date(created_milestone["date"]), timedelta(hours=24), tender_data ) self.assertEqual(created_milestone["dueDate"], expected_date.isoformat()) # get milestone by its direct link response = self.app.get("/tenders/{}/{}s/{}/milestones/{}".format( self.tender_id, self.context_name, self.context_id, created_milestone["id"] )) direct_milestone = response.json["data"] self.assertEqual(created_milestone, direct_milestone) # can't post another response = self.app.post_json( "/tenders/{}/{}s/{}/milestones?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), {"data": request_data}, status=422 ) self.assertEqual( response.json, {"status": "error", "errors": [{"description": [ {"milestones": ["There can be only one '24h' milestone"]}], "location": "body", "name": "{}s".format(self.context_name)}]} ) # can't update status of context until dueDate activation_data = {"status": "active", "qualified": True, "eligible": True} response = self.app.patch_json( "/tenders/{}/{}s/{}?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), {"data": activation_data}, status=403 ) self.assertEqual( response.json, { "status": "error", "errors": [ { "description": "Can't change status to 'active' " "until milestone.dueDate: {}".format(created_milestone["dueDate"]), "location": "body", "name": "data" }] } ) # try upload documents self.assert_upload_docs_status(bid_id, winner_token) # wait until milestone dueDate ends with patch("openprocurement.tender.core.validation.get_now", lambda: get_now() + timedelta(hours=24)): self.assert_upload_docs_status(bid_id, winner_token, success=upload_allowed_by_default) response = self.app.patch_json( "/tenders/{}/{}s/{}?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), {"data": activation_data}, status=200 ) self.assertEqual(response.json["data"]["status"], "active") # check appending milestone at active qualification status # remove milestone to skip "only one" validator tender = self.db.get(self.tender_id) context = tender["{}s".format(self.context_name)][0] context["milestones"] = [] self.db.save(tender) response = self.app.post_json( "/tenders/{}/{}s/{}/milestones?acc_token={}".format( self.tender_id, self.context_name, self.context_id, self.tender_token ), {"data": request_data}, status=403 ) self.assertEqual( response.json, {"status": "error", "errors": [ {"description": "Not allowed in current 'active' {} status".format(self.context_name), "location": "body", "name": "data"}]} )
def reset_auction_period(self): def check_chronograph(auction_period_data=None): if self.initial_lots: data = { "data": { "lots": [{ "auctionPeriod": auction_period_data }] } } if auction_period_data else None ch_response = self.check_chronograph(data) ch_response_item = ch_response.json["data"]["lots"][0] else: data = { "data": { "auctionPeriod": auction_period_data } } if auction_period_data else None ch_response = self.check_chronograph(data) ch_response_item = ch_response.json["data"] return ch_response, ch_response_item self.set_status("active.tendering", {"status": "active.enquiries"}) response, item = check_chronograph() self.assertEqual(response.json["data"]["status"], "active.tendering") self.assertIn("auctionPeriod", item) self.assertIn("shouldStartAfter", item["auctionPeriod"]) self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertEqual( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"])) response, item = check_chronograph( auction_period_data={"startDate": "9999-01-01T00:00:00"}) self.assertEqual(response.status, "200 OK") self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn("9999-01-01T00:00:00", item["auctionPeriod"]["startDate"]) self.set_status("active.auction", {"status": "active.tendering"}) response = self.check_chronograph() self.assertEqual(response.json["data"]["status"], "active.auction") item = response.json["data"]["lots"][ 0] if self.initial_lots else response.json["data"] self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) response, item = check_chronograph( auction_period_data={"startDate": "9999-01-01T00:00:00"}) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "active.auction") self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn("9999-01-01T00:00:00", item["auctionPeriod"]["startDate"]) self.assertIn("9999-01-01T00:00:00", response.json["data"]["next_check"]) now = get_now() response, item = check_chronograph( auction_period_data={"startDate": now.isoformat()}) self.assertEqual(response.json["data"]["status"], "active.auction") item = response.json["data"]["lots"][ 0] if self.initial_lots else response.json["data"] self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn(now.isoformat(), item["auctionPeriod"]["startDate"]) self.assertGreater(parse_date(response.json["data"]["next_check"]), parse_date(item["auctionPeriod"]["startDate"])) self.assertEqual(response.json["data"]["next_check"], self.db.get(self.tender_id)["next_check"]) tender_period_end_date = response.json["data"]["tenderPeriod"]["endDate"] response, item = check_chronograph( auction_period_data={"startDate": tender_period_end_date}) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "active.auction") self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn(tender_period_end_date, item["auctionPeriod"]["startDate"]) self.assertGreater( parse_date(response.json["data"]["next_check"]), parse_date(response.json["data"]["tenderPeriod"]["endDate"])) self.assertGreater( self.db.get(self.tender_id)["next_check"], response.json["data"]["tenderPeriod"]["endDate"]) self.time_shift("active.auction", shift=-timedelta(days=2)) response, item = check_chronograph() self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertNotIn("next_check", response.json["data"]) self.assertNotIn("next_check", self.db.get(self.tender_id)) shouldStartAfter = item["auctionPeriod"]["shouldStartAfter"] response, item = check_chronograph() self.assertEqual(item["auctionPeriod"]["shouldStartAfter"], shouldStartAfter) self.assertNotIn("next_check", response.json["data"]) response, item = check_chronograph( auction_period_data={"startDate": "9999-01-01T00:00:00"}) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "active.auction") self.assertGreaterEqual(item["auctionPeriod"]["shouldStartAfter"], response.json["data"]["tenderPeriod"]["endDate"]) self.assertIn("9999-01-01T00:00:00", item["auctionPeriod"]["startDate"]) self.assertIn("9999-01-01T00:00:00", response.json["data"]["next_check"])
def test_docs(self): self.app.authorization = ('Basic', ('broker', '')) # empty frameworks listing self.initial_data["qualificationPeriod"]["endDate"] = ( get_now() + timedelta(days=60)).isoformat() response = self.app.get('/frameworks') self.assertEqual(response.json['data'], []) # create frameworks with open(TARGET_DIR + 'create-electroniccatalogue.http', 'w') as self.app.file_obj: response = self.app.post_json('/frameworks', {'data': self.initial_data}) self.assertEqual(response.status, '201 Created') framework = response.json['data'] self.framework_id = framework["id"] owner_token = response.json['access']['token'] with open(TARGET_DIR + 'patch-electroniccatalogue-draft.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/frameworks/{}?acc_token={}'.format(framework['id'], owner_token), { 'data': { "procuringEntity": { "contactPoint": { "telephone": "+0440000001" } }, "title": "updated in draft status" } }) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'upload-framework-document.http', 'w') as self.app.file_obj: response = self.app.post( '/frameworks/{}/documents?acc_token={}'.format( framework['id'], owner_token), upload_files=[('file', 'framework.doc', b'content')]) with open(TARGET_DIR + 'framework-documents.http', 'w') as self.app.file_obj: response = self.app.get( '/frameworks/{}/documents?acc_token={}'.format( framework['id'], owner_token)) with open(TARGET_DIR + 'upload-framework-document-2.http', 'w') as self.app.file_obj: response = self.app.post( '/frameworks/{}/documents?acc_token={}'.format( framework['id'], owner_token), upload_files=[('file', 'framework_additional_docs.doc', b'additional info')]) doc_id = response.json['data']['id'] with open(TARGET_DIR + 'upload-framework-document-3.http', 'w') as self.app.file_obj: response = self.app.put( '/frameworks/{}/documents/{}?acc_token={}'.format( framework['id'], doc_id, owner_token), upload_files=[('file', 'framework_additional_docs.doc', b'extended additional info')]) with open(TARGET_DIR + 'get-framework-document-3.http', 'w') as self.app.file_obj: response = self.app.get( '/frameworks/{}/documents/{}?acc_token={}'.format( framework['id'], doc_id, owner_token)) with open( TARGET_DIR + 'patch-electroniccatalogue-draft-to-active.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/frameworks/{}?acc_token={}'.format(framework['id'], owner_token), {'data': { "status": "active" }}) self.assertEqual(response.status, '200 OK') # Submissions self.tick(delta=timedelta(days=16)) with open(TARGET_DIR + 'register-submission.http', 'w') as self.app.file_obj: response = self.app.post_json( '/submissions', { 'data': { "tenderers": [tenderer], "frameworkID": self.framework_id, } }) self.assertEqual(response.status, '201 Created') self.submission_id = response.json["data"]["id"] self.submission_token = response.json["access"]["token"] with open(TARGET_DIR + 'upload-submission-document.http', 'w') as self.app.file_obj: response = self.app.post( '/submissions/{}/documents?acc_token={}'.format( self.submission_id, self.submission_token), upload_files=[('file', 'submission_docs.doc', b'additional info')]) self.assertEqual(response.status, '201 Created') with open(TARGET_DIR + 'get-submission-documents.http', 'w') as self.app.file_obj: response = self.app.get('/submissions/{}/documents'.format( self.submission_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-submission.http', 'w') as self.app.file_obj: response = self.app.get('/submissions/{}'.format( self.submission_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'updating-submission.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/submissions/{}?acc_token={}'.format(self.submission_id, self.submission_token), {'data': { "tenderers": [{ "name": "НАЗВА" }] }}, ) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'deleting-submission.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/submissions/{}?acc_token={}'.format(self.submission_id, self.submission_token), {'data': { "status": "deleted" }}, ) self.assertEqual(response.status, '200 OK') response = self.app.post_json( '/submissions'.format(self.submission_id, self.submission_token), { 'data': { "tenderers": [tenderer], "frameworkID": self.framework_id, } }) self.submission_id = response.json["data"]["id"] self.submission_token = response.json["access"]["token"] with open(TARGET_DIR + 'activating-submission.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/submissions/{}?acc_token={}'.format(self.submission_id, self.submission_token), {'data': { "status": "active" }}, ) self.assertEqual(response.status, '200 OK') self.qualification_id = response.json["data"]["qualificationID"] with open(TARGET_DIR + 'submission-listing.http', 'w') as self.app.file_obj: response = self.app.get('/submissions'.format(self.framework_id)) self.assertEqual(response.status, '200 OK') # Qualification with open(TARGET_DIR + 'get-qualification.http', 'w') as self.app.file_obj: response = self.app.get('/qualifications/{}'.format( self.qualification_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'upload-qualification-document.http', 'w') as self.app.file_obj: response = self.app.post( '/qualifications/{}/documents?acc_token={}'.format( self.qualification_id, owner_token), upload_files=[('file', 'qualification.doc', b'content')]) self.assertEqual(response.status, '201 Created') with open(TARGET_DIR + 'qualification-documents.http', 'w') as self.app.file_obj: response = self.app.get('/qualifications/{}/documents'.format( self.qualification_id, owner_token)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-qualification-documents.http', 'w') as self.app.file_obj: response = self.app.get('/qualifications/{}/documents'.format( self.qualification_id)) self.assertEqual(response.status, '200 OK') # with open(TARGET_DIR + 'get-qualification.http', 'w') as self.app.file_obj: # response = self.app.get('/qualifications/{}'.format(self.qualification_id)) # self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'unsuccessful-qualification.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/qualifications/{}?acc_token={}'.format( self.qualification_id, owner_token), {'data': { "status": "unsuccessful" }}, ) self.assertEqual(response.status, '200 OK') response = self.app.post_json( '/submissions'.format(self.submission_id, self.submission_token), { 'data': { "tenderers": [tenderer], "frameworkID": self.framework_id, } }) self.submission_id = response.json["data"]["id"] self.submission_token = response.json["access"]["token"] response = self.app.patch_json( '/submissions/{}?acc_token={}'.format(self.submission_id, self.submission_token), {'data': { "status": "active" }}, ) self.qualification_id = response.json["data"]["qualificationID"] with open(TARGET_DIR + 'activation-qualification.http', 'w') as self.app.file_obj: response = self.app.patch_json( '/qualifications/{}?acc_token={}'.format( self.qualification_id, owner_token), {'data': { "status": "active" }}, ) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-framework-with-agreement.http', 'w') as self.app.file_obj: response = self.app.get(f'/frameworks/{self.framework_id}') self.assertEqual(response.status, '200 OK') agreement_id = response.json["data"]["agreementID"] with open(TARGET_DIR + 'get-agreement.http', 'w') as self.app.file_obj: response = self.app.get(f'/agreements/{agreement_id}') self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'agreement-listing.http', 'w') as self.app.file_obj: response = self.app.get(f'/agreements') self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-submissions-by-framework-id.http', 'w') as self.app.file_obj: response = self.app.get('/frameworks/{}/submissions'.format( self.framework_id, self.submission_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-qualifications-by-framework-id.http', 'w') as self.app.file_obj: response = self.app.get('/frameworks/{}/qualifications'.format( self.framework_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'qualification-listing.http', 'w') as self.app.file_obj: response = self.app.get('/qualifications'.format( self.framework_id)) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'get-framework.http', 'w') as self.app.file_obj: response = self.app.get('/frameworks/{}'.format(framework['id'])) self.assertEqual(response.status, '200 OK') with open(TARGET_DIR + 'framework-listing.http', 'w') as self.app.file_obj: response = self.app.get('/frameworks'.format(framework['id'])) self.assertEqual(len(response.json['data']), 1) with open(TARGET_DIR + 'patch-electroniccatalogue-active.http', 'w') as self.app.file_obj: new_endDate = ( parse_date(framework["qualificationPeriod"]["endDate"]) + timedelta(days=15)).isoformat() response = self.app.patch_json( '/frameworks/{}?acc_token={}'.format(framework['id'], owner_token), { 'data': { "procuringEntity": { "contactPoint": { "telephone": "+0440000002", "name": "зміна", "email": "*****@*****.**" } }, "description": "Назва предмета закупівлі1", "qualificationPeriod": { "endDate": new_endDate } } }) self.assertEqual(response.status, '200 OK')
def switch_bid_status_unsuccessul_to_active(self): bid_id, bid_token = self.initial_bids_tokens.items()[0] response = self.app.get("/tenders/{}/qualifications?acc_token={}".format(self.tender_id, self.tender_token)) self.assertEqual(response.content_type, "application/json") qualifications = response.json["data"] self.assertEqual(len(qualifications), 3) qualification_id = "" for qualification in qualifications: status = "active" if qualification["bidID"] == bid_id: status = "unsuccessful" qualification_id = qualification["id"] response = self.app.patch_json( "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, qualification["id"], self.tender_token), {"data": {"status": status, "qualified": True, "eligible": True}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], status) response = self.app.patch_json( "/tenders/{}?acc_token={}".format(self.tender_id, self.tender_token), {"data": {"status": "active.pre-qualification.stand-still"}}, ) self.assertEqual(response.status, "200 OK") end_date = parse_date(response.json["data"]["qualificationPeriod"]["endDate"]) date = parse_date(response.json["data"]["date"]) duration = (end_date - date).total_seconds() if SANDBOX_MODE: duration = ceil(duration) * 1440 duration = duration / 86400 # days float self.assertEqual(int(duration), 5) # create complaint response = self.app.post_json( "/tenders/{}/qualifications/{}/complaints?acc_token={}".format(self.tender_id, qualification_id, bid_token), { "data": test_complaint }, ) self.assertEqual(response.status, "201 Created") self.assertEqual(response.content_type, "application/json") complaint = response.json["data"] complaint_token = response.json["access"]["token"] if RELEASE_2020_04_19 < get_now(): self.assertEqual(response.json["data"]["status"], "draft") with change_auth(self.app, ("Basic", ("bot", ""))): response = self.app.patch_json( "/tenders/{}/qualifications/{}/complaints/{}".format( self.tender_id, qualification_id, complaint["id"]), {"data": {"status": "pending"}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["data"]["status"], "pending") self.app.authorization = ("Basic", ("reviewer", "")) now = get_now() data = {"status": "accepted"} if RELEASE_2020_04_19 < now: data.update({ "reviewDate": now.isoformat(), "reviewPlace": "some", }) response = self.app.patch_json( "/tenders/{}/qualifications/{}/complaints/{}".format(self.tender_id, qualification_id, complaint["id"]), {"data": data}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["data"]["status"], "accepted") if RELEASE_2020_04_19 < now: self.assertEqual(response.json["data"]["reviewPlace"], "some") self.assertEqual(response.json["data"]["reviewDate"], now.isoformat()) response = self.app.patch_json( "/tenders/{}/qualifications/{}/complaints/{}".format(self.tender_id, qualification_id, complaint["id"]), {"data": {"status": "satisfied"}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.content_type, "application/json") self.assertEqual(response.json["data"]["status"], "satisfied") # Cancell qualification self.app.authorization = ("Basic", ("broker", "")) response = self.app.patch_json( "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, qualification_id, self.tender_token), {"data": {"status": "cancelled"}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "cancelled") new_qualification_id = response.headers["location"].split("/")[-1] response = self.app.patch_json( "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, new_qualification_id, self.tender_token), {"data": {"status": "active", "qualified": True, "eligible": True}}, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "active") response = self.app.get("/tenders/{}/bids".format(self.tender_id)) for b in response.json["data"]: self.assertEqual(b["status"], "active")
def switch_qualification_complaints_draft(self): # generate qualifications self.set_status("active.pre-qualification", extra={"status": "active.tendering"}) response = self.check_chronograph() qualifications = response.json["data"]["qualifications"] self.assertEqual(len(qualifications), 2) # activate qualifications for qualification in qualifications: response = self.app.patch_json( "/tenders/{}/qualifications/{}?acc_token={}".format( self.tender_id, qualification["id"], self.tender_token), { "data": { "status": "active", "qualified": True, "eligible": True } }, ) self.assertEqual(response.status, "200 OK") self.assertEqual(response.json["data"]["status"], "active") response = self.app.patch_json( "/tenders/{}?acc_token={}".format(self.tender_id, self.tender_token), {"data": { "status": "active.pre-qualification.stand-still" }}, ) self.assertEqual(response.status, "200 OK") tender = response.json["data"] qualification = tender["qualifications"][0] # let's post a draft complaint token = list(self.initial_bids_tokens.values())[0] response = self.app.post_json( "/tenders/{}/qualifications/{}/complaints?acc_token={}".format( self.tender_id, qualification["id"], token), {"data": test_draft_complaint}, ) self.assertEqual(response.json["data"]["status"], "draft") # get tender and check next_check response = self.app.get("/tenders/{}".format(self.tender_id)) self.assertEqual(parse_date(response.json["data"].get("next_check")), parse_date(tender["qualificationPeriod"]["endDate"])) # and once the date passed tender = self.db.get(self.tender_id) tender["qualificationPeriod"] = dict( startDate=(get_now() - timedelta(days=20)).isoformat(), endDate=(get_now() - timedelta(days=10)).isoformat()) self.db.save(tender) # switch response = self.check_chronograph() data = response.json["data"] complaint = data["qualifications"][0]["complaints"][0] self.assertEqual(complaint["status"], "mistaken") self.assertEqual(complaint["rejectReason"], "complaintPeriodEnded") self.assertNotEqual(data.get("next_check"), tender["qualificationPeriod"]["endDate"])