def test_fail_classification_id(app): request_plan_data = deepcopy(test_plan_data) request_plan_data["classification"] = { "scheme": u"ДК021", "description": "Personal care products", "id": "33700000-7", } del request_plan_data["items"] app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json request_tender_data = deepcopy(test_below_tender_data) request_tender_data["items"][0]["classification"] = { "scheme": u"ДК021", "description": "Antiperspirants", "id": "33711120-4", } response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}, status=422) error_data = response.json["errors"] assert len(error_data) > 0 error = error_data[0] assert error["name"] == "items[0].classification.id" assert ( error["description"] == "Plan classification.id 33700000-7 and item's 33711120-4 " "should be of the same group 3370" )
def test_fail_classification_id_336(app): request_plan_data = deepcopy(test_plan_data) request_plan_data["classification"] = { "scheme": "ДК021", "description": "Pharmaceutical products", "id": "33600000-6", } del request_plan_data["items"] app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json request_tender_data = deepcopy(test_below_tender_data) request_tender_data["items"] = request_tender_data["items"][:1] request_tender_data["items"][0]["classification"] = { "scheme": "ДК021", "description": "Makeup kits", "id": "33711420-7", } response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}, status=422) error_data = response.json["errors"] assert len(error_data) > 0 error = error_data[0] assert error["name"] == "items[0].classification.id" assert (error["description"] == "Plan classification.id 33600000-6 and item's 33711420-7 " "should be of the same group 336")
def test_fail_complete_manually(app, value): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = "scheduled" test_data["tender"]["procurementMethodType"] = value if value == "aboveThresholdUA.defense": patch_date = get_now() + timedelta(days=1) else: patch_date = get_now() - timedelta(days=1) if value in ("aboveThresholdUA.defense", "simple.defense"): with patch( "openprocurement.planning.api.validation.RELEASE_SIMPLE_DEFENSE_FROM", patch_date): response = app.post_json("/plans", {"data": test_data}, status=403) assert response.status == "403 Forbidden" assert response.json["errors"] == [{ u'description': u'procuringEntity with general kind cannot publish this type of procedure.' u' Procurement method types allowed for this kind: centralizedProcurement, reporting,' u' negotiation, negotiation.quick, priceQuotation, belowThreshold, aboveThresholdUA, aboveThresholdEU,' u' competitiveDialogueUA, competitiveDialogueEU, esco, closeFrameworkAgreementUA.', u'location': u'body', u'name': u'kind' }] test_data["procuringEntity"]["kind"] = "defense" with patch( "openprocurement.planning.api.validation.RELEASE_SIMPLE_DEFENSE_FROM", patch_date): response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"]["status"] == "scheduled" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json("/plans/{}?acc_token={}".format( plan_id, acc_token), {"data": { "status": "complete" }}, status=422) assert response.json == { "status": "error", "errors": [{ "location": "body", "name": "status", "description": [ "Can't complete plan with '{}' tender.procurementMethodType". format(value) ], }], }
def test_post_milestone_author_validate_identifier(app, centralized_plan): """ milestone can only be posted if author equals plan.procuringEntity """ plan, access_token = centralized_plan app.authorization = ("Basic", ("broker", "broker")) data = test_milestone_data(app) data["author"]["name"] = "ЦЗО 2" app.post_json("/plans/{}/milestones".format(plan["id"]), {"data": data}, status=201)
def test_procurement_method_type_cpb(app): app.authorization = ("Basic", ("broker", "broker")) request_plan_data = deepcopy(test_plan_data) request_plan_data["tender"]["procurementMethod"] = "" request_plan_data["tender"]["procurementMethodType"] = "centralizedProcurement" response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": test_below_tender_data}) assert response.status == "201 Created"
def test_fail_procurement_method_type_validation(app): app.authorization = ("Basic", ("broker", "broker")) request_plan_data = deepcopy(test_plan_data) request_plan_data["tender"]["procurementMethodType"] = "aboveThresholdUA" response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json response = app.post_json( "/plans/{}/tenders".format(plan["data"]["id"]), {"data": test_below_tender_data}, status=422 ) errors = response.json["errors"] assert len(errors) == 1 assert errors[0]["name"] == "procurementMethodType" assert errors[0]["description"] == "procurementMethodType doesn't match: aboveThresholdUA != belowThreshold"
def test_plan_default_status(app): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data.pop("status", None) response = app.post_json("/plans", {"data": test_data}) assert response.json["data"].get("status") == "scheduled" test_data["status"] = None response = app.post_json("/plans", {"data": test_data}) assert response.json["data"].get("status") == "scheduled" response = app.get("/plans") assert response.status == "200 OK" assert len(response.json["data"]) == 2
def test_fail_post_another_milestone(app, centralized_milestone, test_status): """ broker can't post another milestone with the same author till the first milestone in scheduled or met statuses """ milestone_data, plan_data = centralized_milestone[ "milestone"], centralized_milestone["plan"] milestone, milestone_token = milestone_data["data"], milestone_data[ "token"] plan, plan_token = plan_data["data"], plan_data["token"] # set milestone status if test_status != milestone["status"]: plan_source = app.app.registry.db.get(plan["id"]) plan_source["milestones"][0]["status"] = test_status app.app.registry.db.save(plan_source) response = app.post_json("/plans/{}/milestones".format(plan["id"]), {"data": test_milestone_data(app)}, status=422) assert response.json == { u'status': u'error', u'errors': [{ u'description': u'An active milestone already exists for this author', u'location': u'data', u'name': u'author' }] }
def test_fail_update_back_to_draft(app, initial_status): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = initial_status response = app.post_json("/plans", {"data": test_data}) assert response.json["data"].get("status") == "scheduled" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] if initial_status is None: plan = app.app.registry.db.get(plan_id) del plan["status"] app.app.registry.db.save(plan) response = app.patch_json("/plans/{}?acc_token={}".format( plan_id, acc_token), {"data": { "status": "draft" }}, status=422) assert response.json == { u"status": u"error", u"errors": [{ u"description": u"Plan status can not be changed back to 'draft'", u"location": u"body", u"name": u"status", }], }
def test_cancel_compatibility_completed_plan(app): """ well I don't know if it's an appropriate case. it's probably not """ app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" plan = response.json["data"] acc_token = response.json["access"]["token"] obj = app.app.registry.db.get(plan["id"]) del obj["status"] obj["tender_id"] = "a" * 32 app.app.registry.db.save(obj) response = app.get("/plans/{}".format(plan["id"])) assert response.json["data"]["status"] == "complete" # complete ! response = app.patch_json( "/plans/{}?acc_token={}".format(plan["id"], acc_token), { "data": { "cancellation": { "reason": "Because it's possible", "status": "active" } } }) assert response.status == "200 OK" assert response.json["data"]["status"] == "cancelled" # cancelled !
def test_plan_update_draft(app, mode, status): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) if mode != "real": test_data["mode"] = "test" test_data["status"] = "draft" response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"].get("status") == "draft" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": { "status": status }}) assert response.status == "200 OK" assert response.json["data"].get("status") == status response = app.get("/plans?mode={}".format(mode)) assert response.status == "200 OK" assert len(response.json["data"]) == 1 assert response.json["data"][0]["id"] == plan_id response = app.get("/plans?feed=changes&mode={}".format(mode)) assert response.status == "200 OK" assert len(response.json["data"]) == 1 assert response.json["data"][0]["id"] == plan_id
def test_update_status_invalid(app): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = "draft" response = app.post_json("/plans", {"data": test_data}) assert response.json["data"].get("status") == "draft" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"status": "invalid"}}, status=422 ) assert response.json == { "status": "error", "errors": [ { "location": "body", "name": "status", "description": ["Value must be one of ['draft', 'scheduled', 'cancelled', 'complete']."], } ], } response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"status": "cancelled"}}, status=422 ) assert response.json == { "status": "error", "errors": [ {"description": ["An active cancellation object is required"], "location": "body", "name": "status"} ], }
def test_cancel_plan_1_step(app): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = "scheduled" response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"].get("status") == "scheduled" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"cancellation": {"reason": "", "status": "active"}}}, status=422, ) assert response.json == { "status": "error", "errors": [ {"location": "body", "name": "cancellation", "description": {"reason": ["String value is too short."]}} ], } response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"cancellation": {"reason": "Because", "status": "active"}}}, ) assert response.status == "200 OK" assert response.json["data"]["cancellation"]["status"] == "active" assert response.json["data"]["status"] == "cancelled" plan = app.app.registry.databases.plans.get(plan_id) assert {c["path"] for c in plan["revisions"][-1]["changes"]} == {"/cancellation", "/status"}
def test_cancel_plan_2_steps(app, initial_status): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = initial_status response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"].get("status") == initial_status plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"cancellation": {"reason": "Because", "status": "pending"}}}, ) assert response.status == "200 OK" assert response.json["data"]["cancellation"]["status"] == "pending" assert response.json["data"].get("status") == initial_status create_time = response.json["data"]["cancellation"]["date"] response = app.patch_json( "/plans/{}?acc_token={}".format(plan_id, acc_token), {"data": {"cancellation": {"status": "active"}}} ) assert response.status == "200 OK" assert response.json["data"]["cancellation"]["status"] == "active" assert response.json["data"]["cancellation"]["date"] > create_time assert response.json["data"]["status"] == "cancelled" get_response = app.get("/plans/{}".format(plan_id)) assert get_response.json["data"]["cancellation"]["date"] == response.json["data"]["cancellation"]["date"]
def test_fail_post_milestone_author(app, centralized_plan): """ milestone can only be posted if author equals plan.procuringEntity """ plan, access_token = centralized_plan app.authorization = ("Basic", ("broker", "broker")) data = test_milestone_data(app) data["author"] = { "identifier": { "scheme": "UA-EDR", "id": "222222", "legalName": "ЦЗО 2" }, "name": "ЦЗО 2" } response = app.post_json("/plans/{}/milestones".format(plan["id"]), {"data": data}, status=422) assert response.json == { u"status": u"error", u"errors": [{ u"description": u"Should match plan.procuringEntity", u"location": u"data", u"name": u"author" }] }
def test_fail_complete_manually(app, value): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = "scheduled" test_data["tender"]["procurementMethodType"] = value response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"]["status"] == "scheduled" plan_id = response.json["data"]["id"] acc_token = response.json["access"]["token"] response = app.patch_json("/plans/{}?acc_token={}".format( plan_id, acc_token), {"data": { "status": "complete" }}, status=422) assert response.json == { "status": "error", "errors": [{ "location": "body", "name": "status", "description": [ "Can't complete plan with '{}' tender.procurementMethodType". format(value) ], }], }
def test_fail_tender_creation(app): app.authorization = ("Basic", ("broker", "broker")) request_tender_data = deepcopy(test_below_tender_data) request_plan_data = deepcopy(test_plan_data) plan = create_plan_for_tender(app, request_tender_data, request_plan_data) # rm milestones that causes data error request_tender_data["enquiryPeriod"][ "endDate"] = "2019-01-02T00:00:00+02:00" response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}, status=422) assert response.json == { "status": "error", "errors": [{ "description": { "startDate": ["period should begin before its end"] }, "location": "body", "name": "enquiryPeriod", }], } # get plan form db plan_from_db = app.app.registry.databases.plans.get(plan["data"]["id"]) assert plan_from_db.get("tender_id") is None
def centralized_plan(app): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["tender"]["procurementMethod"] = "" test_data["tender"]["procurementMethodType"] = "centralizedProcurement" test_data["procuringEntity"] = central_procuring_entity response = app.post_json("/plans", {"data": test_data}) return response.json["data"], response.json["access"]["token"]
def test_create_cancelled(app, replaced_status): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = replaced_status # this will be replaced by "switch_status" serializable test_data["cancellation"] = {"reason": "Because it's possible", "status": "active"} response = app.post_json("/plans", {"data": test_data}) assert response.status == "201 Created" assert response.json["data"].get("status") == "cancelled"
def test_fail_cd_second_stage_creation(app, plan, request_tender_data): app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}, status=403) error_data = response.json["errors"] assert len(error_data) > 0 error = error_data[0] assert error["name"] == "accreditation" assert u"Broker Accreditation level does not permit tender creation" == error["description"]
def test_success_classification_id(app): request_plan_data = deepcopy(test_plan_data) request_plan_data["classification"] = {"scheme": u"ДК021", "description": "Antiperspirants", "id": "33711120-4"} del request_plan_data["items"] app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json request_tender_data = deepcopy(test_below_tender_data) request_tender_data["items"][0]["classification"] = { "scheme": u"ДК021", "description": "Make-up preparations", "id": "33711200-9", } response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}) assert response.status == "201 Created"
def test_plan_tenders_404(app): app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans/{}/tenders".format("a" * 32), {"data": {}}, status=404) assert response.status == "404 Not Found" assert response.content_type == "application/json" assert response.json == { u"status": u"error", u"errors": [{u"description": u"Not Found", u"location": u"url", u"name": u"plan_id"}], }
def test_success_classification_id_336(app): request_plan_data = deepcopy(test_plan_data) request_plan_data["classification"] = {"scheme": u"ДК021", "description": "Insulin", "id": "33615100-5"} del request_plan_data["items"] app.authorization = ("Basic", ("broker", "broker")) response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json request_tender_data = deepcopy(test_below_tender_data) request_tender_data["items"] = request_tender_data["items"][:1] request_tender_data["items"][0]["classification"] = { "scheme": u"ДК021", "description": "Medicinal products for dermatology", "id": "33631000-2", } response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}) assert response.status == "201 Created"
def centralized_milestone(app, centralized_plan): plan, access_token = centralized_plan response = app.post_json("/plans/{}/milestones".format(plan["id"]), {"data": test_milestone_data(app)}) assert response.status_code == 201 result = dict(milestone=dict(data=response.json["data"], token=response.json["access"]["token"]), plan=dict(data=plan, token=access_token)) return result
def test_forbidden_update_milestone_documents(app, centralized_milestone): """ Plan owner or just broker can't manage milestone documents """ milestone_data, plan_data = centralized_milestone[ "milestone"], centralized_milestone["plan"] milestone, milestone_token = milestone_data["data"], milestone_data[ "token"] plan, plan_token = plan_data["data"], plan_data["token"] app.authorization = ("Basic", ("broker", "broker")) response = app.post_json( "/plans/{}/milestones/{}/documents?acc_token={}".format( plan["id"], milestone["id"], plan_token), {"data": {}}, status=403) assert response.json == { u"status": u"error", u"errors": [{ u"description": u"Forbidden", u"location": u"url", u"name": u"permission" }] } # put document = milestone["documents"][0] response = app.put_json( "/plans/{}/milestones/{}/documents/{}?acc_token={}".format( plan["id"], milestone["id"], document["id"], plan_token), {"data": {}}, status=403) assert response.json == { u"status": u"error", u"errors": [{ u"description": u"Forbidden", u"location": u"url", u"name": u"permission" }] } # patch response = app.patch_json( "/plans/{}/milestones/{}/documents/{}?acc_token={}".format( plan["id"], milestone["id"], document["id"], plan_token), {"data": {}}, status=403) assert response.json == { u"status": u"error", u"errors": [{ u"description": u"Forbidden", u"location": u"url", u"name": u"permission" }] }
def test_success_plan_tenders_creation(app, request_tender_data): app.authorization = ("Basic", ("broker", "broker")) request_plan_data = deepcopy(test_plan_data) if request_tender_data["procurementMethodType"] in ( "aboveThresholdUA.defense", "simple.defense"): request_plan_data['procuringEntity']['kind'] = 'defense' plan = create_plan_for_tender(app, request_tender_data, request_plan_data) response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}) assert response.status == "201 Created" tender_data = response.json["data"] assert tender_data["plans"] == [{"id": plan["data"]["id"]}] assert tender_data["title"] == request_tender_data["title"] assert response.headers[ "Location"] == "http://localhost/api/2.5/tenders/{}".format( tender_data["id"]) # get plan response = app.get("/plans/{}".format(plan["data"]["id"])) assert response.json["data"]["tender_id"] == tender_data["id"] # removing status (if the tender was created before the plan statuses release) plan_from_db = app.app.registry.databases.plans.get(plan["data"]["id"]) del plan_from_db["status"] app.app.registry.databases.plans.save(plan_from_db) # add another tender response = app.post_json("/plans/{}/tenders".format(plan["data"]["id"]), {"data": request_tender_data}, status=422) error_data = response.json["errors"] assert len(error_data) == 1 error = error_data[0] assert error["location"] == "body" assert error["name"] == "tender_id" assert error["description"] == "This plan has already got a tender" # check plan status get_response = app.get("/plans/{}".format(plan["data"]["id"])) assert get_response.json["data"]["status"] == "complete"
def test_fail_cfa_second_stage_creation(app, plan): app.authorization = ("Basic", ("broker", "broker")) response = app.post_json( "/plans/{}/tenders".format(plan["data"]["id"]), {"data": cfa_selection_tender_data}, status=422 ) error_data = response.json["errors"] assert len(error_data) > 0 error = error_data[0] assert error["name"] == "procurementMethodType" assert error["description"].startswith(u"Should be one of the first stage values:")
def test_fail_identifier_scheme_validation(app): app.authorization = ("Basic", ("broker", "broker")) request_plan_data = deepcopy(test_plan_data) request_plan_data["procuringEntity"]["identifier"]["scheme"] = "AE-DCCI" response = app.post_json("/plans", {"data": request_plan_data}) plan = response.json response = app.post_json( "/plans/{}/tenders?acc_token={}".format(plan["data"]["id"], plan["access"]["token"]), {"data": test_below_tender_data}, status=422, ) errors = response.json["errors"] assert len(errors) == 1 assert errors[0]["name"] == "procuringEntity" plan_identifier = plan["data"]["procuringEntity"]["identifier"] tender_identifier = test_below_tender_data["procuringEntity"]["identifier"] assert errors[0]["description"] == "procuringEntity.identifier doesn't match: {} {} != {} {}".format( plan_identifier["scheme"], plan_identifier["id"], tender_identifier["scheme"], tender_identifier["id"] )
def test_fail_create_plan_with_milestone(app): app.authorization = ("Basic", ("broker", "broker")) test_data = deepcopy(test_plan_data) test_data["status"] = "draft" test_data["milestones"] = [{ "title": MILESTONE_APPROVAL_TITLE, "type": Milestone.TYPE_APPROVAL, "author": milestone_author, "dueDate": "2001-10-30T11:15:26.641038+03:00" }] response = app.post_json("/plans", {"data": test_data}) assert "milestones" not in response.json["data"]
def test_fail_pass_plans(app, plan, request_tender_data): """ "plans" field cannot be set via 'data' """ app.authorization = ("Basic", ("broker", "broker")) tender_data = dict(**request_tender_data) tender_data["plans"] = [{"id": plan["data"]["id"]}] response = app.post_json("/tenders", {"data": request_tender_data}) assert response.status == "201 Created" tender_data = response.json["data"] assert "plans" not in tender_data # NOT in assert tender_data["title"] == request_tender_data["title"]