def check_auction_time(self): if self.auctionPeriod and self.auctionPeriod.startDate and self.auctionPeriod.shouldStartAfter \ and self.auctionPeriod.startDate > calculate_business_date(parse_date(self.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): self.auctionPeriod.startDate = None for lot in self.lots: if lot.auctionPeriod and lot.auctionPeriod.startDate and lot.auctionPeriod.shouldStartAfter \ and lot.auctionPeriod.startDate > calculate_business_date(parse_date(lot.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): lot.auctionPeriod.startDate = None
def initialize(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL) self.enquiryPeriod = EnquiryPeriod( dict(startDate=self.tenderPeriod.startDate, endDate=endDate, clarificationsUntil=calculate_business_date( endDate, ENQUIRY_STAND_STILL_TIME, self, True)))
def tender_enquiryPeriod(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME, self) return EnquiryPeriod( dict(startDate=self.tenderPeriod.startDate, endDate=endDate, clarificationsUntil=calculate_business_date( endDate, ENQUIRY_STAND_STILL_TIME, self, True)))
def collection_post(self): """Post a complaint """ tender = self.context if tender.status != 'active.tendering': self.request.errors.add( 'body', 'data', 'Can\'t add complaint in current ({}) tender status'.format( tender.status)) self.request.errors.status = 403 return complaint = self.request.validated['complaint'] if complaint.status == 'claim': 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 complaint.dateSubmitted = get_now() elif complaint.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 complaint.dateSubmitted = get_now() complaint.type = 'complaint' else: complaint.status = 'draft' complaint.complaintID = '{}.{}{}'.format( tender.tenderID, self.server_id, self.complaints_len(tender) + 1) set_ownership(complaint, self.request) tender.complaints.append(complaint) if save_tender(self.request): self.LOGGER.info( 'Created tender complaint {}'.format(complaint.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_create'}, {'complaint_id': complaint.id})) self.request.response.status = 201 self.request.response.headers['Location'] = self.request.route_url( 'Tender Complaints', tender_id=tender.id, complaint_id=complaint.id) return { 'data': complaint.serialize(tender.status), 'access': { 'token': complaint.owner_token } }
def tender_enquiryPeriod(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL, self) return EnquiryPeriod( dict(startDate=self.tenderPeriod.startDate, endDate=endDate, invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate, clarificationsUntil=calculate_business_date( endDate, ENQUIRY_STAND_STILL_TIME, self, True)))
def validate_tenderPeriod(self, data, period): # if data['_rev'] is None when tender was created just now if not data['_rev'] and calculate_business_date( get_now(), -timedelta(minutes=10)) >= period.startDate: raise ValidationError( u"tenderPeriod.startDate should be in greater than current date" ) if period and calculate_business_date(period.startDate, TENDER_PERIOD, data) > period.endDate: raise ValidationError( u"tenderPeriod should be greater than 15 days")
def initialize(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL, self) self.enquiryPeriod = EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate, endDate=endDate, invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate, clarificationsUntil=calculate_business_date(endDate, ENQUIRY_STAND_STILL_TIME, self, True))) now = get_now() self.date = now if self.lots: for lot in self.lots: lot.date = now
def invalidate_bids_data(self): if self.auctionPeriod and self.auctionPeriod.startDate and self.auctionPeriod.shouldStartAfter \ and self.auctionPeriod.startDate > calculate_business_date(parse_date(self.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): self.auctionPeriod.startDate = None for lot in self.lots: if lot.auctionPeriod and lot.auctionPeriod.startDate and lot.auctionPeriod.shouldStartAfter \ and lot.auctionPeriod.startDate > calculate_business_date(parse_date(lot.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): lot.auctionPeriod.startDate = None self.enquiryPeriod.invalidationDate = get_now() for bid in self.bids: if bid.status not in ["deleted", "draft"]: bid.status = "invalid"
def invalidate_bids_data(self): if self.auctionPeriod and self.auctionPeriod.startDate and self.auctionPeriod.shouldStartAfter \ and self.auctionPeriod.startDate > calculate_business_date(parse_date(self.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): self.auctionPeriod.startDate = None for lot in self.lots: if lot.auctionPeriod and lot.auctionPeriod.startDate and lot.auctionPeriod.shouldStartAfter \ and lot.auctionPeriod.startDate > calculate_business_date(parse_date(lot.auctionPeriod.shouldStartAfter), AUCTION_PERIOD_TIME, self, True): lot.auctionPeriod.startDate = None self.enquiryPeriod.invalidationDate = get_now() for bid in self.bids: if bid.status != "deleted": bid.status = "invalid"
def complaintPeriod(self): if self.tenderPeriod.startDate < COMPLAINT_OLD_SUBMIT_TIME_BEFORE: return Period( dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date( self.tenderPeriod.endDate, -COMPLAINT_OLD_SUBMIT_TIME, self))) else: normalized_end = calculate_normalized_date( self.tenderPeriod.endDate, self) return Period( dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(normalized_end, -COMPLAINT_SUBMIT_TIME, self, True)))
def complaintPeriod(self): normalized_end = calculate_normalized_date(self.tenderPeriod.endDate, self) return Period( dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(normalized_end, -COMPLAINT_SUBMIT_TIME, self)))
def validate_update_tender(self, operation): tender = self.request.validated['tender'] if tender.status not in ['active.tendering']: self.request.errors.add('body', 'data', 'Can\'t {} lot in current ({}) tender status'.format(operation, tender.status)) self.request.errors.status = 403 return if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD) > tender.tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by {0.days} days'.format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return return True
def validate_update_tender(self, operation): if self.request.authenticated_role != 'auction' and self.request.validated['tender_status'] not in ['active.tendering', STAGE2_STATUS] or \ self.request.authenticated_role == 'auction' and self.request.validated['tender_status'] not in ['active.auction', 'active.qualification']: self.request.errors.add('body', 'data', 'Can\'t {} document in current ({}) tender status'.format(operation, self.request.validated['tender_status'])) self.request.errors.status = 403 return if self.request.validated['tender_status'] == 'active.tendering' and calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, self.request.validated['tender']) > self.request.validated['tender'].tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by {0.days} days'.format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return return True
def validate_update_tender(self, operation): if self.request.authenticated_role != 'auction' and self.request.validated['tender_status'] != 'active.tendering' or \ self.request.authenticated_role == 'auction' and self.request.validated['tender_status'] not in ['active.auction', 'active.qualification']: self.request.errors.add('body', 'data', 'Can\'t {} document in current ({}) tender status'.format(operation, self.request.validated['tender_status'])) self.request.errors.status = 403 return if self.request.validated['tender_status'] == 'active.tendering' and calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD) > self.request.validated['tender'].tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by {0.days} days'.format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return return True
def shouldStartAfter(self): if self.endDate: return tender = self.__parent__ if tender.lots or tender.status not in ['active.tendering', 'active.pre-qualification.stand-still', 'active.auction']: return if tender.status == 'active.tendering' and tender.tenderPeriod.endDate: return calculate_business_date(tender.tenderPeriod.endDate, TENDERING_AUCTION, tender).isoformat() elif self.startDate and get_now() > calc_auction_end_time(tender.numberOfBids, self.startDate): return calc_auction_end_time(tender.numberOfBids, self.startDate).isoformat() elif tender.qualificationPeriod and tender.qualificationPeriod.endDate: return tender.qualificationPeriod.endDate.isoformat()
def validate_update_tender(self, operation): tender = self.request.validated['tender'] if self.request.authenticated_role != 'auction' and self.request.validated['tender_status'] != 'active.tendering' or \ self.request.authenticated_role == 'auction' and self.request.validated['tender_status'] not in ['active.auction', 'active.qualification']: self.request.errors.add('body', 'data', 'Can\'t {} document in current ({}) tender status'.format(operation, self.request.validated['tender_status'])) self.request.errors.status = 403 return if self.request.validated['tender_status'] == 'active.tendering': if calculate_business_date(get_now(), timedelta(days=7)) >= tender.tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by 7 days') self.request.errors.status = 403 return return True
def collection_post(self): """Post a complaint """ tender = self.context if tender.status != 'active.tendering': self.request.errors.add('body', 'data', 'Can\'t add complaint in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return complaint = self.request.validated['complaint'] if complaint.status == 'claim': 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 complaint.dateSubmitted = get_now() elif complaint.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 complaint.dateSubmitted = get_now() complaint.type = 'complaint' else: complaint.status = 'draft' complaint.complaintID = '{}.{}{}'.format(tender.tenderID, self.server_id, self.complaints_len(tender) + 1) set_ownership(complaint, self.request) tender.complaints.append(complaint) if save_tender(self.request): self.LOGGER.info('Created tender complaint {}'.format(complaint.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_create'}, {'complaint_id': complaint.id})) self.request.response.status = 201 self.request.response.headers['Location'] = self.request.route_url('Tender Complaints', tender_id=tender.id, complaint_id=complaint.id) return { 'data': complaint.serialize(tender.status), 'access': { 'token': complaint.owner_token } }
def shouldStartAfter(self): if self.endDate: return tender = self.__parent__ if tender.lots or tender.status not in ['active.tendering', 'active.pre-qualification.stand-still', 'active.auction']: return start_after = None if tender.status == 'active.tendering' and tender.tenderPeriod.endDate: start_after = calculate_business_date(tender.tenderPeriod.endDate, TENDERING_AUCTION, tender) elif self.startDate and get_now() > calc_auction_end_time(tender.numberOfBids, self.startDate): start_after = calc_auction_end_time(tender.numberOfBids, self.startDate) elif tender.qualificationPeriod and tender.qualificationPeriod.endDate: start_after = tender.qualificationPeriod.endDate if start_after: return rounding_shouldStartAfter(start_after, tender).isoformat()
def validate_update_tender(self, operation): tender = self.request.validated["tender"] if tender.status not in ["active.tendering"]: self.request.errors.add( "body", "data", "Can't {} lot in current ({}) tender status".format(operation, tender.status) ) self.request.errors.status = 403 return if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, tender) > tender.tenderPeriod.endDate: self.request.errors.add( "body", "data", "tenderPeriod should be extended by {0.days} days".format(TENDERING_EXTRA_PERIOD) ) self.request.errors.status = 403 return return True
def shouldStartAfter(self): if self.endDate: return tender = get_tender(self) lot = self.__parent__ if tender.status not in ['active.tendering', 'active.pre-qualification.stand-still', 'active.auction'] or lot.status != 'active': return start_after = None if tender.status == 'active.tendering' and tender.tenderPeriod.endDate: start_after = calculate_business_date(tender.tenderPeriod.endDate, TENDERING_AUCTION, tender) elif self.startDate and get_now() > calc_auction_end_time(lot.numberOfBids, self.startDate): start_after = calc_auction_end_time(lot.numberOfBids, self.startDate) elif tender.qualificationPeriod and tender.qualificationPeriod.endDate: start_after = tender.qualificationPeriod.endDate if start_after: return rounding_shouldStartAfter(start_after, tender).isoformat()
def validate_update_tender(self, operation): tender = self.request.validated['tender'] if tender.status not in ['active.tendering']: self.request.errors.add( 'body', 'data', 'Can\'t {} lot in current ({}) tender status'.format( operation, tender.status)) self.request.errors.status = 403 return if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, tender) > tender.tenderPeriod.endDate: self.request.errors.add( 'body', 'data', 'tenderPeriod should be extended by {0.days} days'.format( TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return return True
def shouldStartAfter(self): if self.endDate: return tender = get_tender(self) lot = self.__parent__ if tender.status not in [ 'active.tendering', 'active.pre-qualification.stand-still', 'active.auction' ] or lot.status != 'active': return if tender.status == 'active.tendering' and tender.tenderPeriod.endDate: return calculate_business_date(tender.tenderPeriod.endDate, TENDERING_AUCTION).isoformat() elif self.startDate and get_now() > calc_auction_end_time( lot.numberOfBids, self.startDate): return calc_auction_end_time(lot.numberOfBids, self.startDate).isoformat() elif tender.qualificationPeriod and tender.qualificationPeriod.endDate: return tender.qualificationPeriod.endDate.isoformat()
def patch(self): """Post an Answer """ tender = self.request.validated['tender'] if tender.status != 'active.tendering': self.request.errors.add('body', 'data', 'Can\'t update question 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.relatedItem]): self.request.errors.add('body', 'data', 'Can update question only in active lot status') self.request.errors.status = 403 return now = get_now() #TODO business days if now > calculate_business_date(tender.enquiryPeriod.endDate, ENQUIRY_STAND_STILL_TIME): self.request.errors.add('body', 'data', 'Can update question only in enquiryPeriod.stand-still') self.request.errors.status = 403 return if apply_patch(self.request, src=self.request.context.serialize()): self.LOGGER.info('Updated tender question {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_question_patch'})) return {'data': self.request.context.serialize(tender.status)}
def patch(self): """Tender Edit (partial) For example here is how procuring entity can change number of items to be procured and total Value of a tender: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "tenderID": "UA-64e93250be76435397e8c992ed4214d1", "dateModified": "2014-10-27T08:12:34.956Z", "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } """ tender = self.context if self.request.authenticated_role != 'Administrator' and tender.status in ['complete', 'unsuccessful', 'cancelled']: self.request.errors.add('body', 'data', 'Can\'t update tender in current ({}) status'.format(tender.status)) self.request.errors.status = 403 return data = self.request.validated['data'] if self.request.authenticated_role == 'tender_owner' and 'status' in data and data['status'] not in ['active.pre-qualification.stand-still', tender.status]: self.request.errors.add('body', 'data', 'Can\'t update tender status') self.request.errors.status = 403 return if self.request.authenticated_role == 'tender_owner' and self.request.validated['tender_status'] == 'active.tendering': if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']: self.request.validated['tender'].tenderPeriod.import_data(data['tenderPeriod']) if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD) > self.request.validated['tender'].tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by {0.days} days'.format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return self.request.validated['tender'].initialize() self.request.validated['data']["enquiryPeriod"] = self.request.validated['tender'].enquiryPeriod.serialize() apply_patch(self.request, save=False, src=self.request.validated['tender_src']) if self.request.authenticated_role == 'chronograph': check_status(self.request) elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering': tender.invalidate_bids_data() elif self.request.authenticated_role == 'tender_owner' and self.request.validated['tender_status'] == 'active.pre-qualification' and tender.status == "active.pre-qualification.stand-still": if all_bids_are_reviewed(self.request): tender.qualificationPeriod.endDate = calculate_business_date(get_now(), COMPLAINT_STAND_STILL) else: self.request.errors.add('body', 'data', 'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified'.format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return save_tender(self.request) self.LOGGER.info('Updated tender {}'.format(tender.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'})) return {'data': tender.serialize(tender.status)}
def patch(self): """Update of award Example request to change the award: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607/awards/71b6c23ed8944d688e92a31ec8c3f61a HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 } } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "date": "2014-10-28T11:44:17.947Z", "status": "active", "suppliers": [ { "id": { "name": "Державне управління справами", "scheme": "https://ns.openprocurement.org/ua/edrpou", "uid": "00037256", "uri": "http://www.dus.gov.ua/" }, "address": { "countryName": "Україна", "postalCode": "01220", "region": "м. Київ", "locality": "м. Київ", "streetAddress": "вул. Банкова, 11, корпус 1" } } ], "value": { "amount": 600, "currency": "UAH", "valueAddedTaxIncluded": true } } } """ tender = self.request.validated['tender'] if tender.status != 'active': self.request.errors.add( 'body', 'data', 'Can\'t update award in current ({}) tender status'.format( tender.status)) self.request.errors.status = 403 return award = self.request.context if not self.validate_lot_cancellation('update'): return award_status = award.status apply_patch(self.request, save=False, src=self.request.context.serialize()) if award.status == "active" and not award.qualified: self.request.errors.add( 'body', 'data', 'Can\'t update award to active status with not qualified') self.request.errors.status = 403 return if award.lotID and \ [aw.lotID for aw in tender.awards if aw.status in['pending', 'active']].count(award.lotID) > 1: self.request.errors.add( 'body', 'lotID', 'Another award is already using this lotID.') self.request.errors.status = 403 return if award_status == 'pending' and award.status == 'active': normalized_end = calculate_normalized_date(get_now(), tender, True) award.complaintPeriod.endDate = calculate_business_date( normalized_end, self.stand_still_delta, tender) tender.contracts.append( type(tender).contracts.model_class({ 'awardID': award.id, 'suppliers': award.suppliers, 'date': get_now(), 'value': award.value, 'items': [i for i in tender.items if i.relatedLot == award.lotID], 'contractID': '{}-{}{}'.format(tender.tenderID, self.server_id, len(tender.contracts) + 1) })) # add_next_award(self.request) elif award_status == 'active' and award.status == 'cancelled' and any( [i.status == 'satisfied' for i in award.complaints]): now = get_now() cancelled_awards = [] for i in tender.awards: if i.lotID != award.lotID: continue if not i.complaintPeriod.endDate or i.complaintPeriod.endDate > now: i.complaintPeriod.endDate = now i.status = 'cancelled' cancelled_awards.append(i.id) for i in tender.contracts: if i.awardID in cancelled_awards: i.status = 'cancelled' elif award_status == 'active' and award.status == 'cancelled': now = get_now() if award.complaintPeriod.endDate > now: award.complaintPeriod.endDate = now for i in tender.contracts: if i.awardID == award.id: i.status = 'cancelled' # add_next_award(self.request) elif award_status == 'pending' and award.status == 'unsuccessful': award.complaintPeriod.endDate = get_now() # add_next_award(self.request) elif award_status == 'unsuccessful' and award.status == 'cancelled' and any( [i.status == 'satisfied' for i in award.complaints]): now = get_now() cancelled_awards = [] for i in tender.awards: if i.lotID != award.lotID: continue if not i.complaintPeriod.endDate or i.complaintPeriod.endDate > now: i.complaintPeriod.endDate = now i.status = 'cancelled' cancelled_awards.append(i.id) for i in tender.contracts: if i.awardID in cancelled_awards: i.status = 'cancelled' elif award_status != award.status: self.request.errors.add( 'body', 'data', 'Can\'t update award in current ({}) status'.format( award_status)) self.request.errors.status = 403 return elif self.request.authenticated_role != 'Administrator' and award_status != 'pending': self.request.errors.add( 'body', 'data', 'Can\'t update award in current ({}) status'.format( award_status)) self.request.errors.status = 403 return if save_tender(self.request): self.LOGGER.info( 'Updated tender award {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_patch'}, {'TENDER_REV': tender.rev})) return {'data': award.serialize("view")}
def patch(self): """Update of award Example request to change the award: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607/awards/71b6c23ed8944d688e92a31ec8c3f61a HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 } } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "date": "2014-10-28T11:44:17.947Z", "status": "active", "suppliers": [ { "id": { "name": "Державне управління справами", "scheme": "https://ns.openprocurement.org/ua/edrpou", "uid": "00037256", "uri": "http://www.dus.gov.ua/" }, "address": { "countryName": "Україна", "postalCode": "01220", "region": "м. Київ", "locality": "м. Київ", "streetAddress": "вул. Банкова, 11, корпус 1" } } ], "value": { "amount": 600, "currency": "UAH", "valueAddedTaxIncluded": true } } } """ tender = self.request.validated['tender'] if tender.status not in ['active.qualification', 'active.awarded']: self.request.errors.add('body', 'data', 'Can\'t update award in current ({}) tender status'.format(tender.status)) self.request.errors.status = 403 return award = self.request.context if any([i.status != 'active' for i in tender.lots if i.id == award.lotID]): self.request.errors.add('body', 'data', 'Can update award only in active lot status') self.request.errors.status = 403 return award_status = award.status apply_patch(self.request, save=False, src=self.request.context.serialize()) if award_status == 'pending' and award.status == 'active': award.complaintPeriod.endDate = calculate_business_date(get_now(), STAND_STILL_TIME) tender.contracts.append(type(tender).contracts.model_class({ 'awardID': award.id, 'suppliers': award.suppliers, 'value': award.value, 'items': [i for i in tender.items if i.relatedLot == award.lotID ], 'contractID': '{}-{}{}'.format(tender.tenderID, self.server_id, len(tender.contracts) +1) })) add_next_award(self.request) elif award_status == 'active' and award.status == 'cancelled': award.complaintPeriod.endDate = get_now() for i in tender.contracts: if i.awardID == award.id: i.status = 'cancelled' add_next_award(self.request) elif award_status == 'pending' and award.status == 'unsuccessful': award.complaintPeriod.endDate = calculate_business_date(get_now(), STAND_STILL_TIME) add_next_award(self.request) elif award_status == 'unsuccessful' and award.status == 'cancelled' and any([i.status == 'satisfied' for i in award.complaints]): if tender.status == 'active.awarded': tender.status = 'active.qualification' tender.awardPeriod.endDate = None now = get_now() award.complaintPeriod.endDate = now cancelled_awards = [] for i in tender.awards: if i.lotID != award.lotID: continue i.complaintPeriod.endDate = now i.status = 'cancelled' cancelled_awards.append(i.id) for i in tender.contracts: if i.awardID in cancelled_awards: i.status = 'cancelled' add_next_award(self.request) else: self.request.errors.add('body', 'data', 'Can\'t update award in current ({}) status'.format(award_status)) self.request.errors.status = 403 return if save_tender(self.request): self.LOGGER.info('Updated tender award {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_award_patch'})) return {'data': award.serialize("view")}
def complaintPeriod(self): return Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(self.tenderPeriod.startDate , COMPLAINT_SUBMIT_TIME, self)))
def initialize(self): self.enquiryPeriod = Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME)))
def tender_enquiryPeriod(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL, self) return EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate, endDate=endDate, invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate, clarificationsUntil=calculate_business_date(endDate, ENQUIRY_STAND_STILL_TIME, self, True)))
def complaintPeriod(self): return Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(self.tenderPeriod.endDate, -COMPLAINT_SUBMIT_TIME)))
def initialize(self): if not self.tenderPeriod.startDate: self.tenderPeriod.startDate = get_now() self.enquiryPeriod = Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME))) if hasattr(self, "auctionPeriod") and hasattr(self.auctionPeriod, "startDate"): self.auctionPeriod.startDate = ""
def validate_tenderPeriod(self, data, period): if period and calculate_business_date(period.startDate, TENDER_PERIOD) > period.endDate: raise ValidationError(u"tenderPeriod should be greater than 15 days")
def tender_enquiryPeriod(self): return Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME)))
def patch(self): """Tender Edit (partial) For example here is how procuring entity can change number of items to be procured and total Value of a tender: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "tenderID": "UA-64e93250be76435397e8c992ed4214d1", "dateModified": "2014-10-27T08:12:34.956Z", "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } """ tender = self.context if self.request.authenticated_role != 'Administrator' and tender.status in [ 'complete', 'unsuccessful', 'cancelled' ]: self.request.errors.add( 'body', 'data', 'Can\'t update tender in current ({}) status'.format( tender.status)) self.request.errors.status = 403 return data = self.request.validated['data'] if self.request.authenticated_role == 'tender_owner' and 'status' in data and data[ 'status'] not in [ 'active.pre-qualification.stand-still', tender.status ]: self.request.errors.add('body', 'data', 'Can\'t update tender status') self.request.errors.status = 403 return if self.request.authenticated_role == 'tender_owner' and self.request.validated[ 'tender_status'] == 'active.tendering': if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']: self.request.validated['tender'].tenderPeriod.import_data( data['tenderPeriod']) if calculate_business_date( get_now(), TENDERING_EXTRA_PERIOD, self.request.validated['tender'] ) > self.request.validated['tender'].tenderPeriod.endDate: self.request.errors.add( 'body', 'data', 'tenderPeriod should be extended by {0.days} days'. format(TENDERING_EXTRA_PERIOD)) self.request.errors.status = 403 return self.request.validated['tender'].initialize() self.request.validated['data'][ "enquiryPeriod"] = self.request.validated[ 'tender'].enquiryPeriod.serialize() apply_patch(self.request, save=False, src=self.request.validated['tender_src']) if self.request.authenticated_role == 'chronograph': check_status(self.request) elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering': tender.invalidate_bids_data() elif self.request.authenticated_role == 'tender_owner' and self.request.validated[ 'tender_status'] == 'active.pre-qualification' and tender.status == "active.pre-qualification.stand-still": if all_bids_are_reviewed(self.request): tender.qualificationPeriod.endDate = calculate_business_date( get_now(), COMPLAINT_STAND_STILL, self.request.validated['tender']) tender.check_auction_time() else: self.request.errors.add( 'body', 'data', 'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified' ) self.request.errors.status = 403 return save_tender(self.request) self.LOGGER.info('Updated tender {}'.format(tender.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'})) return {'data': tender.serialize(tender.status)}
def validate_tenderPeriod(self, data, period): if period and calculate_business_date(period.startDate, TENDER_PERIOD, data, True) > period.endDate: raise ValidationError( u"tenderPeriod should be greater than {0.days} working days". format(TENDER_PERIOD))
def validate_tenderPeriod(self, data, period): # if data['_rev'] is None when tender was created just now if not data['_rev'] and calculate_business_date(get_now(), -timedelta(minutes=10)) >= period.startDate: raise ValidationError(u"tenderPeriod.startDate should be in greater than current date") if period and calculate_business_date(period.startDate, TENDER_PERIOD) > period.endDate: raise ValidationError(u"tenderPeriod should be greater than 15 days")
def patch(self): """Tender Edit (partial) For example here is how procuring entity can change number of items to be procured and total Value of a tender: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "tenderID": "UA-64e93250be76435397e8c992ed4214d1", "dateModified": "2014-10-27T08:12:34.956Z", "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } """ tender = self.context if self.request.authenticated_role != 'Administrator' and tender.status in ['complete', 'unsuccessful', 'cancelled']: self.request.errors.add('body', 'data', 'Can\'t update tender in current ({}) status'.format(tender.status)) self.request.errors.status = 403 return data = self.request.validated['data'] if self.request.authenticated_role == 'tender_owner' and 'status' in data and data['status'] not in ['cancelled', tender.status]: self.request.errors.add('body', 'data', 'Can\'t update tender status') self.request.errors.status = 403 return # TODO move to validators if self.request.authenticated_role == 'tender_owner' and self.request.validated['tender_status'] == 'active.tendering': if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']: self.request.validated['tender'].tenderPeriod.import_data(data['tenderPeriod']) if calculate_business_date(get_now(), timedelta(days=7)) > self.request.validated['tender'].tenderPeriod.endDate: self.request.errors.add('body', 'data', 'tenderPeriod should be extended by 7 days') self.request.errors.status = 403 return self.request.validated['tender'].initialize() self.request.validated['data']["enquiryPeriod"] = self.request.validated['tender'].enquiryPeriod.serialize() self.request.validated['data']["auctionPeriod"] = {'startDate': None} if self.request.authenticated_role == 'chronograph': apply_patch(self.request, save=False, src=self.request.validated['tender_src']) check_status(self.request) save_tender(self.request) else: if tender.status == data.get('status', tender.status): # invalidate bids on tender change data = get_invalidated_bids_data(self.request) else: data = self.request.validated['data'] apply_patch(self.request, data=data, 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)}
def tender_enquiryPeriod(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME, self) return EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate, endDate=endDate, clarificationsUntil=calculate_business_date(endDate, ENQUIRY_STAND_STILL_TIME, self, True)))
def patch(self): """Tender Edit (partial) For example here is how procuring entity can change number of items to be procured and total Value of a tender: .. sourcecode:: http PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1 Host: example.com Accept: application/json { "data": { "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { "data": { "id": "4879d3f8ee2443169b5fbbc9f89fa607", "tenderID": "UA-64e93250be76435397e8c992ed4214d1", "dateModified": "2014-10-27T08:12:34.956Z", "value": { "amount": 600 }, "itemsToBeProcured": [ { "quantity": 6 } ] } } """ tender = self.context if self.request.authenticated_role != "Administrator" and tender.status in [ "complete", "unsuccessful", "cancelled", ]: self.request.errors.add("body", "data", "Can't update tender in current ({}) status".format(tender.status)) self.request.errors.status = 403 return data = self.request.validated["data"] if ( self.request.authenticated_role == "tender_owner" and "status" in data and data["status"] not in ["active.pre-qualification.stand-still", tender.status] ): self.request.errors.add("body", "data", "Can't update tender status") self.request.errors.status = 403 return if ( self.request.authenticated_role == "tender_owner" and self.request.validated["tender_status"] == "active.tendering" ): if "tenderPeriod" in data and "endDate" in data["tenderPeriod"]: self.request.validated["tender"].tenderPeriod.import_data(data["tenderPeriod"]) if ( calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, self.request.validated["tender"]) > self.request.validated["tender"].tenderPeriod.endDate ): self.request.errors.add( "body", "data", "tenderPeriod should be extended by {0.days} days".format(TENDERING_EXTRA_PERIOD), ) self.request.errors.status = 403 return self.request.validated["tender"].initialize() self.request.validated["data"]["enquiryPeriod"] = self.request.validated[ "tender" ].enquiryPeriod.serialize() apply_patch(self.request, save=False, src=self.request.validated["tender_src"]) if self.request.authenticated_role == "chronograph": check_status(self.request) elif self.request.authenticated_role == "tender_owner" and tender.status == "active.tendering": tender.invalidate_bids_data() elif ( self.request.authenticated_role == "tender_owner" and self.request.validated["tender_status"] == "active.pre-qualification" and tender.status == "active.pre-qualification.stand-still" ): if any( [ i["status"] in self.request.validated["tender"].block_complaint_status for q in self.request.validated["tender"]["qualifications"] for i in q["complaints"] ] ): self.request.errors.add( "body", "data", "Can't switch to 'active.pre-qualification.stand-still' before resolve all complaints", ) self.request.errors.status = 403 return if all_bids_are_reviewed(self.request): normalized_date = calculate_normalized_date(get_now(), tender, True) tender.qualificationPeriod.endDate = calculate_business_date( normalized_date, COMPLAINT_STAND_STILL, self.request.validated["tender"] ) tender.check_auction_time() else: self.request.errors.add( "body", "data", "Can't switch to 'active.pre-qualification.stand-still' while not all bids are qualified", ) self.request.errors.status = 403 return save_tender(self.request) self.LOGGER.info( "Updated tender {}".format(tender.id), extra=context_unpack(self.request, {"MESSAGE_ID": "tender_patch"}) ) return {"data": tender.serialize(tender.status)}
def complaintPeriod(self): normalized_end = calculate_normalized_date(self.tenderPeriod.endDate, self) return Period(dict(startDate=self.tenderPeriod.startDate, endDate=calculate_business_date(normalized_end, -COMPLAINT_SUBMIT_TIME, self)))
def validate_tenderPeriod(self, data, period): if period and calculate_business_date(period.startDate, TENDER_PERIOD) > period.endDate: raise ValidationError(u"tenderPeriod should be greater than 5 days")
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 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 initialize(self): endDate = calculate_business_date(self.tenderPeriod.endDate, -ENQUIRY_PERIOD_TIME, self) self.enquiryPeriod = EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate, endDate=endDate, invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate, clarificationsUntil=calculate_business_date(endDate, ENQUIRY_STAND_STILL_TIME, self, True)))