def post(self):
        complaint = self.request.context
        tender = self.request.validated['tender']
        award_id = self.request.validated['award_id']
        data = self.request.validated['ownership_data']

        if complaint.transfer_token == sha512(data['transfer']).hexdigest():
            location = self.request.route_path('Tender Award Complaints', tender_id=tender.id, award_id=award_id, complaint_id=complaint.id)
            location = location[len(ROUTE_PREFIX):]  # strips /api/<version>
            transfer = extract_transfer(self.request, transfer_id=data['id'])
            if transfer.get('usedFor') and transfer.get('usedFor') != location:
                self.request.errors.add('body', 'transfer', 'Transfer already used')
                self.request.errors.status = 403
                return
        else:
            self.request.errors.add('body', 'transfer', 'Invalid transfer')
            self.request.errors.status = 403
            return

        update_ownership(complaint, transfer)

        transfer.usedFor = location
        self.request.validated['transfer'] = transfer
        if save_transfer(self.request):
            self.LOGGER.info('Updated transfer relation {}'.format(transfer.id),
                             extra=context_unpack(self.request, {'MESSAGE_ID': 'transfer_relation_update'}))

            if save_tender(self.request):
                self.LOGGER.info('Updated award {} complaint {} ownership of tender {}'.format(complaint.id, award_id, tender.id),
                                 extra=context_unpack(self.request, {'MESSAGE_ID': 'award_complaint_ownership_update'}, {'complaint_id': complaint.id, 'award_id': award_id, 'tender_id': tender.id}))

                return {'data': complaint.serialize('view')}
def check_initial_bids_count(request):
    tender = request.validated['tender']
    if tender.lots:
        [setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < MINIMAL_NUMBER_OF_BIDS and i.auctionPeriod and i.auctionPeriod.startDate]
        for i in tender.lots:
            # gather all bids by lot id
            bids = [bid
                    for bid in tender.bids
                    if i.id in [i_lot.relatedLot for i_lot in bid.lotValues
                                if i_lot.status in ["active", "pending"]] and bid.status in ["active", "pending"]]

            if i.numberOfBids < MINIMAL_NUMBER_OF_BIDS or not validate_unique_bids(bids) and i.status == 'active':
                setattr(i, 'status', 'unsuccessful')
                for bid_index, bid in enumerate(tender.bids):
                    for lot_index, lot_value in enumerate(bid.lotValues):
                        if lot_value.relatedLot == i.id:
                            setattr(tender.bids[bid_index].lotValues[lot_index], 'status', 'unsuccessful')

        if not set([i.status for i in tender.lots]).difference(set(['unsuccessful', 'cancelled'])):
            LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                        extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
            tender.status = 'unsuccessful'
    elif tender.numberOfBids < MINIMAL_NUMBER_OF_BIDS or not validate_unique_bids(tender.bids):
        LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
        tender.status = 'unsuccessful'
def check_initial_bids_count(request):
    tender = request.validated['tender']
    if tender.lots:
        [setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod and i.auctionPeriod.startDate]

        for i in tender.lots:
            if i.numberOfBids < 2 and i.status == 'active':
                setattr(i, 'status', 'unsuccessful')
                for bid_index, bid in enumerate(tender.bids):
                    for lot_index, lot_value in enumerate(bid.lotValues):
                        if lot_value.relatedLot == i.id:
                            setattr(tender.bids[bid_index].lotValues[lot_index], 'status', 'unsuccessful')

        # [setattr(i, 'status', 'unsuccessful') for i in tender.lots if i.numberOfBids < 2 and i.status == 'active']

        if not set([i.status for i in tender.lots]).difference(set(['unsuccessful', 'cancelled'])):
            LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                        extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
            tender.status = 'unsuccessful'
    elif tender.numberOfBids < 2:
        LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
        if tender.auctionPeriod and tender.auctionPeriod.startDate:
            tender.auctionPeriod.startDate = None
        tender.status = 'unsuccessful'
def check_status(request):
    tender = request.validated['tender']
    now = get_now()

    if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \
            not has_unanswered_complaints(tender) and not has_unanswered_questions(tender):
        for complaint in tender.complaints:
            check_complaint_status(request, complaint)
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'}))
        tender.status = 'active.pre-qualification'
        tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now})
        check_initial_bids_count(request)
        prepare_qualifications(request)
        return

    elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([
        i.status in tender.block_complaint_status
        for q in tender.qualifications
        for i in q.complaints
    ]):
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.stage2.pending'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active_stage2_pending'}))
        tender.status = 'active.stage2.pending'
        check_initial_bids_count(request)
        return
def check_status(request):
    tender = request.validated['tender']
    now = get_now()

    if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \
            not has_unanswered_complaints(tender) and not has_unanswered_questions(tender):
        for complaint in tender.complaints:
            check_complaint_status(request, complaint)
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'}))
        tender.status = 'active.pre-qualification'
        tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now})
        remove_draft_bids(request)
        check_initial_bids_count(request)
        prepare_qualifications(request)
        return

    elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([
        i.status in tender.block_complaint_status
        for q in tender.qualifications
        for i in q.complaints
    ]):
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'}))
        tender.status = 'active.auction'
        check_initial_bids_count(request)
        return

    elif not tender.lots and tender.status == 'active.awarded':
        standStillEnds = [
            a.complaintPeriod.endDate.astimezone(TZ)
            for a in tender.awards
            if a.complaintPeriod.endDate
        ]
        if not standStillEnds:
            return
        standStillEnd = max(standStillEnds)
        if standStillEnd <= now:
            check_tender_status(request)
    elif tender.lots and tender.status in ['active.qualification', 'active.awarded']:
        if any([i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]):
            return
        for lot in tender.lots:
            if lot['status'] != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            standStillEnds = [
                a.complaintPeriod.endDate.astimezone(TZ)
                for a in lot_awards
                if a.complaintPeriod.endDate
            ]
            if not standStillEnds:
                continue
            standStillEnd = max(standStillEnds)
            if standStillEnd <= now:
                check_tender_status(request)
                return
def check_initial_bids_count(request):
    tender = request.validated['tender']
    if tender.lots:
        [setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod and i.auctionPeriod.startDate]
        [setattr(i, 'status', 'unsuccessful') for i in tender.lots if i.numberOfBids < 2 and i.status == 'active']
        if not set([i.status for i in tender.lots]).difference(set(['unsuccessful', 'cancelled'])):
            LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                        extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
            tender.status = 'unsuccessful'
    elif tender.numberOfBids < 2:
        LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
        if tender.auctionPeriod and tender.auctionPeriod.startDate:
            tender.auctionPeriod.startDate = None
        tender.status = 'unsuccessful'
示例#7
0
 def collection_post(self):
     """Tender Bid Document Upload
     """
     if self.request.validated["tender_status"] not in ["active.tendering", "active.qualification"]:
         self.request.errors.add(
             "body",
             "data",
             "Can't add document in current ({}) tender status".format(self.request.validated["tender_status"]),
         )
         self.request.errors.status = 403
         return
     if self.request.validated["tender_status"] == "active.qualification" and not [
         i
         for i in self.request.validated["tender"].awards
         if i.status == "pending" and i.bid_id == self.request.validated["bid_id"]
     ]:
         self.request.errors.add("body", "data", "Can't add document because award of bid is not in pending state")
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.context.documents.append(document)
     if save_tender(self.request):
         LOGGER.info(
             "Created tender bid document {}".format(document.id),
             extra=context_unpack(
                 self.request, {"MESSAGE_ID": "tender_bid_document_create"}, {"document_id": document.id}
             ),
         )
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers["Location"] = self.request.current_route_url(
             _route_name=document_route, document_id=document.id, _query={}
         )
         return {"data": document.serialize("view")}
示例#8
0
 def patch(self):
     """Tender Bid Document Update"""
     if self.request.validated["tender_status"] not in ["active.tendering", "active.qualification"]:
         self.request.errors.add(
             "body",
             "data",
             "Can't update document in current ({}) tender status".format(self.request.validated["tender_status"]),
         )
         self.request.errors.status = 403
         return
     if self.request.validated["tender_status"] == "active.qualification" and not [
         i
         for i in self.request.validated["tender"].awards
         if i.status == "pending" and i.bid_id == self.request.validated["bid_id"]
     ]:
         self.request.errors.add(
             "body", "data", "Can't update document because award of bid is not in pending state"
         )
         self.request.errors.status = 403
         return
     if apply_patch(self.request, src=self.request.context.serialize()):
         update_file_content_type(self.request)
         LOGGER.info(
             "Updated tender bid document {}".format(self.request.context.id),
             extra=context_unpack(self.request, {"MESSAGE_ID": "tender_bid_document_patch"}),
         )
         return {"data": self.request.context.serialize("view")}
    def patch(self):
        """Update of contract
        """
        if self.request.validated['tender_status'] not in ['active', 'complete']:
            self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status']))
            self.request.errors.status = 403
            return
        data = self.request.validated['data']
        if self.request.context.status == 'cancelled':
            self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) status'.format(self.request.context.status))
            self.request.errors.status = 403
            return
        if self.request.context.status != 'active' and 'status' in data and data['status'] == 'active':
            tender = self.request.validated['tender']
            award = [a for a in tender.awards if a.id == self.request.context.awardID][0]
            stand_still_end = award.complaintPeriod.endDate
            if stand_still_end > get_now():
                self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat()))
                self.request.errors.status = 403
                return

        contract_status = self.request.context.status
        apply_patch(self.request, save=False, src=self.request.context.serialize())
        if contract_status != self.request.context.status and contract_status != 'pending' and self.request.context.status != 'active':
            self.request.errors.add('body', 'data', 'Can\'t update contract status')
            self.request.errors.status = 403
            return

        check_tender_status(self.request)
        if save_tender(self.request):
            LOGGER.info('Updated tender contract {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'}))
            return {'data': self.request.context.serialize()}
 def collection_post(self):
     """Post a cancellation
     """
     tender = self.request.validated["tender"]
     if tender.status in ["complete", "cancelled", "unsuccessful"]:
         self.request.errors.add(
             "body", "data", "Can't add cancellation in current ({}) tender status".format(tender.status)
         )
         self.request.errors.status = 403
         return
     cancellation = self.request.validated["cancellation"]
     if cancellation.status == "active":
         tender.status = "cancelled"
     tender.cancellations.append(cancellation)
     if save_tender(self.request):
         self.LOGGER.info(
             "Created tender cancellation {}".format(cancellation.id),
             extra=context_unpack(
                 self.request, {"MESSAGE_ID": "tender_cancellation_create"}, {"cancellation_id": cancellation.id}
             ),
         )
         self.request.response.status = 201
         self.request.response.headers["Location"] = self.request.route_url(
             "Tender Cancellations", tender_id=tender.id, cancellation_id=cancellation.id
         )
         return {"data": cancellation.serialize("view")}
 def collection_post(self):
     """Post a complaint
     """
     auction = self.context
     if auction.status not in ['active.enquiries', 'active.tendering']:
         self.request.errors.add('body', 'data', 'Can\'t add complaint in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     complaint = self.request.validated['complaint']
     complaint.date = get_now()
     if complaint.status == 'claim':
         complaint.dateSubmitted = get_now()
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(auction.auctionID, self.server_id, sum([len(i.complaints) for i in auction.awards], len(auction.complaints)) + 1)
     set_ownership(complaint, self.request)
     auction.complaints.append(complaint)
     if save_auction(self.request):
         self.LOGGER.info('Created auction complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_complaint_create'}, {'complaint_id': complaint.id}))
         self.request.response.status = 201
         route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=route, complaint_id=complaint.id, _query={})
         return {
             'data': complaint.serialize(auction.status),
             'access': {
                 'token': complaint.owner_token
             }
         }
示例#12
0
 def patch(self):
     """Post a complaint resolution
     """
     tender = self.request.validated['tender']
     if tender.status not in ['active.enquiries', 'active.tendering', 'active.auction', 'active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     if self.context.status not in ['draft', 'claim', 'answered', 'pending']:
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.context.status))
         self.request.errors.status = 403
         return
     data = self.request.validated['data']
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered', 'pending'] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and tender.status in ['active.enquiries', 'active.tendering'] and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and tender.status in ['active.enquiries', 'active.tendering'] and self.context.status == 'draft' and data.get('status', self.context.status) == 'claim':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is True and data.get('status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is False and data.get('status', self.context.status) == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateEscalated = get_now()
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('resolution', self.context.resolution) and data.get('resolutionType', self.context.resolutionType) and data.get('status', self.context.status) == 'answered':
         if len(data.get('resolution', self.context.resolution)) < 20:
             self.request.errors.add('body', 'data', 'Can\'t update complaint: resolution too short')
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # reviewers
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get('status', self.context.status) in ['resolved', 'invalid', 'declined']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     else:
         self.request.errors.add('body', 'data', 'Can\'t update complaint')
         self.request.errors.status = 403
         return
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in ['draft', 'claim', 'answered', 'pending'] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info('Updated tender complaint {}'.format(self.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'}))
         return {'data': self.context.serialize("view")}
 def collection_post(self):
     """Post a complaint
     """
     tender = self.context
     complaint = self.request.validated['complaint']
     if complaint.status == 'claim':
         validate_submit_claim_time(self.request)
     elif complaint.status == 'pending':
         validate_submit_complaint_time(self.request)
         complaint.dateSubmitted = get_now()
         complaint.type = 'complaint'
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(tender.tenderID, self.server_id, self.complaints_len(tender) + 1)
     set_ownership(complaint, self.request)
     tender.complaints.append(complaint)
     if save_tender(self.request):
         self.LOGGER.info('Created tender complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_create'}, {'complaint_id': complaint.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('{}:Tender Complaints'.format(tender.procurementMethodType), tender_id=tender.id, complaint_id=complaint.id)
         return {
             'data': complaint.serialize(tender.status),
             'access': {
                 'token': complaint.owner_token
             }
         }
 def collection_post(self):
     """Auction Bid Document Upload
     """
     if self.request.validated['auction_status'] not in ['active.tendering', 'active.qualification']:
         self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) auction status'.format(self.request.validated['auction_status']))
         self.request.errors.status = 403
         return
     auction = self.request.validated['auction']
     if self.request.validated['auction_status'] == 'active.tendering' and (auction.tenderPeriod.startDate and get_now() < auction.tenderPeriod.startDate or get_now() > auction.tenderPeriod.endDate):
         self.request.errors.add('body', 'data', 'Document can be added only during the tendering period: from ({}) to ({}).'.format(auction.auctionPeriod.startDate and auction.auctionPeriod.startDate.isoformat(), auction.auctionPeriod.endDate.isoformat()))
         self.request.errors.status = 403
         return
     if self.request.validated['auction_status'] == 'active.qualification' and not [i for i in self.request.validated['auction'].awards if i.status == 'pending' and i.bid_id == self.request.validated['bid_id']]:
         self.request.errors.add('body', 'data', 'Can\'t add document because award of bid is not in pending state')
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.context.documents.append(document)
     if self.request.validated['auction_status'] == 'active.tendering':
         self.request.validated['auction'].modified = False
     if save_auction(self.request):
         self.LOGGER.info('Created auction bid document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_document_create'}, {'document_id': document.id}))
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={})
         return {'data': document.serialize("view")}
    def delete(self):
        """Cancelling the proposal

        Example request for cancelling the proposal:

        .. sourcecode:: http

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

        """
        bid = self.request.context
        if self.request.validated['tender_status'] != 'active.tendering':
            self.request.errors.add('body', 'data', 'Can\'t delete bid in current ({}) tender status'.format(self.request.validated['tender_status']))
            self.request.errors.status = 403
            return
        tender = self.request.validated['tender']
        if tender.tenderPeriod.startDate and get_now() < tender.tenderPeriod.startDate or get_now() > tender.tenderPeriod.endDate:
            self.request.errors.add('body', 'data', 'Bid can be deleted only during the tendering period: from ({}) to ({}).'.format(tender.tenderPeriod.startDate and tender.tenderPeriod.startDate.isoformat(), tender.tenderPeriod.endDate.isoformat()))
            self.request.errors.status = 403
            return
        bid.status = 'deleted'
        if tender.lots:
            bid.lotValues = []
        self.request.validated['tender'].modified = False
        if save_tender(self.request):
            res = bid.serialize("view")
            self.LOGGER.info('Deleted tender bid {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_delete'}))
            return {'data': res}
 def collection_post(self):
     """Post a cancellation
     """
     tender = self.request.validated['tender']
     if tender.status in ['complete', 'cancelled', 'unsuccessful']:
         self.request.errors.add('body', 'data', 'Can\'t add cancellation in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     cancellation_data = self.request.validated['data']
     if any([i.status != 'active' for i in tender.lots if i.id == cancellation_data.get('relatedLot')]):
         self.request.errors.add('body', 'data', 'Can add cancellation only in active lot status')
         self.request.errors.status = 403
         return
     cancellation = Cancellation(cancellation_data)
     cancellation.__parent__ = self.request.context
     if cancellation.relatedLot and cancellation.status == 'active':
         [setattr(i, 'status', 'cancelled') for i in tender.lots if i.id == cancellation.relatedLot]
         check_tender_status(self.request)
     elif cancellation.status == 'active':
         tender.status = 'cancelled'
     tender.cancellations.append(cancellation)
     if save_tender(self.request):
         LOGGER.info('Created tender cancellation {}'.format(cancellation.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_cancellation_create'}, {'cancellation_id': cancellation.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Tender Cancellations', tender_id=tender.id, cancellation_id=cancellation.id)
         return {'data': cancellation.serialize("view")}
 def collection_post(self):
     """Tender Award Document Upload
     """
     if self.request.validated["tender_status"] != "active":
         self.request.errors.add(
             "body",
             "data",
             "Can't add document in current ({}) tender status".format(self.request.validated["tender_status"]),
         )
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.request.validated["award"].documents.append(document)
     if save_tender(self.request):
         LOGGER.info(
             "Created tender award document {}".format(document.id),
             extra=context_unpack(
                 self.request, {"MESSAGE_ID": "tender_award_document_create"}, {"document_id": document.id}
             ),
         )
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers["Location"] = self.request.current_route_url(
             _route_name=document_route, document_id=document.id, _query={}
         )
         return {"data": document.serialize("view")}
示例#18
0
    def patch(self):
        """Update of proposal

        Example request to change bid proposal:

        .. sourcecode:: http

            PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607/bids/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": {
                    "value": {
                        "amount": 600,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """
        if self.request.validated['tender_status'] != 'active.tendering':
            self.request.errors.add('body', 'data', 'Can\'t update bid in current ({}) tender status'.format(self.request.validated['tender_status']))
            self.request.errors.status = 403
            return
        if self.request.authenticated_role != 'Administrator':
            bid_status_to = self.request.validated['data'].get("status", self.request.context.status)
            if bid_status_to != 'pending':
                self.request.errors.add('body', 'bid', 'Can\'t update bid to ({}) status'.format(bid_status_to))
                self.request.errors.status = 403
                return
        value = self.request.validated['data'].get("value") and self.request.validated['data']["value"].get("amount")
        if value and value != self.request.context.get("value", {}).get("amount"):
            self.request.validated['data']['date'] = get_now().isoformat()
        if self.request.context.lotValues:
            lotValues = dict([(i.relatedLot, i.value.amount) for i in self.request.context.lotValues])
            for lotvalue in self.request.validated['data'].get("lotValues", []):
                if lotvalue['relatedLot'] in lotValues and lotvalue.get("value", {}).get("amount") != lotValues[lotvalue['relatedLot']]:
                    lotvalue['date'] = get_now().isoformat()
        self.request.validated['tender'].modified = False
        if apply_patch(self.request, src=self.request.context.serialize()):
            self.LOGGER.info('Updated tender bid {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_patch'}))
            return {'data': self.request.context.serialize("view")}
示例#19
0
 def collection_post(self):
     """Post a complaint
     """
     tender = self.context
     if tender.status not in ['active.enquiries', 'active.tendering']:
         self.request.errors.add('body', 'data', 'Can\'t add complaint in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     complaint = self.request.validated['complaint']
     if complaint.status == 'claim':
         complaint.dateSubmitted = get_now()
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(tender.tenderID, self.server_id, sum([len(i.complaints) for i in tender.awards], len(tender.complaints)) + 1)
     set_ownership(complaint, self.request)
     tender.complaints.append(complaint)
     if save_tender(self.request):
         self.LOGGER.info('Created tender complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_create'}, {'complaint_id': complaint.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Tender Complaints', tender_id=tender.id, complaint_id=complaint.id)
         return {
             'data': complaint.serialize(tender.status),
             'access': {
                 'token': complaint.owner_token
             }
         }
 def patch(self):
     """Tender Bid Document Update"""
     if self.request.validated['tender_status'] not in ['active.tendering', 'active.qualification']:
         self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) tender status'.format(self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] == 'active.qualification' and not [i for i in self.request.validated['tender'].awards if i.status == 'pending' and i.bid_id == self.request.validated['bid_id']]:
         self.request.errors.add('body', 'data', 'Can\'t update document because award of bid is not in pending state')
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] != 'active.tendering' and 'confidentiality' in self.request.validated['data']:
         if self.context.confidentiality != self.request.validated['data']['confidentiality']:
             self.request.errors.add('body', 'data', 'Can\'t update document confidentiality in current ({}) tender status'.format(self.request.validated['tender_status']))
             self.request.errors.status = 403
             return
     bid = getattr(self.context, "__parent__")
     if bid and bid.status in ['invalid', 'unsuccessful', 'deleted']:
         self.request.errors.add('body', 'data', 'Can\'t update document data for \'{}\' bid'.format(bid.status))
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] == 'active.tendering':
         self.request.validated['tender'].modified = False
     if apply_patch(self.request, src=self.request.context.serialize()):
         update_file_content_type(self.request)
         self.LOGGER.info('Updated tender bid document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_document_patch'}))
         return {'data': self.request.context.serialize("view")}
 def collection_post(self):
     """Tender Contract Document Upload
     """
     if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) tender status'.format(self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     tender = self.request.validated['tender']
     contract = self.request.validated['contract']
     if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.awards if a.id == contract.awardID]]):
         self.request.errors.add('body', 'data', 'Can add document only in active lot status')
         self.request.errors.status = 403
         return
     if contract.status not in ['pending', 'active']:
         self.request.errors.add('body', 'data', 'Can\'t add document in current contract status')
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.context.documents.append(document)
     if save_tender(self.request):
         self.LOGGER.info('Created tender contract document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_document_create'}, {'document_id': document.id}))
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={})
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Post a complaint for award
     """
     tender = self.request.validated['tender']
     if tender.status != 'active':
         self.request.errors.add('body', 'data', 'Can\'t add complaint in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     if self.context.complaintPeriod and \
        (self.context.complaintPeriod.startDate and self.context.complaintPeriod.startDate > get_now() or
             self.context.complaintPeriod.endDate and self.context.complaintPeriod.endDate < get_now()):
         self.request.errors.add('body', 'data', 'Can add complaint only in complaintPeriod')
         self.request.errors.status = 403
         return
     complaint = self.request.validated['complaint']
     complaint.type = 'complaint'
     if complaint.status == 'pending':
         complaint.dateSubmitted = get_now()
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(tender.tenderID, self.server_id, sum([len(i.complaints) for i in tender.awards], 1))
     set_ownership(complaint, self.request)
     self.context.complaints.append(complaint)
     if save_tender(self.request):
         self.LOGGER.info('Created tender award complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_complaint_create'}, {'complaint_id': complaint.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Tender negotiation Award Complaints', tender_id=tender.id, award_id=self.request.validated['award_id'], complaint_id=complaint['id'])
         return {
             'data': complaint.serialize("view"),
             'access': {
                 'token': complaint.owner_token
             }
         }
 def patch(self):
     """Post a complaint resolution
     """
     tender = self.request.validated['tender']
     if tender.status not in ['active.enquiries', 'active.tendering', 'active.auction', 'active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     if self.request.context.status != 'pending':
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.request.context.status))
         self.request.errors.status = 403
         return
     if self.request.validated['data'].get('status', self.request.context.status) == 'cancelled':
         self.request.errors.add('body', 'data', 'Can\'t cancel complaint')
         self.request.errors.status = 403
         return
     apply_patch(self.request, save=False, src=self.request.context.serialize())
     if self.request.context.status == 'resolved' and tender.status != 'active.enquiries':
         for i in tender.complaints:
             if i.status == 'pending':
                 i.status = 'cancelled'
         [setattr(i, 'status', 'cancelled') for i in tender.lots]
         tender.status = 'cancelled'
     elif self.request.context.status in ['declined', 'invalid'] and tender.status == 'active.awarded':
         check_tender_status(self.request)
     if save_tender(self.request):
         LOGGER.info('Updated tender complaint {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'}))
         return {'data': self.request.context.serialize("view")}
 def put(self):
     """Auction Award Complaint Document Update"""
     if self.request.authenticated_role != self.context.author:
         self.request.errors.add('url', 'role', 'Can update document only author')
         self.request.errors.status = 403
         return
     if self.request.validated['auction_status'] not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) auction status'.format(self.request.validated['auction_status']))
         self.request.errors.status = 403
         return
     if any([i.status != 'active' for i in self.request.validated['auction'].lots if i.id == self.request.validated['award'].lotID]):
         self.request.errors.add('body', 'data', 'Can update document only in active lot status')
         self.request.errors.status = 403
         return
     if self.request.validated['complaint'].status not in STATUS4ROLE.get(self.request.authenticated_role, []):
         self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) complaint status'.format(self.request.validated['complaint'].status))
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     document.author = self.request.authenticated_role
     self.request.validated['complaint'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction award complaint document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_complaint_document_put'}))
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Post a cancellation
     """
     auction = self.request.validated['auction']
     if auction.status in ['complete', 'cancelled', 'unsuccessful']:
         self.request.errors.add('body', 'data', 'Can\'t add cancellation in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     cancellation = self.request.validated['cancellation']
     cancellation.date = get_now()
     if any([i.status != 'active' for i in auction.lots if i.id == cancellation.relatedLot]):
         self.request.errors.add('body', 'data', 'Can add cancellation only in active lot status')
         self.request.errors.status = 403
         return
     if cancellation.relatedLot and cancellation.status == 'active':
         self.cancel_lot(cancellation)
     elif cancellation.status == 'active':
         self.cancel_auction()
     auction.cancellations.append(cancellation)
     if save_auction(self.request):
         self.LOGGER.info('Created auction cancellation {}'.format(cancellation.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_cancellation_create'}, {'cancellation_id': cancellation.id}))
         self.request.response.status = 201
         route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=route, cancellation_id=cancellation.id, _query={})
         return {'data': cancellation.serialize("view")}
 def patch(self):
     """Contract Document Update"""
     if apply_patch(self.request, src=self.request.context.serialize()):
         update_file_content_type(self.request)
         self.LOGGER.info('Updated contract document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_patch'}))
         return {'data': self.request.context.serialize("view")}
 def patch(self):
     """Post a complaint resolution for award
     """
     tender = self.request.validated['tender']
     if tender.status != 'active':
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status))
         self.request.errors.status = 403
         return
     if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied']:
         self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.context.status))
         self.request.errors.status = 403
         return
     data = self.request.validated['data']
     complaintPeriod = self.request.validated['award'].complaintPeriod
     is_complaintPeriod = complaintPeriod.startDate < get_now() and complaintPeriod.endDate > get_now() if complaintPeriod.endDate else complaintPeriod.startDate < get_now()
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered', 'pending', 'accepted'] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get('status', self.context.status) == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateSubmitted = get_now()
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['pending', 'accepted']:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('tendererAction', self.context.tendererAction) and data.get('status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'invalid':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'accepted':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['declined', 'satisfied']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     else:
         self.request.errors.add('body', 'data', 'Can\'t update complaint')
         self.request.errors.status = 403
         return
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied'] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info('Updated tender award complaint {}'.format(self.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_complaint_patch'}))
         return {'data': self.context.serialize("view")}
 def put(self):
     """Tender Bid Document Update"""
     if self.request.validated['tender_status'] not in ['active.tendering', 'active.qualification']:
         self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) tender status'.format(self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     tender = self.request.validated['tender']
     if self.request.validated['tender_status'] == 'active.tendering' and (tender.tenderPeriod.startDate and get_now() < tender.tenderPeriod.startDate or get_now() > tender.tenderPeriod.endDate):
         self.request.errors.add('body', 'data', 'Document can be updated only during the tendering period: from ({}) to ({}).'.format(tender.tenderPeriod.startDate and tender.tenderPeriod.startDate.isoformat(), tender.tenderPeriod.endDate.isoformat()))
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] == 'active.qualification' and not [i for i in self.request.validated['tender'].awards if i.status == 'pending' and i.bid_id == self.request.validated['bid_id']]:
         self.request.errors.add('body', 'data', 'Can\'t update document because award of bid is not in pending state')
         self.request.errors.status = 403
         return
     bid = getattr(self.context, "__parent__")
     if bid and bid.status in ['invalid', 'unsuccessful', 'deleted']:
         self.request.errors.add('body', 'data', 'Can\'t update document in \'{}\' bid'.format(bid.status))
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     getattr(self.request.validated['bid'], self.container).append(document)
     if self.request.validated['tender_status'] == 'active.tendering':
         self.request.validated['tender'].modified = False
     if save_tender(self.request):
         self.LOGGER.info('Updated tender bid document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_document_put'}))
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Tender Bid Document Upload
     """
     if self.request.validated['tender_status'] not in ['active.tendering', 'active.qualification']:
         self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) tender status'.format(self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] == 'active.qualification' and not [i for i in self.request.validated['tender'].awards if i.status == 'pending' and i.bid_id == self.request.validated['bid_id']]:
         self.request.errors.add('body', 'data', 'Can\'t add document because award of bid is not in pending state')
         self.request.errors.status = 403
         return
     if self.context.status in ['invalid', 'unsuccessful', 'deleted']:
         self.request.errors.add('body', 'data', 'Can\'t add document to \'{}\' bid'.format(self.context.status))
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     getattr(self.context, self.container).append(document)
     if self.request.validated['tender_status'] == 'active.tendering':
         self.request.validated['tender'].modified = False
     if save_tender(self.request):
         self.LOGGER.info('Created tender bid document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_bid_document_create'}, {'document_id': document.id}))
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={})
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Auction Award Complaint Document Upload
     """
     if self.request.validated['auction_status'] not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) auction status'.format(self.request.validated['auction_status']))
         self.request.errors.status = 403
         return
     if any([i.status != 'active' for i in self.request.validated['auction'].lots if i.id == self.request.validated['award'].lotID]):
         self.request.errors.add('body', 'data', 'Can add document only in active lot status')
         self.request.errors.status = 403
         return
     if self.context.status not in STATUS4ROLE.get(self.request.authenticated_role, []):
         self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) complaint status'.format(self.context.status))
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     document.author = self.request.authenticated_role
     self.context.documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Created auction award complaint document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_complaint_document_create'}, {'document_id': document.id}))
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={})
         return {'data': document.serialize("view")}
 def patch(self):
     """Patch the complaint
     """
     tender = self.request.validated['tender']
     data = self.request.validated['data']
     is_qualificationPeriod = tender.qualificationPeriod.startDate < get_now(
     ) and (not tender.qualificationPeriod.endDate
            or tender.qualificationPeriod.endDate > get_now())
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'draft', 'claim', 'answered'
     ] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'pending', 'accepted'
     ] and data.get('status', self.context.status) == 'stopping':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_qualificationPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and is_qualificationPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'claim':
         if self.request.validated[
                 'qualification'].status == 'unsuccessful' and self.request.validated[
                     'qualification'].bidID != self.context.bid_id:
             raise_operation_error(
                 self.request,
                 'Can add claim only on unsuccessful qualification of your bid'
             )
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_qualificationPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in [
             'pending', 'accepted'
     ]:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in [
             'claim', 'satisfied'
     ] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'resolution', self.context.resolution) and data.get(
                 'resolutionType',
                 self.context.resolutionType) and data.get(
                     'status', self.context.status) == 'answered':
         if len(data.get('resolution', self.context.resolution)) < 20:
             raise_operation_error(
                 self.request,
                 'Can\'t update complaint: resolution too short')
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get(
             'tendererAction', self.context.tendererAction) and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'accepted', 'stopping'
     ] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'stopping'
     ] and data.get('status',
                    self.context.status) in ['invalid', 'mistaken']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get(
             'status', self.context.status) == 'accepted':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'accepted', 'stopping'
     ] and data.get('status', self.context.status) == 'declined':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get(
             'status', self.context.status) == 'satisfied':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         tender.status = 'active.pre-qualification'
         if tender.qualificationPeriod.endDate:
             tender.qualificationPeriod.endDate = None
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'accepted', 'stopping'
     ] and data.get('status', self.context.status) == 'stopped':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.dateCanceled = self.context.dateCanceled or get_now()
     else:
         raise_operation_error(self.request, 'Can\'t update complaint')
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if save_tender(self.request):
         self.LOGGER.info(
             'Updated tender qualification complaint {}'.format(
                 self.context.id),
             extra=context_unpack(
                 self.request,
                 {'MESSAGE_ID': 'tender_qualification_complaint_patch'}))
         return {'data': self.context.serialize("view")}
示例#32
0
    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_with_working_days(
                    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":
            # invalidate bids on tender change
            tender.invalidate_bids_data()
        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)}
 def collection_post(self):
     """Tender Bid Document Upload
     """
     if self.request.validated['tender_status'] not in [
             'active.tendering', 'active.qualification'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t add document in current ({}) tender status'.format(
                 self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     tender = self.request.validated['tender']
     if self.request.validated['tender_status'] == 'active.tendering' and (
             tender.tenderPeriod.startDate
             and get_now() < tender.tenderPeriod.startDate
             or get_now() > tender.tenderPeriod.endDate):
         self.request.errors.add(
             'body', 'data',
             'Document can be added only during the tendering period: from ({}) to ({}).'
             .format(
                 tender.tenderPeriod.startDate
                 and tender.tenderPeriod.startDate.isoformat(),
                 tender.tenderPeriod.endDate.isoformat()))
         self.request.errors.status = 403
         return
     if self.request.validated[
             'tender_status'] == 'active.qualification' and not [
                 i for i in self.request.validated['tender'].awards
                 if i.status == 'pending'
                 and i.bid_id == self.request.validated['bid_id']
             ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t add document because award of bid is not in pending state'
         )
         self.request.errors.status = 403
         return
     if self.context.status in ['invalid', 'unsuccessful', 'deleted']:
         self.request.errors.add(
             'body', 'data', 'Can\'t add document to \'{}\' bid'.format(
                 self.context.status))
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     getattr(self.context, self.container).append(document)
     if self.request.validated['tender_status'] == 'active.tendering':
         self.request.validated['tender'].modified = False
     if save_tender(self.request):
         self.LOGGER.info(
             'Created tender bid document {}'.format(document.id),
             extra=context_unpack(
                 self.request, {'MESSAGE_ID': 'tender_bid_document_create'},
                 {'document_id': document.id}))
         self.request.response.status = 201
         document_route = self.request.matched_route.name.replace(
             "collection_", "")
         self.request.response.headers[
             'Location'] = self.request.current_route_url(
                 _route_name=document_route,
                 document_id=document.id,
                 _query={})
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Post a complaint
     """
     tender = self.request.validated['tender']
     if tender.status not in ['active.pre-qualification.stand-still']:
         self.request.errors.add(
             'body', 'data',
             'Can\'t add complaint in current ({}) tender status'.format(
                 tender.status))
         self.request.errors.status = 403
         return
     if any([
             i.status != 'active' for i in tender.lots
             if i.id == self.context.lotID
     ]):
         self.request.errors.add(
             'body', 'data', 'Can add complaint only in active lot status')
         self.request.errors.status = 403
         return
     if tender.qualificationPeriod and \
        (tender.qualificationPeriod.startDate and tender.qualificationPeriod.startDate > get_now() or
             tender.qualificationPeriod.endDate and tender.qualificationPeriod.endDate < get_now()):
         self.request.errors.add(
             'body', 'data',
             'Can add complaint only in qualificationPeriod')
         self.request.errors.status = 403
         return
     complaint = self.request.validated['complaint']
     complaint.relatedLot = self.context.lotID
     complaint.date = get_now()
     if complaint.status == 'claim':
         complaint.dateSubmitted = get_now()
     elif complaint.status == 'pending':
         complaint.type = 'complaint'
         complaint.dateSubmitted = get_now()
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(
         tender.tenderID, self.server_id,
         self.complaints_len(tender) + 1)
     set_ownership(complaint, self.request)
     self.context.complaints.append(complaint)
     if save_tender(self.request):
         self.LOGGER.info(
             'Created tender qualification complaint {}'.format(
                 complaint.id),
             extra=context_unpack(
                 self.request,
                 {'MESSAGE_ID': 'tender_qualification_complaint_create'},
                 {'complaint_id': complaint.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url(
             'Tender EU Qualification Complaints',
             tender_id=tender.id,
             qualification_id=self.request.validated['qualification_id'],
             complaint_id=complaint['id'])
         return {
             'data': complaint.serialize("view"),
             'access': {
                 'token': complaint.owner_token
             }
         }
示例#35
0
    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
        config = getAdapter(tender, IContentConfigurator)
        data = self.request.validated['data']
        now = get_now()
        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(now, tender, True)
                tender.qualificationPeriod.endDate = calculate_business_date(
                    normalized_date, config.qualification_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'
                )
        elif self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.qualification' and \
                tender.status == "active.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 a in self.request.validated['tender']['awards']
                    for i in a['complaints'] if a['lotID'] in active_lots]):
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.qualification.stand-still\' before resolve all complaints'
                )
            if all_awards_are_reviewed(self.request):
                normalized_date = calculate_normalized_date(now, tender, True)
                tender.awardPeriod.endDate = calculate_business_date(
                    normalized_date, config.qualification_complaint_stand_still, self.request.validated['tender']
                )
                for award in [a for a in tender.awards if a.status != 'cancelled']:
                    award['complaintPeriod'] = {
                        'startDate': now.isoformat(),
                        'endDate': tender.awardPeriod.endDate.isoformat()
                    }
            else:
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.qualification.stand-still\' while not all awards 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)}
示例#36
0
    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
        if self.request.authenticated_role != 'Administrator' and tender.status in [
                'complete', 'unsuccessful', 'cancelled'
        ]:
            self.request.errors.add(
                'body', 'data',
                'Can\'t update tender in current ({}) status'.format(
                    tender.status))
            self.request.errors.status = 403
            return
        data = self.request.validated['data']
        if self.request.authenticated_role == 'tender_owner' and 'status' in data and data[
                'status'] not in [
                    'active.pre-qualification.stand-still', tender.status
                ]:
            self.request.errors.add('body', 'data',
                                    'Can\'t update tender status')
            self.request.errors.status = 403
            return

        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'])
                if calculate_business_date(
                        get_now(), TENDERING_EXTRA_PERIOD
                ) > self.request.validated['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
                self.request.validated['tender'].initialize()
                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":
            if all_bids_are_reviewed(self.request):
                tender.qualificationPeriod.endDate = calculate_business_date(
                    get_now(), COMPLAINT_STAND_STILL)
            else:
                self.request.errors.add(
                    'body', 'data',
                    'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified'
                    .format(TENDERING_EXTRA_PERIOD))
                self.request.errors.status = 403
                return

        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)}
示例#37
0
def check_status(request):
    tender = request.validated["tender"]
    now = get_now()

    for complaint in tender.complaints:
        check_complaint_status(request, complaint, now)
    for award in tender.awards:
        if award.status == "active" and not any([i.awardID == award.id for i in tender.contracts]):
            add_contract(request, award, now)
            add_next_award(request)
        for complaint in award.complaints:
            check_complaint_status(request, complaint, now)
    if (
        tender.status == "active.enquiries"
        and not tender.tenderPeriod.startDate
        and tender.enquiryPeriod.endDate.astimezone(TZ) <= now
    ):
        LOGGER.info(
            "Switched tender {} to {}".format(tender.id, "active.tendering"),
            extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.tendering"}),
        )
        tender.status = "active.tendering"
        return
    elif (
        tender.status == "active.enquiries"
        and tender.tenderPeriod.startDate
        and tender.tenderPeriod.startDate.astimezone(TZ) <= now
    ):
        LOGGER.info(
            "Switched tender {} to {}".format(tender.id, "active.tendering"),
            extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.tendering"}),
        )
        tender.status = "active.tendering"
        return
    elif not tender.lots and tender.status == "active.tendering" and tender.tenderPeriod.endDate <= now:
        LOGGER.info(
            "Switched tender {} to {}".format(tender["id"], "active.auction"),
            extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.auction"}),
        )
        tender.status = "active.auction"
        remove_draft_bids(request)
        check_bids(request)
        if tender.numberOfBids < 2 and tender.auctionPeriod:
            tender.auctionPeriod.startDate = None
        return
    elif (
            tender.lots
            and tender.status == "active.tendering"
            and tender.tenderPeriod.endDate <= now
    ):
        LOGGER.info(
            "Switched tender {} to {}".format(tender["id"], "active.auction"),
            extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.auction"}),
        )
        tender.status = "active.auction"
        remove_draft_bids(request)
        check_bids(request)
        [setattr(i.auctionPeriod, "startDate", None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod]
        return
    elif not tender.lots and tender.status == "active.awarded":
        standStillEnds = [a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate]
        if not standStillEnds:
            return
        standStillEnd = max(standStillEnds)
        if standStillEnd <= now:
            check_tender_status(request)
    elif tender.lots and tender.status in ["active.qualification", "active.awarded"]:
        if any([i["status"] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]):
            return
        for lot in tender.lots:
            if lot["status"] != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            standStillEnds = [a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate]
            if not standStillEnds:
                continue
            standStillEnd = max(standStillEnds)
            if standStillEnd <= now:
                check_tender_status(request)
                return
示例#38
0
    def patch(self):
        """Auction Edit (partial)

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

        .. sourcecode:: http

            PATCH /auctions/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",
                    "auctionID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:12:34.956Z",
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        """
        auction = self.context
        if self.request.authenticated_role != 'Administrator' and auction.status in [
                'complete', 'unsuccessful', 'cancelled'
        ]:
            self.request.errors.add(
                'body', 'data',
                'Can\'t update auction in current ({}) status'.format(
                    auction.status))
            self.request.errors.status = 403
            return
        if self.request.authenticated_role == 'chronograph':
            apply_patch(self.request,
                        save=False,
                        src=self.request.validated['auction_src'])
            check_status(self.request)
            save_auction(self.request)
        else:
            apply_patch(self.request,
                        src=self.request.validated['auction_src'])
        self.LOGGER.info('Updated auction {}'.format(auction.id),
                         extra=context_unpack(self.request,
                                              {'MESSAGE_ID': 'auction_patch'}))
        return {'data': auction.serialize(auction.status)}
示例#39
0
    return dict([(i, j) for i, j in asset.serialize(asset.status).items() if i in fields])


def save_asset(request):
    asset = request.validated['asset']
    if asset.mode == u'test':
        set_modetest_titles(asset)
    patch = get_revision_changes(asset.serialize("plain"), request.validated['asset_src'])
    if patch:
        revision = prepare_revision(asset, patch, request.authenticated_userid)
        asset.revisions.append(type(asset).revisions.model_class(revision))
        old_dateModified = asset.dateModified
        if getattr(asset, 'modified', True):
            asset.dateModified = get_now()
        try:
            asset.store(request.registry.db)
        except ModelValidationError, e:
            for i in e.message:
                request.errors.add('body', i, e.message[i])
            request.errors.status = 422
        except ResourceConflict, e:  # pragma: no cover
            request.errors.add('body', 'data', str(e))
            request.errors.status = 409
        except Exception, e:  # pragma: no cover
            request.errors.add('body', 'data', str(e))
        else:
            LOGGER.info('Saved asset {}: dateModified {} -> {}'.format(asset.id, old_dateModified and old_dateModified.isoformat(), asset.dateModified.isoformat()),
                        extra=context_unpack(request, {'MESSAGE_ID': 'save_asset'}, {'RESULT': asset.rev}))
            return True

示例#40
0
def check_status(request):
    auction = request.validated['auction']
    now = get_now()
    for complaint in auction.complaints:
        check_complaint_status(request, complaint, now)
    for award in auction.awards:
        for complaint in award.complaints:
            check_complaint_status(request, complaint, now)
    if not auction.lots and auction.status == 'active.tendering' and auction.tenderPeriod.endDate <= now:
        LOGGER.info('Switched auction {} to {}'.format(auction['id'],
                                                       'active.auction'),
                    extra=context_unpack(
                        request,
                        {'MESSAGE_ID': 'switched_auction_active.auction'}))
        auction.status = 'active.auction'
        remove_draft_bids(request)
        remove_invalid_bids(request)
        check_bids(request)
        return
    elif auction.lots and auction.status == 'active.tendering' and auction.tenderPeriod.endDate <= now:
        LOGGER.info('Switched auction {} to {}'.format(auction['id'],
                                                       'active.auction'),
                    extra=context_unpack(
                        request,
                        {'MESSAGE_ID': 'switched_auction_active.auction'}))
        auction.status = 'active.auction'
        remove_draft_bids(request)
        remove_invalid_bids(request)
        check_bids(request)
        [
            setattr(i.auctionPeriod, 'startDate', None) for i in auction.lots
            if i.numberOfBids < 2 and i.auctionPeriod
        ]
        return
    elif not auction.lots and auction.status == 'active.awarded':
        standStillEnds = [
            a.complaintPeriod.endDate.astimezone(TZ) for a in auction.awards
            if a.complaintPeriod.endDate
        ]
        if not standStillEnds:
            return
        standStillEnd = max(standStillEnds)
        if standStillEnd <= now:
            check_auction_status(request)
    elif auction.lots and auction.status in [
            'active.qualification', 'active.awarded'
    ]:
        if any([
                i['status'] in auction.block_complaint_status
                and i.relatedLot is None for i in auction.complaints
        ]):
            return
        for lot in auction.lots:
            if lot['status'] != 'active':
                continue
            lot_awards = [i for i in auction.awards if i.lotID == lot.id]
            standStillEnds = [
                a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards
                if a.complaintPeriod.endDate
            ]
            if not standStillEnds:
                continue
            standStillEnd = max(standStillEnds)
            if standStillEnd <= now:
                check_auction_status(request)
                return
def check_status(request):
    tender = request.validated['tender']
    now = get_now()
    active_lots = [lot.id for lot in tender.lots
                   if lot.status == 'active'] if tender.lots else [None]
    configurator = request.content_configurator
    for award in tender.awards:
        if award.status == 'active' and not any(
            [i.awardID == award.id for i in tender.contracts]):
            tender.contracts.append(
                type(tender).contracts.model_class({
                    'awardID':
                    award.id,
                    'suppliers':
                    award.suppliers,
                    'value':
                    award.value,
                    'date':
                    now,
                    'items':
                    [i for i in tender.items if i.relatedLot == award.lotID],
                    'contractID':
                    '{}-{}{}'.format(tender.tenderID,
                                     request.registry.server_id,
                                     len(tender.contracts) + 1)
                }))
            add_next_award(
                request,
                reverse=configurator.reverse_awarding_criteria,
                awarding_criteria_key=configurator.awarding_criteria_key)

    if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \
            not has_unanswered_complaints(tender) and not has_unanswered_questions(tender):
        for complaint in tender.complaints:
            check_complaint_status(request, complaint)
        LOGGER.info(
            'Switched tender {} to {}'.format(tender['id'],
                                              'active.pre-qualification'),
            extra=context_unpack(
                request,
                {'MESSAGE_ID': 'switched_tender_active.pre-qualification'}))
        tender.status = 'active.pre-qualification'
        tender.qualificationPeriod = type(tender).qualificationPeriod(
            {'startDate': now})
        remove_draft_bids(request)
        check_initial_bids_count(request)
        prepare_qualifications(request)
        return

    elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any(
        [
            i.status in tender.block_complaint_status
            for q in tender.qualifications
            for i in q.complaints if q.lotID in active_lots
        ]):
        LOGGER.info('Switched tender {} to {}'.format(tender['id'],
                                                      'active.auction'),
                    extra=context_unpack(
                        request,
                        {'MESSAGE_ID': 'switched_tender_active.auction'}))
        tender.status = 'active.auction'
        check_initial_bids_count(request)
        return

    elif not tender.lots and tender.status == 'active.awarded':
        standStillEnds = [
            a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards
            if a.complaintPeriod.endDate
        ]
        if not standStillEnds:
            return
        standStillEnd = max(standStillEnds)
        if standStillEnd <= now:
            check_tender_status(request)
    elif tender.lots and tender.status in [
            'active.qualification', 'active.awarded'
    ]:
        if any([
                i['status'] in tender.block_complaint_status
                and i.relatedLot is None for i in tender.complaints
        ]):
            return
        for lot in tender.lots:
            if lot['status'] != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            standStillEnds = [
                a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards
                if a.complaintPeriod.endDate
            ]
            if not standStillEnds:
                continue
            standStillEnd = max(standStillEnds)
            if standStillEnd <= now:
                check_tender_status(request)
                return
 def patch(self):
     """Post a complaint resolution
     """
     tender = self.request.validated["tender"]
     data = self.request.validated["data"]
     # complaint_owner
     if (
         self.request.authenticated_role == "complaint_owner"
         and self.context.status in ["draft", "claim", "answered"]
         and data.get("status", self.context.status) == "cancelled"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif (
         self.request.authenticated_role == "complaint_owner"
         and self.context.status in ["pending", "accepted"]
         and data.get("status", self.context.status) == "stopping"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif (
         self.request.authenticated_role == "complaint_owner"
         and tender.status == "active.tendering"
         and self.context.status == "draft"
         and data.get("status", self.context.status) == self.context.status
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "complaint_owner"
         and tender.status == "active.tendering"
         and self.context.status == "draft"
         and data.get("status", self.context.status) == "claim"
     ):
         validate_submit_claim_time(self.request)
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif (
         self.request.authenticated_role == "complaint_owner"
         and tender.status == "active.tendering"
         and self.context.status in ["draft", "claim"]
         and data.get("status", self.context.status) == "pending"
     ):
         validate_submit_complaint_time(self.request)
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = "complaint"
         self.context.dateSubmitted = get_now()
     elif (
         self.request.authenticated_role == "complaint_owner"
         and self.context.status == "answered"
         and data.get("status", self.context.status) == self.context.status
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "complaint_owner"
         and self.context.status == "answered"
         and data.get("satisfied", self.context.satisfied) is True
         and data.get("status", self.context.status) == "resolved"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "complaint_owner"
         and self.context.status == "answered"
         and data.get("satisfied", self.context.satisfied) is False
         and data.get("status", self.context.status) == "pending"
     ):
         validate_submit_complaint_time(self.request)
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = "complaint"
         self.context.dateEscalated = get_now()
     # tender_owner
     elif (
         self.request.authenticated_role == "tender_owner"
         and self.context.status == "claim"
         and data.get("status", self.context.status) == self.context.status
     ):
         validate_update_claim_time(self.request)
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "tender_owner"
         and self.context.status == "satisfied"
         and data.get("status", self.context.status) == self.context.status
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "tender_owner"
         and self.context.status == "claim"
         and data.get("resolution", self.context.resolution)
         and data.get("resolutionType", self.context.resolutionType)
         and data.get("status", self.context.status) == "answered"
     ):
         validate_update_claim_time(self.request)
         if len(data.get("resolution", self.context.resolution)) < 20:
             raise_operation_error(self.request, "Can't update complaint: resolution too short")
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == "tender_owner" and self.context.status in ["pending", "accepted"]:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "tender_owner"
         and self.context.status == "satisfied"
         and data.get("tendererAction", self.context.tendererAction)
         and data.get("status", self.context.status) == "resolved"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif (
         self.request.authenticated_role == "aboveThresholdReviewers"
         and self.context.status in ["pending", "accepted", "stopping"]
         and data.get("status", self.context.status) == self.context.status
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif (
         self.request.authenticated_role == "aboveThresholdReviewers"
         and self.context.status in ["pending", "stopping"]
         and data.get("status", self.context.status) in ["invalid", "mistaken"]
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif (
         self.request.authenticated_role == "aboveThresholdReviewers"
         and self.context.status == "pending"
         and data.get("status", self.context.status) == "accepted"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif (
         self.request.authenticated_role == "aboveThresholdReviewers"
         and self.context.status in ["accepted", "stopping"]
         and data.get("status", self.context.status) in ["declined", "satisfied"]
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     elif (
         self.request.authenticated_role == "aboveThresholdReviewers"
         and self.context.status in ["pending", "accepted", "stopping"]
         and data.get("status", self.context.status) == "stopped"
     ):
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.dateCanceled = self.context.dateCanceled or get_now()
     else:
         raise_operation_error(self.request, "Can't update complaint")
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in [
         "draft",
         "claim",
         "answered",
         "pending",
         "accepted",
         "satisfied",
         "stopping",
     ] and tender.status in ["active.qualification", "active.awarded"]:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info(
             "Updated tender complaint {}".format(self.context.id),
             extra=context_unpack(self.request, {"MESSAGE_ID": "tender_complaint_patch"}),
         )
         return {"data": self.context.serialize("view")}
示例#43
0
def check_status(request):
    tender = request.validated['tender']
    now = get_now()

    if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \
        not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \
        not any([i.id for i in tender.questions if not i.answer]):
        for complaint in tender.complaints:
            check_complaint_status(request, complaint)
        LOGGER.info(
            'Switched tender {} to {}'.format(tender['id'],
                                              'active.pre-qualification'),
            extra=context_unpack(
                request,
                {'MESSAGE_ID': 'switched_tender_active.pre-qualification'}))
        tender.status = 'active.pre-qualification'
        tender.qualificationPeriod = type(tender).qualificationPeriod(
            {'startDate': now})
        check_initial_bids_count(request)
        prepare_qualifications(request)
        return

    elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any(
        [
            i.status in BLOCK_COMPLAINT_STATUS for q in tender.qualifications
            for i in q.complaints
        ]):
        LOGGER.info('Switched tender {} to {}'.format(tender['id'],
                                                      'active.auction'),
                    extra=context_unpack(
                        request,
                        {'MESSAGE_ID': 'switched_tender_active.auction'}))
        tender.status = 'active.auction'
        check_initial_bids_count(request)
        return

    elif not tender.lots and tender.status == 'active.awarded':
        standStillEnds = [
            a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards
            if a.complaintPeriod.endDate
        ]
        if not standStillEnds:
            return
        standStillEnd = max(standStillEnds)
        if standStillEnd <= now:
            pending_complaints = any([
                i['status'] in ['claim', 'answered', 'pending']
                for i in tender.complaints
            ])
            pending_awards_complaints = any([
                i['status'] in ['claim', 'answered', 'pending']
                for a in tender.awards for i in a.complaints
            ])
            awarded = any([i['status'] == 'active' for i in tender.awards])
            if not pending_complaints and not pending_awards_complaints and not awarded:
                LOGGER.info(
                    'Switched tender {} to {}'.format(tender.id,
                                                      'unsuccessful'),
                    extra=context_unpack(
                        request,
                        {'MESSAGE_ID': 'switched_tender_unsuccessful'}))
                check_tender_status(request)
                return
    elif tender.lots and tender.status in [
            'active.qualification', 'active.awarded'
    ]:
        if any([
                i['status'] in ['claim', 'answered', 'pending']
                for i in tender.complaints
        ]):
            return
        lots_ends = []
        for lot in tender.lots:
            if lot['status'] != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            standStillEnds = [
                a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards
                if a.complaintPeriod.endDate
            ]
            if not standStillEnds:
                continue
            standStillEnd = max(standStillEnds)
            if standStillEnd <= now:
                pending_awards_complaints = any([
                    i['status'] in ['claim', 'answered', 'pending']
                    for a in lot_awards for i in a.complaints
                ])
                awarded = any([i['status'] == 'active' for i in lot_awards])
                if not pending_awards_complaints and not awarded:
                    LOGGER.info(
                        'Switched lot {} of tender {} to {}'.format(
                            lot['id'], tender.id, 'unsuccessful'),
                        extra=context_unpack(
                            request,
                            {'MESSAGE_ID': 'switched_lot_unsuccessful'},
                            {'LOT_ID': lot['id']}))
                    check_tender_status(request)
示例#44
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())
        configurator = self.request.content_configurator

        now = get_now()

        if award_status != award.status and award.status == "unsuccessful":
            if award.complaintPeriod:
                award.complaintPeriod.startDate = now
            else:
                award.complaintPeriod = {"startDate": now.isoformat()}
        if (tender.status == "active.qualification.stand-still"
                and award_status == "active" and award.status == "cancelled"):
            for aw in tender.awards:
                if aw.lotID == award.lotID:
                    aw.status = "cancelled"
            add_next_awards(
                self.request,
                reverse=configurator.reverse_awarding_criteria,
                awarding_criteria_key=configurator.awarding_criteria_key,
                regenerate_all_awards=True,
                lot_id=award.lotID,
            )
            self.context.dateDecision = now
            tender.status = "active.qualification"
            if tender.awardPeriod.endDate:
                tender.awardPeriod.endDate = None
        else:
            if award_status == "pending" and award.status == "unsuccessful":
                add_next_awards(
                    self.request,
                    reverse=configurator.reverse_awarding_criteria,
                    awarding_criteria_key=configurator.awarding_criteria_key,
                )
            elif award_status == "pending" and award.status == "active":
                pass
            elif award_status == "active" and award.status == "cancelled":
                add_next_awards(
                    self.request,
                    reverse=configurator.reverse_awarding_criteria,
                    awarding_criteria_key=configurator.awarding_criteria_key,
                    lot_id=award.lotID,
                )
            elif award_status == "unsuccessful" and award.status == "cancelled":
                for aw in tender.awards:
                    if aw.lotID == award.lotID:
                        aw.status = "cancelled"
                add_next_awards(
                    self.request,
                    reverse=configurator.reverse_awarding_criteria,
                    awarding_criteria_key=configurator.awarding_criteria_key,
                    regenerate_all_awards=True,
                    lot_id=award.lotID,
                )
            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")}
示例#45
0
def check_tender_status(request):
    tender = request.validated["tender"]
    now = get_now()
    if tender.lots:
        if any([i.status in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]):
            return
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if not lot_awards:
                continue
            last_award = lot_awards[-1]
            pending_complaints = any(
                [i["status"] in tender.block_complaint_status and i.relatedLot == lot.id for i in tender.complaints]
            )
            pending_awards_complaints = any(
                [i.status in tender.block_complaint_status for a in lot_awards for i in a.complaints]
            )
            stand_still_end = max([a.complaintPeriod.endDate or now for a in lot_awards])
            if pending_complaints or pending_awards_complaints or not stand_still_end <= now:
                continue
            elif last_award.status == "unsuccessful":
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(lot.id, tender.id, "unsuccessful"),
                    extra=context_unpack(request, {"MESSAGE_ID": "switched_lot_unsuccessful"}, {"LOT_ID": lot.id}),
                )
                lot.status = "unsuccessful"
                continue
            elif last_award.status == "active" and any(
                [i.status == "active" and i.awardID == last_award.id for i in tender.contracts]
            ):
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(lot.id, tender.id, "complete"),
                    extra=context_unpack(request, {"MESSAGE_ID": "switched_lot_complete"}, {"LOT_ID": lot.id}),
                )
                lot.status = "complete"
        statuses = set([lot.status for lot in tender.lots])
        if statuses == set(["cancelled"]):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "cancelled"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_cancelled"}),
            )
            tender.status = "cancelled"
        elif not statuses.difference(set(["unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"
        elif not statuses.difference(set(["complete", "unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "complete"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_complete"}),
            )
            tender.status = "complete"
    else:
        pending_complaints = any([i.status in tender.block_complaint_status for i in tender.complaints])
        pending_awards_complaints = any(
            [i.status in tender.block_complaint_status for a in tender.awards for i in a.complaints]
        )
        stand_still_ends = [a.complaintPeriod.endDate for a in tender.awards if a.complaintPeriod.endDate]
        stand_still_end = max(stand_still_ends) if stand_still_ends else now
        stand_still_time_expired = stand_still_end < now
        last_award_status = tender.awards[-1].status if tender.awards else ""
        if (
            not pending_complaints
            and not pending_awards_complaints
            and stand_still_time_expired
            and last_award_status == "unsuccessful"
        ):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"
        if tender.contracts and tender.contracts[-1].status == "active":
            tender.status = "complete"
    if tender.procurementMethodType == "belowThreshold":
        check_ignored_claim(tender)
def check_tender_status(request):
    tender = request.validated["tender"]
    now = get_now()
    if tender.lots:
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if not lot_awards:
                continue
            last_award = lot_awards[-1]
            if last_award.status == "unsuccessful":
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(
                        lot.id, tender.id, "unsuccessful"),
                    extra=context_unpack(
                        request, {"MESSAGE_ID": "switched_lot_unsuccessful"},
                        {"LOT_ID": lot.id}),
                )
                lot.status = "unsuccessful"
                continue
            elif last_award.status == "active" and any([
                    i.status == "active" and i.awardID == last_award.id
                    for i in tender.contracts
            ]):
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(
                        lot.id, tender.id, "complete"),
                    extra=context_unpack(
                        request, {"MESSAGE_ID": "switched_lot_complete"},
                        {"LOT_ID": lot.id}),
                )
                lot.status = "complete"
        statuses = set([lot.status for lot in tender.lots])

        if statuses == set(["cancelled"]):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "cancelled"),
                extra=context_unpack(
                    request, {"MESSAGE_ID": "switched_tender_cancelled"}),
            )
            tender.status = "cancelled"
        elif not statuses.difference(set(["unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(
                    request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"
        elif not statuses.difference(
                set(["complete", "unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "complete"),
                extra=context_unpack(
                    request, {"MESSAGE_ID": "switched_tender_complete"}),
            )
            tender.status = "complete"
    else:
        last_award_status = tender.awards[-1].status if tender.awards else ""
        if last_award_status == "unsuccessful":
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(
                    request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"
        if tender.contracts and tender.contracts[-1].status == "active":
            tender.status = "complete"
示例#47
0
def patch_eu(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"):
        if all_bids_are_reviewed(self.request):
            tender.qualificationPeriod.endDate = calculate_tender_business_date(
                get_now(), 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"
            )
    elif (self.request.authenticated_role == "tender_owner" and
          self.request.validated["tender_status"] == "active.pre-qualification"
          and tender.status != "active.pre-qualification.stand-still"):
        raise_operation_error(self.request, "Can't update tender status")

    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)}
示例#48
0
    def patch(self):
        """Update of contract
        """
        if self.request.validated['auction_status'] not in [
                'active.qualification', 'active.awarded'
        ]:
            self.request.errors.add(
                'body', 'data',
                'Can\'t update contract in current ({}) auction status'.format(
                    self.request.validated['auction_status']))
            self.request.errors.status = 403
            return
        auction = self.request.validated['auction']
        if any([
                i.status != 'active' for i in auction.lots if i.id in [
                    a.lotID for a in auction.awards
                    if a.id == self.request.context.awardID
                ]
        ]):
            self.request.errors.add(
                'body', 'data',
                'Can update contract only in active lot status')
            self.request.errors.status = 403
            return
        data = self.request.validated['data']

        if data['value']:
            for ro_attr in ('valueAddedTaxIncluded', 'currency'):
                if data['value'][ro_attr] != getattr(self.context.value,
                                                     ro_attr):
                    self.request.errors.add(
                        'body', 'data',
                        'Can\'t update {} for contract value'.format(ro_attr))
                    self.request.errors.status = 403
                    return

            award = [
                a for a in auction.awards
                if a.id == self.request.context.awardID
            ][0]
            if data['value']['amount'] < award.value.amount:
                self.request.errors.add(
                    'body', 'data',
                    'Value amount should be greater or equal to awarded amount ({})'
                    .format(award.value.amount))
                self.request.errors.status = 403
                return

        if self.request.context.status != 'active' and 'status' in data and data[
                'status'] == 'active':
            award = [
                a for a in auction.awards
                if a.id == self.request.context.awardID
            ][0]
            stand_still_end = award.complaintPeriod.endDate
            if stand_still_end > get_now():
                self.request.errors.add(
                    'body', 'data',
                    'Can\'t sign contract before stand-still period end ({})'.
                    format(stand_still_end.isoformat()))
                self.request.errors.status = 403
                return
            pending_complaints = [
                i for i in auction.complaints
                if i.status in ['claim', 'answered', 'pending']
                and i.relatedLot in [None, award.lotID]
            ]
            pending_awards_complaints = [
                i for a in auction.awards for i in a.complaints
                if i.status in ['claim', 'answered', 'pending']
                and a.lotID == award.lotID
            ]
            if pending_complaints or pending_awards_complaints:
                self.request.errors.add(
                    'body', 'data',
                    'Can\'t sign contract before reviewing all complaints')
                self.request.errors.status = 403
                return
            if not self.request.context.documents:
                self.request.errors.add(
                    'body', 'data', 'Cant\'t sign contract without document')
                self.request.errors.status = 403
                return
        contract_status = self.request.context.status
        apply_patch(self.request,
                    save=False,
                    src=self.request.context.serialize())
        if contract_status != self.request.context.status and (
                contract_status != 'pending'
                or self.request.context.status != 'active'):
            self.request.errors.add('body', 'data',
                                    'Can\'t update contract status')
            self.request.errors.status = 403
            return
        if self.request.context.status == 'active' and not self.request.context.dateSigned:
            self.request.context.dateSigned = get_now()
        check_auction_status(self.request)
        if save_auction(self.request):
            self.LOGGER.info(
                'Updated auction contract {}'.format(self.request.context.id),
                extra=context_unpack(self.request,
                                     {'MESSAGE_ID': 'auction_contract_patch'}))
            return {'data': self.request.context.serialize()}
示例#49
0
    def get(self):
        """Auctions List

        Get Auctions List
        ----------------

        Example request to get auctions list:

        .. sourcecode:: http

            GET /auctions HTTP/1.1
            Host: example.com
            Accept: application/json

        This is what one should expect in response:

        .. sourcecode:: http

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

            {
                "data": [
                    {
                        "id": "64e93250be76435397e8c992ed4214d1",
                        "dateModified": "2014-10-27T08:06:58.158Z"
                    }
                ]
            }

        """
        # http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options
        params = {}
        pparams = {}
        fields = self.request.params.get('opt_fields', '')
        if fields:
            params['opt_fields'] = fields
            pparams['opt_fields'] = fields
            fields = fields.split(',')
            view_fields = fields + ['dateModified', 'id']
        limit = self.request.params.get('limit', '')
        if limit:
            params['limit'] = limit
            pparams['limit'] = limit
        limit = int(limit) if limit.isdigit() and (100 if fields else 1000) >= int(limit) > 0 else 100
        descending = bool(self.request.params.get('descending'))
        offset = self.request.params.get('offset', '')
        if descending:
            params['descending'] = 1
        else:
            pparams['descending'] = 1
        feed = self.request.params.get('feed', '')
        view_map = FEED.get(feed, VIEW_MAP)
        changes = view_map is CHANGES_VIEW_MAP
        if feed and feed in FEED:
            params['feed'] = feed
            pparams['feed'] = feed
        mode = self.request.params.get('mode', '')
        if mode and mode in view_map:
            params['mode'] = mode
            pparams['mode'] = mode
        view_limit = limit + 1 if offset else limit
        if changes:
            if offset:
                view_offset = decrypt(self.server.uuid, self.db.name, offset)
                if view_offset and view_offset.isdigit():
                    view_offset = int(view_offset)
                else:
                    self.request.errors.add('params', 'offset', 'Offset expired/invalid')
                    self.request.errors.status = 404
                    return
            if not offset:
                view_offset = 'now' if descending else 0
        else:
            if offset:
                view_offset = offset
            else:
                view_offset = '9' if descending else ''
        list_view = view_map.get(mode, view_map[u''])
        if self.update_after:
            view = partial(list_view, self.db, limit=view_limit, startkey=view_offset, descending=descending, stale='update_after')
        else:
            view = partial(list_view, self.db, limit=view_limit, startkey=view_offset, descending=descending)
        if fields:
            if not changes and set(fields).issubset(set(FIELDS)):
                results = [
                    (dict([(i, j) for i, j in x.value.items() + [('id', x.id), ('dateModified', x.key)] if i in view_fields]), x.key)
                    for x in view()
                ]
            elif changes and set(fields).issubset(set(FIELDS)):
                results = [
                    (dict([(i, j) for i, j in x.value.items() + [('id', x.id)] if i in view_fields]), x.key)
                    for x in view()
                ]
            elif fields:
                self.LOGGER.info('Used custom fields for auctions list: {}'.format(','.join(sorted(fields))),
                            extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_list_custom'}))

                results = [
                    (dict([(k, j) for k, j in i[u'doc'].items() if k in view_fields]), i.key)
                    for i in view(include_docs=True)
                ]
        else:
            results = [
                ({'id': i.id, 'dateModified': i.value['dateModified']} if changes else {'id': i.id, 'dateModified': i.key}, i.key)
                for i in view()
            ]
        if results:
            params['offset'], pparams['offset'] = results[-1][1], results[0][1]
            if offset and view_offset == results[0][1]:
                results = results[1:]
            elif offset and view_offset != results[0][1]:
                results = results[:limit]
                params['offset'], pparams['offset'] = results[-1][1], view_offset
            results = [i[0] for i in results]
            if changes:
                params['offset'] = encrypt(self.server.uuid, self.db.name, params['offset'])
                pparams['offset'] = encrypt(self.server.uuid, self.db.name, pparams['offset'])
        else:
            params['offset'] = offset
            pparams['offset'] = offset
        data = {
            'data': results,
            'next_page': {
                "offset": params['offset'],
                "path": self.request.route_path('Auctions', _query=params),
                "uri": self.request.route_url('Auctions', _query=params)
            }
        }
        if descending or offset:
            data['prev_page'] = {
                "offset": pparams['offset'],
                "path": self.request.route_path('Auctions', _query=pparams),
                "uri": self.request.route_url('Auctions', _query=pparams)
            }
        return data
示例#50
0
 def _patch_document_log(self):
     self.LOGGER.info(
         "Updated plan milestone document {}".format(self.request.context.id),
         extra=context_unpack(self.request,
                              {"MESSAGE_ID": "plan_milestone_document_patch"}),
     )
示例#51
0
    try:
        _, rev = request.registry.db.save({
            '_id': db_doc.id,
            '_rev': db_doc.rev,
            'doc_type': resource
        })
    except ResourceConflict, e:  # pragma: no cover
        request.errors.add('body', 'data', str(e))
        request.errors.status = 409
    except Exception, e:  # pragma: no cover
        request.errors.add('body', 'data', str(e))
    else:
        LOGGER.info('Deleted {} {}: dateModified {} -> None'.format(
            resource, db_doc.id, db_doc.dateModified.isoformat()),
                    extra=context_unpack(request,
                                         {'MESSAGE_ID': 'delete_resource'},
                                         {'RESULT': rev}))
        return True


def dump_resource(request):
    arch_pubkey = getattr(request.registry, 'arch_pubkey', None)
    res_secretkey = SecretKey()
    archive_box = Box(res_secretkey, arch_pubkey)
    res_pubkey = res_secretkey.pk
    del res_secretkey
    data = request.context.serialize()
    json_data = dumps(data)
    encrypted_data = archive_box.encrypt(json_data)
    return {'item': b64encode(encrypted_data), 'pubkey': b64encode(res_pubkey)}
 def patch(self):
     """Tender Bid Document Update"""
     if self.request.validated['tender_status'] not in [
             'active.tendering', 'active.qualification'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update document in current ({}) tender status'.format(
                 self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     tender = self.request.validated['tender']
     if self.request.validated['tender_status'] == 'active.tendering' and (
             tender.tenderPeriod.startDate
             and get_now() < tender.tenderPeriod.startDate
             or get_now() > tender.tenderPeriod.endDate):
         self.request.errors.add(
             'body', 'data',
             'Document can be updated only during the tendering period: from ({}) to ({}).'
             .format(
                 tender.tenderPeriod.startDate
                 and tender.tenderPeriod.startDate.isoformat(),
                 tender.tenderPeriod.endDate.isoformat()))
         self.request.errors.status = 403
         return
     if self.request.validated[
             'tender_status'] == 'active.qualification' and not [
                 i for i in self.request.validated['tender'].awards
                 if i.status == 'pending'
                 and i.bid_id == self.request.validated['bid_id']
             ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update document because award of bid is not in pending state'
         )
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] != 'active.tendering' and 'confidentiality' in self.request.validated['data'] \
             and self.context.confidentiality != self.request.validated['data']['confidentiality']:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update document confidentiality in current ({0}) tender status'
             .format(self.request.validated['tender_status']))
         self.request.errors.status = 403
         return
     bid = getattr(self.context, "__parent__")
     if bid and bid.status in ['invalid', 'unsuccessful', 'deleted']:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update document data for \'{}\' bid'.format(
                 bid.status))
         self.request.errors.status = 403
         return
     if self.request.validated['tender_status'] == 'active.tendering':
         self.request.validated['tender'].modified = False
     if apply_patch(self.request, src=self.request.context.serialize()):
         update_file_content_type(self.request)
         self.LOGGER.info('Updated tender bid document {}'.format(
             self.request.context.id),
                          extra=context_unpack(
                              self.request,
                              {'MESSAGE_ID': 'tender_bid_document_patch'}))
         return {'data': self.request.context.serialize("view")}
    def collection_post(self):
        """Registration of new bid proposal

        Creating new Bid proposal
        -------------------------

        Example request to create bid proposal:

        .. sourcecode:: http

            POST /auctions/4879d3f8ee2443169b5fbbc9f89fa607/bids HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "tenderers": [
                        {
                            "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": 489,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        This is what one should expect in response:

        .. sourcecode:: http

            HTTP/1.1 201 Created
            Content-Type: application/json

            {
                "data": {
                    "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                    "status": "registration",
                    "date": "2014-10-28T11:44:17.947Z",
                    "tenderers": [
                        {
                            "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": 489,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """
        # See https://github.com/open-contracting/standard/issues/78#issuecomment-59830415
        # for more info upon schema
        auction = self.request.validated['auction']
        if self.request.validated['auction_status'] != 'active.tendering':
            self.request.errors.add(
                'body', 'data',
                'Can\'t add bid in current ({}) auction status'.format(
                    self.request.validated['auction_status']))
            self.request.errors.status = 403
            return
        if auction.tenderPeriod.startDate and get_now(
        ) < auction.tenderPeriod.startDate or get_now(
        ) > auction.tenderPeriod.endDate:
            self.request.errors.add(
                'body', 'data',
                'Bid can be added only during the tendering period: from ({}) to ({}).'
                .format(
                    auction.tenderPeriod.startDate
                    and auction.tenderPeriod.startDate.isoformat(),
                    auction.tenderPeriod.endDate.isoformat()))
            self.request.errors.status = 403
            return
        bid = self.request.validated['bid']
        set_ownership(bid, self.request)
        auction.bids.append(bid)
        auction.modified = False
        if save_auction(self.request):
            self.LOGGER.info(
                'Created auction bid {}'.format(bid.id),
                extra=context_unpack(self.request,
                                     {'MESSAGE_ID': 'auction_bid_create'},
                                     {'bid_id': bid.id}))
            self.request.response.status = 201
            route = self.request.matched_route.name.replace("collection_", "")
            self.request.response.headers[
                'Location'] = self.request.current_route_url(_route_name=route,
                                                             bid_id=bid.id,
                                                             _query={})
            return {
                'data': bid.serialize('view'),
                'access': {
                    'token': bid.owner_token
                }
            }
示例#54
0
 def patch(self):
     """Post a complaint resolution
     """
     tender = self.request.validated['tender']
     if tender.status != 'active.tendering':
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) tender status'.format(
                 tender.status))
         self.request.errors.status = 403
         return
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending', 'accepted',
             'satisfied', 'stopping'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) status'.format(
                 self.context.status))
         self.request.errors.status = 403
         return
     data = self.request.validated['data']
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'draft', 'claim', 'answered'
     ] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'pending', 'accepted'
     ] and data.get('status', self.context.status) == 'stopping':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'claim':
         if get_now() > calculate_business_date(tender.tenderPeriod.endDate,
                                                -CLAIM_SUBMIT_TIME, tender):
             self.request.errors.add(
                 'body', 'data',
                 'Can submit claim not later than {0.days} days before tenderPeriod end'
                 .format(CLAIM_SUBMIT_TIME))
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status in [
             'draft', 'claim'
     ] and data.get('status', self.context.status) == 'pending':
         if get_now() > tender.complaintPeriod.endDate:
             self.request.errors.add(
                 'body', 'data',
                 'Can submit complaint not later than {0.days} days before tenderPeriod end'
                 .format(COMPLAINT_SUBMIT_TIME))
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is True and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is False and data.get(
                 'status', self.context.status) == 'pending':
         if get_now() > tender.complaintPeriod.endDate:
             self.request.errors.add(
                 'body', 'data',
                 'Can submit complaint not later than {0.days} days before tenderPeriod end'
                 .format(COMPLAINT_SUBMIT_TIME))
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateEscalated = get_now()
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'status', self.context.status) == self.context.status:
         now = get_now()
         if now > tender.enquiryPeriod.clarificationsUntil:
             self.request.errors.add(
                 'body', 'data',
                 'Can update claim only before enquiryPeriod.clarificationsUntil'
             )
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'resolution', self.context.resolution) and data.get(
                 'resolutionType',
                 self.context.resolutionType) and data.get(
                     'status', self.context.status) == 'answered':
         now = get_now()
         if now > tender.enquiryPeriod.clarificationsUntil:
             self.request.errors.add(
                 'body', 'data',
                 'Can update claim only before enquiryPeriod.clarificationsUntil'
             )
             self.request.errors.status = 403
             return
         if len(data.get('resolution', self.context.resolution)) < 20:
             self.request.errors.add(
                 'body', 'data',
                 'Can\'t update complaint: resolution too short')
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in [
             'pending', 'accepted'
     ]:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get(
             'tendererAction', self.context.tendererAction) and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'accepted', 'stopping'
     ] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'stopping'
     ] and data.get('status',
                    self.context.status) in ['invalid', 'mistaken']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get(
             'status', self.context.status) == 'accepted':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get(
             'status', self.context.status) in ['declined', 'satisfied']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'accepted', 'stopping'
     ] and data.get('status', self.context.status) == 'stopped':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.dateCanceled = self.context.dateCanceled or get_now()
     else:
         self.request.errors.add('body', 'data', 'Can\'t update complaint')
         self.request.errors.status = 403
         return
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending', 'accepted',
             'satisfied', 'stopping'
     ] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info(
             'Updated tender complaint {}'.format(self.context.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'tender_complaint_patch'}))
         return {'data': self.context.serialize("view")}
示例#55
0
    def post(self):
        """This API request is targeted to creating new Tenders by procuring organizations.

        Creating new Tender
        -------------------

        Example request to create tender:

        .. sourcecode:: http

            POST /tenders HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "procuringEntity": {
                        "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": 500,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    },
                    "itemsToBeProcured": [
                        {
                            "description": "футляри до державних нагород",
                            "primaryClassification": {
                                "scheme": "CPV",
                                "id": "44617100-9",
                                "description": "Cartons"
                            },
                            "additionalClassification": [
                                {
                                    "scheme": "ДКПП",
                                    "id": "17.21.1",
                                    "description": "папір і картон гофровані, паперова й картонна тара"
                                }
                            ],
                            "unitOfMeasure": "item",
                            "quantity": 5
                        }
                    ],
                    "enquiryPeriod": {
                        "endDate": "2014-10-31T00:00:00"
                    },
                    "tenderPeriod": {
                        "startDate": "2014-11-03T00:00:00",
                        "endDate": "2014-11-06T10:00:00"
                    },
                    "awardPeriod": {
                        "endDate": "2014-11-13T00:00:00"
                    },
                    "deliveryDate": {
                        "endDate": "2014-11-20T00:00:00"
                    },
                    "minimalStep": {
                        "amount": 35,
                        "currency": "UAH"
                    }
                }
            }

        This is what one should expect in response:

        .. sourcecode:: http

            HTTP/1.1 201 Created
            Location: http://localhost/api/0.1/tenders/64e93250be76435397e8c992ed4214d1
            Content-Type: application/json

            {
                "data": {
                    "id": "64e93250be76435397e8c992ed4214d1",
                    "tenderID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:06:58.158Z",
                    "procuringEntity": {
                        "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": 500,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    },
                    "itemsToBeProcured": [
                        {
                            "description": "футляри до державних нагород",
                            "primaryClassification": {
                                "scheme": "CPV",
                                "id": "44617100-9",
                                "description": "Cartons"
                            },
                            "additionalClassification": [
                                {
                                    "scheme": "ДКПП",
                                    "id": "17.21.1",
                                    "description": "папір і картон гофровані, паперова й картонна тара"
                                }
                            ],
                            "unitOfMeasure": "item",
                            "quantity": 5
                        }
                    ],
                    "enquiryPeriod": {
                        "endDate": "2014-10-31T00:00:00"
                    },
                    "tenderPeriod": {
                        "startDate": "2014-11-03T00:00:00",
                        "endDate": "2014-11-06T10:00:00"
                    },
                    "awardPeriod": {
                        "endDate": "2014-11-13T00:00:00"
                    },
                    "deliveryDate": {
                        "endDate": "2014-11-20T00:00:00"
                    },
                    "minimalStep": {
                        "amount": 35,
                        "currency": "UAH"
                    }
                }
            }

        """
        tender_id = generate_id()
        tender = self.request.validated["tender"]
        tender.id = tender_id
        if not tender.get("tenderID"):
            tender.tenderID = generate_tender_id(get_now(), self.db,
                                                 self.server_id)
        self.request.registry.notify(TenderInitializeEvent(tender))
        if self.request.json["data"].get("status") == "draft":
            tender.status = "draft"
        access = set_ownership(tender, self.request)
        self.request.validated["tender"] = tender
        self.request.validated["tender_src"] = {}
        if save_tender(self.request):
            self.LOGGER.info(
                "Created tender {} ({})".format(tender_id, tender.tenderID),
                extra=context_unpack(
                    self.request,
                    {"MESSAGE_ID": "tender_create"},
                    {
                        "tender_id": tender_id,
                        "tenderID": tender.tenderID,
                        "tender_mode": tender.mode
                    },
                ),
            )
            self.request.response.status = 201
            self.request.response.headers["Location"] = self.request.route_url(
                "{}:Tender".format(tender.procurementMethodType),
                tender_id=tender_id)
            return {"data": tender.serialize(tender.status), "access": access}
示例#56
0
    :return: True if Ok
    """
    transfer = request.validated['transfer']
    transfer.date = get_now()
    try:
        transfer.store(request.registry.db)
    except ModelValidationError, e:  # pragma: no cover
        for i in e.message:
            request.errors.add('body', i, e.message[i])
        request.errors.status = 422
    except Exception, e:  # pragma: no cover
        request.errors.add('body', 'data', str(e))
    else:
        LOGGER.info('Saved transfer {}: at {}'.format(transfer.id,
                                                      get_now().isoformat()),
                    extra=context_unpack(request,
                                         {'MESSAGE_ID': 'save_transfer'}))
        return True


def set_ownership(item, request, access_token=None, transfer_token=None):
    item.owner = request.authenticated_userid
    item.access_token = sha512(access_token).hexdigest()
    item.transfer_token = sha512(transfer_token).hexdigest()


def update_ownership(tender, transfer):
    tender.owner = transfer.owner
    tender.owner_token = transfer.access_token
    tender.transfer_token = transfer.transfer_token
 def patch(self):
     """Post a complaint resolution
     """
     auction = self.request.validated['auction']
     if auction.status not in [
             'active.tendering', 'active.auction', 'active.qualification',
             'active.awarded'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) auction status'.
             format(auction.status))
         self.request.errors.status = 403
         return
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) status'.format(
                 self.context.status))
         self.request.errors.status = 403
         return
     data = self.request.validated['data']
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'draft', 'claim', 'answered', 'pending'
     ] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and auction.status in [
             'active.tendering'
     ] and self.context.status == 'draft' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and auction.status in [
             'active.tendering'
     ] and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'claim':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is True and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is False and data.get(
                 'status', self.context.status) == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateEscalated = get_now()
     elif self.request.authenticated_role == 'auction_owner' and self.context.status == 'claim' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'auction_owner' and self.context.status == 'claim' and data.get(
             'resolution', self.context.resolution) and data.get(
                 'resolutionType',
                 self.context.resolutionType) and data.get(
                     'status', self.context.status) == 'answered':
         if len(data.get('resolution', self.context.resolution)) < 20:
             self.request.errors.add(
                 'body', 'data',
                 'Can\'t update complaint: resolution too short')
             self.request.errors.status = 403
             return
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'auction_owner' and self.context.status == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # reviewers
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get(
             'status',
             self.context.status) in ['resolved', 'invalid', 'declined']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     else:
         self.request.errors.add('body', 'data', 'Can\'t update complaint')
         self.request.errors.status = 403
         return
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending'
     ] and auction.status in ['active.qualification', 'active.awarded']:
         check_auction_status(self.request)
     if save_auction(self.request):
         self.LOGGER.info(
             'Updated auction complaint {}'.format(self.context.id),
             extra=context_unpack(
                 self.request, {'MESSAGE_ID': 'auction_complaint_patch'}))
         return {'data': self.context.serialize("view")}
    def patch(self):
        """Update of proposal

        Example request to change bid proposal:

        .. sourcecode:: http

            PATCH /auctions/4879d3f8ee2443169b5fbbc9f89fa607/bids/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": {
                    "value": {
                        "amount": 600,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """

        if self.request.authenticated_role != 'Administrator' and self.request.validated[
                'auction_status'] != 'active.tendering':
            self.request.errors.add(
                'body', 'data',
                'Can\'t update bid in current ({}) auction status'.format(
                    self.request.validated['auction_status']))
            self.request.errors.status = 403
            return
        auction = self.request.validated['auction']
        if self.request.authenticated_role != 'Administrator' and (
                auction.tenderPeriod.startDate
                and get_now() < auction.tenderPeriod.startDate
                or get_now() > auction.tenderPeriod.endDate):
            self.request.errors.add(
                'body', 'data',
                'Bid can be updated only during the tendering period: from ({}) to ({}).'
                .format(
                    auction.tenderPeriod.startDate
                    and auction.tenderPeriod.startDate.isoformat(),
                    auction.tenderPeriod.endDate.isoformat()))
            self.request.errors.status = 403
            return
        if self.request.authenticated_role != 'Administrator':
            bid_status_to = self.request.validated['data'].get("status")
            if bid_status_to != self.request.context.status and bid_status_to != "active":
                self.request.errors.add(
                    'body', 'bid',
                    'Can\'t update bid to ({}) status'.format(bid_status_to))
                self.request.errors.status = 403
                return
        value = self.request.validated['data'].get(
            "value") and self.request.validated['data']["value"].get("amount")
        if value and value != self.request.context.get("value",
                                                       {}).get("amount"):
            self.request.validated['data']['date'] = get_now().isoformat()
        if self.request.context.lotValues:
            lotValues = dict([(i.relatedLot, i.value.amount)
                              for i in self.request.context.lotValues])
            for lotvalue in self.request.validated['data'].get(
                    "lotValues", []):
                if lotvalue['relatedLot'] in lotValues and lotvalue.get(
                        "value",
                    {}).get("amount") != lotValues[lotvalue['relatedLot']]:
                    lotvalue['date'] = get_now().isoformat()
        self.request.validated['auction'].modified = False
        if apply_patch(self.request, src=self.request.context.serialize()):
            self.LOGGER.info(
                'Updated auction bid {}'.format(self.request.context.id),
                extra=context_unpack(self.request,
                                     {'MESSAGE_ID': 'auction_bid_patch'}))
            return {'data': self.request.context.serialize("view")}
 def patch(self):
     """Post a complaint resolution for award
     """
     tender = self.request.validated['tender']
     if tender.status not in ['active.qualification', 'active.awarded']:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) tender status'.format(
                 tender.status))
         self.request.errors.status = 403
         return
     if any([
             i.status != 'active' for i in tender.lots
             if i.id == self.request.validated['award'].lotID
     ]):
         self.request.errors.add(
             'body', 'data',
             'Can update complaint only in active lot status')
         self.request.errors.status = 403
         return
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending'
     ]:
         self.request.errors.add(
             'body', 'data',
             'Can\'t update complaint in current ({}) status'.format(
                 self.context.status))
         self.request.errors.status = 403
         return
     data = self.request.validated['data']
     complaintPeriod = self.request.validated['award'].complaintPeriod
     is_complaintPeriod = complaintPeriod.startDate < get_now(
     ) and complaintPeriod.endDate > get_now(
     ) if complaintPeriod.endDate else complaintPeriod.startDate < get_now(
     )
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'draft', 'claim', 'answered', 'pending'
     ] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'claim':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is True and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'satisfied', self.context.satisfied) is False and data.get(
                 'status', self.context.status) == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateEscalated = get_now()
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'resolution', self.context.resolution) and len(
                 data.get('resolution', self.context.resolution
                          or "")) >= 20 and data.get(
                              'resolutionType',
                              self.context.resolutionType) and data.get(
                                  'status',
                                  self.context.status) == 'answered':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'pending':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # reviewers
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get(
             'status',
             self.context.status) in ['resolved', 'invalid', 'declined']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     else:
         self.request.errors.add('body', 'data', 'Can\'t update complaint')
         self.request.errors.status = 403
         return
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending'
     ] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         LOGGER.info('Updated tender award complaint {}'.format(
             self.context.id),
                     extra=context_unpack(
                         self.request,
                         {'MESSAGE_ID': 'tender_award_complaint_patch'}))
         return {'data': self.context.serialize("view")}
    def post(self):
        """This API request is targeted to creating new Auctions by procuring organizations.

        Creating new Auction
        -------------------

        Example request to create auction:

        .. sourcecode:: http

            POST /auctions HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "procuringEntity": {
                        "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": 500,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    },
                    "itemsToBeProcured": [
                        {
                            "description": "футляри до державних нагород",
                            "primaryClassification": {
                                "scheme": "CAV",
                                "id": "44617100-9",
                                "description": "Cartons"
                            },
                            "additionalClassification": [
                                {
                                    "scheme": "ДКПП",
                                    "id": "17.21.1",
                                    "description": "папір і картон гофровані, паперова й картонна тара"
                                }
                            ],
                            "unitOfMeasure": "item",
                            "quantity": 5
                        }
                    ],
                    "enquiryPeriod": {
                        "endDate": "2014-10-31T00:00:00"
                    },
                    "tenderPeriod": {
                        "startDate": "2014-11-03T00:00:00",
                        "endDate": "2014-11-06T10:00:00"
                    },
                    "awardPeriod": {
                        "endDate": "2014-11-13T00:00:00"
                    },
                    "deliveryDate": {
                        "endDate": "2014-11-20T00:00:00"
                    },
                    "minimalStep": {
                        "amount": 35,
                        "currency": "UAH"
                    }
                }
            }

        This is what one should expect in response:

        .. sourcecode:: http

            HTTP/1.1 201 Created
            Location: http://localhost/api/0.1/auctions/64e93250be76435397e8c992ed4214d1
            Content-Type: application/json

            {
                "data": {
                    "id": "64e93250be76435397e8c992ed4214d1",
                    "auctionID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:06:58.158Z",
                    "procuringEntity": {
                        "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": 500,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    },
                    "itemsToBeProcured": [
                        {
                            "description": "футляри до державних нагород",
                            "primaryClassification": {
                                "scheme": "CAV",
                                "id": "44617100-9",
                                "description": "Cartons"
                            },
                            "additionalClassification": [
                                {
                                    "scheme": "ДКПП",
                                    "id": "17.21.1",
                                    "description": "папір і картон гофровані, паперова й картонна тара"
                                }
                            ],
                            "unitOfMeasure": "item",
                            "quantity": 5
                        }
                    ],
                    "enquiryPeriod": {
                        "endDate": "2014-10-31T00:00:00"
                    },
                    "tenderPeriod": {
                        "startDate": "2014-11-03T00:00:00",
                        "endDate": "2014-11-06T10:00:00"
                    },
                    "awardPeriod": {
                        "endDate": "2014-11-13T00:00:00"
                    },
                    "deliveryDate": {
                        "endDate": "2014-11-20T00:00:00"
                    },
                    "minimalStep": {
                        "amount": 35,
                        "currency": "UAH"
                    }
                }
            }

        """
        self.request.registry.getAdapter(self.request.validated['auction'],
                                         IAuctionManager).create_auction(
                                             self.request)
        auction_id = generate_id()
        auction = self.request.validated['auction']
        auction.id = auction_id
        auction.auctionID = generate_auction_id(get_now(), self.db,
                                                self.server_id)
        if hasattr(auction, "initialize"):
            auction.initialize()
        status = self.request.json_body['data'].get('status')
        if status and status in ['draft', 'pending.verification']:
            auction.status = status
        acc = set_ownership(auction, self.request)
        self.request.validated['auction'] = auction
        self.request.validated['auction_src'] = {}
        if save_auction(self.request):
            self.LOGGER.info(
                'Created auction {} ({})'.format(auction_id,
                                                 auction.auctionID),
                extra=context_unpack(self.request,
                                     {'MESSAGE_ID': 'auction_create'}, {
                                         'auction_id': auction_id,
                                         'auctionID': auction.auctionID
                                     }))
            self.request.response.status = 201
            auction_route_name = get_auction_route_name(self.request, auction)
            self.request.response.headers['Location'] = self.request.route_url(
                route_name=auction_route_name, auction_id=auction_id)
            return {'data': auction.serialize(auction.status), 'access': acc}