def validate_patch_tender_stage2_data(request):
    data = validate_json_data(request)
    if request.context.status == 'draft':
        default_statuses = ['active.tendering', STAGE2_STATUS]
        if data.get('status') not in default_statuses:
            raise_operation_error(request, 'Can\'t update tender in current ({0}) status'.format(data['status']))
        request.validated['data'] = {'status': data.get('status')}
        request.context.status = data.get('status')
        return
    if data:
        if 'items' in data:
            items = request.context.items
            cpv_group_lists = [i.classification.id[:3] for i in items]
            for item in data['items']:
                if 'classification' in item and 'id' in item['classification']:
                    cpv_group_lists.append(item['classification']['id'][:3])
            if len(set(cpv_group_lists)) != 1:
                request.errors.add('body', 'item', 'Can\'t change classification')
                request.errors.status = 403
                raise error_handler(request.errors)
        if 'enquiryPeriod' in data:
            if apply_data_patch(request.context.enquiryPeriod.serialize(), data['enquiryPeriod']):
                request.errors.add('body', 'item', 'Can\'t change enquiryPeriod')
                request.errors.status = 403
                raise error_handler(request.errors)
    if request.context.status == STAGE2_STATUS and data.get('status') == 'active.tendering':
        data = validate_data(request, type(request.tender), True, data)
        if data:  # if no error then add status to validate data
            request.context.status = 'active.tendering'
            data['status'] = 'active.tendering'
    else:
        data = validate_data(request, type(request.tender), True, data)

    return data
def validate_firm_to_create_bid(request):
    tender = request.validated['tender']
    bid = request.validated['bid']
    firm_keys = prepare_shortlistedFirms(tender.shortlistedFirms)
    bid_keys = prepare_bid_identifier(bid)
    if not (bid_keys <= firm_keys):
        raise_operation_error(request, 'Firm can\'t create bid')
 def validate_update_tender(self):
     """ TODO move validators
     This class is inherited from openua package, but validate_update_tender function has different validators (check using working days).
     For now, we have no way to use different validators on methods according to procedure type.
     """
     if self.request.validated['tender_status'] == 'active.tendering' and calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, self.request.validated['tender'], True) > self.request.validated['tender'].tenderPeriod.endDate:
         raise_operation_error(self.request, 'tenderPeriod should be extended by {0.days} working days'.format(TENDERING_EXTRA_PERIOD))
     return True
Beispiel #4
0
    def patch_as_complaint_owner(self, data):
        tender = self.request.validated["tender"]
        data = self.request.validated["data"]
        status = self.context.status
        new_status = data.get("status", status)

        is_qualificationPeriod = tender.qualificationPeriod.startDate < get_now(
        ) and (not tender.qualificationPeriod.endDate
               or tender.qualificationPeriod.endDate > get_now())

        new_rules = get_first_revision_date(tender,
                                            get_now()) > RELEASE_2020_04_19

        if (status in ["draft", "claim", "answered"]
                and new_status == "cancelled"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateCanceled = get_now()
        elif (new_rules and status == "draft"
              and self.context.type == "complaint"
              and new_status == "mistaken"):
            self.context.rejectReason = "cancelledByComplainant"
            apply_patch(self.request, save=False, src=self.context.serialize())
        elif (status in ["pending", "accepted"] and new_status == "stopping"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateCanceled = get_now()
        elif (is_qualificationPeriod and status == "draft"
              and new_status == status):
            apply_patch(self.request, save=False, src=self.context.serialize())
        elif (is_qualificationPeriod and status == "draft"
              and new_status == "claim"):
            if (self.request.validated["qualification"].status
                    == "unsuccessful"
                    and self.request.validated["qualification"].bidID !=
                    self.context.bid_id):
                raise_operation_error(
                    self.request,
                    "Can add claim only on unsuccessful qualification of your bid"
                )
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateSubmitted = get_now()
        elif (is_qualificationPeriod and status == "draft"
              and new_status == "pending" and not new_rules):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.type = "complaint"
            self.context.dateSubmitted = get_now()
        elif (status == "answered" and new_status == status):
            apply_patch(self.request, save=False, src=self.context.serialize())
        else:
            raise_operation_error(
                self.request,
                "Can't update complaint from {} to {} status".format(
                    status, new_status))
Beispiel #5
0
    def patch_as_abovethresholdreviewers(self, data):
        tender = self.request.validated["tender"]
        data = self.request.validated["data"]
        status = self.context.status
        new_status = data.get("status", status)

        new_rules = get_first_revision_date(tender,
                                            get_now()) > RELEASE_2020_04_19

        if (self.request.authenticated_role == "aboveThresholdReviewers"
                and status in ["pending", "accepted", "stopping"]
                and new_status == status):
            apply_patch(self.request, save=False, src=self.context.serialize())
        elif (self.request.authenticated_role == "aboveThresholdReviewers"
              and status in ["pending", "stopping"]
              and ((not new_rules and new_status in ["invalid", "mistaken"]) or
                   (new_status == "invalid"))):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateDecision = get_now()
            self.context.acceptance = False
        elif (self.request.authenticated_role == "aboveThresholdReviewers"
              and status == "pending" and new_status == "accepted"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateAccepted = get_now()
            self.context.acceptance = True
        elif (self.request.authenticated_role == "aboveThresholdReviewers"
              and status in ["accepted", "stopping"]
              and new_status == "declined"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateDecision = get_now()
        elif (self.request.authenticated_role == "aboveThresholdReviewers"
              and status in ["accepted", "stopping"]
              and new_status == "satisfied"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateDecision = get_now()
            tender.status = "active.pre-qualification"
            if tender.qualificationPeriod.endDate:
                tender.qualificationPeriod.endDate = None
        elif (
                self.request.authenticated_role == "aboveThresholdReviewers"
                and
            ((not new_rules and status in ["pending", "accepted", "stopping"])
             or (new_rules and status in ["accepted", "stopping"]))
                and new_status == "stopped"):
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateDecision = get_now()
            self.context.dateCanceled = self.context.dateCanceled or get_now()
        else:
            raise_operation_error(
                self.request,
                "Can't update complaint from {} to {} status".format(
                    status, new_status))
Beispiel #6
0
def validate_document_operation_in_not_allowed_tender_status(request, **kwargs):
    if (
        request.authenticated_role != "auction"
        and request.validated["tender_status"] not in ("draft", "draft.pending", "active.enquiries")
        or request.authenticated_role == "auction"
        and request.validated["tender_status"] not in ("active.auction", "active.qualification")
    ):
        raise_operation_error(
            request,
            "Can't {} document in current ({}) tender status".format(
                OPERATIONS.get(request.method), request.validated["tender_status"]
            ),
        )
Beispiel #7
0
def validate_patch_submission_data(request, **kwargs):
    data = validate_json_data(request)
    data = validate_data(request, type(request.submission), True, data)
    submission = request.validated["submission"]
    framework_id = data.get("frameworkID", submission["frameworkID"])
    framework = get_framework_by_id(request, framework_id)
    if not framework:
        raise_operation_error(
            request,
            "frameworkID must be one of exists frameworks",
        )
    request.validated["framework"] = framework
    return data
def validate_patch_milestone_status(request, **kwargs):
    milestone = request.context
    curr_status = milestone.status
    new_status = request.validated["data"].get("status", curr_status)

    if curr_status == new_status:
        return

    if new_status != "met":
        raise_operation_error(
            request,
            f"Can't switch milestone status from `{curr_status}` to `{new_status}`"
        )
 def validate_update_tender(self):
      """ TODO move validators
      This class is inherited in openua package, but validate_update_tender function has different validators.
      For now, we have no way to use different validators on methods according to procedure type.
      """
      if self.request.authenticated_role != 'auction' and self.request.validated['tender_status'] not in ['active.tendering', STAGE2_STATUS] or \
         self.request.authenticated_role == 'auction' and self.request.validated['tender_status'] not in ['active.auction', 'active.qualification']:
          raise_operation_error(self.request, 'Can\'t {} document in current ({}) tender status'.format(OPERATIONS.get(self.request.method), self.request.validated['tender_status']))
      if self.request.validated['tender_status'] == 'active.tendering' and calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, self.request.validated['tender']) > self.request.validated['tender'].tenderPeriod.endDate:
          raise_operation_error(self.request, 'tenderPeriod should be extended by {0.days} days'.format(TENDERING_EXTRA_PERIOD))
      if self.request.method in ['PUT', 'PATCH']:
          validate_tender_document_update_not_by_author_or_tender_owner(self.request)
      return True
Beispiel #10
0
def validate_update_complaint_not_in_allowed_tender_status(request):
    tender = request.validated["tender"]
    if tender.status not in [
            "active.enquiries",
            "active.tendering",
            "active.auction",
            "active.qualification",
            "active.awarded",
    ]:
        raise_operation_error(
            request,
            "Can't update complaint in current ({}) tender status".format(
                tender.status))
Beispiel #11
0
def validate_update_contracting_value_identical(request):
    if requested_fields_changes(request, ("amountPaid",)):
        value = request.validated["data"].get("value")
        paid_data = request.validated["json_data"].get("amountPaid")
        for attr in ("valueAddedTaxIncluded", "currency"):
            if value and paid_data and paid_data.get(attr) is not None:
                paid = ContractValue(paid_data)
                if value.get(attr) != paid.get(attr):
                    raise_operation_error(
                        request,
                        "{} of {} should be identical to {} of value of contract".format(attr, "amountPaid", attr),
                        name="amountPaid",
                    )
Beispiel #12
0
def validate_json_data_in_active_enquiries(request, **kwargs):
    source = request.validated["data"]
    tender = request.validated["tender_src"]
    data = source
    if "tenderPeriod" in source and "endDate" in source["tenderPeriod"]:
        data["tenderPeriod"] = {"endDate": source["tenderPeriod"]["endDate"]}

    if len(source["items"]) != len(tender["items"]):
        raise_operation_error(request, "Can't update tender items. Items count mismatch")
    if [item["id"] for item in source["items"]] != [item["id"] for item in tender["items"]]:
        raise_operation_error(request, "Can't update tender items. Items order mismatch")

    request.validated["data"] = data
def validate_update_milestone_value(request):
    milestone = request.context
    changes = milestone.__parent__.changes
    pending_change = True if len(
        changes) > 0 and changes[-1].status == 'pending' else False
    if not pending_change and milestone.status in ['pending', 'scheduled']:
        value = request.validated['data']['value']
        for k in value.keys():
            v = getattr(milestone.value, k)
            if v != value[k]:
                raise_operation_error(
                    request,
                    "Contract doesn't have any change in 'pending' status.")
def validate_update_contract_value(request,
                                   name="value",
                                   attrs=("currency", )):
    data = request.validated["data"]
    value = data.get(name)
    if value:
        for ro_attr in attrs:
            field = getattr(request.context, name)
            if field and value.get(ro_attr) != field.to_native().get(ro_attr):
                raise_operation_error(request,
                                      "Can't update {} for contract {}".format(
                                          ro_attr, name),
                                      name=name)
def validate_update_contracting_paid_amount(request):
    data = request.validated["data"]
    value = data.get("value")
    paid = data.get("amountPaid")
    if paid:
        validate_update_contracting_value_amount(request, name="amountPaid")
        for attr in ("amount", "amountNet"):
            paid_amount = paid.get(attr)
            value_amount = value.get(attr)
            if value_amount and paid_amount > value_amount:
                raise_operation_error(
                    request, "AmountPaid {} can`t be greater than value {}".format(attr, attr), name="amountPaid"
                )
Beispiel #16
0
def validate_submission_data(request, **kwargs):
    update_logging_context(request, {"submission_id": "__new__"})
    data = validate_json_data(request)
    model = request.submission_from_data(data, create=False)
    data = validate_data(request, model, data=data)
    framework = get_framework_by_id(request, data["frameworkID"])
    if not framework:
        raise_operation_error(
            request,
            "frameworkID must be one of exists frameworks",
        )
    request.validated["framework"] = framework
    return data
def validate_bid_document_operation_period(request):
    tender = request.validated['tender']
    if request.validated['tender_status'] == 'active.tendering' and (
            tender.tenderPeriod.startDate
            and get_now() < tender.tenderPeriod.startDate
            or get_now() > tender.tenderPeriod.endDate):
        raise_operation_error(
            request,
            'Document can be {} only during the tendering period: from ({}) to ({}).'
            .format(
                'added' if request.method == 'POST' else 'updated',
                tender.tenderPeriod.startDate
                and tender.tenderPeriod.startDate.isoformat(),
                tender.tenderPeriod.endDate.isoformat()))
Beispiel #18
0
def validate_patch_asset_data(request, error_handler, **kwargs):
    data = validate_json_data(request)
    editing_roles = request.content_configurator.available_statuses[
        request.context.status]['editing_permissions']
    if request.authenticated_role not in editing_roles:
        msg = 'Can\'t update {} in current ({}) status'.format(
            request.validated['resource_type'], request.context.status)
        raise_operation_error(request, error_handler, msg)
    default_status = type(request.asset).fields['status'].default
    if data.get('status') == default_status and data.get(
            'status') != request.context.status:
        raise_operation_error(
            request, error_handler,
            'Can\'t switch asset to {} status'.format(default_status))
Beispiel #19
0
def validate_activate_submission(request, **kwargs):
    db = request.registry.db
    submission = request.validated["submission"]
    old_status = submission.status
    new_status = request.validated["data"].get("status", old_status)
    if new_status != "active" or old_status == new_status:
        return
    key = [submission.frameworkID, submission.tenderers[0].identifier.id]
    res = submissions_active_by_framework_id_count_view(db, key=key)
    if res:
        raise_operation_error(
            request,
            "Tenderer already have active submission for framework {}".format(
                submission.frameworkID))
    def patch_as_tender_owner(self, data):
        context = self.context
        status = context.status
        new_status = data.get("status", status)

        if status in ["pending", "accepted"] or new_status == status and status in ["claim", "satisfied"]:
            apply_patch(self.request, save=False, src=context.serialize())

        elif status == "claim" and new_status == "answered":
            if not data.get("resolution", context.resolution) or not data.get("resolutionType", context.resolutionType):
                raise_operation_error(self.request, "Can't update complaint: resolution and resolutionType required")

            if len(data.get("resolution", context.resolution)) < 20:
                raise_operation_error(self.request, "Can't update complaint: resolution too short")
            apply_patch(self.request, save=False, src=context.serialize())
            context.dateAnswered = get_now()

        elif status == "satisfied" and new_status == "resolved":
            if not data.get("tendererAction", context.tendererAction):
                raise_operation_error(self.request, "Can't update complaint: tendererAction required")

            apply_patch(self.request, save=False, src=context.serialize())
        else:
            raise_operation_error(self.request,
                                  "Can't update complaint from {} to {} status".format(status, new_status))
    def patch_draft_as_complaint_owner(self, data):
        context = self.context
        status = context.status
        new_status = data.get("status", self.context.status)

        if new_status == self.context.status:
            apply_patch(self.request, save=False, src=context.serialize())
        elif status == "draft" and new_status == "mistaken":
            apply_patch(self.request, save=False, src=context.serialize())
        elif new_status == "pending":
            apply_patch(self.request, save=False, src=context.serialize())
            context.dateSubmitted = get_now()
        else:
            raise_operation_error(self.request, "Can't update draft complaint into {} status".format(new_status))
def validate_change_data(request, **kwargs):
    update_logging_context(request, {"change_id": "__new__"})
    data = validate_json_data(request)
    if not "rationaleType" in data:
        raise_operation_error(request, "Can't add change without rationaleType")
    model = queryUtility(IChange, data["rationaleType"])
    if not model:
        raise_operation_error(
            request,
            "rationaleType should be one of {}".format(
                ["taxRate", "itemPriceVariation", "thirdParty", "partyWithdrawal"]
            ),
        )
    return validate_data(request, model, data=data)
def validate_view_financial_bid_documents_allowed_in_tender_status(request):
    tender_status = request.validated["tender_status"]
    view_forbidden_states = (
        "active.tendering",
        "active.pre-qualification",
        "active.pre-qualification.stand-still",
        "active.auction",
    )
    if tender_status in view_forbidden_states and request.authenticated_role != "bid_owner":
        raise_operation_error(
            request,
            "Can't view bid documents in current ({}) tender status".format(
                tender_status),
        )
Beispiel #24
0
 def validate_question(self, operation):
     """ TODO move validators
     This class is inherited from below package, but validate_question function has different validators.
     For now, we have no way to use different validators on methods according to procedure type.
     """
     tender = self.request.validated["tender"]
     now = get_now()
     if operation == "add" and (now < tender.enquiryPeriod.startDate
                                or now > tender.enquiryPeriod.endDate):
         raise_operation_error(self.request,
                               "Can add question only in enquiryPeriod")
     if operation == "update" and tender.status != "active.tendering":
         raise_operation_error(
             self.request,
             "Can't update question in current ({}) tender status".format(
                 tender.status))
     question = self.request.validated["question"]
     items_dict = {i.id: i.relatedLot for i in tender.items}
     if any([
             i.status != "active" for i in tender.lots
             if question.questionOf == "lot" and i.id ==
             question.relatedItem or question.questionOf == "item"
             and i.id == items_dict[question.relatedItem]
     ]):
         raise_operation_error(
             self.request,
             "Can {} question only in active lot status".format(operation))
     if operation == "update" and now > tender.enquiryPeriod.clarificationsUntil:
         raise_operation_error(
             self.request,
             "Can update question only before enquiryPeriod.clarificationsUntil"
         )
     return True
def validate_patch_qualification_data(request, **kwargs):
    data = validate_json_data(request)
    qualification = request.validated["qualification"]
    framework_id = data.get("frameworkID", qualification["frameworkID"])
    framework = get_framework_by_id(request.registry.db, framework_id)
    if not framework:
        raise_operation_error(
            request,
            "frameworkID must be one of existing frameworks",
        )
    request.validated["framework_src"] = framework
    request.validated["framework"] = Framework(framework)
    request.validated["framework"].__parent__ = qualification.__parent__
    return validate_data(request, type(request.qualification), True, data)
Beispiel #26
0
 def validate_award_document(self, operation):
     """ TODO move validators
     This class is inherited in openua package, but validate_award_document function has different validators.
     For now, we have no way to use different validators on methods according to procedure type.
     """
     if self.request.validated['tender_status'] != 'active.qualification':
         raise_operation_error(self.request, 'Can\'t {} document in current ({}) tender status'.format(operation, self.request.validated['tender_status']))
     if any([i.status != 'active' for i in self.request.validated['tender'].lots if i.id == self.request.validated['award'].lotID]):
         raise_operation_error(self.request, 'Can {} document only in active lot status'.format(operation))
     if operation == 'update' and self.request.authenticated_role != (self.context.author or 'tender_owner'):
         self.request.errors.add('url', 'role', 'Can update document only author')
         self.request.errors.status = 403
         raise error_handler(self.request.errors)
     return True
def _validate_plan_availability(request):
    data = request.validated["data"]
    procurement_method_type = data.get("tender",
                                       {}).get("procurementMethodType", "")
    now = get_now()
    if ((now >= RELEASE_SIMPLE_DEFENSE_FROM
         and procurement_method_type == "aboveThresholdUA.defense")
            or (now < RELEASE_SIMPLE_DEFENSE_FROM
                and procurement_method_type == "simple.defense")):
        raise_operation_error(
            request,
            "procedure with procurementMethodType = {} is not available".
            format(procurement_method_type),
        )
def validate_submission_status(request, **kwargs):
    status_map = {
        "draft": ("draft", "active", "deleted"),
    }
    curr_status = request.validated["submission_src"]["status"]
    new_status = request.validated["data"].get("status", curr_status)

    available_statuses = status_map.get(curr_status, [])

    if new_status not in available_statuses:
        raise_operation_error(
            request,
            "Can't update submission from current ({}) to new ({}) status".
            format(curr_status, new_status))
Beispiel #29
0
def validate_contract_document_operation(request, **kwargs):
    operation = OPERATIONS.get(request.method)
    if request.validated["tender_status"] not in\
       ["active.qualification", "active.awarded"]:
        raise_operation_error(
            request,
            "Can't {} document in current ({}) tender status".format(
                operation, request.validated["tender_status"]),
        )
    if request.validated["contract"].status not in ["pending", "active"]:
        raise_operation_error(
            request,
            "Can't {} document in current contract status".format(operation))
    return True
Beispiel #30
0
def validate_agreement_data(request, **kwargs):
    update_logging_context(request, {"agreement_id": "__new__"})
    data = validate_json_data(request)
    model = request.agreement_from_data(data, create=False)
    _validate_agreement_accreditation_level(request, model)
    if data.get("frameworkID"):
        framework = get_framework_by_id(request, data["frameworkID"])
        if not framework:
            raise_operation_error(
                request,
                "frameworkID must be one of exists frameworks",
            )
        request.validated["framework"] = framework
    return validate_data(request, model, data=data)
Beispiel #31
0
def validate_complaint_document_operation_not_in_allowed_status(request):
    if request.validated["tender_status"] not in [
            "active.enquiries",
            "active.tendering",
            "active.auction",
            "active.qualification",
            "active.awarded",
    ]:
        raise_operation_error(
            request,
            "Can't {} document in current ({}) tender status".format(
                OPERATIONS.get(request.method),
                request.validated["tender_status"]),
        )
Beispiel #32
0
def validate_download_bid_document(request):
    tender = request.validated["tender"]
    bid = request.validated["bid"]

    acc_token = extract_access_token(request)
    auth_user_id = request.authenticated_userid

    if request.params.get("download"):
        document = request.validated["document"]
        is_owner = (auth_user_id == bid.owner and acc_token == bid.owner_token)
        is_tender_owner = (auth_user_id == tender.owner
                           and acc_token == tender.owner_token)
        if document.confidentiality == "buyerOnly" and not is_owner and not is_tender_owner:
            raise_operation_error(request, "Document download forbidden.")
    def patch_as_complaint_owner(self, data):
        status = self.context.status
        new_status = data.get("status", status)

        if status in ["draft", "claim", "answered"] and new_status == "cancelled":
            apply_patch(self.request, save=False, src=self.context.serialize())
            self.context.dateCanceled = get_now()
        elif status == "draft":
            complaint_period = self.request.validated["award"].complaintPeriod
            is_complaint_period = (
                complaint_period.startDate < get_now() < complaint_period.endDate
                if complaint_period.endDate
                else complaint_period.startDate < get_now()
            )
            if not is_complaint_period:
                raise_operation_error(self.request, "Can't update draft complaint not in complaintPeriod")

            if new_status == status:
                apply_patch(self.request, save=False, src=self.context.serialize())
            elif new_status == "claim":
                apply_patch(self.request, save=False, src=self.context.serialize())
                self.context.dateSubmitted = get_now()
            else:
                raise_operation_error(self.request, "Can't update draft complaint to {} status".format(new_status))

        elif status == "answered" and new_status == status:
            apply_patch(self.request, save=False, src=self.context.serialize())

        elif status == "answered" and new_status == "resolved":
            if not isinstance(data.get("satisfied", self.context.satisfied), bool):
                raise_operation_error(self.request, "Can't resolve answered claim: satisfied required")

            apply_patch(self.request, save=False, src=self.context.serialize())
        else:
            raise_operation_error(self.request, "Can't update complaint from {} to {}".format(status, new_status))
Beispiel #34
0
    def collection_post(self):
        """Post a complaint
        """
        tender = self.request.validated["tender"]
        old_rules = get_first_revision_date(tender) < RELEASE_2020_04_19

        complaint = self.request.validated["complaint"]
        complaint.relatedLot = self.context.lotID
        complaint.date = get_now()
        complaint.bid_id = get_bid_id(self.request)
        if complaint.status == "claim" and complaint.type == "claim":
            complaint.dateSubmitted = get_now()
        elif old_rules and complaint.status == "pending":
            complaint.type = "complaint"
            complaint.dateSubmitted = get_now()
        else:
            complaint.status = "draft"
        if (self.context.status == "unsuccessful"
                and complaint.status == "claim"
                and self.context.bidID != complaint.bid_id):
            raise_operation_error(
                self.request,
                "Can add claim only on unsuccessful qualification of your bid")
        complaint.complaintID = "{}.{}{}".format(
            tender.tenderID,
            self.server_id,
            calculate_total_complaints(tender) + 1,
        )
        access = set_ownership(complaint, self.request)
        self.context.complaints.append(complaint)
        if save_tender(self.request):
            self.LOGGER.info(
                "Created tender qualification complaint {}".format(
                    complaint.id),
                extra=context_unpack(
                    self.request,
                    {"MESSAGE_ID": "tender_qualification_complaint_create"},
                    {"complaint_id": complaint.id},
                ),
            )
            self.request.response.status = 201
            self.request.response.headers["Location"] = self.request.route_url(
                "{}:Tender Qualification Complaints".format(
                    tender.procurementMethodType),
                tender_id=tender.id,
                qualification_id=self.request.validated["qualification_id"],
                complaint_id=complaint["id"],
            )
            return {"data": complaint.serialize("view"), "access": access}
def stage2_bid_post(self):
    tender = self.request.validated['tender']
    bid = self.request.validated['bid']
    # TODO can't move validator because of self.allowed_bid_status_on_create
    if bid.status not in self.allowed_bid_status_on_create:
        raise_operation_error(self.request, 'Bid can be added only with status: {}.'.format(self.allowed_bid_status_on_create))
    tender.modified = False
    api_set_ownership(bid, self.request)
    tender.bids.append(bid)
    if save_tender(self.request):
        self.LOGGER.info('Created tender bid {}'.format(bid.id),
                         extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_create'},
                                              {'bid_id': bid.id}))
        self.request.response.status = 201
        self.request.response.headers['Location'] = self.request.route_url('{}:Tender Bids'.format(tender.procurementMethodType), tender_id=tender.id,
                                                                           bid_id=bid['id'])
        return {
            'data': bid.serialize('view'),
            'access': {
                'token': bid.owner_token
            }
        }
def validate_credentials_generate(request):
    contract = request.validated['contract']
    if contract.status != "active":
        raise_operation_error(request, 'Can\'t generate credentials in current ({}) contract status'.format(contract.status))
def validate_terminate_contract_without_amountPaid(request):
    contract = request.validated['contract']
    if contract.status == 'terminated' and not contract.amountPaid:
        raise_operation_error(request, 'Can\'t terminate contract while \'amountPaid\' is not set')
def validate_contract_update_not_in_allowed_status(request):
    contract = request.validated['contract']
    if request.authenticated_role != 'Administrator' and contract.status != 'active':
        raise_operation_error(request, 'Can\'t update contract in current ({}) status'.format(contract.status))
def validate_update_contract_change_status(request):
    data = request.validated['data']
    if not data.get("dateSigned", ''):
        raise_operation_error(request, 'Can\'t update contract change status. \'dateSigned\' is required.')
def validate_contract_change_update_not_in_allowed_change_status(request):
    change = request.validated['change']
    if change.status == 'active':
        raise_operation_error(request, 'Can\'t update contract change in current ({}) status'.format(change.status))
def validate_create_contract_change(request):
    contract = request.validated['contract']
    if contract.changes and contract.changes[-1].status == 'pending':
        raise_operation_error(request, 'Can\'t create new contract change while any (pending) change exists')
def validate_contract_change_add_not_in_allowed_contract_status(request):
    contract = request.validated['contract']
    if contract.status != 'active':
        raise_operation_error(request, 'Can\'t add contract change in current ({}) contract status'.format(contract.status))
def validate_submit_claim_time(request):
    tender = request.context
    claim_submit_time = request.content_configurator.tender_claim_submit_time
    if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -claim_submit_time, tender, True):
        raise_operation_error(request,'Can submit claim not later than {0.days} days before tenderPeriod end'.format(claim_submit_time))
 def patch(self):
     """Post a complaint resolution
     """
     tender = self.request.validated['tender']
     data = self.request.validated['data']
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered'] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status in ['pending', 'accepted'] and data.get('status', self.context.status) == 'stopping':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == 'claim':
         if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -CLAIM_SUBMIT_TIME, tender, True):
             raise_operation_error(self.request, 'Can submit claim not later than {0.days} days before tenderPeriod end'.format(CLAIM_SUBMIT_TIME))
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status in ['draft', 'claim'] and data.get('status', self.context.status) == 'pending':
         if get_now() > tender.complaintPeriod.endDate:
             raise_operation_error(self.request, 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME))
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is True and data.get('status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is False and data.get('status', self.context.status) == 'pending':
         if get_now() > tender.complaintPeriod.endDate:
             raise_operation_error(self.request, 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME))
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateEscalated = get_now()
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('status', self.context.status) == self.context.status:
         now = get_now()
         if now > tender.enquiryPeriod.clarificationsUntil:
             raise_operation_error(self.request, 'Can update claim only before enquiryPeriod.clarificationsUntil')
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('resolution', self.context.resolution) and data.get('resolutionType', self.context.resolutionType) and data.get('status', self.context.status) == 'answered':
         now = get_now()
         if now > tender.enquiryPeriod.clarificationsUntil:
             raise_operation_error(self.request, 'Can update claim only before enquiryPeriod.clarificationsUntil')
         if len(data.get('resolution', self.context.resolution)) < 20:
             raise_operation_error(self.request, 'Can\'t update complaint: resolution too short')
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['pending', 'accepted']:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('tendererAction', self.context.tendererAction) and data.get('status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['pending', 'accepted', 'stopping'] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['pending', 'stopping'] and data.get('status', self.context.status) in ['invalid', 'mistaken']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'accepted':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['accepted', 'stopping'] and data.get('status', self.context.status) in ['declined', 'satisfied']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['pending', 'accepted', 'stopping'] and data.get('status', self.context.status) == 'stopped':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.dateCanceled = self.context.dateCanceled or get_now()
     else:
         raise_operation_error(self.request, 'Can\'t update complaint')
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'stopping'] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info('Updated tender complaint {}'.format(self.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'}))
         return {'data': self.context.serialize("view")}
def validate_tender_period_extension_with_working_days(request):
    tender = request.context
    extra_period = request.content_configurator.tendering_period_extra
    if calculate_business_date(get_now(), extra_period, tender, True) > request.validated['tender'].tenderPeriod.endDate:
        raise_operation_error(request,'tenderPeriod should be extended by {0.days} working days'.format(extra_period))
    def patch(self):
        """Tender Edit (partial)

        For example here is how procuring entity can change number of items to be procured and total Value of a tender:

        .. sourcecode:: http

            PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        And here is the response to be expected:

        .. sourcecode:: http

            HTTP/1.0 200 OK
            Content-Type: application/json

            {
                "data": {
                    "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                    "tenderID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:12:34.956Z",
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        """
        tender = self.context
        data = self.request.validated['data']
        if self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] in ['active.tendering', STAGE2_STATUS]:
            if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']:
                self.request.validated['tender'].tenderPeriod.import_data(data['tenderPeriod'])
                validate_tender_period_extension(self.request)
                self.request.registry.notify(TenderInitializeEvent(self.request.validated['tender']))
                self.request.validated['data']["enquiryPeriod"] = self.request.validated['tender'].enquiryPeriod.serialize()

        apply_patch(self.request, save=False, src=self.request.validated['tender_src'])
        if self.request.authenticated_role == 'chronograph':
            check_status_eu(self.request)
        elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering':
            tender.invalidate_bids_data()
        elif self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.pre-qualification' and \
                tender.status == "active.pre-qualification.stand-still":
            if all_bids_are_reviewed(self.request):
                tender.qualificationPeriod.endDate = calculate_business_date(get_now(), COMPLAINT_STAND_STILL,
                                                                             self.request.validated['tender'])
                tender.check_auction_time()
            else:
                raise_operation_error(self.request, 'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified')

        save_tender(self.request)
        self.LOGGER.info('Updated tender {}'.format(tender.id),
                         extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'}))
        return {'data': tender.serialize(tender.status)}
 def validate_update_tender(self):
     tender = self.request.validated['tender']
     if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, tender, True) > tender.tenderPeriod.endDate:
         raise_operation_error(self.request, 'tenderPeriod should be extended by {0.days} working days'.format(TENDERING_EXTRA_PERIOD))
     return True
def validate_credentials_generation(request):
    if request.validated['tender'].status != "draft.stage2":
        raise_operation_error(request, 'Can\'t generate credentials in current ({}) contract status'.format(request.validated['tender'].status))
def validate_tender_update(request):
    tender = request.context
    data = request.validated['data']
    if request.authenticated_role == 'tender_owner' and 'status' in data and \
            data['status'] not in ['active.pre-qualification.stand-still', 'active.stage2.waiting', tender.status]:
        raise_operation_error(request, 'Can\'t update tender status')
def validate_contract_document_operation_not_in_allowed_contract_status(request):
    if request.validated['contract'].status != 'active':
        raise_operation_error(request, 'Can\'t {} document in current ({}) contract status'.format(OPERATIONS.get(request.method), request.validated['contract'].status))
def validate_add_document_to_active_change(request):
    data = request.validated['data']
    if "relatedItem" in data and data.get('documentOf') == 'change':
        if not [1 for c in request.validated['contract'].changes if c.id == data['relatedItem'] and c.status == 'pending']:
            raise_operation_error(request, 'Can\'t add document to \'active\' change')
def validate_lot_operation_for_stage2(request):
    operations = {"POST": "create", "PATCH": "update", "DELETE": "delete"}
    raise_operation_error(request, 'Can\'t {} lot for tender stage2'.format(operations.get(request.method)))