Beispiel #1
0
class Document(ConfidentialDocument):
    """ Document model with new feature as Description of the decision to purchase """
    class Options:
        roles = {
            'edit':
            blacklist('id', 'url', 'datePublished', 'dateModified', ''),
            'embedded':
            schematics_embedded_role,
            'view': (blacklist('revisions') + schematics_default_role),
            'restricted_view':
            (blacklist('revisions', 'url') + schematics_default_role),
            'revisions':
            whitelist('url', 'dateModified'),
        }

    isDescriptionDecision = BooleanType(default=False)

    def validate_confidentialityRationale(self, data, val):
        if data['confidentiality'] != 'public' and not data[
                'isDescriptionDecision']:
            if not val:
                raise ValidationError(u"confidentialityRationale is required")
            elif len(val) < 30:
                raise ValidationError(
                    u"confidentialityRationale should contain at least 30 characters"
                )
class Bid(Bid):
    class Options:
        roles = {
            'create': whitelist('value', 'tenderers', 'parameters', 'lotValues', 'status', 'qualified', 'eligible'),
        }
    documents = ListType(ModelType(Document), default=list(), validators=[validate_disallow_dgfPlatformLegalDetails])
    tenderers = ListType(ModelType(FinantialOrganization), required=True, min_size=1, max_size=1)
    eligible = BooleanType(required=True, choices=[True])
class Document(EUConfidentialDocument):
    isDescriptionDecision = BooleanType(default=False)

    def validate_confidentialityRationale(self, data, val):
        if data["confidentiality"] != "public" and not data["isDescriptionDecision"]:
            if not val:
                raise ValidationError("confidentialityRationale is required")
            elif len(val) < 30:
                raise ValidationError("confidentialityRationale should contain at least 30 characters")
Beispiel #4
0
class Bid(BaseBid):
    class Options:
        roles = {
            'create':
            whitelist('value', 'tenderers', 'parameters', 'lotValues',
                      'status', 'qualified'),
        }

    tenderers = ListType(ModelType(Organization),
                         required=True,
                         min_size=1,
                         max_size=1)
    documents = ListType(ModelType(Document), default=list())
    qualified = BooleanType(required=True, choices=[True])
class Bid(BaseBid):
    class Options:
        roles = {
            'create': whitelist('value', 'tenderers', 'parameters', 'lotValues', 'status', 'qualified'),
        }

    status = StringType(choices=['active', 'draft', 'invalid'], default='active')
    tenderers = ListType(ModelType(Organization), required=True, min_size=1, max_size=1)
    documents = ListType(ModelType(Document), default=list())
    qualified = BooleanType(required=True, choices=[True])

    @bids_validation_wrapper
    def validate_value(self, data, value):
        BaseBid._validator_functions['value'](self, data, value)
Beispiel #6
0
class Bid(BaseBid):
    class Options:
        roles = {
            'create':
            whitelist('value', 'tenderers', 'parameters', 'lotValues',
                      'status', 'qualified'),
        }

    status = StringType(choices=['active', 'draft', 'invalid'],
                        default='active')
    tenderers = ListType(ModelType(Organization),
                         required=True,
                         min_size=1,
                         max_size=1)
    documents = ListType(
        ModelType(Document),
        default=list(),
        validators=[validate_disallow_dgfPlatformLegalDetails])
    qualified = BooleanType(required=True, choices=[True])
Beispiel #7
0
class Auction(BaseAuction):
    """Data regarding auction process - publicly inviting prospective contractors to submit bids for evaluation and selecting a winner or winners."""
    class Options:
        roles = {
            'create': create_role,
            'edit_active.tendering': edit_role,
            'Administrator': Administrator_role,
        }

    awards = ListType(ModelType(Award), default=list())
    bids = ListType(ModelType(Bid), default=list(
    ))  # A list of all the companies who entered submissions for the auction.
    cancellations = ListType(ModelType(Cancellation), default=list())
    complaints = ListType(ModelType(Complaint), default=list())
    contracts = ListType(ModelType(Contract), default=list())
    dgfID = StringType()
    dgfDecisionID = StringType()
    dgfDecisionDate = DateType()
    documents = ListType(ModelType(Document), default=list(
    ))  # All documents and attachments related to the auction.
    enquiryPeriod = ModelType(
        Period
    )  # The period during which enquiries may be made and will be answered.
    tenderPeriod = ModelType(
        Period
    )  # The period when the auction is open for submissions. The end date is the closing date for auction submissions.
    tenderAttempts = IntType(choices=[1, 2, 3, 4])
    auctionPeriod = ModelType(AuctionAuctionPeriod, required=True, default={})
    procurementMethodType = StringType(default="dgfOtherAssets")
    procuringEntity = ModelType(ProcuringEntity, required=True)
    status = StringType(choices=[
        'draft', 'active.tendering', 'active.auction', 'active.qualification',
        'active.awarded', 'complete', 'cancelled', 'unsuccessful'
    ],
                        default='active.tendering')
    questions = ListType(ModelType(Question), default=list())
    features = ListType(
        ModelType(Feature),
        validators=[validate_features_uniq, validate_not_available])
    lots = ListType(ModelType(Lot),
                    default=list(),
                    validators=[validate_lots_uniq, validate_not_available])
    items = ListType(ModelType(Item),
                     required=True,
                     min_size=1,
                     validators=[validate_items_uniq])
    suspended = BooleanType()

    def __acl__(self):
        return [
            (Allow, '{}_{}'.format(self.owner,
                                   self.owner_token), 'edit_auction'),
            (Allow, '{}_{}'.format(self.owner,
                                   self.owner_token), 'edit_auction_award'),
            (Allow, '{}_{}'.format(self.owner, self.owner_token),
             'upload_auction_documents'),
        ]

    def initialize(self):
        if not self.enquiryPeriod:
            self.enquiryPeriod = type(self).enquiryPeriod.model_class()
        if not self.tenderPeriod:
            self.tenderPeriod = type(self).tenderPeriod.model_class()
        now = get_now()
        self.tenderPeriod.startDate = self.enquiryPeriod.startDate = now
        pause_between_periods = self.auctionPeriod.startDate - (
            self.auctionPeriod.startDate.replace(
                hour=20, minute=0, second=0, microsecond=0) -
            timedelta(days=1))
        self.enquiryPeriod.endDate = self.tenderPeriod.endDate = calculate_business_date(
            self.auctionPeriod.startDate, -pause_between_periods, self)
        self.auctionPeriod.startDate = None
        self.auctionPeriod.endDate = None
        self.date = now
        if self.lots:
            for lot in self.lots:
                lot.date = now
        self.documents.append(
            type(self).documents.model_class(DGF_PLATFORM_LEGAL_DETAILS))

    def validate_documents(self, data, docs):
        if (data.get('revisions')[0].date if data.get('revisions') else get_now()) > DGF_PLATFORM_LEGAL_DETAILS_FROM and \
                (docs and docs[0].documentType != 'x_dgfPlatformLegalDetails' or any([i.documentType == 'x_dgfPlatformLegalDetails' for i in docs[1:]])):
            raise ValidationError(
                u"First document should be document with x_dgfPlatformLegalDetails documentType"
            )

    def validate_tenderPeriod(self, data, period):
        pass

    def validate_value(self, data, value):
        if value.currency != u'UAH':
            raise ValidationError(u"currency should be only UAH")

    def validate_dgfID(self, data, dgfID):
        if not dgfID:
            if (data.get('revisions')[0].date if data.get('revisions') else
                    get_now()) > DGF_ID_REQUIRED_FROM:
                raise ValidationError(u'This field is required.')

    def validate_dgfDecisionID(self, data, dgfID):
        if not dgfID:
            if (data.get('revisions')[0].date if data.get('revisions') else
                    get_now()) > DGF_DECISION_REQUIRED_FROM:
                raise ValidationError(u'This field is required.')

    def validate_dgfDecisionDate(self, data, dgfID):
        if not dgfID:
            if (data.get('revisions')[0].date if data.get('revisions') else
                    get_now()) > DGF_DECISION_REQUIRED_FROM:
                raise ValidationError(u'This field is required.')

    @serializable(serialize_when_none=False)
    def next_check(self):
        if self.suspended:
            return None
        now = get_now()
        checks = []
        if self.status == 'active.tendering' and self.tenderPeriod and self.tenderPeriod.endDate:
            checks.append(self.tenderPeriod.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.qualification':
            for award in self.awards:
                if award.status == 'pending.verification':
                    checks.append(
                        award.verificationPeriod.endDate.astimezone(TZ))
                elif award.status == 'pending.payment':
                    checks.append(award.paymentPeriod.endDate.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
            ]
            for award in self.awards:
                if award.status == 'active':
                    checks.append(award.signingPeriod.endDate.astimezone(TZ))

            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'):
            from openprocurement.api.utils import calculate_business_date
            for complaint in self.complaints:
                if complaint.status == 'claim' and complaint.dateSubmitted:
                    checks.append(
                        calculate_business_date(complaint.dateSubmitted,
                                                COMPLAINT_STAND_STILL_TIME,
                                                self))
                elif complaint.status == 'answered' and complaint.dateAnswered:
                    checks.append(
                        calculate_business_date(complaint.dateAnswered,
                                                COMPLAINT_STAND_STILL_TIME,
                                                self))
            for award in self.awards:
                for complaint in award.complaints:
                    if complaint.status == 'claim' and complaint.dateSubmitted:
                        checks.append(
                            calculate_business_date(
                                complaint.dateSubmitted,
                                COMPLAINT_STAND_STILL_TIME, self))
                    elif complaint.status == 'answered' and complaint.dateAnswered:
                        checks.append(
                            calculate_business_date(
                                complaint.dateAnswered,
                                COMPLAINT_STAND_STILL_TIME, self))
        return min(checks).isoformat() if checks else None
Beispiel #8
0
class Bid(BaseBid):
    class Options:
        roles = {
            'create':
            whitelist('value', 'tenderers', 'parameters', 'lotValues',
                      'status', 'qualified'),
            'embedded':
            view_bid_role,
            'view':
            view_bid_role,
            'auction_view':
            whitelist('value', 'lotValues', 'id', 'date', 'parameters',
                      'participationUrl', 'owner'),
            'active.qualification':
            view_bid_role,
            'active.awarded':
            view_bid_role,
            'complete':
            view_bid_role,
            'unsuccessful':
            view_bid_role,
            'cancelled':
            view_bid_role,
        }

    status = StringType(choices=['active', 'draft', 'invalid'],
                        default='active')
    tenderers = ListType(ModelType(Organization),
                         required=True,
                         min_size=1,
                         max_size=1)
    parameters = ListType(ModelType(Parameter),
                          default=list(),
                          validators=[validate_parameters_uniq])
    lotValues = ListType(ModelType(LotValue), default=list())
    documents = ListType(
        ModelType(Document),
        default=list(),
        validators=[validate_disallow_dgfPlatformLegalDetails])
    qualified = BooleanType(required=True, choices=[True])
    participationUrl = URLType()
    owner_token = StringType()
    owner = StringType()

    def validate_participationUrl(self, data, url):
        if url and isinstance(data['__parent__'], Model) and get_auction(
                data['__parent__']).lots:
            raise ValidationError(u"url should be posted for each lot of bid")

    def validate_lotValues(self, data, values):
        if isinstance(data['__parent__'], Model):
            auction = data['__parent__']
            if auction.lots and not values:
                raise ValidationError(u'This field is required.')

    def validate_value(self, data, value):
        pass

    def validate_parameters(self, data, parameters):
        if isinstance(data['__parent__'], Model):
            auction = data['__parent__']
            if auction.lots:
                lots = [i.relatedLot for i in data['lotValues']]
                items = [i.id for i in auction.items if i.relatedLot in lots]
                codes = dict([
                    (i.code, [x.value for x in i.enum])
                    for i in (auction.features or [])
                    if i.featureOf == 'tenderer'
                    or i.featureOf == 'lot' and i.relatedItem in lots
                    or i.featureOf == 'item' and i.relatedItem in items
                ])
                if set([i['code'] for i in parameters]) != set(codes):
                    raise ValidationError(
                        u"All features parameters is required.")
            elif not parameters and auction.features:
                raise ValidationError(u'This field is required.')
            elif set([i['code'] for i in parameters]) != set(
                [i.code for i in (auction.features or [])]):
                raise ValidationError(u"All features parameters is required.")

    @serializable(serialized_name="participationUrl",
                  serialize_when_none=False)
    def participation_url(self):
        root = self.__parent__
        auction_id = root.id
        bidder_id = self.id
        parents = []
        while root.__parent__ is not None:
            parents[0:0] = [root]
            root = root.__parent__
        request = root.request
        auction_url = request.registry.auction_module_url
        signature = quote(
            b64encode(request.registry.signer.signature(bidder_id)))
        participation_url = '{}/auctions/{}/login?bidder_id={}&signature={}'.format(
            auction_url, auction_id, bidder_id, signature)
        if not self.participationUrl:
            return participation_url