Beispiel #1
0
        class QuestionPack(Model):

            question = ModelType(Question)
class ContractItem(BaseItem):
    class Options:
        roles = {"edit_contract": whitelist("unit")}

    unit = ModelType(Unit)
class BaseLot(BaseResourceItem):
    class Options:
        roles = {
            'create': create_role,
            'plain': plain_role,
            'edit': edit_role,
            'view': view_role,
            'listing': listing_role,
            'default': schematics_default_role,
            'Administrator': Administrator_role,
            # Draft role
            'draft': view_role,
            'edit_draft': whitelist('status'),
            # Pending role
            'pending': view_role,
            'edit_pending': edit_role,
            # Deleted role
            'deleted': view_role,
            'edit_deleted': whitelist(),
            # Verification role
            'verification': view_role,
            'edit_verification': whitelist(),
            # Recomposed role
            'recomposed': view_role,
            'edit_recomposed': whitelist(),
            # Active.salable role
            'active.salable':  view_role,
            'edit_active.salable': whitelist('status'),
            # pending.dissolution role
            'pending.dissolution': view_role,
            'edit_pending.dissolution': whitelist('status'),
            # Dissolved role
            'dissolved': view_role,
            'edit_dissolved': whitelist(),
            # Active.awaiting role
            'active.awaiting': view_role,
            'edit_active.awaiting': whitelist(),
            # Active.auction role
            'active.auction': view_role,
            'edit_active.auction': edit_role,
            # pending.sold role
            'pending.sold': view_role,
            'edit.pending.sold': whitelist(),
            # Sold role
            'sold': view_role,
            'concierge': whitelist('status'),
            'convoy': whitelist('status', 'auctions')
        }

    lotID = StringType()  # lotID should always be the same as the OCID. It is included to make the flattened data structure more convenient.
    lotIdentifier = StringType(required=True, min_length=1)
    date = IsoDateTimeType()
    title = StringType(required=True)
    title_en = StringType()
    title_ru = StringType()
    description = StringType()
    description_en = StringType()
    description_ru = StringType()
    lotCustodian = ModelType(Organization, required=True)
    documents = ListType(ModelType(Document), default=list())  # All documents and attachments related to the lot.

    create_accreditation = 1
    edit_accreditation = 2

    def __local_roles__(self):
        roles = dict([('{}_{}'.format(self.owner, self.owner_token), 'lot_owner')])
        return roles

    def get_role(self):
        root = self.__parent__
        request = root.request
        if request.authenticated_role == 'Administrator':
            role = 'Administrator'
        elif request.authenticated_role == 'concierge':
            role = 'concierge'
        elif request.authenticated_role == 'convoy':
            role = 'convoy'
        else:
            role = 'edit_{}'.format(request.context.status)
        return role

    def __acl__(self):
        acl = [
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_lot'),
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'upload_lot_documents'),
        ]
        return acl
Beispiel #4
0
class Plan(SchematicsDocument, Model):
    """Plan model"""

    class Options:
        _edit_role = whitelist(
            "procuringEntity", "tender", "budget", "classification", "additionalClassifications", "documents",
            "items", "buyers", "status", "cancellation", "procurementMethodType",
        )
        _create_role = _edit_role + whitelist("mode")
        _common_view = _create_role + whitelist(
            "doc_id", "tender_id", "planID", "datePublished", "owner", "milestones", "switch_status",
        )
        roles = {
            "plain": _common_view + whitelist("owner_token", "transfer_token"),
            "revision": whitelist("revisions"),
            "create": _create_role,
            "edit": _edit_role,
            "view": _common_view + whitelist("dateModified"),
            "listing": whitelist("dateModified", "doc_id"),
            "Administrator": whitelist("status", "mode", "procuringEntity"),
            "default": schematics_default_role,
        }

    def __local_roles__(self):
        return dict([("{}_{}".format(self.owner, self.owner_token), "plan_owner")])

    # fields

    # procuringEntity:identifier:scheme *
    # procuringEntity:identifier:id *
    # procuringEntity:name *
    # procuringEntity:identifier:legalName *
    procuringEntity = ModelType(PlanOrganization, required=True)

    # tender:tenderPeriod:startDate *
    # tender:procurementMethod *
    tender = ModelType(PlanTender, required=True)

    # budget:project:name
    # budget:project:id
    # budget:id *
    # budget:description *
    # budget:currency
    # budget:amount *
    # budget:amountNet
    budget = ModelType(Budget, required=False)

    # classification:scheme *
    # classification:id *
    # classification:description *
    classification = ModelType(CPVClassification, required=True)

    # additionalClassifications[0]:scheme
    # additionalClassifications[0]:id
    # additionalClassifications[0]:description
    additionalClassifications = ListType(ModelType(Classification, required=True), default=list(), required=False)

    documents = ListType(
        ModelType(Document, required=True), default=list()
    )  # All documents and attachments related to the tender.
    tender_id = MD5Type()
    planID = StringType()
    mode = StringType(choices=["test"])  # flag for test data ?
    items = ListType(ModelType(PlanItem, required=True), required=False, validators=[validate_items_uniq])
    buyers = ListType(ModelType(PlanOrganization, required=True), min_size=1, max_size=1)
    status = StringType(choices=["draft", "scheduled", "cancelled", "complete"], default="scheduled")
    cancellation = ModelType(Cancellation)
    milestones = ListType(ModelType(Milestone, required=True), validators=[validate_items_uniq], default=list())

    _attachments = DictType(DictType(BaseType), default=dict())  # couchdb attachments
    dateModified = IsoDateTimeType()
    datePublished = IsoDateTimeType(default=get_now)
    owner_token = StringType()
    transfer_token = StringType()
    owner = StringType()
    procurementMethodType = StringType()
    revisions = ListType(ModelType(Revision, required=True), default=list())

    create_accreditations = (ACCR_1, ACCR_3, ACCR_5)

    __name__ = ""

    def __acl__(self):
        acl = [
            (Allow, "{}_{}".format(self.owner, self.owner_token), "edit_plan"),
            (Allow, "{}_{}".format(self.owner, self.owner_token), "upload_plan_documents"),
        ]
        return acl

    def __repr__(self):
        return "<%s:%r@%r>" % (type(self).__name__, self.id, self.rev)

    @serializable(serialized_name="id")
    def doc_id(self):
        """A property that is serialized by schematics exports."""
        return self._id

    @serializable(serialized_name="status")
    def switch_status(self):
        if isinstance(self.cancellation, Cancellation) and self.cancellation.status == "active":
            return "cancelled"
        if self.tender_id is not None:
            return "complete"
        return self.status

    def validate_status(self, data, status):
        if status == "cancelled":
            cancellation = data.get("cancellation")
            if not isinstance(cancellation, Cancellation) or cancellation.status != "active":
                raise ValidationError(u"An active cancellation object is required")
        elif status == "complete":
            if not data.get("tender_id"):
                method = data.get("tender").get("procurementMethodType")
                if method not in ("belowThreshold", "reporting", ""):
                    raise ValidationError(u"Can't complete plan with '{}' tender.procurementMethodType".format(method))

    def validate_items(self, data, items):
        cpv_336_group = items[0].classification.id[:3] == "336" if items else False
        if (
            not cpv_336_group
            and get_first_revision_date(data, default=get_now()) > CPV_ITEMS_CLASS_FROM
            and items
            and len(set([i.classification.id[:4] for i in items])) != 1
        ):
            raise ValidationError(u"CPV class of items should be identical")
        else:
            validate_cpv_group(items)

    def validate_budget(self, data, budget):
        if not budget and data["tender"]["procurementMethodType"] != "esco":
            raise ValidationError(u"This field is required.")

    def validate_buyers(self, data, value):
        validation_date = get_first_revision_date(data, default=get_now())
        if validation_date >= PLAN_BUYERS_REQUIRED_FROM and not value:
            raise ValidationError(BaseType.MESSAGES["required"])

    def import_data(self, raw_data, **kw):
        """
        Converts and imports the raw data into the instance of the model
        according to the fields in the model.
        :param raw_data:
            The data to be imported.
        """
        data = self.convert(raw_data, **kw)
        del_keys = [
            k
            for k in data.keys()
            if data[k] == self.__class__.fields[k].default
            and k not in ("status",)  # save status even if it's changed to default
            or data[k] == getattr(self, k)
        ]
        for k in del_keys:
            del data[k]
        self._data.update(data)
        return self
class Contract(SchematicsDocument, BaseContract):
    """ Contract """

    revisions = ListType(ModelType(Revision), default=list())
    dateModified = IsoDateTimeType()
    _attachments = DictType(DictType(BaseType), default=dict())  # couchdb attachments
    items = ListType(ModelType(Item), required=False, min_size=1, validators=[validate_items_uniq])
    tender_token = StringType(required=True)
    tender_id = StringType(required=True)
    owner_token = StringType(default=lambda: uuid4().hex)
    owner = StringType()
    mode = StringType(choices=['test'])
    status = StringType(choices=['terminated', 'active'], default='active')
    suppliers = ListType(ModelType(Organization), min_size=1, max_size=1)
    procuringEntity = ModelType(ProcuringEntity, required=True)  # The entity managing the procurement, which may be different from the buyer who is paying / using the items being procured.
    changes = ListType(ModelType(Change), default=list())
    documents = ListType(ModelType(Document), default=list())
    amountPaid = ModelType(Value)
    terminationDetails = StringType()

    create_accreditation = 3  # TODO

    class Options:
        roles = {
            'plain': plain_role,
            'create': contract_create_role,
            'edit_active': contract_edit_role,
            'edit_terminated': whitelist(),
            'view': contract_view_role,
            'Administrator': contract_administrator_role,
            'default': schematics_default_role,
        }

    def __local_roles__(self):
        return dict([('{}_{}'.format(self.owner, self.owner_token), 'contract_owner'),
                     ('{}_{}'.format(self.owner, self.tender_token), 'tender_owner')])

    def __acl__(self):
        acl = [
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_contract'),
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'upload_contract_documents'),
            (Allow, '{}_{}'.format(self.owner, self.tender_token), 'generate_credentials')
        ]
        return acl

    def import_data(self, raw_data, **kw):
        """
        Converts and imports the raw data into the instance of the model
        according to the fields in the model.
        :param raw_data:
            The data to be imported.
        """
        data = self.convert(raw_data, **kw)
        del_keys = [k for k in data.keys() if data[k] == self.__class__.fields[k].default or data[k] == getattr(self, k)]
        for k in del_keys:
            del data[k]

        self._data.update(data)
        return self

    def get_role(self):
        root = self.__parent__
        request = root.request
        if request.authenticated_role == 'Administrator':
            role = 'Administrator'
        else:
            role = 'edit_{}'.format(request.context.status)
        return role

    @serializable(serialized_name='id')
    def doc_id(self):
        """A property that is serialized by schematics exports."""
        return self._id

    @serializable(serialized_name='amountPaid', serialize_when_none=False, type=ModelType(Value))
    def contract_amountPaid(self):
        if self.amountPaid:
            return Value(dict(amount=self.amountPaid.amount,
                              currency=self.value.currency,
                              valueAddedTaxIncluded=self.value.valueAddedTaxIncluded))
class NegotiationTender(ReportingTender):
    """ Negotiation """
    class Options:
        namespace = "Tender"
        roles = ReportingTender.Options.roles

    items = ListType(
        ModelType(Item, required=True),
        required=True,
        min_size=1,
        validators=[
            validate_cpv_group, validate_items_uniq, validate_classification_id
        ],
    )
    awards = ListType(ModelType(Award, required=True), default=list())
    contracts = ListType(ModelType(Contract, required=True), default=list())
    cause = StringType(
        choices=[
            "artContestIP",
            "noCompetition",
            "twiceUnsuccessful",
            "additionalPurchase",
            "additionalConstruction",
            "stateLegalServices",
        ],
        required=True,
    )
    causeDescription = StringType(required=True, min_length=1)
    causeDescription_en = StringType(min_length=1)
    causeDescription_ru = StringType(min_length=1)
    procurementMethodType = StringType(default="negotiation")

    create_accreditations = (ACCR_3, ACCR_5)
    central_accreditations = (ACCR_5, )
    edit_accreditations = (ACCR_4, )

    procuring_entity_kinds = ["general", "special", "defense", "central"]

    lots = ListType(ModelType(Lot, required=True),
                    default=list(),
                    validators=[validate_lots_uniq])

    cancellations = ListType(ModelType(NegotiationCancellation, required=True),
                             default=list())

    # Required milestones
    def validate_milestones(self, data, value):
        required = get_first_revision_date(
            data, default=get_now()) > MILESTONES_VALIDATION_FROM
        if required and (value is None or len(value) < 1):
            raise ValidationError(
                "Tender should contain at least one milestone")

    def __acl__(self):
        acl = [
            (Allow, "g:brokers", "create_award_complaint"),
            (Allow, "g:brokers", "create_cancellation_complaint"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_complaint"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_cancellation"),
        ]

        self._acl_cancellation(acl)
        return acl

    @serializable(serialize_when_none=False)
    def next_check(self):
        checks = []
        extend_next_check_by_complaint_period_ends(self, checks)
        return min(checks).isoformat() if checks else None
class HealthResponse(NodeHealth):
    slave_nodes = ListType(ModelType(NodeHealth),
                           serialize_when_none=False,
                           required=False)
Beispiel #8
0
class Award(BaseEUAward):
    """ESCO award model"""

    value = ModelType(ESCOValue)
    items = ListType(ModelType(Item))
Beispiel #9
0
class Feature(BaseFeature):
    enum = ListType(ModelType(FeatureValue), default=list(), min_size=1, validators=[validate_values_uniq])
Beispiel #10
0
class LotValue(BaseLotValue):

    value = ModelType(ESCOValue, required=True)

    def validate_value(self, data, value):
        pass
Beispiel #11
0
class Contract(BaseEUContract):
    """ESCO contract model"""

    value = ModelType(ESCOValue)
    items = ListType(ModelType(Item))
class PluginInitResponse(Model):
    _metadata = ModelType(PluginMetadata, default=PluginMetadata, serialized_name='metadata')
Beispiel #13
0
 class Player(Model):
     id = IntType()
     location = ModelType(Location)
Beispiel #14
0
 class Question(Model):
     id = StringType()
     resources = ModelType(QuestionResources)
Beispiel #15
0
class ComplexModel(Model):
    user = ModelType(User)
    description = StringType()
    is_allowed = BooleanType()
Beispiel #16
0
class Tender(BaseTender):
    """ ESCO Tender model """
    class Options:
        roles = {
            'plain': plain_role,
            'create': create_role_eu + blacklist('minValue', 'tender_minValue', 'minimalStep', 'tender_minimalStep'),
            'edit': edit_role_eu + blacklist('minValue', 'tender_minValue', 'minimalStep', 'tender_minimalStep'),
            'edit_draft': edit_role_eu + blacklist('minValue', 'tender_minValue', 'minimalStep', 'tender_minimalStep'),
            'edit_active.tendering': edit_role_eu + blacklist('minValue', 'tender_minValue', 'minimalStep', 'tender_minimalStep'),
            'edit_active.pre-qualification': whitelist('status'),
            'edit_active.pre-qualification.stand-still': whitelist(),
            'edit_active.auction': whitelist(),
            'edit_active.qualification': whitelist(),
            'edit_active.awarded': whitelist(),
            'edit_complete': whitelist(),
            'edit_unsuccessful': whitelist(),
            'edit_cancelled': whitelist(),
            'view': view_role,
            'listing': listing_role,
            'auction_view': auction_view_role + whitelist('NBUdiscountRate', 'minimalStepPercentage', 'yearlyPaymentsPercentageRange', 'fundingKind', 'procurementMethodType'),
            'auction_post': auction_post_role,
            'auction_patch': auction_patch_role,
            'draft': enquiries_role,
            'active.tendering': enquiries_role,
            'active.pre-qualification': pre_qualifications_role,
            'active.pre-qualification.stand-still': pre_qualifications_role,
            'active.auction': pre_qualifications_role,
            'active.qualification': view_role,
            'active.awarded': view_role,
            'complete': view_role,
            'unsuccessful': view_role,
            'cancelled': view_role,
            'chronograph': chronograph_role,
            'chronograph_view': chronograph_view_role,
            'Administrator': Administrator_role,
            'default': schematics_default_role,
            'contracting': whitelist('doc_id', 'owner'),
        }

    procurementMethodType = StringType(default="esco")
    title_en = StringType(required=True, min_length=1)

    items = ListType(ModelType(Item), required=True, min_size=1, validators=[validate_cpv_group, validate_items_uniq])  # The goods and services to be purchased, broken into line items wherever possible. Items should not be duplicated, but a quantity of 2 specified instead.
    minValue = ModelType(Value, required=False, default={'amount': 0, 'currency': 'UAH', 'valueAddedTaxIncluded': True})  # The total estimated value of the procurement.

    enquiryPeriod = ModelType(EnquiryPeriod, required=False)
    tenderPeriod = ModelType(PeriodStartEndRequired, required=True)
    auctionPeriod = ModelType(TenderAuctionPeriod, default={})
    hasEnquiries = BooleanType()  # A Yes/No field as to whether enquiries were part of tender process.
    awardPeriod = ModelType(Period)  # The date or period on which an award is anticipated to be made.
    numberOfBidders = IntType()  # The number of unique tenderers who participated in the tender
    bids = SifterListType(BidModelType(Bid), default=list(), filter_by='status', filter_in_values=['invalid', 'invalid.pre-qualification', 'deleted'])  # A list of all the companies who entered submissions for the tender.
    procuringEntity = ModelType(ProcuringEntity, required=True)  # The entity managing the procurement, which may be different from the buyer who is paying / using the items being procured.
    awards = ListType(ModelType(Award), default=list())
    contracts = ListType(ModelType(Contract), default=list())
    minimalStep = ModelType(Value, required=False)  # Not required, blocked for create/edit, since we have minimalStepPercentage in esco
    minimalStepPercentage = FloatType(required=True, min_value=0.005, max_value=0.03)
    questions = ListType(ModelType(Question), default=list())
    complaints = ListType(ComplaintModelType(Complaint), default=list())
    auctionUrl = URLType()
    cancellations = ListType(ModelType(Cancellation), default=list())
    features = ListType(ModelType(Feature), validators=[validate_features_uniq])
    lots = ListType(ModelType(Lot), default=list(), validators=[validate_lots_uniq])
    guarantee = ModelType(Guarantee)
    documents = ListType(ModelType(Document), default=list())  # All documents and attachments related to the tender.
    qualifications = ListType(ModelType(Qualification), default=list())
    qualificationPeriod = ModelType(Period)
    status = StringType(choices=['draft', 'active.tendering', 'active.pre-qualification', 'active.pre-qualification.stand-still', 'active.auction',
                                 'active.qualification', 'active.awarded', 'complete', 'cancelled', 'unsuccessful'], default='active.tendering')
    NBUdiscountRate = FloatType(required=True, min_value=0, max_value=0.99)
    fundingKind = StringType(choices=['budget', 'other'], required=True, default='other')
    yearlyPaymentsPercentageRange = FloatType(required=True, default=0.8, min_value=0, max_value=1)
    submissionMethodDetails = StringType(default="quick(mode:no-auction)")  # TODO: temporary decision, while esco auction is not ready. Remove after adding auction. Remove function "check_submission_method_details" in openprocurement.tender.esco.subscribers
    announcementDate = datetime(2017, 9, 19) # XXX

    create_accreditation = 3
    edit_accreditation = 4
    special_fields = ['fundingKind', 'yearlyPaymentsPercentageRange']
    procuring_entity_kinds = ['general', 'special', 'defense']
    block_tender_complaint_status = OpenUATender.block_tender_complaint_status
    block_complaint_status = OpenUATender.block_complaint_status

    def import_data(self, raw_data, **kw):
        """
        Converts and imports the raw data into the instance of the model
        according to the fields in the model.
        :param raw_data:
            The data to be imported.
        """
        data = self.convert(raw_data, **kw)
        del_keys = [k for k in data.keys() if data[k] == self.__class__.fields[k].default or data[k] == getattr(self, k)]
        for k in del_keys:
            if k in self.special_fields:
                # skip special fields :)
                continue
            del data[k]
        self._data.update(data)
        return self



    def __local_roles__(self):
        roles = dict([('{}_{}'.format(self.owner, self.owner_token), 'tender_owner')])
        for i in self.bids:
            roles['{}_{}'.format(i.owner, i.owner_token)] = 'bid_owner'
        return roles

    def __acl__(self):
        acl = [
            (Allow, '{}_{}'.format(i.owner, i.owner_token), 'create_qualification_complaint')
            for i in self.bids
            if i.status in ['active', 'unsuccessful']
        ]
        acl.extend([
            (Allow, '{}_{}'.format(i.owner, i.owner_token), 'create_award_complaint')
            for i in self.bids
            if i.status == 'active'
        ])
        acl.extend([
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_tender'),
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'upload_tender_documents'),
            (Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_complaint'),
        ])
        return acl

    @serializable(serialized_name="enquiryPeriod", type=ModelType(EnquiryPeriod))
    def tender_enquiryPeriod(self):
        endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL, self)
        return EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate,
                                  endDate=endDate,
                                  invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate,
                                  clarificationsUntil=calculate_business_date(endDate, ENQUIRY_STAND_STILL_TIME, self, True)))

    @serializable(type=ModelType(Period))
    def complaintPeriod(self):
        normalized_end = calculate_normalized_date(self.tenderPeriod.endDate, self)
        return Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(normalized_end, -COMPLAINT_SUBMIT_TIME, self)))

    @serializable(serialize_when_none=False)
    def next_check(self):
        now = get_now()
        checks = []
        if self.status == 'active.tendering' and self.tenderPeriod.endDate and \
                not has_unanswered_complaints(self) and not has_unanswered_questions(self):
            checks.append(self.tenderPeriod.endDate.astimezone(TZ))
        elif self.status == 'active.pre-qualification.stand-still' and self.qualificationPeriod and self.qualificationPeriod.endDate:
            active_lots = [lot.id for lot in self.lots if lot.status == 'active'] if self.lots else [None]
            if not any([
                i.status in self.block_complaint_status
                for q in self.qualifications
                for i in q.complaints
                if q.lotID in active_lots
            ]):
                checks.append(self.qualificationPeriod.endDate.astimezone(TZ))
        elif not self.lots and self.status == 'active.auction' and self.auctionPeriod and self.auctionPeriod.startDate and not self.auctionPeriod.endDate:
            if now < self.auctionPeriod.startDate:
                checks.append(self.auctionPeriod.startDate.astimezone(TZ))
            elif now < calc_auction_end_time(self.numberOfBids, self.auctionPeriod.startDate).astimezone(TZ):
                checks.append(calc_auction_end_time(self.numberOfBids, self.auctionPeriod.startDate).astimezone(TZ))
        elif self.lots and self.status == 'active.auction':
            for lot in self.lots:
                if lot.status != 'active' or not lot.auctionPeriod or not lot.auctionPeriod.startDate or lot.auctionPeriod.endDate:
                    continue
                if now < lot.auctionPeriod.startDate:
                    checks.append(lot.auctionPeriod.startDate.astimezone(TZ))
                elif now < calc_auction_end_time(lot.numberOfBids, lot.auctionPeriod.startDate).astimezone(TZ):
                    checks.append(calc_auction_end_time(lot.numberOfBids, lot.auctionPeriod.startDate).astimezone(TZ))
        elif not self.lots and self.status == 'active.awarded' and not any([
                i.status in self.block_complaint_status
                for i in self.complaints
            ]) and not any([
                i.status in self.block_complaint_status
                for a in self.awards
                for i in a.complaints
            ]):
            standStillEnds = [
                a.complaintPeriod.endDate.astimezone(TZ)
                for a in self.awards
                if a.complaintPeriod.endDate
            ]
            last_award_status = self.awards[-1].status if self.awards else ''
            if standStillEnds and last_award_status == 'unsuccessful':
                checks.append(max(standStillEnds))
        elif self.lots and self.status in ['active.qualification', 'active.awarded'] and not any([
                i.status in self.block_complaint_status and i.relatedLot is None
                for i in self.complaints
            ]):
            for lot in self.lots:
                if lot['status'] != 'active':
                    continue
                lot_awards = [i for i in self.awards if i.lotID == lot.id]
                pending_complaints = any([
                    i['status'] in self.block_complaint_status and i.relatedLot == lot.id
                    for i in self.complaints
                ])
                pending_awards_complaints = any([
                    i.status in self.block_complaint_status
                    for a in lot_awards
                    for i in a.complaints
                ])
                standStillEnds = [
                    a.complaintPeriod.endDate.astimezone(TZ)
                    for a in lot_awards
                    if a.complaintPeriod.endDate
                ]
                last_award_status = lot_awards[-1].status if lot_awards else ''
                if not pending_complaints and not pending_awards_complaints and standStillEnds and last_award_status == 'unsuccessful':
                    checks.append(max(standStillEnds))
        if self.status.startswith('active'):
            for award in self.awards:
                if award.status == 'active' and not any([i.awardID == award.id for i in self.contracts]):
                    checks.append(award.date)
        return min(checks).isoformat() if checks else None

    @serializable
    def numberOfBids(self):
        """A property that is serialized by schematics exports."""
        return len([bid for bid in self.bids if bid.status in ("active", "pending",)])

    @serializable(serialized_name="minValue", type=ModelType(Value))
    def tender_minValue(self):
        return Value(dict(amount=sum([i.minValue.amount for i in self.lots]),
                          currency=self.minValue.currency,
                          valueAddedTaxIncluded=self.minValue.valueAddedTaxIncluded)) if self.lots else self.minValue

    @serializable(serialized_name="guarantee", serialize_when_none=False, type=ModelType(Guarantee))
    def tender_guarantee(self):
        if self.lots:
            lots_amount = [i.guarantee.amount for i in self.lots if i.guarantee]
            if not lots_amount:
                return self.guarantee
            guarantee = {'amount': sum(lots_amount)}
            lots_currency = [i.guarantee.currency for i in self.lots if i.guarantee]
            guarantee['currency'] = lots_currency[0] if lots_currency else None
            if self.guarantee:
                guarantee['currency'] = self.guarantee.currency
            return Guarantee(guarantee)
        else:
            return self.guarantee

    @serializable(serialized_name="minimalStep", type=ModelType(Value), serialize_when_none=False)
    def tender_minimalStep(self):
        pass
        # return Value(dict(amount=min([i.minimalStep.amount for i in self.lots]),
        #                   currency=self.minimalStep.currency,
        #                   valueAddedTaxIncluded=self.minimalStep.valueAddedTaxIncluded)) if self.lots else self.minimalStep

    @serializable(serialized_name="minimalStepPercentage")
    def tender_minimalStepPercentage(self):
        return min([i.minimalStepPercentage for i in self.lots]) if self.lots else self.minimalStepPercentage

    @serializable(serialized_name="yearlyPaymentsPercentageRange")
    def tender_yearlyPaymentsPercentageRange(self):
        return min([i.yearlyPaymentsPercentageRange for i in self.lots]) if self.lots else self.yearlyPaymentsPercentageRange

    def validate_items(self, data, items):
        cpv_336_group = items[0].classification.id[:3] == '336' if items else False
        if not cpv_336_group and (data.get('revisions')[0].date if data.get('revisions') else get_now()) > CPV_ITEMS_CLASS_FROM and items and len(set([i.classification.id[:4] for i in items])) != 1:
            raise ValidationError(u"CPV class of items should be identical")
        else:
            validate_cpv_group(items)

    def validate_features(self, data, features):
        if features and data['lots'] and any([
            round(vnmax([
                i
                for i in features
                if i.featureOf == 'tenderer' or i.featureOf == 'lot' and i.relatedItem == lot['id'] or i.featureOf == 'item' and i.relatedItem in [j.id for j in data['items'] if j.relatedLot == lot['id']]
            ]), 15) > 0.25
            for lot in data['lots']
        ]):
            raise ValidationError(u"Sum of max value of all features for lot should be less then or equal to 25%")
        elif features and not data['lots'] and round(vnmax(features), 15) > 0.25:
            raise ValidationError(u"Sum of max value of all features should be less then or equal to 25%")

    def validate_auctionUrl(self, data, url):
        if url and data['lots']:
            raise ValidationError(u"url should be posted for each lot")

    def validate_minimalStep(self, data, value):
        pass
    #     if value and value.amount and data.get('minValue'):
    #         if data.get('minValue').currency != value.currency:
    #             raise ValidationError(u"currency should be identical to currency of minValue of tender")
    #         if data.get('minValue').valueAddedTaxIncluded != value.valueAddedTaxIncluded:
    #             raise ValidationError(u"valueAddedTaxIncluded should be identical to valueAddedTaxIncluded of minValue of tender")

    def validate_tenderPeriod(self, data, period):
        # if data['_rev'] is None when tender was created just now
        if not data['_rev'] and calculate_business_date(get_now(), -timedelta(minutes=10)) >= period.startDate:
            raise ValidationError(u"tenderPeriod.startDate should be in greater than current date")
        if period and calculate_business_date(period.startDate, TENDERING_DURATION, data) > period.endDate:
            raise ValidationError(u"tenderPeriod should be greater than {} days".format(TENDERING_DAYS))

    def validate_awardPeriod(self, data, period):
        if period and period.startDate and data.get('auctionPeriod') and data.get('auctionPeriod').endDate and period.startDate < data.get('auctionPeriod').endDate:
            raise ValidationError(u"period should begin after auctionPeriod")
        if period and period.startDate and data.get('tenderPeriod') and data.get('tenderPeriod').endDate and period.startDate < data.get('tenderPeriod').endDate:
            raise ValidationError(u"period should begin after tenderPeriod")

    def validate_lots(self, data, value):
        if len(set([lot.guarantee.currency for lot in value if lot.guarantee])) > 1:
            raise ValidationError(u"lot guarantee currency should be identical to tender guarantee currency")
        if len(set([lot.fundingKind for lot in value])) > 1:
            raise ValidationError(u"lot funding kind should be identical to tender funding kind")

    def validate_yearlyPaymentsPercentageRange(self, data, value):
        if data['fundingKind'] == 'other' and value != 0.8:
            raise ValidationError('when fundingKind is other, yearlyPaymentsPercentageRange should be equal 0.8')
        if data['fundingKind'] == 'budget' and (value > 0.8 or value < 0):
            raise ValidationError('when fundingKind is budget, yearlyPaymentsPercentageRange should be less or equal 0.8, and more or equal 0')

    def check_auction_time(self):
        if self.auctionPeriod and self.auctionPeriod.startDate and self.auctionPeriod.shouldStartAfter \
                and self.auctionPeriod.startDate > calculate_business_date(parse_date(self.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True):
            self.auctionPeriod.startDate = None
        for lot in self.lots:
            if lot.auctionPeriod and lot.auctionPeriod.startDate and lot.auctionPeriod.shouldStartAfter \
                    and lot.auctionPeriod.startDate > calculate_business_date(parse_date(lot.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True):
                lot.auctionPeriod.startDate = None

    def invalidate_bids_data(self):
        self.check_auction_time()
        self.enquiryPeriod.invalidationDate = get_now()
        for bid in self.bids:
            if bid.status not in ["deleted", "draft"]:
                bid.status = "invalid"
class ReportingTender(BaseTender):
    """Data regarding tender process - publicly inviting prospective contractors
       to submit bids for evaluation and selecting a winner or winners.
    """
    class Options:
        namespace = "Tender"
        _parent_roles = BaseTender.Options.roles
        _all_forbidden = whitelist()

        _edit_fields = whitelist(
            "procuringEntity",
            "items",
            "value",
            "cause",
            "causeDescription",
            "causeDescription_en",
            "causeDescription_ru",
        )
        _edit_role = _parent_roles["edit"] + _edit_fields
        _read_only_fields = whitelist(
            "lots",
            "contracts",
            # fields below are not covered by the tests
            "awards",
            "cancellations",
        )
        _view_role = _parent_roles["view"] + _edit_fields + _read_only_fields

        roles = {
            "create":
            _parent_roles["create"] + _edit_fields + whitelist("lots"),
            "edit_draft": _parent_roles["edit_draft"],
            "edit": _edit_role,
            "edit_active": _edit_role,
            "edit_active.awarded": _all_forbidden,
            "edit_complete": _all_forbidden,
            "edit_unsuccessful": _all_forbidden,
            "edit_cancelled": _all_forbidden,
            "view": _view_role,
            "draft": _view_role,
            "active": _view_role,
            "active.awarded": _view_role,
            "complete": _view_role,
            "unsuccessful": _view_role,
            "cancelled": _view_role,
            "Administrator": _parent_roles["Administrator"],
            "chronograph": _parent_roles["chronograph"],
            "chronograph_view": _parent_roles["chronograph_view"],
            "plain": _parent_roles["plain"],
            "listing": _parent_roles["listing"],
            "contracting": _parent_roles["contracting"],
            "default": _parent_roles["default"],
        }

    items = ListType(
        ModelType(Item, required=True),
        required=True,
        min_size=1,
        validators=[
            validate_cpv_group, validate_items_uniq, validate_classification_id
        ],
    )  # The goods and services to be purchased, broken into line items wherever possible. Items should not be duplicated, but a quantity of 2 specified instead.
    value = ModelType(
        Value, required=True)  # The total estimated value of the procurement.
    procurementMethod = StringType(
        choices=["open", "selective", "limited"], default="limited"
    )  # Specify tendering method as per GPA definitions of Open, Selective, Limited (http://www.wto.org/english/docs_e/legal_e/rev-gpr-94_01_e.htm)
    procurementMethodType = StringType(default="reporting")
    procuringEntity = ModelType(
        ProcuringEntity, required=True
    )  # The entity managing the procurement, which may be different from the buyer who is paying / using the items being procured.
    awards = ListType(ModelType(Award, required=True), default=list())
    contracts = ListType(ModelType(Contract, required=True), default=list())
    status = StringType(
        choices=["draft", "active", "complete", "cancelled", "unsuccessful"],
        default="active")
    mode = StringType(choices=["test"])
    cancellations = ListType(ModelType(ReportingCancellation, required=True),
                             default=list())

    create_accreditations = (ACCR_1, ACCR_3, ACCR_5)
    central_accreditations = (ACCR_5, )
    edit_accreditations = (ACCR_2, )

    procuring_entity_kinds = [
        "general", "special", "defense", "central", "other"
    ]

    block_complaint_status = OpenUATender.block_complaint_status

    __parent__ = None

    def get_role(self):
        root = self.__parent__
        request = root.request
        if request.authenticated_role == "Administrator":
            role = "Administrator"
        elif request.authenticated_role == "chronograph":
            role = "chronograph"
        elif request.authenticated_role == "contracting":
            role = "contracting"
        else:
            role = "edit_{}".format(request.context.status)
        return role

    def __acl__(self):
        acl = [
            (Allow, "g:brokers", "create_award_complaint"),
            (Allow, "g:brokers", "create_cancellation_complaint"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_tender"),
            (Allow, "{}_{}".format(self.owner, self.owner_token),
             "upload_tender_documents"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_complaint"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_cancellation"),
        ]
        return acl

    # Not required milestones
    def validate_milestones(self, data, value):
        pass
Beispiel #18
0
class Lot(BaseLot):
    class Options:
        roles = {
            'create': whitelist('id', 'title', 'title_en', 'title_ru', 'description', 'description_en', 'description_ru', 'guarantee', 'minimalStepPercentage', 'fundingKind', 'yearlyPaymentsPercentageRange'),
            'edit': whitelist('title', 'title_en', 'title_ru', 'description', 'description_en', 'description_ru', 'guarantee', 'minimalStepPercentage', 'fundingKind', 'yearlyPaymentsPercentageRange'),
            'embedded': embedded_lot_role,
            'view': default_lot_role,
            'default': default_lot_role,
            'auction_view': default_lot_role,
            'auction_patch': whitelist('id', 'auctionUrl'),
            'chronograph': whitelist('id', 'auctionPeriod'),
            'chronograph_view': whitelist('id', 'auctionPeriod', 'numberOfBids', 'status'),
        }

    minValue = ModelType(Value, required=False, default={'amount': 0, 'currency': 'UAH', 'valueAddedTaxIncluded': True})
    minimalStep = ModelType(Value, required=False)  # Not required, blocked for create/edit, since we have minimalStepPercentage in esco
    minimalStepPercentage = FloatType(required=True, min_value=0.005, max_value=0.03)
    auctionPeriod = ModelType(LotAuctionPeriod, default={})
    auctionUrl = URLType()
    guarantee = ModelType(Guarantee)
    fundingKind = StringType(choices=['budget', 'other'], required=True, default='other')
    yearlyPaymentsPercentageRange = FloatType(required=True, default=0.8, min_value=0, max_value=1)

    @serializable
    def numberOfBids(self):
        """A property that is serialized by schematics exports."""
        bids = [
            bid
            for bid in self.__parent__.bids
            if self.id in [i.relatedLot for i in bid.lotValues if i.status in ["active", "pending"]] and bid.status in ["active", "pending"]
        ]
        return len(bids)

    @serializable(serialized_name="guarantee", serialize_when_none=False, type=ModelType(Guarantee))
    def lot_guarantee(self):
        if self.guarantee:
            currency = self.__parent__.guarantee.currency if self.__parent__.guarantee else self.guarantee.currency
            return Guarantee(dict(amount=self.guarantee.amount, currency=currency))

    @serializable(serialized_name="fundingKind")
    def lot_fundingKind(self):
        return self.__parent__.fundingKind  # if self.__parent__.fundingKind else self.fundingKind

    @serializable(serialized_name="minimalStep", type=ModelType(Value), serialize_when_none=False)
    def lot_minimalStep(self):
        pass
        # return Value(dict(amount=self.minimalStep.amount,
        #                   currency=self.__parent__.minimalStep.currency,
        #                   valueAddedTaxIncluded=self.__parent__.minimalStep.valueAddedTaxIncluded))

    @serializable(serialized_name="minValue", type=ModelType(Value))
    def lot_minValue(self):
        return Value(dict(amount=self.minValue.amount,
                          currency=self.__parent__.minValue.currency,
                          valueAddedTaxIncluded=self.__parent__.minValue.valueAddedTaxIncluded))

    def validate_yearlyPaymentsPercentageRange(self, data, value):
        if data['fundingKind'] == 'other' and value != 0.8:
            raise ValidationError('when fundingKind is other, yearlyPaymentsPercentageRange should be equal 0.8')
        if data['fundingKind'] == 'budget' and (value > 0.8 or value < 0):
            raise ValidationError('when fundingKind is budget, yearlyPaymentsPercentageRange should be less or equal 0.8, and more or equal 0')
class Unit(BaseUnit):
    value = ModelType(Value)
        class Player(Model):
            total_points = IntType()

            @serializable(type=ModelType(ExperienceLevel))
            def xp_level(self):
                return None if not self.total_points else ExperienceLevel()
Beispiel #21
0
 class Card(Model):
     user = ModelType(User)
 class QuestionPack(Model):
     id = LongType()
     questions = ListType(ModelType(Question))
Beispiel #23
0
class Bid(BidResponsesMixin, BaseBid):
    class Options:
        _all_documents = whitelist("documents", "eligibilityDocuments",
                                   "financialDocuments",
                                   "qualificationDocuments")
        _edit = whitelist("value", "lotValues", "parameters",
                          "subcontractingDetails", "tenderers", "status",
                          "requirementResponses")
        _create = _all_documents + _edit + {"selfEligible", "selfQualified"}
        _open_view = _create + whitelist("id", "date", "participationUrl",
                                         "requirementResponses")
        _qualification_view = whitelist("id", "status", "tenderers",
                                        "documents", "eligibilityDocuments",
                                        "requirementResponses")
        roles = {
            "create":
            _create,
            "edit":
            _edit,
            "active.tendering":
            whitelist(),
            "active.enquiries":
            whitelist(),
            "invalid.pre-qualification":
            _qualification_view,
            "active.pre-qualification":
            _qualification_view,
            "active.pre-qualification.stand-still":
            _qualification_view,
            "active.auction":
            _qualification_view,
            "bid.unsuccessful":
            _qualification_view +
            whitelist("selfEligible", "selfQualified", "parameters",
                      "subcontractingDetails"),
            "active.qualification":
            _open_view,
            "active.qualification.stand-still":
            _open_view,
            "active.awarded":
            _open_view,
            "unsuccessful":
            _open_view,
            "complete":
            _open_view,
            "cancelled":
            _open_view,
            "view":
            _open_view,
            "embedded":
            _open_view,
            "default":
            _open_view + whitelist("owner_token", "owner", "serialize_status"),
            "invalid":
            whitelist("id", "status"),
            "deleted":
            whitelist("id", "status"),
            "auction_post":
            whitelist("id", "lotValues", "value", "date"),
            "auction_view":
            whitelist("id", "lotValues", "value", "date", "parameters",
                      "participationUrl", "status", "requirementResponses"),
            "auction_patch":
            whitelist("id", "lotValues", "participationUrl"),
            "Administrator":
            whitelist("tenderers"),
        }

    documents = ListType(ConfidentialDocumentModelType(EUConfidentialDocument,
                                                       required=True),
                         default=list())
    financialDocuments = ListType(ConfidentialDocumentModelType(
        EUConfidentialDocument, required=True),
                                  default=list())
    eligibilityDocuments = ListType(ConfidentialDocumentModelType(
        EUConfidentialDocument, required=True),
                                    default=list())
    qualificationDocuments = ListType(ConfidentialDocumentModelType(
        EUConfidentialDocument, required=True),
                                      default=list())
    lotValues = ListType(ModelType(LotValue, required=True), default=list())
    selfQualified = BooleanType(required=True, choices=[True])
    selfEligible = BooleanType(choices=[True])
    subcontractingDetails = StringType()
    parameters = ListType(ModelType(BidParameter, required=True),
                          default=list(),
                          validators=[validate_parameters_uniq])
    status = StringType(
        choices=[
            "draft", "pending", "active", "invalid",
            "invalid.pre-qualification", "unsuccessful", "deleted"
        ],
        default="pending",
    )
    value = ModelType(Value)

    def serialize(self, role=None, context=None):
        if role and role != "create" and self.status in [
                "invalid", "invalid.pre-qualification", "deleted"
        ]:
            role = self.status
        elif role and role != "create" and self.status == "unsuccessful":
            role = "bid.unsuccessful"
        return super(Bid, self).serialize(role)

    @serializable(serialized_name="status")
    def serialize_status(self):
        if self.status in [
                "draft",
                "invalid",
                "invalid.pre-qualification",
                "unsuccessful",
                "deleted",
        ] or self.__parent__.status in ["active.tendering", "cancelled"]:
            return self.status
        if self.__parent__.lots:
            active_lots = [
                lot.id for lot in self.__parent__.lots
                if lot.status in ("active", "complete")
            ]
            if not self.lotValues:
                return "invalid"
            elif [
                    i.relatedLot for i in self.lotValues
                    if i.status == "pending" and i.relatedLot in active_lots
            ]:
                return "pending"
            elif [
                    i.relatedLot for i in self.lotValues
                    if i.status == "active" and i.relatedLot in active_lots
            ]:
                return "active"
            else:
                return "unsuccessful"
        return self.status

    @bids_validation_wrapper
    def validate_value(self, data, value):
        BaseBid._validator_functions["value"](self, data, value)

    @bids_validation_wrapper
    def validate_lotValues(self, data, lotValues):
        BaseBid._validator_functions["lotValues"](self, data, lotValues)

    @bids_validation_wrapper
    def validate_participationUrl(self, data, participationUrl):
        BaseBid._validator_functions["participationUrl"](self, data,
                                                         participationUrl)

    @bids_validation_wrapper
    def validate_parameters(self, data, parameters):
        BaseBid._validator_functions["parameters"](self, data, parameters)
 class Game(Model):
     id = StringType()
     question_pack = ModelType(QuestionPack)
class Organization(BaseOrganization):
    """An organization."""
    contactPoint = ModelType(ContactPoint, required=True)
    additionalContactPoints = ListType(ModelType(ContactPoint, required=True),
                                       required=False)
 class PlayerCategoryInfo(PlayerInfo):
     categories = DictType(ModelType(CategoryStatsInfo))
class PriceQuotationTender(Tender):
    """
    Data regarding tender process - publicly inviting prospective contractors
    to submit bids for evaluation and selecting a winner or winners.
    """
    class Options:
        namespace = "Tender"
        _core_roles = Tender.Options.roles
        # without _serializable_fields they won't be calculated
        # (even though serialized_name is in the role)
        _serializable_fields = whitelist("tender_guarantee", "tender_value",
                                         "tender_minimalStep")
        _edit_fields = _serializable_fields + whitelist(
            "next_check",
            "numberOfBidders",
            "items",
            "tenderPeriod",
            "procuringEntity",
            "guarantee",
            "minimalStep",
        )
        _edit_role = _core_roles["edit"] \
            + _edit_fields + whitelist(
                "contracts",
                "numberOfBids",
                "status",
                "value",
                "profile"
            )
        _create_role = _core_roles["create"] \
                       + _core_roles["edit"] \
                       + _edit_fields \
                       + whitelist("contracts",
                                   "numberOfBids",
                                   "value",
                                   "profile")
        _edit_pq_bot_role = whitelist("items", "shortlistedFirms", "status",
                                      "criteria", "value",
                                      "unsuccessfulReason")
        _view_tendering_role = (
            _core_roles["view"] + _edit_fields +
            whitelist("awards", 'value', "awardPeriod", "cancellations",
                      "contracts", "profile", "shortlistedFirms", "criteria",
                      "noticePublicationDate", "unsuccessfulReason"))
        _view_role = _view_tendering_role + whitelist("bids", "numberOfBids")
        _all_forbidden = whitelist()
        roles = {
            "create": _create_role + whitelist("classification"),
            "edit": _edit_role,
            "edit_draft": _edit_role,
            "edit_draft.unsuccessful": _edit_role,
            "edit_draft.publishing": _edit_pq_bot_role,
            "edit_active.tendering": _all_forbidden,
            "edit_active.qualification": _all_forbidden,
            "edit_active.awarded": _all_forbidden,
            "edit_complete": _all_forbidden,
            "edit_unsuccessful": _all_forbidden,
            "edit_cancelled": _all_forbidden,
            "draft": _view_tendering_role,
            "draft.unsuccessful": _view_tendering_role,
            "draft.publishing": _view_tendering_role,
            "active.tendering": _view_tendering_role,
            "view": _view_role,
            "active.qualification": _view_role,
            "active.awarded": _view_role,
            "complete": _view_role,
            "unsuccessful": _view_role,
            "cancelled": _view_role,
            "chronograph": _core_roles["chronograph"],
            "chronograph_view": _core_roles["chronograph_view"],
            "Administrator": _core_roles["Administrator"],
            "plain": _core_roles["plain"],
            "listing": _core_roles["listing"],
            "contracting": _core_roles["contracting"],
            "default": _core_roles["default"],
            "bots": _edit_pq_bot_role,
        }

    status = StringType(choices=[
        "draft", "draft.publishing", "draft.unsuccessful", "active.tendering",
        "active.qualification", "active.awarded", "complete", "cancelled",
        "unsuccessful"
    ],
                        default="draft")

    # The goods and services to be purchased,
    # broken into line items wherever possible.
    # Items should not be duplicated, but a quantity of 2 specified instead.
    items = ListType(
        ModelType(TenderItem, required=True),
        required=True,
        min_size=1,
        validators=[validate_items_uniq],
    )
    # The total estimated value of the procurement.
    value = ModelType(Value, required=True)
    # The period when the tender is open for submissions.
    # The end date is the closing date for tender submissions.
    tenderPeriod = ModelType(PeriodEndRequired, required=True)
    # The date or period on which an award is anticipated to be made.
    awardPeriod = ModelType(Period)
    # The number of unique tenderers who participated in the tender
    numberOfBidders = IntType()
    # A list of all the companies who entered submissions for the tender.
    bids = ListType(ModelType(Bid, required=True), default=list())
    # The entity managing the procurement,
    # which may be different from the buyer
    # who is paying / using the items being procured.
    procuringEntity = ModelType(ProcuringEntity, required=True)
    awards = ListType(ModelType(Award, required=True), default=list())
    contracts = ListType(ModelType(Contract, required=True), default=list())
    cancellations = ListType(ModelType(Cancellation, required=True),
                             default=list())
    documents = ListType(
        ModelType(Document, required=True),
        default=list())  # All documents and attachments related to the tender.
    guarantee = ModelType(Guarantee)
    procurementMethod = StringType(choices=["selective"], default="selective")
    procurementMethodType = StringType(default=PMT)
    profile = StringType(required=True)
    shortlistedFirms = ListType(ModelType(ShortlistedFirm), default=list())
    criteria = ListType(ModelType(Criterion), default=list())
    classification = ModelType(Classification)
    noticePublicationDate = IsoDateTimeType()
    unsuccessfulReason = ListType(StringType)

    procuring_entity_kinds = PQ_KINDS

    def validate_buyers(self, data, value):
        pass

    def validate_milestones(self, data, value):
        # a hack to avoid duplicating all bese model fields
        if value:
            raise ValidationError(
                "Milestones are not applicable to pricequotation")

    def get_role(self):
        root = self.__parent__
        request = root.request
        if request.authenticated_role in\
           ("Administrator", "chronograph", "contracting", "bots"):
            role = request.authenticated_role
        else:
            role = "edit_{}".format(request.context.status)
        return role

    @serializable(serialize_when_none=False)
    def next_check(self):
        checks = []
        if self.status == "active.tendering" and self.tenderPeriod.endDate:
            checks.append(self.tenderPeriod.endDate.astimezone(TZ))

        if self.status.startswith("active"):
            for award in self.awards:
                if award.status == 'pending':
                    checks.append(
                        calculate_tender_business_date(award.date,
                                                       QUALIFICATION_DURATION,
                                                       self,
                                                       working_days=True))
                if award.status == "active" and not\
                   any([i.awardID == award.id for i in self.contracts]):
                    checks.append(award.date)
        return min(checks).isoformat() if checks else None

    @serializable
    def numberOfBids(self):
        """A property that is serialized by schematics exports."""
        return len(self.bids)

    def validate_items(self, data, items):
        if data["status"] in ("draft", "draft.publishing",
                              "draft.unsuccessful"):
            return
        if not all((i.classification for i in items)):
            return
        cpv_336_group = items[0].classification.id[:3] == "336"\
            if items else False
        if (not cpv_336_group and items
                and len(set([i.classification.id[:4] for i in items])) != 1):
            raise ValidationError("CPV class of items should be identical")
        else:
            validate_cpv_group(items)
        validate_classification_id(items)

    def validate_awardPeriod(self, data, period):
        if (period and period.startDate and data.get("tenderPeriod")
                and data.get("tenderPeriod").endDate
                and period.startDate < data.get("tenderPeriod").endDate):
            raise ValidationError("period should begin after tenderPeriod")

    def validate_tenderPeriod(self, data, period):
        if period and period.startDate and period.endDate:
            _validate_tender_period_duration(data,
                                             period,
                                             TENDERING_DURATION,
                                             working_days=True)

    def validate_profile(self, data, profile):
        result = PROFILE_PATTERN.findall(profile)
        if len(result) != 1:
            raise ValidationError("The profile value doesn't match id pattern")

    def __local_roles__(self):
        roles = dict([("{}_{}".format(self.owner,
                                      self.owner_token), "tender_owner")])
        for i in self.bids:
            roles["{}_{}".format(i.owner, i.owner_token)] = "bid_owner"
        return roles

    def _acl_contract(self, acl):
        acl.extend([
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_contract"),
            (Allow, "{}_{}".format(self.owner, self.owner_token),
             "upload_contract_documents"),
        ])

    def _acl_cancellation(self, acl):
        acl.extend([
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_tender"),
            (Allow, "{}_{}".format(self.owner, self.owner_token),
             "upload_tender_documents"),
            (Allow, "{}_{}".format(self.owner,
                                   self.owner_token), "edit_cancellation"),
        ])

    def __acl__(self):
        acl = [
            (Allow, "g:bots", "upload_award_documents"),
        ]
        self._acl_cancellation(acl)
        self._acl_contract(acl)
        return acl
 class Question(Model):
     question_id = StringType(required=True)
     resources = DictType(ListType(ModelType(QuestionResource)))
Beispiel #29
0
class Question(BaseQuestion):
    author = ModelType(Organization, required=True)
Beispiel #30
0
 class QuestionResources(Model):
     pictures = ListType(ModelType(QuestionResource))