class DGFFinancialBid(DGFOtherBid):
    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(FinancialOrganization), required=True, min_size=1, max_size=1)
    eligible = BooleanType(required=True, choices=[True])
Beispiel #2
0
class Bid(BaseBid):
    class Options:
        roles = {
            'create': whitelist('tenderers', 'status', 'qualified', 'eligible'),
            'edit': whitelist('status', 'tenderers'),
        }

    status = StringType(choices=['active', 'draft', 'invalid'], default='active')
    qualified = BooleanType(required=True, choices=[True])
    documents = ListType(ModelType(AppraisalBidDocument), default=list())
    eligible = BooleanType(required=True, choices=[True])

    def validate_value(self, data, value):
        if isinstance(data['__parent__'], Model):
            auction = data['__parent__']
            if not value:
                return
            if auction.get('value').currency != value.currency:
                raise ValidationError(u"currency of bid should be identical to currency of value of auction")
            if auction.get('value').valueAddedTaxIncluded != value.valueAddedTaxIncluded:
                raise ValidationError(u"valueAddedTaxIncluded of bid should be identical to valueAddedTaxIncluded of value of auction")

    @serializable(serialized_name="participationUrl", serialize_when_none=False)
    def participation_url(self):
        if not self.participationUrl and self.status == "active":
            request = get_auction(self).__parent__.request
            url = generate_auction_url(request, bid_id=str(self.id))
            return url
class DGFFinancialAssets(DGFOtherAssets):
    """Data regarding auction process - publicly inviting prospective contractors to submit bids for evaluation and selecting a winner or winners."""
    _internal_type = "dgfFinancialAssets"
    bids = ListType(ModelType(DGFFinancialBid), default=list())
    eligibilityCriteria = StringType(default=DGF_ELIGIBILITY_CRITERIA['ua'])
    eligibilityCriteria_en = StringType(default=DGF_ELIGIBILITY_CRITERIA['en'])
    eligibilityCriteria_ru = StringType(default=DGF_ELIGIBILITY_CRITERIA['ru'])
class DGFOtherBid(BaseBid):
    class Options:
        roles = {
            'create': whitelist('value', 'tenderers', 'parameters', 'lotValues', 'status', 'qualified'),
        }

    status = StringType(choices=['active', 'draft', 'invalid'], default='active')
    documents = ListType(ModelType(Document), default=list(), validators=[validate_disallow_dgfPlatformLegalDetails])
    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)
class SwiftsureAuction(BaseAuction):
    """Data regarding auction process

    Publicly inviting prospective contractors to submit bids for evaluation and selecting a winner or winners.
    """
    class Options:
        roles = swiftsure_auction_roles
    _internal_type = "swiftsure"
    awards = ListType(ModelType(Award), default=list())
    # A list of all the companies who entered submissions for the auction.
    bids = ListType(ModelType(Bid), default=list())
    cancellations = ListType(ModelType(swiftsureCancellation), default=list())
    complaints = ListType(ComplaintModelType(Complaint), default=list())
    contracts = ListType(ModelType(Contract), default=list())
    merchandisingObject = MD5Type()
    # All documents and attachments related to the auction.
    documents = ListType(ModelType(swiftsureDocument), default=list())
    # The period during which enquiries may be made and will be answered.
    enquiryPeriod = ModelType(Period)
    # The period when the auction is open for submissions. The end date is the
    # closing date for auction submissions.
    tenderPeriod = ModelType(Period)
    tenderAttempts = IntType(choices=[1, 2, 3, 4, 5, 6, 7, 8])
    auctionPeriod = ModelType(AuctionAuctionPeriod, required=True, default={})
    status = StringType(choices=SWIFTSURE_STATUSES, default=SWIFTSURE_DEFAULT_STATUS)
    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(LokiItem),
        default=list(),
        validators=[validate_items_uniq],
        min_size=1)
    suspended = BooleanType()
    registrationFee = ModelType(Guarantee)
    bankAccount = ModelType(BankAccount)
    auctionParameters = ModelType(AuctionParameters)
    minNumberOfQualifiedBids = IntType(choices=[1], default=1)
    procuringEntity = ModelType(SwiftsureProcuringEntity, required=True)
    contractTerms = ModelType(
        ContractTerms,
        validators=[validate_contract_type])

    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 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 == 'auction':
            role = 'auction_{}'.format(request.method.lower())
        elif request.authenticated_role == 'convoy':
            role = 'convoy'
        else:
            role = 'edit_{}'.format(request.context.status)
        return role

    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()
        start_date = TZ.localize(
            self.auctionPeriod.startDate.replace(
                tzinfo=None))
        self.auctionPeriod.startDate = None
        self.auctionPeriod.endDate = None
        self.tenderPeriod.startDate = self.enquiryPeriod.startDate = now
        pause_between_periods = start_date - (
            start_date.replace(hour=20, minute=0, second=0, microsecond=0) -
            # set period end at 19:30-20:30 to reduce system load
            timedelta(days=1, minutes=randint(-30, 30))
        )
        end_date = calculate_business_date(
            start_date, -pause_between_periods, self)
        self.enquiryPeriod.endDate = end_date
        self.tenderPeriod.endDate = self.enquiryPeriod.endDate
        self.date = now
        if self.lots:
            for lot in self.lots:
                lot.date = now

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

    def validate_merchandisingObject(self, data, merchandisingObject):
        if data['status'] == 'pending.activation' and not merchandisingObject:
            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))
        # Use next_check part from awarding 2.0
        request = get_request_from_root(self)
        if request is not None:
            awarding_check = request.registry.getAdapter(
                self, IAwardingNextCheck).add_awarding_checks(self)
            if awarding_check is not None:
                checks.append(awarding_check)
        if self.status.startswith('active'):
            for complaint in self.complaints:
                if complaint.status == 'claim' and complaint.dateSubmitted:
                    checks.append(
                        calculate_business_date(
                            complaint.dateSubmitted,
                            AUCTIONS_COMPLAINT_STAND_STILL_TIME,
                            self))
                elif complaint.status == 'answered' and complaint.dateAnswered:
                    checks.append(
                        calculate_business_date(
                            complaint.dateAnswered,
                            AUCTIONS_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,
                                AUCTIONS_COMPLAINT_STAND_STILL_TIME,
                                self))
                    elif complaint.status == 'answered' and complaint.dateAnswered:
                        checks.append(
                            calculate_business_date(
                                complaint.dateAnswered,
                                AUCTIONS_COMPLAINT_STAND_STILL_TIME,
                                self))
        return min(checks).isoformat() if checks else None
class ProcuringEntity(flashProcuringEntity):
    identifier = ModelType(Identifier, required=True)
    additionalIdentifiers = ListType(ModelType(Identifier))
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':
            (blacklist('enquiryPeriod', 'tenderPeriod', 'rectificationPeriod',
                       'auction_value', 'auction_minimalStep',
                       'auction_guarantee', 'eligibilityCriteria',
                       'eligibilityCriteria_en', 'eligibilityCriteria_ru',
                       'minNumberOfQualifiedBids') + edit_role),
            'Administrator':
            (whitelist('rectificationPeriod') + Administrator_role),
        }

    _internal_type = "propertyLease"
    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())
    lotIdentifier = StringType()
    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.
    rectificationPeriod = ModelType(
        RectificationPeriod
    )  # The period during which editing of main procedure fields are allowed
    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, 5, 6, 7, 8, 9, 10])
    auctionPeriod = ModelType(AuctionAuctionPeriod, required=True, default={})
    procurementMethodType = StringType()
    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(PropertyItem),
                     required=True,
                     min_size=1,
                     validators=[validate_items_uniq])
    minNumberOfQualifiedBids = IntType(choices=[1, 2], default=2)
    contractTerms = ModelType(ContractTerms, required=True)

    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):  # TODO: get rid of this method
        pass

    def validate_tenderPeriod(self, data, period):
        if not (period and period.startDate and period.endDate):
            return
        if get_auction_creation_date(data) < MINIMAL_EXPOSITION_REQUIRED_FROM:
            return
        if calculate_business_date(period.startDate, MINIMAL_EXPOSITION_PERIOD,
                                   data) > period.endDate:
            raise ValidationError(
                u"tenderPeriod should be greater than 6 days")

    def validate_rectificationPeriod(self, data, period):
        if not (period and period.startDate) or not period.endDate:
            return
        if period.endDate > TZ.localize(
                calculate_business_date(data['tenderPeriod']['endDate'],
                                        -MINIMAL_PERIOD_FROM_RECTIFICATION_END,
                                        data).replace(tzinfo=None)):
            raise ValidationError(
                u"rectificationPeriod.endDate should come at least 5 working days earlier than tenderPeriod.endDate"
            )

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

    def validate_lotIdentifier(self, data, lotIdentifier):
        if not lotIdentifier:
            if get_auction_creation_date(data) > DGF_ID_REQUIRED_FROM:
                raise ValidationError(u'This field is required.')

    @serializable(serialize_when_none=False)
    def next_check(self):
        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))
        # Use next_check part from awarding
        request = get_request_from_root(self)
        if request is not None:
            awarding_check = request.registry.getAdapter(
                self, IAwardingNextCheck).add_awarding_checks(self)
            if awarding_check is not None:
                checks.append(awarding_check)
        if self.status.startswith('active'):
            from openprocurement.auctions.core.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
class LeaseTerms(Model):

    leaseDuration = IsoDurationType(required=True)
    taxHolidays = ListType(ModelType(TaxHolidays))
    escalationClauses = ListType(ModelType(EscalationClauses))
class Cancellation(BaseCancellation):
    documents = ListType(ModelType(Document), default=list())
Beispiel #11
0
class AppraisalCancellation(dgfCancellation):
    documents = ListType(
        ModelType(AppraisalCancellationDocument),
        default=list(),
    )
Beispiel #12
0
class AppraisalAuction(BaseAuction):
    """Data regarding auction process - publicly inviting prospective contractors to submit bids for evaluation and selecting a winner or winners."""
    class Options:
        roles = appraisal_auction_roles

    _internal_type = "appraisal"
    description = StringType(required=True)
    awards = ListType(ModelType(AppraisalAward), default=list())
    cancellations = ListType(ModelType(AppraisalCancellation), default=list())
    complaints = ListType(ComplaintModelType(Complaint), default=list())
    contracts = ListType(ModelType(AppraisalContract), default=list())
    documents = ListType(ModelType(AppraisalDocument), 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.
    rectificationPeriod = ModelType(RectificationPeriod)
    tenderAttempts = IntType(choices=[1, 2, 3, 4, 5, 6, 7, 8])
    status = StringType(choices=AUCTION_STATUSES, default='draft')
    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(AppraisalItem),
                     required=True,
                     min_size=1,
                     validators=[validate_items_uniq])
    suspended = BooleanType()
    bids = ListType(ModelType(Bid), default=list(
    ))  # A list of all the companies who entered submissions for the auction.
    auctionPeriod = ModelType(AuctionAuctionPeriod, required=True, default={})
    auctionParameters = ModelType(AppraisalAuctionParameters)
    minimalStep = ModelType(Value)
    registrationFee = ModelType(Guarantee, required=True)
    guarantee = ModelType(Guarantee, required=True)
    bankAccount = ModelType(BankAccount)
    procuringEntity = ModelType(SwiftsureProcuringEntity, required=True)
    lotIdentifier = StringType(required=True)

    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 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 == 'auction':
            role = 'auction_{}'.format(request.method.lower())
        elif request.authenticated_role == 'convoy':
            role = 'convoy'
        elif request.authenticated_role == 'concierge':
            role = 'concierge'
        else:
            role = 'edit_{}'.format(request.context.status)
            rectification_period_exists = self.rectification_period.endDate is not None
            rectification_period_not_finished = rectification_period_exists and get_now(
            ) < self.rectification_period.endDate
            if request.context.status == 'active.tendering' and rectification_period_not_finished:
                role += '_during_rectification_period'
        return role

    def initialize(self):
        pass

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

    def validate_tenderPeriod(self, data, value):
        if value and value.get('startDate') and value.get('endDate'):

            min_end_date_limit = calculate_business_date(
                value['startDate'],
                timedelta(days=MIN_TENDER_PERIOD_DAYS_AMOUNT),
                data,
                working_days=True)
            if value['endDate'] < min_end_date_limit:
                raise ValidationError(
                    u"tenderPeriod should be at least {} working days".format(
                        MIN_TENDER_PERIOD_DAYS_AMOUNT))

    @serializable(serialized_name="minimalStep", type=ModelType(Value))
    def auction_minimalStep(self):
        return Value(dict(amount=0))

    @serializable(serialized_name="rectificationPeriod",
                  type=ModelType(RectificationPeriod),
                  serialize_when_none=False)
    def rectification_period(self):
        if self.tenderPeriod:
            self.rectificationPeriod = RectificationPeriod(
            ) if not self.rectificationPeriod else self.rectificationPeriod
            self.rectificationPeriod.startDate = self.tenderPeriod.startDate

            # for a new type of procedure we should allow tenderPeriod of 1 day.
            # In this case rectificationPeriod does not exist. But if rectificationPeriod does not exist
            # procedure is editable. To make it unchangeable,
            # we should create rectificationPeriod with startDate == endDate == tenderPeriod.startDate
            five_working_days_after_start_date = calculate_business_date(
                self.tenderPeriod.startDate,
                timedelta(days=5),
                None,
                working_days=True)
            if self.tenderPeriod.endDate < five_working_days_after_start_date:
                self.rectificationPeriod.endDate = self.rectificationPeriod.startDate
                return self.rectificationPeriod

            self.rectificationPeriod.endDate = calculate_business_date(
                self.tenderPeriod.endDate.astimezone(TZ),
                -timedelta(days=5),
                self,
                working_days=True)

            if self.rectificationPeriod.startDate > self.rectificationPeriod.endDate:
                self.rectificationPeriod.startDate = self.rectificationPeriod.endDate = None

        return self.rectificationPeriod

    @serializable(serialized_name="tenderPeriod", type=ModelType(Period))
    def tender_period(self):
        if self.tenderPeriod and self.auctionPeriod.startDate:
            end_date = calculate_business_date(self.auctionPeriod.startDate,
                                               DUTCH_PERIOD, self)
            if SANDBOX_MODE and self.submissionMethodDetails and 'quick' in self.submissionMethodDetails:
                end_date = self.auctionPeriod.startDate + QUICK_DUTCH_PERIOD
            if self.auctionPeriod.endDate and self.auctionPeriod.endDate <= self.tenderPeriod.endDate:
                end_date = self.auctionPeriod.endDate.astimezone(TZ)
            self.tenderPeriod.endDate = end_date
        return self.tenderPeriod

    @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.enquiryPeriod and self.enquiryPeriod.endDate:
            checks.append(self.enquiryPeriod.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(
                    NUMBER_OF_STAGES,
                    self.auctionPeriod.startDate).astimezone(TZ):
                checks.append(
                    calc_auction_end_time(
                        NUMBER_OF_STAGES,
                        self.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))
        if self.status.startswith('active'):
            from openprocurement.auctions.core.utils import calculate_business_date
            for complaint in self.complaints:
                if complaint.status == 'claim' and complaint.dateSubmitted:
                    checks.append(
                        calculate_business_date(
                            complaint.dateSubmitted,
                            AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
                elif complaint.status == 'answered' and complaint.dateAnswered:
                    checks.append(
                        calculate_business_date(
                            complaint.dateAnswered,
                            AUCTIONS_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,
                                AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
                    elif complaint.status == 'answered' and complaint.dateAnswered:
                        checks.append(
                            calculate_business_date(
                                complaint.dateAnswered,
                                AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
        return min(checks).isoformat() if checks else None
Beispiel #13
0
class AppraisalContract(Contract):
    items = ListType(ModelType(AppraisalItem))
Beispiel #14
0
class AppraisalAward(Award):
    items = ListType(ModelType(AppraisalItem))

    VERIFICATION_PERIOD_PARAMS = APPRAISAL_VERIFICATION_PERIOD_PARAMS
    SIGNING_PERIOD_PARAMS = APPRAISAL_SIGNING_PERIOD_PARAMS
Beispiel #15
0
class AppraisalAward(Award):
    items = ListType(ModelType(AppraisalItem))
class DGFOtherAssets(BaseAuction):
    """Data regarding auction process

    publicly inviting prospective contractors to submit bids
    for evaluation and selecting a winner or winners.
    """
    class Options:
        roles = dgf_auction_roles
    _internal_type = "dgfOtherAssets"
    awards = ListType(ModelType(Award), default=list())
    # A list of all the companies who entered submissions for the auction.
    bids = ListType(ModelType(DGFOtherBid), default=list())
    cancellations = ListType(ModelType(Cancellation), default=list())
    complaints = ListType(ComplaintModelType(Complaint), default=list())
    contracts = ListType(ModelType(Contract), default=list())
    dgfID = StringType()
    merchandisingObject = MD5Type()
    dgfDecisionID = StringType()
    dgfDecisionDate = DateType()
    # All documents and attachments related to the auction.
    documents = ListType(ModelType(Document), default=list())
    # The period during which enquiries may be made and will be answered.
    enquiryPeriod = ModelType(Period)
    # The period when the auction is open for submissions. The end date is the closing date for auction submissions.
    tenderPeriod = ModelType(Period)
    tenderAttempts = IntType(choices=[1, 2, 3, 4, 5, 6, 7, 8])
    auctionPeriod = ModelType(AuctionAuctionPeriod, required=True, default={})
    status = StringType(
        choices=[
            'draft',
            'pending.verification',
            'invalid',
            'active.tendering',
            'active.auction',
            'active.qualification',
            'active.awarded',
            'complete',
            'cancelled',
            'unsuccessful'
        ],
        default='active.tendering'
    )
    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), default=list(), validators=[validate_items_uniq])
    suspended = BooleanType()
    rectificationPeriod = ModelType(RectificationPeriod)

    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 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 == 'auction':
            role = 'auction_{}'.format(request.method.lower())
        elif request.authenticated_role == 'convoy':
            role = 'convoy'
        else:  # on PATCH of the owner
            now = get_now()
            if self.status == 'active.tendering':
                if now in self.rectificationPeriod:
                    role = 'edit_active.tendering_during_rectificationPeriod'
                else:
                    role = 'edit_active.tendering_after_rectificationPeriod'
            else:
                role = 'edit_{0}'.format(self.status)
        return role

    @serializable(serialized_name='rectificationPeriod', serialize_when_none=False)
    def generate_rectificationPeriod(self):
        """Generate rectificationPeriod only when it not defined"""
        # avoid period generation if
        if getattr(self, 'tenderPeriod') is None:
            return
        if (
            # it's already generated
            (
                getattr(self, 'rectificationPeriod', False)
                # and not just present, but actually holds some real value
                and self.rectificationPeriod.startDate is not None
            )
        ):
            return self.rectificationPeriod.serialize()
        start = self.tenderPeriod.startDate
        end = calculate_business_date(start, RECTIFICATION_PERIOD_DURATION, self, working_days=True)

        period = RectificationPeriod()
        period.startDate = start
        period.endDate = end

        return period.serialize()

    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()
        start_date = TZ.localize(self.auctionPeriod.startDate.replace(tzinfo=None))
        self.auctionPeriod.startDate = None
        self.auctionPeriod.endDate = None
        self.tenderPeriod.startDate = self.enquiryPeriod.startDate = now
        pause_between_periods = start_date - (start_date.replace(hour=20, minute=0, second=0, microsecond=0) - timedelta(days=1))
        end_date = calculate_business_date(start_date, -pause_between_periods, self)
        self.enquiryPeriod.endDate = end_date
        self.tenderPeriod.endDate = self.enquiryPeriod.endDate
        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_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 and data['status'] not in ['draft', 'pending.verification', 'invalid']:
            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, dgfDecisionID):
        if not dgfDecisionID:
            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, dgfDecisionDate):
        if not dgfDecisionDate:
            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_merchandisingObject(self, data, merchandisingObject):
        if data['status'] == 'pending.verification' and not merchandisingObject:
            raise ValidationError(u'This field is required.')

    def validate_items(self, data, items):
        if data['status'] not in ['draft', 'pending.verification', 'invalid']:
            if not items:
                raise ValidationError(u'This field is required.')
            elif len(items) < 1:
                raise ValidationError(u'Please provide at least 1 item.')

    @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))
        # Use next_check part from awarding 2.0
        request = get_request_from_root(self)
        if request is not None:
            awarding_check = request.registry.getAdapter(self, IAwardingNextCheck).add_awarding_checks(self)
            if awarding_check is not None:
                checks.append(awarding_check)
        if self.status.startswith('active'):
            from openprocurement.auctions.core.utils import calculate_business_date
            for complaint in self.complaints:
                if complaint.status == 'claim' and complaint.dateSubmitted:
                    checks.append(calculate_business_date(complaint.dateSubmitted, AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
                elif complaint.status == 'answered' and complaint.dateAnswered:
                    checks.append(calculate_business_date(complaint.dateAnswered, AUCTIONS_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, AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
                    elif complaint.status == 'answered' and complaint.dateAnswered:
                        checks.append(calculate_business_date(complaint.dateAnswered, AUCTIONS_COMPLAINT_STAND_STILL_TIME, self))
        return min(checks).isoformat() if checks else None