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
             }
         }
 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 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):
     """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 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 patch(self):
     """Post a complaint resolution
     """
     auction = self.request.validated['auction']
     if auction.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 ({}) 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.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 auction.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()
     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 post(self):
     """Report auction results for lot.
     """
     apply_patch(self.request, save=False, src=self.request.validated['auction_src'])
     if all([i.auctionPeriod and i.auctionPeriod.endDate for i in self.request.validated['auction'].lots if i.numberOfBids > 1 and i.status == 'active']):
         cleanup_bids_for_cancelled_lots(self.request.validated['auction'])
         add_next_award(self.request)
     if save_auction(self.request):
         self.LOGGER.info('Report auction results', extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_auction_post'}))
         return {'data': self.request.validated['auction'].serialize(self.request.validated['auction'].status)}
 def put(self):
     """Auction Award Document Update"""
     if not self.validate_award_document('update'):
         return
     document = upload_file(self.request)
     self.request.validated['award'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction award document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_document_put'}))
         return {'data': document.serialize("view")}
Example #9
0
 def put(self):
     """Auction Contract Document Update"""
     if not self.validate_contract_document('update'):
         return
     document = upload_file(self.request)
     self.request.validated['contract'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction contract document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_contract_document_put'}))
         return {'data': document.serialize("view")}
 def put(self):
     """Auction Award Document Update"""
     if not self.validate_award_document('update'):
         return
     document = upload_file(self.request)
     document.author = self.request.authenticated_role
     self.request.validated['award'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction award document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_document_put'}))
         return {'data': document.serialize("view")}
Example #11
0
    def patch(self):
        award = self.request.validated['award']

        manager = self.request.registry.getAdapter(award, IAwardManagerAdapter)
        manager.change_award(self.request, server_id=self.server_id)
        if save_auction(self.request):
            self.LOGGER.info(
                'Updated auction award {}'.format(self.request.context.id),
                extra=context_unpack(self.request,
                                     {'MESSAGE_ID': 'auction_award_patch'}))
            return {'data': award.serialize("view")}
 def put(self):
     """Auction Cancellation Document Update"""
     if self.request.validated['auction_status'] in ['complete', 'cancelled', 'unsuccessful']:
         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
     document = upload_file(self.request)
     self.request.validated['cancellation'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction cancellation document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_cancellation_document_put'}))
         return {'data': document.serialize("view")}
 def collection_post(self):
     apply_patch(self.request, save=False, src=self.request.validated['auction_src'])
     auction = self.request.validated['auction']
     adapter = self.request.registry.getAdapter(auction, IAuctionManager)
     invalidate_bids_under_threshold(auction)
     if any([i.status == 'active' for i in auction.bids]):
         self.request.content_configurator.start_awarding()
     else:
         adapter.pendify_auction_status('unsuccessful')
     if save_auction(self.request):
         self.LOGGER.info('Report auction results', extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_auction_post'}))
         return {'data': self.request.validated['auction'].serialize(self.request.validated['auction'].status)}
Example #14
0
 def put(self):
     """Auction Bid Document Update"""
     if not self.validate_bid_document('update'):
         return
     document = upload_file(self.request)
     self.request.validated['bid'].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('Updated auction bid document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_document_put'}))
         return {'data': document.serialize("view")}
 def put(self):
     """Auction Bid Document Update"""
     if not self.validate_bid_document('update'):
         return
     document = upload_file(self.request)
     self.request.validated['bid'].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('Updated auction bid document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_document_put'}))
         return {'data': document.serialize("view")}
Example #16
0
 def put(self):
     """Auction Award Document Update"""
     if self.request.authenticated_role != self.request.context.author:
         self.request.errors.add('url', 'role', 'Can update document only author')
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     document.author = self.request.authenticated_role
     self.request.validated['award'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction award document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_document_put'}))
         return {'data': document.serialize("view")}
 def put(self):
     """Auction Document Update"""
     if self.request.authenticated_role != 'auction' and self.request.validated['auction_status'] != 'active.enquiries' or \
        self.request.authenticated_role == 'auction' and self.request.validated['auction_status'] not in ['active.auction', 'active.qualification']:
         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
     document = upload_file(self.request)
     self.request.validated['auction'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Updated auction document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_document_put'}))
         return {'data': document.serialize("view")}
Example #18
0
 def collection_post(self):
     """Auction Award Document Upload
     """
     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 document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_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")}
 def collection_post(self):
     """Auction Award Document Upload
     """
     if not self.validate_award_document('add'):
         return
     document = upload_file(self.request)
     self.context.documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Created auction award document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_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")}
    def patch(self):
        """Update of contract
        """
        contract = self.request.context
        contract_manager = self.request.registry.getAdapter(
            contract, IContractManagerAdapter)
        contract_manager.change_contract(self.request, context=self.context)

        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()}
 def patch(self):
     """Post a complaint resolution for award
     """
     auction = self.request.validated['auction']
     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.type = 'complaint'
         self.context.dateEscalated = get_now()
     # auction_owner
     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 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 == '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 award complaint {}'.format(self.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_complaint_patch'}))
         return {'data': self.context.serialize("view")}
Example #22
0
 def put(self):
     """Auction Document Update"""  # TODO rm black box
     if not self.validate_document_editing_period('update'):
         return
     document = upload_file(self.request)
     if self.request.authenticated_role != "auction":
         invalidate_bids_data(self.request.auction)
     self.request.validated['auction'].documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info(
             'Updated auction document {}'.format(self.request.context.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'auction_document_put'}))
         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 delete(self):
     """Lot deleting
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.enquiries']:
         self.request.errors.add('body', 'data', 'Can\'t delete lot in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     lot = self.request.context
     res = lot.serialize("view")
     auction.lots.remove(lot)
     if save_auction(self.request):
         self.LOGGER.info('Deleted auction lot {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_delete'}))
         return {'data': res}
 def collection_post(self):
     auction = self.context.serialize()
     merge_auction_results(auction, self.request)
     apply_patch(self.request, save=False, src=self.request.validated['auction_src'])
     remove_draft_bids(self.request)
     auction = self.request.validated['auction']
     invalidate_empty_bids(auction)
     if any([i.status == 'active' for i in auction.bids]):
         create_awards(self.request)
     else:
         auction.status = 'unsuccessful'
     if save_auction(self.request):
         self.LOGGER.info('Report auction results',
                          extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_auction_post'}))
         return {'data': self.request.validated['auction'].serialize(self.request.validated['auction'].status)}
Example #26
0
 def post(self):
     """Report auction results for lot.
     """
     apply_patch(self.request, save=False, src=self.request.validated['auction_src'])
     auction = self.request.validated['auction']
     if all([i.auctionPeriod and i.auctionPeriod.endDate for i in auction.lots if i.numberOfBids > 1 and i.status == 'active']):
         cleanup_bids_for_cancelled_lots(auction)
         invalidate_bids_under_threshold(auction)
         if any([i.status == 'active' for i in auction.bids]):
             self.request.content_configurator.start_awarding()
         else:
             auction.status = 'unsuccessful'
     if save_auction(self.request):
         self.LOGGER.info('Report auction results', extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_auction_post'}))
         return {'data': self.request.validated['auction'].serialize(self.request.validated['auction'].status)}
Example #27
0
 def patch(self):
     """Auction Document Update"""  # TODO rm black box
     if not self.validate_document_editing_period('update'):
         return
     apply_patch(self.request,
                 save=False,
                 src=self.request.context.serialize())
     if self.request.authenticated_role != "auction":
         invalidate_bids_data(self.request.auction)
     if save_auction(self.request):
         self.LOGGER.info(
             'Updated auction document {}'.format(self.request.context.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'auction_document_patch'}))
         return {'data': self.request.context.serialize("view")}
Example #28
0
 def delete(self):
     """Lot deleting
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.tendering']:
         self.request.errors.add('body', 'data', 'Can\'t delete lot in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     lot = self.request.context
     res = lot.serialize("view")
     auction.lots.remove(lot)
     if save_auction(self.request):
         self.LOGGER.info('Deleted auction lot {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_delete'}))
         return {'data': res}
 def put(self):
     """Auction Bid Document Update"""
     if self.request.validated['auction_status'] not in [
             'active.tendering', 'active.qualification'
     ]:
         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
     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 updated 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 update document because award of bid is not in pending state'
         )
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.request.validated['bid'].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('Updated auction bid document {}'.format(
             self.request.context.id),
                          extra=context_unpack(
                              self.request,
                              {'MESSAGE_ID': 'auction_bid_document_put'}))
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Auction Cancellation Document Upload
     """
     if self.request.validated['auction_status'] in ['complete', 'cancelled', 'unsuccessful']:
         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
     document = upload_file(self.request)
     self.context.documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Created auction cancellation document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_cancellation_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 Document Upload"""
     if self.request.authenticated_role != 'auction' and self.request.validated['auction_status'] != 'active.enquiries' or \
        self.request.authenticated_role == 'auction' and self.request.validated['auction_status'] not in ['active.auction', '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
     document = upload_file(self.request)
     self.context.documents.append(document)
     if save_auction(self.request):
         self.LOGGER.info('Created auction document {}'.format(document.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_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 contract for award
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t add contract in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     contract = self.request.validated['contract']
     auction.contracts.append(contract)
     if save_auction(self.request):
         self.LOGGER.info('Created auction contract {}'.format(contract.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_contract_create'}, {'contract_id': contract.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Auction Contracts', auction_id=auction.id, contract_id=contract['id'])
         return {'data': contract.serialize()}
Example #33
0
 def collection_post(self):
     """Auction Bid Document Upload
     """
     if not self.validate_bid_document('add'):
         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")}
Example #34
0
 def collection_post(self):
     item = self.request.validated['item']
     self.context.items.append(item)
     if save_auction(self.request):
         self.LOGGER.info(
             'Created lot item {}'.format(item.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'auction_item_create'},
                                  {'item_id': item.id}))
         self.request.response.status = 201
         item_route = self.request.matched_route.name.replace(
             "collection_", "")
         self.request.response.headers[
             'Location'] = self.request.current_route_url(
                 _route_name=item_route, item_id=item.id, _query={})
         return {'data': item.serialize("view")}
Example #35
0
 def collection_post(self):
     """Add a lot
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.tendering']:
         self.request.errors.add('body', 'data', 'Can\'t add lot in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     lot = self.request.validated['lot']
     lot.date = get_now()
     auction.lots.append(lot)
     if save_auction(self.request):
         self.LOGGER.info('Created auction lot {}'.format(lot.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_create'}, {'lot_id': lot.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Auction Lots', auction_id=auction.id, lot_id=lot.id)
         return {'data': lot.serialize("view")}
 def collection_post(self):
     """Add a lot
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.enquiries']:
         self.request.errors.add('body', 'data', 'Can\'t add lot in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     lot = self.request.validated['lot']
     lot.date = get_now()
     auction.lots.append(lot)
     if save_auction(self.request):
         self.LOGGER.info('Created auction lot {}'.format(lot.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_create'}, {'lot_id': lot.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Auction Lots', auction_id=auction.id, lot_id=lot.id)
         return {'data': lot.serialize("view")}
Example #37
0
 def collection_post(self):
     award = self.request.validated['award']
     manager = self.request.registry.getAdapter(award, IAwardManagerAdapter)
     manager.create_award(self.request)
     if save_auction(self.request):
         self.LOGGER.info(
             'Created auction award {}'.format(award.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'auction_award_create'},
                                  {'award_id': award.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,
                                                          award_id=award.id,
                                                          _query={})
         return {'data': award.serialize("view")}
Example #38
0
    def put(self):
        """Auction Document Update"""
        if self.request.authenticated_role != 'auction' and self.request.validated['auction_status'] != 'active.tendering' or \
           self.request.authenticated_role == 'auction' and self.request.validated['auction_status'] not in ['active.auction', 'active.qualification']:
            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
        document = dgf_upload_file(self.request)
        self.request.validated['auction'].documents.append(document)

        if self.request.authenticated_role == 'auction_owner':
            invalidate_bids_data(self.request.auction)

        if save_auction(self.request):
            self.LOGGER.info('Updated auction document {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_document_put'}))
            return {'data': document.serialize("view")}
Example #39
0
    def delete(self):
        """Cancelling the proposal

        Example request for cancelling the proposal:

        .. sourcecode:: http

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

        And here is the response to be expected:

        .. sourcecode:: http

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

            {
                "data": {
                    "value": {
                        "amount": 489,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """
        bid = self.request.context
        if self.request.validated['auction_status'] != 'active.tendering':
            self.request.errors.add('body', 'data', 'Can\'t delete bid in current ({}) auction status'.format(self.request.validated['auction_status']))
            self.request.errors.status = 403
            return
        auction = self.request.validated['auction']
        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 deleted 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
        res = bid.serialize("view")
        self.request.validated['auction'].bids.remove(bid)
        self.request.validated['auction'].modified = False
        if save_auction(self.request):
            self.LOGGER.info('Deleted auction bid {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_delete'}))
            return {'data': res}
Example #40
0
 def collection_post(self):
     """Post a contract for award
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t add contract in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     contract = self.request.validated['contract']
     auction.contracts.append(contract)
     if save_auction(self.request):
         self.LOGGER.info('Created auction contract {}'.format(contract.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_contract_create'}, {'contract_id': contract.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, contract_id=contract.id, _query={})
         return {'data': contract.serialize()}
    def delete(self):
        """Cancelling the proposal

        Example request for cancelling the proposal:

        .. sourcecode:: http

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

        And here is the response to be expected:

        .. sourcecode:: http

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

            {
                "data": {
                    "value": {
                        "amount": 489,
                        "currency": "UAH",
                        "valueAddedTaxIncluded": true
                    }
                }
            }

        """
        bid = self.request.context
        if self.request.validated['auction_status'] != 'active.tendering':
            self.request.errors.add('body', 'data', 'Can\'t delete bid in current ({}) auction status'.format(self.request.validated['auction_status']))
            self.request.errors.status = 403
            return
        auction = self.request.validated['auction']
        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 deleted 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
        res = bid.serialize("view")
        self.request.validated['auction'].bids.remove(bid)
        self.request.validated['auction'].modified = False
        if save_auction(self.request):
            self.LOGGER.info('Deleted auction bid {}'.format(self.request.context.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_delete'}))
            return {'data': res}
 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")}
Example #43
0
 def collection_post(self):
     """Post a contract for award
     """
     auction = self.request.validated['auction']
     contract = self.request.validated['contract']
     auction.contracts.append(contract)
     if save_auction(self.request):
         self.LOGGER.info(
             'Created auction contract {}'.format(contract.id),
             extra=context_unpack(self.request,
                                  {'MESSAGE_ID': 'auction_contract_create'},
                                  {'contract_id': contract.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, contract_id=contract.id, _query={})
         return {'data': contract.serialize()}
 def delete(self):
     """Lot deleting
     """
     auction = self.request.validated["auction"]
     if auction.status not in ["active.enquiries"]:
         self.request.errors.add(
             "body", "data", "Can't delete lot in current ({}) auction status".format(auction.status)
         )
         self.request.errors.status = 403
         return
     lot = self.request.context
     res = lot.serialize("view")
     auction.lots.remove(lot)
     if save_auction(self.request):
         self.LOGGER.info(
             "Deleted auction lot {}".format(self.request.context.id),
             extra=context_unpack(self.request, {"MESSAGE_ID": "auction_lot_delete"}),
         )
         return {"data": res}
Example #45
0
 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")}
Example #46
0
    def collection_post(self):
        """Auction Document Upload"""
        if self.request.authenticated_role != 'auction' and self.request.validated['auction_status'] != 'active.tendering' or \
           self.request.authenticated_role == 'auction' and self.request.validated['auction_status'] not in ['active.auction', '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
        document = dgf_upload_file(self.request)
        self.context.documents.append(document)

        if self.request.authenticated_role == 'auction_owner':
            invalidate_bids_data(self.request.auction)

        if save_auction(self.request):
            self.LOGGER.info('Created auction document {}'.format(document.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_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 question
     """
     auction = self.request.validated['auction']
     if auction.status != 'active.enquiries' or get_now() < auction.enquiryPeriod.startDate or get_now() > auction.enquiryPeriod.endDate:
         self.request.errors.add('body', 'data', 'Can add question only in enquiryPeriod')
         self.request.errors.status = 403
         return
     question = self.request.validated['question']
     if any([i.status != 'active' for i in auction.lots if i.id == question.relatedItem]):
         self.request.errors.add('body', 'data', 'Can add question only in active lot status')
         self.request.errors.status = 403
         return
     auction.questions.append(question)
     if save_auction(self.request):
         self.LOGGER.info('Created auction question {}'.format(question.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_question_create'}, {'question_id': question.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Auction Questions', auction_id=auction.id, question_id=question.id)
         return {'data': question.serialize("view")}
Example #48
0
    def post(self):
        """This API request is targeted to creating new Auctions by procuring organizations.
        """
        auction = self.request.validated['auction']

        if auction['_internal_type'] == 'geb':
            manager = self.request.registry.queryMultiAdapter(
                (self.request, auction), IManager)
            applicant = self.request.validated['auction']
            auction = manager.create(applicant)
            if not auction:
                return
        else:
            self.request.registry.getAdapter(
                auction, IAuctionManager).create_auction(self.request)
            auction_id = generate_id()
            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}
 def patch(self):
     """Post a cancellation resolution
     """
     auction = self.request.validated['auction']
     if auction.status in ['complete', 'cancelled', 'unsuccessful']:
         self.request.errors.add('body', 'data', 'Can\'t update cancellation in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     if any([i.status != 'active' for i in auction.lots if i.id == self.request.context.relatedLot]):
         self.request.errors.add('body', 'data', 'Can update cancellation only in active lot status')
         self.request.errors.status = 403
         return
     apply_patch(self.request, save=False, src=self.request.context.serialize())
     if self.request.context.relatedLot and self.request.context.status == 'active':
         self.cancel_lot()
     elif self.request.context.status == 'active':
         self.cancel_auction()
     if save_auction(self.request):
         self.LOGGER.info('Updated auction cancellation {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_cancellation_patch'}))
         return {'data': self.request.context.serialize("view")}
 def collection_post(self):
     """Post a complaint for award
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.qualification', 'active.awarded']:
         self.request.errors.add('body', 'data', 'Can\'t add complaint in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     if any([i.status != 'active' for i in auction.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 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.date = get_now()
     complaint.relatedLot = self.context.lotID
     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)
     self.context.complaints.append(complaint)
     if save_auction(self.request):
         self.LOGGER.info('Created auction award complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_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("view"),
             'access': {
                 'token': complaint.owner_token
             }
         }
 def put(self):
     """Auction Bid Document Update"""
     if self.request.validated['auction_status'] not in ['active.tendering', 'active.qualification']:
         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
     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 updated 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 update document because award of bid is not in pending state')
         self.request.errors.status = 403
         return
     document = upload_file(self.request)
     self.request.validated['bid'].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('Updated auction bid document {}'.format(self.request.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_bid_document_put'}))
         return {'data': document.serialize("view")}
 def collection_post(self):
     """Add a lot
     """
     auction = self.request.validated["auction"]
     if auction.status not in ["active.enquiries"]:
         self.request.errors.add(
             "body", "data", "Can't add lot in current ({}) auction status".format(auction.status)
         )
         self.request.errors.status = 403
         return
     lot = self.request.validated["lot"]
     lot.date = get_now()
     auction.lots.append(lot)
     if save_auction(self.request):
         self.LOGGER.info(
             "Created auction lot {}".format(lot.id),
             extra=context_unpack(self.request, {"MESSAGE_ID": "auction_lot_create"}, {"lot_id": lot.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, lot_id=lot.id, _query={}
         )
         return {"data": lot.serialize("view")}
    def patch(self):
        """Update of award

        Example request to change the award:

        .. sourcecode:: http

            PATCH /auctions/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
                    }
                }
            }

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

        Report auction results
        ----------------------

        Example request to report auction results:

        .. sourcecode:: http

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

            {
                "data": {
                    "dateModified": "2014-10-27T08:06:58.158Z",
                    "bids": [
                        {
                            "value": {
                                "amount": 400,
                                "currency": "UAH"
                            }
                        },
                        {
                            "value": {
                                "amount": 385,
                                "currency": "UAH"
                            }
                        }
                    ]
                }
            }

        This is what one should expect in response:

        .. sourcecode:: http

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

            {
                "data": {
                    "dateModified": "2014-10-27T08:06:58.158Z",
                    "bids": [
                        {
                            "value": {
                                "amount": 400,
                                "currency": "UAH",
                                "valueAddedTaxIncluded": true
                            }
                        },
                        {
                            "value": {
                                "amount": 385,
                                "currency": "UAH",
                                "valueAddedTaxIncluded": true
                            }
                        }
                    ],
                    "minimalStep":{
                        "amount": 35,
                        "currency": "UAH"
                    },
                    "tenderPeriod":{
                        "startDate": "2014-11-04T08:00:00"
                    }
                }
            }

        """
        apply_patch(self.request, save=False, src=self.request.validated['auction_src'])
        if all([i.auctionPeriod and i.auctionPeriod.endDate for i in self.request.validated['auction'].lots if i.numberOfBids > 1 and i.status == 'active']):
            add_next_award(self.request)
        if save_auction(self.request):
            self.LOGGER.info('Report auction results', extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_auction_post'}))
            return {'data': self.request.validated['auction'].serialize(self.request.validated['auction'].status)}
    def collection_post(self):
        """Accept or reject bidder application

        Creating new Award
        ------------------

        Example request to create award:

        .. sourcecode:: http

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

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

        """
        auction = self.request.validated['auction']
        if auction.status != 'active.qualification':
            self.request.errors.add('body', 'data', 'Can\'t create award in current ({}) auction status'.format(auction.status))
            self.request.errors.status = 403
            return
        award = self.request.validated['award']
        if any([i.status != 'active' for i in auction.lots if i.id == award.lotID]):
            self.request.errors.add('body', 'data', 'Can create award only in active lot status')
            self.request.errors.status = 403
            return
        award.complaintPeriod = {'startDate': get_now().isoformat()}
        auction.awards.append(award)
        if save_auction(self.request):
            self.LOGGER.info('Created auction award {}'.format(award.id),
                        extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_create'}, {'award_id': award.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, award_id=award.id, _query={})
            return {'data': award.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
            self.request.response.headers['Location'] = self.request.route_url('Auction Bids', auction_id=auction.id, bid_id=bid['id'])
            return {
                'data': bid.serialize('view'),
                'access': {
                    'token': bid.owner_token
                }
            }
    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
        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()}
 def patch(self):
     """Post a complaint resolution for award
     """
     auction = self.request.validated['auction']
     if auction.status not in ['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 any([i.status != 'active' for i in auction.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.type = 'complaint'
         self.context.dateEscalated = get_now()
     # auction_owner
     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 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 == '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 award complaint {}'.format(self.context.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_award_complaint_patch'}))
         return {'data': self.context.serialize("view")}