def collection_post(self): """Post a cancellation """ tender = self.request.validated['tender'] if tender.status in ['complete', 'cancelled', 'unsuccessful']: self.request.errors.add('body', 'data', 'Can\'t add cancellation in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return cancellation_data = self.request.validated['data'] if any([i.status != 'active' for i in tender.lots if i.id == cancellation_data.get('relatedLot')]): self.request.errors.add('body', 'data', 'Can add cancellation only in active lot status') self.request.errors.status = 403 return cancellation = Cancellation(cancellation_data) cancellation.__parent__ = self.request.context if cancellation.relatedLot and cancellation.status == 'active': [setattr(i, 'status', 'cancelled') for i in tender.lots if i.id == cancellation.relatedLot] check_tender_status(self.request) elif cancellation.status == 'active': tender.status = 'cancelled' tender.cancellations.append(cancellation) if save_tender(self.request): LOGGER.info('Created tender cancellation {}'.format(cancellation.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_cancellation_create'}, {'cancellation_id': cancellation.id})) self.request.response.status = 201 self.request.response.headers['Location'] = self.request.route_url('Tender Cancellations', tender_id=tender.id, cancellation_id=cancellation.id) return {'data': cancellation.serialize("view")}
def patch(self): """Post a complaint resolution for award """ tender = self.request.validated['tender'] if tender.status != 'active': self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied']: self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.context.status)) self.request.errors.status = 403 return data = self.request.validated['data'] complaintPeriod = self.request.validated['award'].complaintPeriod is_complaintPeriod = complaintPeriod.startDate < get_now() and complaintPeriod.endDate > get_now() if complaintPeriod.endDate else complaintPeriod.startDate < get_now() # complaint_owner if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered', 'pending', 'accepted'] and data.get('status', self.context.status) == 'cancelled': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get('status', self.context.status) == 'pending': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateSubmitted = get_now() # tender_owner elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['pending', 'accepted']: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('tendererAction', self.context.tendererAction) and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) # aboveThresholdReviewers elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'invalid': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.acceptance = False elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'accepted': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAccepted = get_now() self.context.acceptance = True elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['declined', 'satisfied']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() else: self.request.errors.add('body', 'data', 'Can\'t update complaint') self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied'] and tender.status in ['active.qualification', 'active.awarded']: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender award complaint {}'.format(self.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_complaint_patch'})) return {'data': self.context.serialize("view")}
def patch(self): """Post a complaint resolution """ tender = self.request.validated['tender'] if tender.status not in ['active.enquiries', 'active.tendering', 'active.auction', 'active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if self.context.status not in ['draft', 'claim', 'answered', 'pending']: self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.context.status)) self.request.errors.status = 403 return data = self.request.validated['data'] # complaint_owner if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered', 'pending'] and data.get('status', self.context.status) == 'cancelled': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and tender.status in ['active.enquiries', 'active.tendering'] and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and tender.status in ['active.enquiries', 'active.tendering'] and self.context.status == 'draft' and data.get('status', self.context.status) == 'claim': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is True and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is False and data.get('status', self.context.status) == 'pending': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateEscalated = get_now() # tender_owner elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('resolution', self.context.resolution) and data.get('resolutionType', self.context.resolutionType) and data.get('status', self.context.status) == 'answered': if len(data.get('resolution', self.context.resolution)) < 20: self.request.errors.add('body', 'data', 'Can\'t update complaint: resolution too short') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAnswered = get_now() elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'pending': apply_patch(self.request, save=False, src=self.context.serialize()) # reviewers elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'reviewers' and self.context.status == 'pending' and data.get('status', self.context.status) in ['resolved', 'invalid', 'declined']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() else: self.request.errors.add('body', 'data', 'Can\'t update complaint') self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in ['draft', 'claim', 'answered', 'pending'] and tender.status in ['active.qualification', 'active.awarded']: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender complaint {}'.format(self.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'})) return {'data': self.context.serialize("view")}
def patch(self): """Post a complaint resolution """ tender = self.request.validated['tender'] if tender.status not in ['active.enquiries', 'active.tendering', 'active.auction', 'active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if self.request.context.status != 'pending': self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.request.context.status)) self.request.errors.status = 403 return if self.request.validated['data'].get('status', self.request.context.status) == 'cancelled': self.request.errors.add('body', 'data', 'Can\'t cancel complaint') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.request.context.serialize()) if self.request.context.status == 'resolved' and tender.status != 'active.enquiries': for i in tender.complaints: if i.status == 'pending': i.status = 'cancelled' [setattr(i, 'status', 'cancelled') for i in tender.lots] tender.status = 'cancelled' elif self.request.context.status in ['declined', 'invalid'] and tender.status == 'active.awarded': check_tender_status(self.request) if save_tender(self.request): LOGGER.info('Updated tender complaint {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'})) return {'data': self.request.context.serialize("view")}
def check_status(request): tender = request.validated['tender'] now = get_now() if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not has_unanswered_complaints(tender) and not has_unanswered_questions(tender): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'})) tender.status = 'active.pre-qualification' tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now}) remove_draft_bids(request) check_initial_bids_count(request) prepare_qualifications(request) return elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([ i.status in tender.block_complaint_status for q in tender.qualifications for i in q.complaints ]): LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_initial_bids_count(request) return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) return
def check_status(request): tender = request.validated['tender'] now = get_now() if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now: for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'})) tender.status = 'active.pre-qualification' tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now}) remove_draft_bids(request) check_initial_bids_count(request) prepare_qualifications(request) return elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([ i.status in tender.block_complaint_status for q in tender.qualifications for i in q.complaints ]): LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_initial_bids_count(request) return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) return
def patch(self): """Post a complaint resolution for award """ tender = self.request.validated["tender"] if tender.status not in ["active.qualification", "active.awarded"]: self.request.errors.add( "body", "data", "Can't update complaint in current ({}) tender status".format(tender.status) ) self.request.errors.status = 403 return if any([i.status != "active" for i in tender.lots if i.id == self.request.validated["award"].lotID]): self.request.errors.add("body", "data", "Can update complaint only in active lot status") self.request.errors.status = 403 return complaint = self.request.context if complaint.status != "pending": self.request.errors.add( "body", "data", "Can't update complaint in current ({}) status".format(complaint.status) ) self.request.errors.status = 403 return if self.request.validated["data"].get("status", complaint.status) == "cancelled": self.request.errors.add("body", "data", "Can't cancel complaint") self.request.errors.status = 403 return apply_patch(self.request, save=False, src=complaint.serialize()) if complaint.status == "resolved": award = self.request.validated["award"] if tender.status == "active.awarded": tender.status = "active.qualification" tender.awardPeriod.endDate = None now = get_now() if award.status == "unsuccessful": for i in tender.awards[tender.awards.index(award) :]: if i.lotID != award.lotID: continue i.complaintPeriod.endDate = now + STAND_STILL_TIME i.status = "cancelled" for j in i.complaints: if j.status == "pending": j.status = "cancelled" for i in tender.contracts: if award.id == i.awardID: i.status = "cancelled" award.complaintPeriod.endDate = now + STAND_STILL_TIME award.status = "cancelled" add_next_award(self.request) elif complaint.status in ["declined", "invalid"] and tender.status == "active.awarded": check_tender_status(self.request) if save_tender(self.request): LOGGER.info( "Updated tender award complaint {}".format(self.request.context.id), extra=context_unpack(self.request, {"MESSAGE_ID": "tender_award_complaint_patch"}), ) return {"data": complaint.serialize("view")}
def patch(self): """Update of contract """ if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status'])) self.request.errors.status = 403 return tender = self.request.validated['tender'] if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.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 self.request.context.status != 'active' and 'status' in data and data['status'] == 'active': award = [a for a in tender.awards if a.id == self.request.context.awardID][0] stand_still_end = award.complaintPeriod.endDate if stand_still_end > get_now(): self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat())) self.request.errors.status = 403 return pending_complaints = [ i for i in tender.complaints if i.status in ['claim', 'answered', 'pending'] and i.relatedLot in [None, award.lotID] ] pending_awards_complaints = [ i for a in tender.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_tender_status(self.request) if save_tender(self.request): LOGGER.info('Updated tender contract {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'})) return {'data': self.request.context.serialize()}
def patch(self): """Update of contract """ if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded', 'complete']: self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status'])) self.request.errors.status = 403 return tender = self.request.validated['tender'] if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.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 self.request.context.status != 'active' and 'status' in data and data['status'] == 'active': award = [a for a in tender.awards if a.id == self.request.context.awardID][0] stand_still_end = award.complaintPeriod.endDate if stand_still_end > get_now(): self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat())) self.request.errors.status = 403 return pending_complaints = [ i for i in tender.complaints if i.status in ['claim', 'answered', 'pending'] and i.relatedLot in [None, award.lotID] ] pending_awards_complaints = [ i for a in tender.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 check_tender_status(self.request) if save_tender(self.request): LOGGER.info('Updated tender contract {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'})) return {'data': self.request.context.serialize()}
def patch(self): """Post a cancellation resolution """ tender = self.request.validated['tender'] if tender.status in ['complete', 'cancelled', 'unsuccessful']: self.request.errors.add('body', 'data', 'Can\'t update cancellation in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if any([i.status != 'active' for i in tender.lots if i.id == self.request.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': [setattr(i, 'status', 'cancelled') for i in tender.lots if i.id == self.request.context.relatedLot] check_tender_status(self.request) elif self.request.context.status == 'active': tender.status = 'cancelled' if save_tender(self.request): LOGGER.info('Updated tender cancellation {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_cancellation_patch'})) return {'data': self.request.context.serialize("view")}
def check_status(request): tender = request.validated['tender'] now = get_now() if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'})) tender.status = 'active.pre-qualification' tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now}) remove_draft_bids(request) check_initial_bids_count(request) prepare_qualifications(request) return elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([ i.status in BLOCK_COMPLAINT_STATUS for q in tender.qualifications for i in q.complaints ]): LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_initial_bids_count(request) return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for a in tender.awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in tender.awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'})) check_tender_status(request) return elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in ['claim', 'answered', 'pending'] for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_awards_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for a in lot_awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in lot_awards ]) if not pending_awards_complaints and not awarded: LOGGER.info('Switched lot {} of tender {} to {}'.format(lot['id'], tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_lot_unsuccessful'}, {'LOT_ID': lot['id']})) check_tender_status(request)
def patch(self): """Post a complaint resolution """ tender = self.request.validated['tender'] if tender.status != 'active.tendering': self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied', 'stopping']: self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) status'.format(self.context.status)) self.request.errors.status = 403 return data = self.request.validated['data'] # complaint_owner if self.request.authenticated_role == 'complaint_owner' and self.context.status in ['draft', 'claim', 'answered'] and data.get('status', self.context.status) == 'cancelled': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status in ['pending', 'accepted'] and data.get('status', self.context.status) == 'stopping': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == 'claim': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -CLAIM_SUBMIT_TIME, tender): self.request.errors.add('body', 'data', 'Can submit claim not later than {0.days} days before tenderPeriod end'.format(CLAIM_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status in ['draft', 'claim'] and data.get('status', self.context.status) == 'pending': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -COMPLAINT_SUBMIT_TIME, tender): self.request.errors.add('body', 'data', 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is True and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is False and data.get('status', self.context.status) == 'pending': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -COMPLAINT_SUBMIT_TIME, tender): self.request.errors.add('body', 'data', 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateEscalated = get_now() # tender_owner elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('status', self.context.status) == self.context.status: now = get_now() if now > tender.enquiryPeriod.clarificationsUntil: self.request.errors.add('body', 'data', 'Can update claim only before enquiryPeriod.clarificationsUntil') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('resolution', self.context.resolution) and data.get('resolutionType', self.context.resolutionType) and data.get('status', self.context.status) == 'answered': now = get_now() if now > tender.enquiryPeriod.clarificationsUntil: self.request.errors.add('body', 'data', 'Can update claim only before enquiryPeriod.clarificationsUntil') self.request.errors.status = 403 return if len(data.get('resolution', self.context.resolution)) < 20: self.request.errors.add('body', 'data', 'Can\'t update complaint: resolution too short') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAnswered = get_now() elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['pending', 'accepted']: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('tendererAction', self.context.tendererAction) and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) # aboveThresholdReviewers elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['pending', 'accepted', 'stopping'] and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'invalid': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.acceptance = False elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'accepted': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAccepted = get_now() self.context.acceptance = True elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['declined', 'satisfied']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in ['accepted', 'stopping'] and data.get('status', self.context.status) == 'stopped': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.dateCanceled = self.context.dateCanceled or get_now() else: self.request.errors.add('body', 'data', 'Can\'t update complaint') self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied', 'stopping'] and tender.status in ['active.qualification', 'active.awarded']: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender complaint {}'.format(self.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'})) return {'data': self.context.serialize("view")}
def check_status(request): tender = request.validated['tender'] now = get_now() active_lots = [lot.id for lot in tender.lots if lot.status == 'active'] if tender.lots else [None] for award in tender.awards: if award.status == 'active' and not any([i.awardID == award.id for i in tender.contracts]): tender.contracts.append(type(tender).contracts.model_class({ 'awardID': award.id, 'suppliers': award.suppliers, 'value': award.value, 'date': now, 'items': [i for i in tender.items if i.relatedLot == award.lotID ], 'contractID': '{}-{}{}'.format(tender.tenderID, request.registry.server_id, len(tender.contracts) + 1) })) add_next_award(request) if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not has_unanswered_complaints(tender) and not has_unanswered_questions(tender): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'})) tender.status = 'active.pre-qualification' tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now}) remove_draft_bids(request) check_initial_bids_count(request) prepare_qualifications(request) return elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([ i.status in tender.block_complaint_status for q in tender.qualifications for i in q.complaints if q.lotID in active_lots ]): LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_initial_bids_count(request) return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) return
def check_status(request): tender = request.validated['tender'] now = get_now() for award in tender.awards: if award.status == 'active' and not any([i.awardID == award.id for i in tender.contracts]): tender.contracts.append(type(tender).contracts.model_class({ 'awardID': award.id, 'suppliers': award.suppliers, 'value': award.value, 'date': now, 'items': [i for i in tender.items if i.relatedLot == award.lotID ], 'contractID': '{}-{}{}'.format(tender.tenderID, request.registry.server_id, len(tender.contracts) + 1) })) add_next_award(request) if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not has_unanswered_complaints(tender) and not has_unanswered_questions(tender): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_bids(request) if tender.numberOfBids < 2 and tender.auctionPeriod: tender.auctionPeriod.startDate = None return elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not has_unanswered_complaints(tender) and not has_unanswered_questions(tender): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_bids(request) [setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod] return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in tender.block_complaint_status for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in tender.block_complaint_status for a in tender.awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in tender.awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'})) check_tender_status(request) return elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in tender.block_complaint_status and i.relatedLot == lot.id for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in tender.block_complaint_status for a in lot_awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in lot_awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched lot {} of tender {} to {}'.format(lot['id'], tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_lot_unsuccessful'}, {'LOT_ID': lot['id']})) check_tender_status(request)
def patch(self): """Post a complaint resolution for award """ tender = self.request.validated['tender'] if tender.status not in ['active.qualification', 'active.awarded']: self.request.errors.add( 'body', 'data', 'Can\'t update complaint in current ({}) tender status'.format( tender.status)) self.request.errors.status = 403 return if any([ i.status != 'active' for i in tender.lots if i.id == self.request.validated['award'].lotID ]): self.request.errors.add( 'body', 'data', 'Can update complaint only in active lot status') self.request.errors.status = 403 return if self.context.status not in [ 'draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied', 'stopping' ]: self.request.errors.add( 'body', 'data', 'Can\'t update complaint in current ({}) status'.format( self.context.status)) self.request.errors.status = 403 return data = self.request.validated['data'] 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' ] and data.get('status', self.context.status) == 'cancelled': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status in [ 'pending', 'accepted' ] and data.get('status', self.context.status) == 'stopping': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and is_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 is_complaintPeriod and self.context.status == 'draft' and data.get( 'status', self.context.status) == 'pending': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get( 'status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) # tender_owner elif self.request.authenticated_role == 'tender_owner' and self.context.status in [ 'pending', 'accepted' ]: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status in [ 'claim', 'satisfied' ] and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get( 'resolution', self.context.resolution) and data.get( 'resolutionType', self.context.resolutionType) and data.get( 'status', self.context.status) == 'answered': if len(data.get('resolution', self.context.resolution)) < 20: self.request.errors.add( 'body', 'data', 'Can\'t update complaint: resolution too short') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAnswered = get_now() elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get( 'tendererAction', self.context.tendererAction) and data.get( 'status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) # aboveThresholdReviewers elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [ 'pending', 'accepted', 'stopping' ] and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [ 'pending', 'stopping' ] and data.get('status', self.context.status) in ['invalid', 'mistaken']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.acceptance = False elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get( 'status', self.context.status) == 'accepted': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAccepted = get_now() self.context.acceptance = True elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get( 'status', self.context.status) in ['declined', 'satisfied']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [ 'accepted', 'stopping' ] and data.get('status', self.context.status) == 'stopped': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.dateCanceled = self.context.dateCanceled or get_now() else: self.request.errors.add('body', 'data', 'Can\'t update complaint') self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in [ 'draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied', 'stopping' ] and tender.status in ['active.qualification', 'active.awarded']: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info( 'Updated tender award complaint {}'.format(self.context.id), extra=context_unpack( self.request, {'MESSAGE_ID': 'tender_award_complaint_patch'})) return {'data': self.context.serialize("view")}
def patch(self): """Update of contract """ if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status'])) self.request.errors.status = 403 return tender = self.request.validated['tender'] if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.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 if any([any([c.status == 'accepted' for c in i.complaints]) for i in tender.awards if i.lotID in [a.lotID for a in tender.awards if a.id == self.request.context.awardID]]): self.request.errors.add('body', 'data', 'Can\'t update contract with accepted complaint') 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 tender.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 less 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 tender.awards if a.id == self.request.context.awardID][0] stand_still_end = award.complaintPeriod.endDate if stand_still_end > get_now(): self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat())) self.request.errors.status = 403 return pending_complaints = [ i for i in tender.complaints if i.status in tender.block_complaint_status and i.relatedLot in [None, award.lotID] ] pending_awards_complaints = [ i for a in tender.awards for i in a.complaints if i.status in tender.block_complaint_status 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_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender contract {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'})) return {'data': self.request.context.serialize()}
def check_status(request): tender = request.validated['tender'] now = get_now() if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' remove_draft_bids(request) check_bids(request) if tender.numberOfBids < 2 and tender.auctionPeriod: tender.auctionPeriod.startDate = None return elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' remove_draft_bids(request) check_bids(request) [setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod] return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for a in tender.awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in tender.awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'})) check_tender_status(request) return elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in PENDING_COMPLAINT_STATUS and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS and i.relatedLot == lot.id for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for a in lot_awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in lot_awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched lot {} of tender {} to {}'.format(lot['id'], tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_lot_unsuccessful'}, {'LOT_ID': lot['id']})) check_tender_status(request)
def check_status(request): tender = request.validated['tender'] now = get_now() if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_bids(request) if tender.numberOfBids < 2 and tender.auctionPeriod: tender.auctionPeriod.startDate = None return elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_bids(request) [ setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod ] return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for a in tender.awards for i in a.complaints ]) awarded = any([i['status'] == 'active' for i in tender.awards]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info( 'Switched tender {} to {}'.format(tender.id, 'unsuccessful'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_tender_unsuccessful'})) check_tender_status(request) return elif tender.lots and tender.status in [ 'active.qualification', 'active.awarded' ]: if any([ i['status'] in PENDING_COMPLAINT_STATUS and i.relatedLot is None for i in tender.complaints ]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS and i.relatedLot == lot.id for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in PENDING_COMPLAINT_STATUS for a in lot_awards for i in a.complaints ]) awarded = any([i['status'] == 'active' for i in lot_awards]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info( 'Switched lot {} of tender {} to {}'.format( lot['id'], tender.id, 'unsuccessful'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_lot_unsuccessful'}, {'LOT_ID': lot['id']})) check_tender_status(request)
def check_status(request): tender = request.validated['tender'] now = get_now() if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in tender.block_tender_complaint_status for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' remove_draft_bids(request) check_bids(request) if tender.numberOfBids < 2 and tender.auctionPeriod: tender.auctionPeriod.startDate = None return elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in tender.block_tender_complaint_status for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack( request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' remove_draft_bids(request) check_bids(request) [ setattr(i.auctionPeriod, 'startDate', None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod ] return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) elif tender.lots and tender.status in [ 'active.qualification', 'active.awarded' ]: if any([ i['status'] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints ]): return for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) return
def patch(self): """Update of contract """ if self.request.validated["tender_status"] not in ["active.qualification", "active.awarded"]: self.request.errors.add( "body", "data", "Can't update contract in current ({}) tender status".format(self.request.validated["tender_status"]), ) self.request.errors.status = 403 return tender = self.request.validated["tender"] if any( [ i.status != "active" for i in tender.lots if i.id in [a.lotID for a in tender.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 tender.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 less 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 tender.awards if a.id == self.request.context.awardID][0] stand_still_end = award.complaintPeriod.endDate if stand_still_end > get_now(): self.request.errors.add( "body", "data", "Can't sign contract before stand-still period end ({})".format(stand_still_end.isoformat()), ) self.request.errors.status = 403 return pending_complaints = [ i for i in tender.complaints if i.status in ["claim", "answered", "pending"] and i.relatedLot in [None, award.lotID] ] pending_awards_complaints = [ i for a in tender.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_tender_status(self.request) if save_tender(self.request): self.LOGGER.info( "Updated tender contract {}".format(self.request.context.id), extra=context_unpack(self.request, {"MESSAGE_ID": "tender_contract_patch"}), ) return {"data": self.request.context.serialize()}
def patch(self): """Update of contract """ if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status'])) self.request.errors.status = 403 return tender = self.request.validated['tender'] if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.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 tender.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 less 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 tender.awards if a.id == self.request.context.awardID][0] stand_still_end = award.complaintPeriod.endDate if stand_still_end > get_now(): self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat())) self.request.errors.status = 403 return pending_complaints = [ i for i in tender.complaints if i.status in PENDING_COMPLAINT_STATUS and i.relatedLot in [None, award.lotID] ] pending_awards_complaints = [ i for a in tender.awards for i in a.complaints if i.status in PENDING_COMPLAINT_STATUS 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_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender contract {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'})) return {'data': self.request.context.serialize()}
def patch(self): """Post a complaint resolution for award """ tender = self.request.validated["tender"] if tender.status not in ["active.qualification", "active.awarded"]: self.request.errors.add( "body", "data", "Can't update complaint in current ({}) tender status".format(tender.status) ) self.request.errors.status = 403 return if any([i.status != "active" for i in tender.lots if i.id == self.request.validated["award"].lotID]): self.request.errors.add("body", "data", "Can update complaint only in active lot status") self.request.errors.status = 403 return if self.context.status not in ["draft", "claim", "answered", "pending"]: self.request.errors.add( "body", "data", "Can't update complaint in current ({}) status".format(self.context.status) ) self.request.errors.status = 403 return data = self.request.validated["data"] complaintPeriod = self.request.validated["award"].complaintPeriod is_complaintPeriod = ( complaintPeriod.startDate < get_now() and complaintPeriod.endDate > get_now() if complaintPeriod.endDate else complaintPeriod.startDate < get_now() ) # complaint_owner if ( self.request.authenticated_role == "complaint_owner" and self.context.status in ["draft", "claim", "answered", "pending"] and data.get("status", self.context.status) == "cancelled" ): apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif ( self.request.authenticated_role == "complaint_owner" and is_complaintPeriod and self.context.status == "draft" and data.get("status", self.context.status) == self.context.status ): apply_patch(self.request, save=False, src=self.context.serialize()) elif ( self.request.authenticated_role == "complaint_owner" and is_complaintPeriod and self.context.status == "draft" and data.get("status", self.context.status) == "claim" ): apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateSubmitted = get_now() elif ( self.request.authenticated_role == "complaint_owner" and self.context.status == "answered" and data.get("status", self.context.status) == self.context.status ): apply_patch(self.request, save=False, src=self.context.serialize()) elif ( self.request.authenticated_role == "complaint_owner" and self.context.status == "answered" and data.get("satisfied", self.context.satisfied) is True and data.get("status", self.context.status) == "resolved" ): apply_patch(self.request, save=False, src=self.context.serialize()) elif ( self.request.authenticated_role == "complaint_owner" and self.context.status == "answered" and data.get("satisfied", self.context.satisfied) is False and data.get("status", self.context.status) == "pending" ): apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateEscalated = get_now() # tender_owner elif ( self.request.authenticated_role == "tender_owner" and self.context.status == "claim" and data.get("status", self.context.status) == self.context.status ): apply_patch(self.request, save=False, src=self.context.serialize()) elif ( self.request.authenticated_role == "tender_owner" and self.context.status == "claim" and data.get("resolution", self.context.resolution) and len(data.get("resolution", self.context.resolution or "")) >= 20 and data.get("resolutionType", self.context.resolutionType) and data.get("status", self.context.status) == "answered" ): apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAnswered = get_now() elif self.request.authenticated_role == "tender_owner" and self.context.status == "pending": apply_patch(self.request, save=False, src=self.context.serialize()) # reviewers elif ( self.request.authenticated_role == "reviewers" and self.context.status == "pending" and data.get("status", self.context.status) == self.context.status ): apply_patch(self.request, save=False, src=self.context.serialize()) elif ( self.request.authenticated_role == "reviewers" and self.context.status == "pending" and data.get("status", self.context.status) in ["resolved", "invalid", "declined"] ): apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() else: self.request.errors.add("body", "data", "Can't update complaint") self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in ["draft", "claim", "answered", "pending"] and tender.status in [ "active.qualification", "active.awarded", ]: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info( "Updated tender award complaint {}".format(self.context.id), extra=context_unpack(self.request, {"MESSAGE_ID": "tender_award_complaint_patch"}), ) return {"data": self.context.serialize("view")}
def check_status(request): tender = request.validated["tender"] now = get_now() if ( not tender.lots and tender.status == "active.tendering" and tender.tenderPeriod.endDate <= now and not has_unanswered_complaints(tender) and not has_unanswered_questions(tender) ): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info( "Switched tender {} to {}".format(tender["id"], "active.auction"), extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.auction"}), ) tender.status = "active.auction" remove_draft_bids(request) check_bids(request) if tender.numberOfBids < 2 and tender.auctionPeriod: tender.auctionPeriod.startDate = None return elif ( tender.lots and tender.status == "active.tendering" and tender.tenderPeriod.endDate <= now and not has_unanswered_complaints(tender) and not has_unanswered_questions(tender) ): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info( "Switched tender {} to {}".format(tender["id"], "active.auction"), extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_active.auction"}), ) tender.status = "active.auction" remove_draft_bids(request) check_bids(request) [setattr(i.auctionPeriod, "startDate", None) for i in tender.lots if i.numberOfBids < 2 and i.auctionPeriod] return elif not tender.lots and tender.status == "active.awarded": standStillEnds = [a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) elif tender.lots and tender.status in ["active.qualification", "active.awarded"]: if any([i["status"] in tender.block_complaint_status and i.relatedLot is None for i in tender.complaints]): return for lot in tender.lots: if lot["status"] != "active": continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: check_tender_status(request) return
def check_status(request): tender = request.validated['tender'] now = get_now() if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \ not any([i.status in BLOCK_COMPLAINT_STATUS for i in tender.complaints]) and \ not any([i.id for i in tender.questions if not i.answer]): for complaint in tender.complaints: check_complaint_status(request, complaint) LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'})) tender.status = 'active.pre-qualification' tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now}) check_initial_bids_count(request) prepare_qualifications(request) return elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([ i.status in BLOCK_COMPLAINT_STATUS for q in tender.qualifications for i in q.complaints ]): LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'})) tender.status = 'active.auction' check_initial_bids_count(request) return elif not tender.lots and tender.status == 'active.awarded': standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in tender.awards if a.complaintPeriod.endDate ] if not standStillEnds: return standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for i in tender.complaints ]) pending_awards_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for a in tender.awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in tender.awards ]) if not pending_complaints and not pending_awards_complaints and not awarded: LOGGER.info('Switched tender {} to {}'.format(tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_unsuccessful'})) check_tender_status(request) return elif tender.lots and tender.status in ['active.qualification', 'active.awarded']: if any([i['status'] in ['claim', 'answered', 'pending'] for i in tender.complaints]): return lots_ends = [] for lot in tender.lots: if lot['status'] != 'active': continue lot_awards = [i for i in tender.awards if i.lotID == lot.id] standStillEnds = [ a.complaintPeriod.endDate.astimezone(TZ) for a in lot_awards if a.complaintPeriod.endDate ] if not standStillEnds: continue standStillEnd = max(standStillEnds) if standStillEnd <= now: pending_awards_complaints = any([ i['status'] in ['claim', 'answered', 'pending'] for a in lot_awards for i in a.complaints ]) awarded = any([ i['status'] == 'active' for i in lot_awards ]) if not pending_awards_complaints and not awarded: LOGGER.info('Switched lot {} of tender {} to {}'.format(lot['id'], tender.id, 'unsuccessful'), extra=context_unpack(request, {'MESSAGE_ID': 'switched_lot_unsuccessful'}, {'LOT_ID': lot['id']})) check_tender_status(request)
def patch(self): """Post a complaint resolution """ tender = self.request.validated['tender'] if tender.status != 'active.tendering': self.request.errors.add('body', 'data', 'Can\'t update complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted', 'satisfied']: 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', 'accepted'] and data.get('status', self.context.status) == 'cancelled': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateCanceled = get_now() elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status == 'draft' and data.get('status', self.context.status) == 'claim': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -CLAIM_SUBMIT_TIME): self.request.errors.add('body', 'data', 'Can submit claim not later than {0.days} days before tenderPeriod end'.format(CLAIM_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and tender.status == 'active.tendering' and self.context.status in ['draft', 'claim'] and data.get('status', self.context.status) == 'pending': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -COMPLAINT_SUBMIT_TIME): self.request.errors.add('body', 'data', 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateSubmitted = get_now() elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is True and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get('satisfied', self.context.satisfied) is False and data.get('status', self.context.status) == 'pending': if get_now() > calculate_business_date(tender.tenderPeriod.endDate, -COMPLAINT_SUBMIT_TIME): self.request.errors.add('body', 'data', 'Can submit complaint not later than {0.days} days before tenderPeriod end'.format(COMPLAINT_SUBMIT_TIME)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.type = 'complaint' self.context.dateEscalated = get_now() # tender_owner elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['claim', 'satisfied'] and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get('resolution', self.context.resolution) and data.get('resolutionType', self.context.resolutionType) and data.get('status', self.context.status) == 'answered': if len(data.get('resolution', self.context.resolution)) < 20: self.request.errors.add('body', 'data', 'Can\'t update complaint: resolution too short') self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAnswered = get_now() elif self.request.authenticated_role == 'tender_owner' and self.context.status in ['pending', 'accepted']: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get('tendererAction', self.context.tendererAction) and data.get('status', self.context.status) == 'resolved': apply_patch(self.request, save=False, src=self.context.serialize()) # aboveThresholdReviewers elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'invalid': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() self.context.acceptance = False elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get('status', self.context.status) == 'accepted': apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateAccepted = get_now() self.context.acceptance = True elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) == self.context.status: apply_patch(self.request, save=False, src=self.context.serialize()) elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['declined', 'satisfied']: apply_patch(self.request, save=False, src=self.context.serialize()) self.context.dateDecision = get_now() else: self.request.errors.add('body', 'data', 'Can\'t update complaint') self.request.errors.status = 403 return if self.context.tendererAction and not self.context.tendererActionDate: self.context.tendererActionDate = get_now() if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted'] and tender.status in ['active.qualification', 'active.awarded']: check_tender_status(self.request) if save_tender(self.request): self.LOGGER.info('Updated tender complaint {}'.format(self.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_patch'})) return {'data': self.context.serialize("view")}
def patch(self): """Tender Edit (partial) For example here is how procuring entity can change number of items to be procured and total Value of a tender: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "tenderID": "UA-64e93250be76435397e8c992ed4214d1", "dateModified": "2014-10-27T08:12:34.956Z", "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } """ tender = self.request.validated['tender'] if self.request.authenticated_role != 'Administrator' and tender.status in ['complete', 'unsuccessful', 'cancelled']: self.request.errors.add('body', 'data', 'Can\'t update tender in current ({}) status'.format(tender.status)) self.request.errors.status = 403 return data = self.request.validated['data'] if self.request.authenticated_role == 'tender_owner' and 'status' in data and data['status'] not in ['cancelled', tender.status]: self.request.errors.add('body', 'data', 'Can\'t update tender status') self.request.errors.status = 403 return if self.request.authenticated_role == 'chronograph' and tender.status == 'active.tendering' and data.get('status', tender.status) == 'active.auction': apply_patch(self.request, save=False, src=self.request.validated['tender_src']) check_bids(self.request) save_tender(self.request) elif self.request.authenticated_role == 'chronograph' and tender.status in ['active.qualification', 'active.awarded'] and data.get('status', tender.status) == tender.status: check_tender_status(self.request) save_tender(self.request) else: apply_patch(self.request, src=self.request.validated['tender_src']) LOGGER.info('Updated tender {}'.format(tender.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'})) return {'data': tender.serialize(tender.status)}