def complaintPeriod(self):
     normalized_end = calculate_normalized_date(self.tenderPeriod.endDate,
                                                self)
     return Period(
         dict(startDate=self.tenderPeriod.startDate,
              endDate=calculate_business_date(normalized_end,
                                              -COMPLAINT_SUBMIT_TIME,
                                              self)))
 def __call__(self, obj, *args, **kwargs):
     complaintPeriod_class = obj._fields['tenderPeriod']
     normalized_end = calculate_normalized_date(obj.tenderPeriod.endDate,
                                                obj)
     return complaintPeriod_class(
         dict(startDate=obj.tenderPeriod.startDate,
              endDate=calculate_business_date(normalized_end,
                                              -COMPLAINT_SUBMIT_TIME, obj)))
 def complaintPeriod(self):
     if self.tenderPeriod.startDate < COMPLAINT_OLD_SUBMIT_TIME_BEFORE:
         return Period(dict(startDate=self.tenderPeriod.startDate,
                            endDate=calculate_business_date(self.tenderPeriod.endDate, -COMPLAINT_OLD_SUBMIT_TIME, self)))
     else:
         normalized_end = calculate_normalized_date(self.tenderPeriod.endDate, self)
         return Period(dict(startDate=self.tenderPeriod.startDate,
                            endDate=calculate_business_date(normalized_end, -COMPLAINT_SUBMIT_TIME, self, True)))
 def complaintPeriod(self):
     if self.tenderPeriod.startDate < COMPLAINT_OLD_SUBMIT_TIME_BEFORE:
         return Period(
             dict(startDate=self.tenderPeriod.startDate,
                  endDate=calculate_business_date(
                      self.tenderPeriod.endDate, -COMPLAINT_OLD_SUBMIT_TIME,
                      self)))
     else:
         normalized_end = calculate_normalized_date(
             self.tenderPeriod.endDate, self)
         return Period(
             dict(startDate=self.tenderPeriod.startDate,
                  endDate=calculate_business_date(normalized_end,
                                                  -COMPLAINT_SUBMIT_TIME,
                                                  self, True)))
    def patch(self):
        """Tender Edit (partial)

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

        .. sourcecode:: http

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

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

        And here is the response to be expected:

        .. sourcecode:: http

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

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

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

        apply_patch(self.request, save=False, src=self.request.validated['tender_src'])
        if self.request.authenticated_role == 'chronograph':
            check_status(self.request)
        elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering':
            tender.invalidate_bids_data()
        elif self.request.authenticated_role == 'tender_owner' and self.request.validated['tender_status'] == 'active.pre-qualification' and tender.status == "active.pre-qualification.stand-still":
            active_lots = [lot.id for lot in tender.lots if lot.status == 'active'] if tender.lots else [None]
            if any([i['status'] in self.request.validated['tender'].block_complaint_status for q in self.request.validated['tender']['qualifications'] for i in q['complaints'] if q['lotID'] in active_lots]):
                raise_operation_error(self.request, 'Can\'t switch to \'active.pre-qualification.stand-still\' before resolve all complaints')
            if all_bids_are_reviewed(self.request):
                normalized_date = calculate_normalized_date(get_now(), tender, True)
                tender.qualificationPeriod.endDate = calculate_business_date(normalized_date, COMPLAINT_STAND_STILL, self.request.validated['tender'])
                tender.check_auction_time()
            else:
                raise_operation_error(self.request, 'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified')

        save_tender(self.request)
        self.LOGGER.info('Updated tender {}'.format(tender.id),
                    extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'}))
        return {'data': tender.serialize(tender.status)}
Ejemplo n.º 6
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']
        award = self.request.context
        award_status = award.status
        apply_patch(self.request,
                    save=False,
                    src=self.request.context.serialize())
        if award_status == 'pending' and award.status == 'active':
            normalized_end = calculate_normalized_date(get_now(), tender, True)
            award.complaintPeriod.endDate = calculate_business_date(
                normalized_end, STAND_STILL_TIME, tender)
            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,
                           reverse=self.request.content_configurator.
                           reverse_awarding_criteria)
        elif award_status == 'active' and award.status == 'cancelled' and any(
            [i.status == 'satisfied' for i in award.complaints]):
            now = get_now()
            cancelled_awards = []
            for i in tender.awards:
                if i.lotID != award.lotID:
                    continue
                if not i.complaintPeriod.endDate or i.complaintPeriod.endDate > now:
                    i.complaintPeriod.endDate = now
                i.status = 'cancelled'
                cancelled_awards.append(i.id)
            for i in tender.contracts:
                if i.awardID in cancelled_awards:
                    i.status = 'cancelled'
            add_next_award(self.request,
                           reverse=self.request.content_configurator.
                           reverse_awarding_criteria)
        elif award_status == 'active' and award.status == 'cancelled':
            now = get_now()
            if award.complaintPeriod.endDate > now:
                award.complaintPeriod.endDate = now
            for i in tender.contracts:
                if i.awardID == award.id:
                    i.status = 'cancelled'
            add_next_award(self.request,
                           reverse=self.request.content_configurator.
                           reverse_awarding_criteria)
        elif award_status == 'pending' and award.status == 'unsuccessful':
            normalized_end = calculate_normalized_date(get_now(), tender, True)
            award.complaintPeriod.endDate = calculate_business_date(
                normalized_end, STAND_STILL_TIME, tender)
            add_next_award(self.request,
                           reverse=self.request.content_configurator.
                           reverse_awarding_criteria)
        elif award_status == 'unsuccessful' and award.status == 'cancelled' and any(
            [i.status == 'satisfied' for i in award.complaints]):
            if tender.status == 'active.awarded':
                tender.status = 'active.qualification'
                tender.awardPeriod.endDate = None
            now = get_now()
            if award.complaintPeriod.endDate > now:
                award.complaintPeriod.endDate = now
            cancelled_awards = []
            for i in tender.awards:
                if i.lotID != award.lotID:
                    continue
                if not i.complaintPeriod.endDate or i.complaintPeriod.endDate > now:
                    i.complaintPeriod.endDate = now
                i.status = 'cancelled'
                cancelled_awards.append(i.id)
            for i in tender.contracts:
                if i.awardID in cancelled_awards:
                    i.status = 'cancelled'
            add_next_award(self.request,
                           reverse=self.request.content_configurator.
                           reverse_awarding_criteria)
        elif self.request.authenticated_role != 'Administrator' and not (
                award_status == 'pending' and award.status == 'pending'):
            raise_operation_error(
                self.request,
                'Can\'t update award in current ({}) status'.format(
                    award_status))
        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")}