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 = calculate_business_date(
         self.auctionPeriod.startDate, -pause_between_periods,
         self).astimezone(TZ)
     time_before_tendering_end = (self.auctionPeriod.startDate.replace(
         hour=9, minute=30, second=0, microsecond=0) +
                                  DUTCH_PERIOD) - self.enquiryPeriod.endDate
     self.tenderPeriod.endDate = calculate_business_date(
         self.enquiryPeriod.endDate, time_before_tendering_end, self)
     if SANDBOX_MODE and self.submissionMethodDetails and 'quick' in self.submissionMethodDetails:
         self.tenderPeriod.endDate = (self.enquiryPeriod.endDate +
                                      QUICK_DUTCH_PERIOD).astimezone(TZ)
     self.auctionPeriod.startDate = None
     self.auctionPeriod.endDate = None
     self.date = now
     self.documents.append(
         type(self).documents.model_class(DGF_PLATFORM_LEGAL_DETAILS))
def switch_to_next_award(request):
    auction = request.validated['auction']
    now = get_now()
    waiting_awards = [
        i for i in auction.awards if i['status'] == 'pending.waiting'
    ]
    if waiting_awards:
        award = waiting_awards[0]
        award.status = 'pending.verification'
        award.verificationPeriod = {'startDate': now}
        award.verificationPeriod.endDate = calculate_business_date(
            now, VERIFY_AUCTION_PROTOCOL_TIME, auction, True)
        award.paymentPeriod = {'startDate': now}
        award.paymentPeriod.endDate = calculate_business_date(
            now, AWARD_PAYMENT_TIME, auction, True)
        award.signingPeriod = {'startDate': now}
        award.signingPeriod.endDate = calculate_business_date(
            now, CONTRACT_SIGNING_TIME, auction, True)
        award.complaintPeriod.endDate = award.signingPeriod.endDate = calculate_business_date(
            now, CONTRACT_SIGNING_TIME, auction, True)
        request.response.headers['Location'] = request.route_url(
            '{}:Auction Awards'.format(auction.procurementMethodType),
            auction_id=auction.id,
            award_id=award['id'])

    elif all([
            award.status in ['cancelled', 'unsuccessful']
            for award in auction.awards
    ]):
        auction.awardPeriod.endDate = now
        auction.status = 'unsuccessful'
Esempio n. 3
0
def calculate_enddate(auction, period, duration):
    period.endDate = calculate_business_date(period.startDate, duration,
                                             auction, True)
    round_to_18_hour_delta = period.endDate.replace(
        hour=18, minute=0, second=0) - period.endDate
    period.endDate = calculate_business_date(period.endDate,
                                             round_to_18_hour_delta, auction,
                                             False)
def check_complaint_status(request, complaint, now=None):
    if not now:
        now = get_now()
    if complaint.status == 'claim' and calculate_business_date(complaint.dateSubmitted, COMPLAINT_STAND_STILL_TIME, request.auction) < now:
        complaint.status = 'pending'
        complaint.type = 'complaint'
        complaint.dateEscalated = now
    elif complaint.status == 'answered' and calculate_business_date(complaint.dateAnswered, COMPLAINT_STAND_STILL_TIME, request.auction) < now:
        complaint.status = complaint.resolutionType
Esempio n. 5
0
 def award_paymentPeriod(self):
     period = self.paymentPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(period.startDate,
                                                  AWARD_PAYMENT_TIME,
                                                  auction, True)
         round_to_18_hour_delta = period.endDate.replace(
             hour=18, minute=0, second=0) - period.endDate
         period.endDate = calculate_business_date(period.endDate,
                                                  round_to_18_hour_delta,
                                                  auction, False)
     return period.to_primitive()
Esempio n. 6
0
 def award_signingPeriod(self):
     period = self.signingPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(period.startDate,
                                                  CONTRACT_SIGNING_TIME,
                                                  auction, True)
         round_to_18_hour_delta = period.endDate.replace(
             hour=18, minute=0, second=0) - period.endDate
         period.endDate = calculate_business_date(period.endDate,
                                                  round_to_18_hour_delta,
                                                  auction, False)
     return period.to_primitive()
Esempio n. 7
0
    def award_verificationPeriod(self):
        period = self.verificationPeriod
        if not period:
            return
        if not period.endDate:
            auction = get_auction(self)
            period.endDate = calculate_business_date(
                period.startDate, VERIFY_AUCTION_PROTOCOL_TIME, auction, True)
            round_to_18_hour_delta = period.endDate.replace(
                hour=18, minute=0, second=0) - period.endDate
            period.endDate = calculate_business_date(period.endDate,
                                                     round_to_18_hour_delta,
                                                     auction, False)

        return period.to_primitive()
    def test_apply_long(self):
        contract, prolongation = self.fixture_created()
        pre_prolongation_contract_signingPeriod = contract.signingPeriod

        target_signingPeriod_endDate = calculate_business_date(
            contract.signingPeriod.startDate,
            PROLONGATION_LONG_PERIOD,
            contract.__parent__,
            working_days=True,
            specific_hour=CONTRACT_SIGNING_PERIOD_END_DATE_HOUR)

        previous_short_prolongation = self.fixture_created()[0]
        previous_short_prolongation.status = 'applied'
        contract.prolongations.append(previous_short_prolongation)

        managed_prolongation = ProlongationManager(prolongation)
        managed_prolongation.apply()
        self.assertEqual(previous_short_prolongation.status, 'applied')

        self.assertEqual(prolongation.status, 'applied')

        # check update of startDate
        self.assertEqual(contract.signingPeriod.startDate,
                         pre_prolongation_contract_signingPeriod.startDate,
                         'startDate of Contract is incorrect')
        # check update of endDate
        self.assertEqual(
            contract.signingPeriod.endDate,
            target_signingPeriod_endDate,
            'endDate of Contract is incorrect',
        )
Esempio n. 9
0
 def test_patch_contract_status_active_payment(self):
     contract = create_contract(self)
     response = patch_contract(
         self,
         contract,
         {'data': {
             'status': 'active.payment'
         }},
     )
     self.assertEqual(response.status, '200 OK')
     response_data = response.json['data']
     self.assertEqual(response_data['status'], 'active.payment')
     self.assertTrue(isinstance(response_data.get('milestones'), list),
                     "Milestones weren't created")
     financial_milestone = response_data['milestones'][0]
     contract = Contract(contract_create_data)
     target_dueDate = calculate_business_date(
         contract.dateSigned,
         MILESTONE_FINANCING_DUEDATE_OFFSET,
         context=None,
         working_days=False,
         specific_hour=18,
         result_is_working_day=True)
     self.assertEqual(
         financial_milestone['dueDate'], target_dueDate.isoformat(),
         "dueDate of financial milestone wasn't calculated right")
 def test_patch_contract_status_active_payment(self):
     contract = create_contract(self)
     contract_id = contract.data.id
     response = self.app.patch_json(
         ENDPOINTS['contracts'].format(contract_id=contract_id) +
         "?acc_token={}".format(contract.access.token),
         {'data': {
             'status': 'active.payment'
         }},
     )
     self.assertEqual(response.status, '200 OK')
     response_data = response.json['data']
     self.assertEqual(response_data['status'], 'active.payment')
     self.assertTrue(isinstance(response_data.get('milestones'), list),
                     "Milestones weren't created")
     financial_milestone = response_data['milestones'][0]
     contract = Contract(contract_create_data)
     target_dueDate = calculate_business_date(
         contract.dateSigned,
         MILESTONE_FINANCING_DUEDATE_OFFSET,
         context=None,
         working_days=True,
         specific_hour=18)
     self.assertEqual(
         financial_milestone['dueDate'], target_dueDate.isoformat(),
         "dueDate of financial milestone wasn't calculated right")
Esempio n. 11
0
 def wrapper():
     return PeriodStartEndRequired({
         "startDate":
         get_now(),
         "endDate":
         calculate_business_date(get_now(), tendering_duration)
     })
 def validate_tenderPeriod(self, data, period):
     """Auction start date must be not closer than MINIMAL_EXPOSITION_PERIOD days and not a holiday"""
     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")
Esempio n. 13
0
def generate_rectificationPeriod(auction):
    now = get_now()
    if not auction.rectificationPeriod:
        period = type(auction).rectificationPeriod.model_class()
    period.startDate = period.startDate or now
    if not period.endDate:
        calculated_endDate = calculate_business_date(auction.tenderPeriod.endDate, -MINIMAL_PERIOD_FROM_RECTIFICATION_END, auction)
        period.endDate = calculated_endDate if calculated_endDate > now else now
    period.invalidationDate = None
    return period
Esempio n. 14
0
    def set_dueDate(self, milestone, contract):
        """Sets dueDate of the Milestone

        Also takes into account milestone's type, so this method can be used on
        any milestone of Ceasefire contracting.

        :param milestone: milestone to work with
        :param contract: contract, related to milestone

        :type milestone: openprocurement.contracting.ceasefire.models.Milestone
        :type start_date: openprocurement.contracting.ceasefire.models.Contract

        :return: dueDate of milestone
        :rtype: datetime.datetime
        """
        if milestone.type_ == 'financing':
            milestone.dueDate = calculate_business_date(
                contract.dateSigned,
                MILESTONE_FINANCING_DUEDATE_OFFSET,
                context=contract,
                working_days=False,
                specific_hour=18,
                result_is_working_day=True)
        elif milestone.type_ == 'approval':
            financing_milestone = search_list_with_dicts(
                contract.milestones, 'type_', 'financing')
            milestone.dueDate = calculate_business_date(
                financing_milestone.dateMet,
                MILESTONE_APPROVAL_DUEDATE_OFFSET,
                context=contract,
                working_days=False,
                specific_hour=18,
                result_is_working_day=True)
        elif milestone.type_ == 'reporting' and milestone.dueDate is None:
            approval_milestone = search_list_with_dicts(
                contract.milestones, 'type_', 'approval')
            milestone.dueDate = datetime.combine(
                date(
                    approval_milestone.dateMet.year +
                    MILESTONE_REPORTING_DUEDATE_OFFSET_YEARS,
                    approval_milestone.dateMet.month,
                    approval_milestone.dateMet.day),
                approval_milestone.dateMet.time())
Esempio n. 15
0
 def award_signingPeriod(self):
     period = self.signingPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(
             period.startDate, CONTRACT_SIGNING_TIME, auction, True,
             AWARDING_PERIODS_END_DATE_HOUR)
     return period.to_primitive()
Esempio n. 16
0
 def award_verificationPeriod(self):
     period = self.verificationPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(
             period.startDate, VERIFY_AUCTION_PROTOCOL_TIME, auction, True,
             AWARDING_PERIODS_END_DATE_HOUR)
     return period.to_primitive()
 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
Esempio n. 18
0
def apply_prolongation_short(test_case):
    pre_prolongation_contract = get_related_contract(test_case)
    add_document_to_prolongation(
        test_case,
        test_case.auction_id,
        test_case.contract_id,
        test_case.prolongation_id,
    )

    patch_data = {
        'data': {
            'status': 'applied',
        }
    }
    patch_prolongation_response = test_case.app.patch_json(
        PATHS['prolongation'].format(
            auction_id=test_case.auction_id,
            contract_id=test_case.contract_id,
            prolongation_id=test_case.prolongation_id,
            token=test_case.auction_token
        ),
        patch_data
    )

    test_case.assertEqual(
        patch_prolongation_response.status,
        '200 OK'
    )
    retrieved_prolongation = Prolongation(
        patch_prolongation_response.json['data']
    )
    retrieved_prolongation.validate()
    test_case.assertEqual(
        retrieved_prolongation.status,
        'applied'
    )
    add_document_to_prolongation(
        test_case,
        test_case.auction_id,
        test_case.contract_id,
        test_case.prolongation_id,
    )
    post_prolongation_contract = get_related_contract(test_case)
    auction = get_auction(test_case)
    contract_signing_period_end_date = calculate_business_date(
        pre_prolongation_contract.signingPeriod.startDate,
        PROLONGATION_SHORT_PERIOD,
        context=auction,
        working_days=True,
        specific_hour=CONTRACT_SIGNING_PERIOD_END_DATE_HOUR
    )
    test_case.assertEqual(
        post_prolongation_contract.signingPeriod.endDate,
        contract_signing_period_end_date
    )
Esempio n. 19
0
 def award_signingPeriod(self):
     period = self.signingPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(
             start=period.startDate,
             context=auction,
             **self.SIGNING_PERIOD_PARAMS)
     return period.to_primitive()
Esempio n. 20
0
 def award_verificationPeriod(self):
     period = self.verificationPeriod
     if not period:
         return
     if not period.endDate:
         auction = get_auction(self)
         period.endDate = calculate_business_date(
             start=period.startDate,
             context=auction,
             **self.VERIFICATION_PERIOD_PARAMS)
     return period.to_primitive()
Esempio n. 21
0
    def _start_awarding(self):
        """
            Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
            First award always in pending.verification status
            others in pending.waiting status
            In case that only one bid was applied, award object
            in pending.admission status will be created for that bid
        """

        auction = self.context
        auction.status = 'active.qualification'
        now = get_now()

        auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
        awarding_type = self.awarding_type
        valid_bids = [bid for bid in auction.bids if self.is_bid_valid(bid)]

        award_status = 'pending.admission' if len(
            valid_bids
        ) == 1 and self.pending_admission_for_one_bid else 'pending'

        bids = chef(valid_bids, auction.features or [], [], True)
        bids_to_qualify = self.get_bids_to_qualify(bids)
        for bid, status in izip_longest(bids[:bids_to_qualify], [award_status],
                                        fillvalue='pending.waiting'):
            bid = bid.serialize()
            award = make_award(self.request,
                               auction,
                               bid,
                               status,
                               now,
                               parent=True)

            if bid['status'] == 'invalid':
                set_award_status_unsuccessful(award, now)
            if award.status == 'pending':
                award.verificationPeriod = self.verificationPeriod()
                award.signingPeriod = self.signingPeriod()
                add_award_route_url(self.request, auction, award,
                                    awarding_type)
            if award.status == 'pending.admission':
                award.admissionPeriod = {
                    'startDate':
                    now,
                    'endDate':
                    calculate_business_date(start=now,
                                            context=auction,
                                            **award.ADMISSION_PERIOD_PARAMS)
                }
                add_award_route_url(self.request, auction, award,
                                    awarding_type)
            auction.awards.append(award)
        return True
 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.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
Esempio n. 23
0
def create_awards(request):
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})

    bids = chef(auction.bids, auction.features or [], [], True)

    for i, status in enumerate(['pending.verification', 'pending.waiting']):
        bid = bids[i].serialize()
        award = type(auction).awards.model_class({
            'bid_id': bid['id'],
            'status': status,
            'date': now,
            'value': bid['value'],
            'suppliers': bid['tenderers'],
            'complaintPeriod': {
                'startDate': now
            }
        })
        if bid['status'] == 'invalid':
            award.status = 'unsuccessful'
            award.complaintPeriod.endDate = now
        if award.status == 'pending.verification':
            award.verificationPeriod = {'startDate': now}
            award.verificationPeriod.endDate = calculate_business_date(
                now, VERIFY_AUCTION_PROTOCOL_TIME, auction, True)
            award.paymentPeriod = {'startDate': now}
            award.paymentPeriod.endDate = calculate_business_date(
                now, AWARD_PAYMENT_TIME, auction, True)
            award.signingPeriod = {'startDate': now}
            award.complaintPeriod.endDate = award.signingPeriod.endDate = calculate_business_date(
                now, CONTRACT_SIGNING_TIME, auction, True)
            request.response.headers['Location'] = request.route_url(
                '{}:Auction Awards'.format(auction.procurementMethodType),
                auction_id=auction.id,
                award_id=award['id'])
        auction.awards.append(award)
Esempio n. 24
0
def create_awards(request):
    """
        Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
        First award always in pending.verification status
        others in pending.waiting status
        In case that only one bid was applied, award object
        in pending.admission status will be created for that bid
    """
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    awarding_type = request.content_configurator.awarding_type
    valid_bids = [bid for bid in auction.bids if bid['value'] is not None]
    if len(valid_bids) == 1:
        bid = valid_bids[0].serialize()
        award = make_award(request,
                           auction,
                           bid,
                           'pending.admission',
                           now,
                           parent=True)
        if bid['status'] == 'invalid':
            set_award_status_unsuccessful(award, now)
        if award.status == 'pending.admission':
            award.admissionPeriod = {
                'startDate':
                now,
                'endDate':
                calculate_business_date(now, VERIFY_ADMISSION_PROTOCOL_TIME,
                                        auction, True,
                                        AWARDING_PERIODS_END_DATE_HOUR)
            }
            add_award_route_url(request, auction, award, awarding_type)
        auction.awards.append(award)
    else:
        bids = chef(valid_bids, auction.features or [], [], True)
        bids_to_qualify = get_bids_to_qualify(bids)
        for bid, status in izip_longest(bids[:bids_to_qualify], ['pending'],
                                        fillvalue='pending.waiting'):
            bid = bid.serialize()
            award = make_award(request, auction, bid, status, now, parent=True)
            if bid['status'] == 'invalid':
                set_award_status_unsuccessful(award, now)
            if award.status == 'pending':
                award.signingPeriod = award.verificationPeriod = {
                    'startDate': now
                }
                add_award_route_url(request, auction, award, awarding_type)
            auction.awards.append(award)
 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
 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_datePublished(self, data, datePublished):
        """Check if datePublished attribute is valid

            datePublished must be non less than `dateCreated` on some
            limit.
        """
        if not data.get('datePublished'):
            return

        offset_from_date_created = calculate_business_date(
            datePublished, PROLONGATION_DATE_PUBLISHED_LIMIT_PERIOD, None)
        if offset_from_date_created < data['dateCreated']:
            raise ValidationError(
                'datePublished must be no less on {limit} days, '
                'than dateCreated'.format(
                    limit=PROLONGATION_DATE_PUBLISHED_LIMIT_PERIOD.days))
    def test_set_dueDate_financing(self):
        self.prepare_mocked_contract()
        manager = CeasefireMilestoneManager(Mock())

        milestone_mock = Mock()
        milestone_mock.type_ = 'financing'

        self.contract.dateSigned = datetime.now()
        target_dueDate = calculate_business_date(
            self.contract.dateSigned,
            MILESTONE_FINANCING_DUEDATE_OFFSET,
            context=None,
            working_days=True,
            specific_hour=18)
        manager.set_dueDate(milestone_mock, self.contract)
        self.assertEqual(milestone_mock.dueDate, target_dueDate,
                         'dueDate has been calculated incorrectly')
Esempio n. 29
0
 def validate_update_tender(self, operation):
     tender = self.request.validated['tender']
     if tender.status not in ['active.tendering']:
         self.request.errors.add(
             'body', 'data',
             'Can\'t {} lot in current ({}) tender status'.format(
                 operation, tender.status))
         self.request.errors.status = 403
         return
     if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD,
                                tender) > tender.tenderPeriod.endDate:
         self.request.errors.add(
             'body', 'data',
             'tenderPeriod should be extended by {0.days} days'.format(
                 TENDERING_EXTRA_PERIOD))
         self.request.errors.status = 403
         return
     return True
    def test_set_dueDate_financing_with_accelerator(self):
        self.prepare_mocked_contract()
        manager = CeasefireMilestoneManager(Mock())

        milestone_mock = Mock()
        milestone_mock.type_ = 'financing'

        if SANDBOX_MODE:
            self.contract.sandbox_parameters = 'quick, accelerator=1440'
        self.contract.dateSigned = datetime.now()

        target_dueDate = calculate_business_date(
            self.contract.dateSigned,
            MILESTONE_FINANCING_DUEDATE_OFFSET,
            context=self.contract,
            working_days=True,
            specific_hour=18)
        manager.set_dueDate(milestone_mock, self.contract)
        self.assertEqual(milestone_mock.dueDate, target_dueDate,
                         'dueDate has been calculated incorrectly')
 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.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
     if not self.rectificationPeriod:
         self.rectificationPeriod = generate_rectificationPeriod(self)
     self.rectificationPeriod.startDate = now
     self.auctionPeriod.startDate = None
     self.auctionPeriod.endDate = None
     self.date = now
     if self.lots:
         for lot in self.lots:
             lot.date = now
    def next_check(self):
        now = get_now()
        checks = []
        if self.status == 'active.enquiries' and self.tenderPeriod.startDate:
            checks.append(self.tenderPeriod.startDate.astimezone(TZ))
        elif self.status == 'active.enquiries' and self.enquiryPeriod.endDate:
            checks.append(self.enquiryPeriod.endDate.astimezone(TZ))
        elif self.status == 'active.tendering' 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.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'):
            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
Esempio n. 33
0
    def patch(self):
        """Update of award

        Example request to change the award:

        .. sourcecode:: http

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

            {
                "data": {
                    "value": {
                        "amount": 600
                    }
                }
            }

        And here is the response to be expected:

        .. sourcecode:: http

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

            {
                "data": {
                    "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                    "date": "2014-10-28T11:44:17.947Z",
                    "status": "active",
                    "suppliers": [
                        {
                            "id": {
                                "name": "Державне управління справами",
                                "scheme": "https://ns.openprocurement.org/ua/edrpou",
                                "uid": "00037256",
                                "uri": "http://www.dus.gov.ua/"
                            },
                            "address": {
                                "countryName": "Україна",
                                "postalCode": "01220",
                                "region": "м. Київ",
                                "locality": "м. Київ",
                                "streetAddress": "вул. Банкова, 11, корпус 1"
                            }
                        }
                    ],
                    "value": {
                        "amount": 600,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """
        tender = self.request.validated['tender']
        if tender.status not in ['active.qualification', 'active.awarded']:
            self.request.errors.add('body', 'data', 'Can\'t update award in current ({}) tender status'.format(tender.status))
            self.request.errors.status = 403
            return
        award = self.request.context
        if any([i.status != 'active' for i in tender.lots if i.id == award.lotID]):
            self.request.errors.add('body', 'data', 'Can update award only in active lot status')
            self.request.errors.status = 403
            return
        award_status = award.status
        apply_patch(self.request, save=False, src=self.request.context.serialize())
        if award_status == 'pending' and award.status == 'active':
            award.complaintPeriod.endDate = calculate_business_date(get_now(), STAND_STILL_TIME, tender, True)
            tender.contracts.append(type(tender).contracts.model_class({
                'awardID': award.id,
                'suppliers': award.suppliers,
                'value': award.value,
                'items': [i for i in tender.items if i.relatedLot == award.lotID ],
                'contractID': '{}-{}{}'.format(tender.tenderID, self.server_id, len(tender.contracts) + 1) }))
            add_next_award(self.request)
        elif award_status == 'active' and award.status == 'cancelled':
            now = get_now()
            if award.complaintPeriod.endDate > now:
                award.complaintPeriod.endDate = now
            for j in award.complaints:
                if j.status not in ['invalid', 'resolved', 'declined']:
                    j.status = 'cancelled'
                    j.cancellationReason = 'cancelled'
                    j.dateCanceled = now
            for i in tender.contracts:
                if i.awardID == award.id:
                    i.status = 'cancelled'
            add_next_award(self.request)
        elif award_status == 'pending' and award.status == 'unsuccessful':
            award.complaintPeriod.endDate = calculate_business_date(get_now(), STAND_STILL_TIME, tender, True)
            add_next_award(self.request)
        elif award_status == 'unsuccessful' and award.status == 'cancelled' and any([i.status in ['claim', 'answered', 'pending', 'resolved'] for i in award.complaints]):
            if tender.status == 'active.awarded':
                tender.status = 'active.qualification'
                tender.awardPeriod.endDate = None
            now = get_now()
            award.complaintPeriod.endDate = now
            cancelled_awards = []
            for i in tender.awards[tender.awards.index(award):]:
                if i.lotID != award.lotID:
                    continue
                i.complaintPeriod.endDate = now
                i.status = 'cancelled'
                for j in i.complaints:
                    if j.status not in ['invalid', 'resolved', 'declined']:
                        j.status = 'cancelled'
                        j.cancellationReason = 'cancelled'
                        j.dateCanceled = now
                cancelled_awards.append(i.id)
            for i in tender.contracts:
                if i.awardID in cancelled_awards:
                    i.status = 'cancelled'
            add_next_award(self.request)
        elif self.request.authenticated_role != 'Administrator' and not(award_status == 'pending' and award.status == 'pending'):
            self.request.errors.add('body', 'data', 'Can\'t update award in current ({}) status'.format(award_status))
            self.request.errors.status = 403
            return
        if save_tender(self.request):
            self.LOGGER.info('Updated tender award {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_patch'}))
            return {'data': award.serialize("view")}