def amountPerformance_npv(self): """ Calculated energy service contract performance indicator """ return to_decimal( npv(self.contractDuration.years, self.contractDuration.days, self.yearlyPaymentsPercentage, self.annualCostsReduction, get_tender(self).noticePublicationDate, get_tender(self).NBUdiscountRate))
def test_get_tender(self): period = PeriodEndRequired({ 'startDate': datetime.now(TZ).isoformat(), 'endDate': datetime.now(TZ).isoformat() }) second_period = PeriodEndRequired({ 'startDate': datetime.now(TZ).isoformat(), 'endDate': datetime.now(TZ).isoformat() }) tender = Tender() period._data['__parent__'] = tender second_period._data['__parent__'] = period parent_tender = get_tender(second_period) self.assertEqual(tender, parent_tender) self.assertIsInstance(parent_tender, Tender) self.assertIsInstance(tender, Tender) period._data['__parent__'] = None with self.assertRaises(AttributeError) as e: get_tender(second_period) self.assertEqual(e.exception.message, "'NoneType' object has no attribute '__parent__'")
def amountPerfomance_npv(self): """ Calculated energy service contract perfomance indicator """ return float(npv(self.contractDuration.years, self.contractDuration.days, self.yearlyPaymentsPercentage, self.annualCostsReduction, get_tender(self).__class__.announcementDate or get_tender(self).enquiryPeriod.startDate, get_tender(self).NBUdiscountRate))
def validate_yearlyPaymentsPercentage(self, data, value): if get_tender(data['__parent__']).fundingKind == 'other' and ( value < Decimal('0.8') or value > Decimal('1')): raise ValidationError( 'yearlyPaymentsPercentage should be greater than 0.8 and less than 1' ) if get_tender(data['__parent__']).fundingKind == 'budget' and ( value < Decimal('0') or value > get_tender( data['__parent__']).yearlyPaymentsPercentageRange): raise ValidationError( 'yearlyPaymentsPercentage should be greater than 0 and less than {}' .format( get_tender( data['__parent__']).yearlyPaymentsPercentageRange))
def validate_reviewPlace(self, data, reviewPlace): tender_date = get_first_revision_date(get_tender(data["__parent__"]), default=get_now()) if tender_date < RELEASE_2020_04_19: return if not reviewPlace and data.get("status") == "accepted": raise ValidationError(u"This field is required.")
def validate_startDate(self, data, value): tender = get_tender(data['__parent__']) if (tender.revisions[0].date if tender.revisions else get_now()) < PERIOD_END_REQUIRED_FROM: return if value and data.get('endDate') and data.get('endDate') < value: raise ValidationError(u"period should begin before its end")
def validate_relatedLot(self, data, relatedLot): if isinstance(data['__parent__'], Model) and ( data['__parent__'].status not in ('invalid', 'deleted', 'draft')) and relatedLot not in [ i.id for i in get_tender(data['__parent__']).lots ]: raise ValidationError(u"relatedLot should be one of lots")
def validate_startDate(self, data, value): tender = get_tender(data["__parent__"]) tender_date = get_first_revision_date(tender, default=get_now()) if tender_date < PERIOD_END_REQUIRED_FROM: return if value and data.get("endDate") and data.get("endDate") < value: raise ValidationError(u"period should begin before its end")
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_tender_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: decision_dates = [ datetime.combine( complaint.dateDecision.date() + timedelta(days=3), time(0, tzinfo=complaint.dateDecision.tzinfo)) for qualification in tender.qualifications for complaint in qualification.complaints if complaint.dateDecision ] decision_dates.append(tender.qualificationPeriod.endDate) start_after = max(decision_dates) if start_after: return rounding_shouldStartAfter(start_after, tender).isoformat()
def serialize(self, role=None, context=None): if role == 'view' and self.type == 'claim' and get_tender( self).status in [ 'active.tendering', 'active.pre-qualification', 'active.pre-qualification.stand-still', 'active.auction' ]: role = 'view_claim' return super(Complaint, self).serialize(role=role, context=context)
def validate_value(self, data, value): if value and isinstance(data['__parent__'], Model) and (data['__parent__'].status not in ('invalid', 'deleted', 'draft')) and data['relatedLot']: lots = [i for i in get_tender(data['__parent__']).lots if i.id == data['relatedLot']] if not lots: return lot = lots[0] if lot.minValue.amount > value.amount: raise ValidationError(u"value of bid should be greater than minValue of lot")
def amount_escp(self): return to_decimal( escp( self.contractDuration.years, self.contractDuration.days, self.yearlyPaymentsPercentage, self.annualCostsReduction, get_tender(self).noticePublicationDate, ))
def validate_relatedItem(self, data, relatedItem): if not relatedItem and data.get("documentOf") in ["item"]: raise ValidationError(u"This field is required.") parent = data["__parent__"] if relatedItem and isinstance(parent, Model): tender = get_tender(parent) items = [i.id for i in tender.items if i] if data.get("documentOf") == "item" and relatedItem not in items: raise ValidationError(u"relatedItem should be one of items")
def validate_rejectReason(self, data, rejectReason): tender_date = get_first_revision_date(get_tender(data["__parent__"]), default=get_now()) if tender_date < RELEASE_2020_04_19: return if not rejectReason and data.get("status") in [ "invalid", "stopped" ] and data.get("type") == "complaint": raise ValidationError(u"This field is required.")
def validate_relatedBuyer(self, data, related_buyer): tender = get_tender(data["__parent__"]) validation_date = get_first_revision_date(tender, default=get_now()) validation_enabled = all([ tender.buyers, tender.status != "draft", validation_date >= MULTI_CONTRACTS_REQUIRED_FROM ]) if validation_enabled and not related_buyer: raise ValidationError(BaseType.MESSAGES["required"])
def serialize(self, role=None, context=None): if (role == "view" and self.type == "claim" and get_tender(self).status in [ "active.tendering", "active.pre-qualification", "active.pre-qualification.stand-still", "active.auction", ]): role = "view_claim" return super(Complaint, self).serialize(role=role, context=context)
def validate_value(self, data, value): if value and isinstance(data['__parent__'], Model) and (data['__parent__'].status not in ('invalid', 'deleted', 'draft')) and data['relatedLot']: lots = [i for i in get_tender(data['__parent__']).lots if i.id == data['relatedLot']] if not lots: return lot = lots[0] if lot.value.amount < value.amount: raise ValidationError(u"value of bid should be less than value of lot") if lot.get('value').currency != value.currency: raise ValidationError(u"currency of bid should be identical to currency of value of lot") if lot.get('value').valueAddedTaxIncluded != value.valueAddedTaxIncluded: raise ValidationError(u"valueAddedTaxIncluded of bid should be identical to valueAddedTaxIncluded of value of lot")
def validate_value(self, data, value): parent = data["__parent__"] if value and isinstance(parent, Model) and parent.status not in self.skip and data["relatedLot"]: lots = [lot for lot in get_tender(parent).lots if lot and lot.id == data["relatedLot"]] if not lots: return lot = lots[0] if lot.get("minValue").currency != value.currency: raise ValidationError(u"currency of bid should be identical to currency of minValue of lot") if lot.get("minValue").valueAddedTaxIncluded != value.valueAddedTaxIncluded: raise ValidationError( u"valueAddedTaxIncluded of bid should be identical to valueAddedTaxIncluded of minValue of lot" )
def validate_value(self, data, value): if value and isinstance(data['__parent__'], Model) and (data['__parent__'].status not in ('invalid', 'deleted', 'draft')) and data['relatedLot']: lots = [i for i in get_tender(data['__parent__']).lots if i.id == data['relatedLot']] if not lots: return lot = lots[0] tender = lot['__parent__'] amount = calculate_npv(tender.NBUdiscountRate, value.annualCostsReduction, value.yearlyPayments, value.contractDuration) #XXX: Calculating value.amount manually if lot.minValue.amount > amount: raise ValidationError(u"value of bid should be greater than minValue of lot") if lot.get('minValue').currency != value.currency: raise ValidationError(u"currency of bid should be identical to currency of minValue of lot") if lot.get('minValue').valueAddedTaxIncluded != value.valueAddedTaxIncluded: raise ValidationError(u"valueAddedTaxIncluded of bid should be identical to valueAddedTaxIncluded of minValue of lot")
def shouldStartAfter(self): if self.endDate: return tender = get_tender(self) lot = self.__parent__ if tender.status not in ["active.tendering", "active.auction"] or lot.status != "active": return if tender.status == "active.auction" and lot.numberOfBids < 2: return if self.startDate and get_now() > calc_auction_end_time(lot.numberOfBids, self.startDate): start_after = calc_auction_end_time(tender.numberOfBids, self.startDate) else: start_after = tender.tenderPeriod.endDate return rounding_shouldStartAfter(start_after, tender).isoformat()
def shouldStartAfter(self): if self.endDate: return tender = get_tender(self) lot = self.__parent__ if tender.status not in ['active.tendering', 'active.auction'] or lot.status != 'active': return if tender.status == 'active.auction' and lot.numberOfBids < 2: return if self.startDate and get_now() > calc_auction_end_time(lot.numberOfBids, self.startDate): return calc_auction_end_time(lot.numberOfBids, self.startDate).isoformat() else: decision_dates = [ datetime.combine(complaint.dateDecision.date() + timedelta(days=3), time(0, tzinfo=complaint.dateDecision.tzinfo)) for complaint in tender.complaints if complaint.dateDecision ] decision_dates.append(tender.tenderPeriod.endDate) return max(decision_dates).isoformat()
def validate_yearlyPaymentsPercentage(self, data, value): parent = data["__parent__"] tender = get_tender(parent) if tender.fundingKind == "other" and value < Decimal("0.8"): raise ValidationError( "yearlyPaymentsPercentage should be greater than 0.8 and less than 1" ) if tender.fundingKind == "budget": if tender.lots: lots = [i for i in tender.lots if i.id == parent["relatedLot"]] if lots and value > lots[0].yearlyPaymentsPercentageRange: raise ValidationError( "yearlyPaymentsPercentage should be greater than 0 and less than {}" .format(lots[0].yearlyPaymentsPercentageRange)) else: if value > tender.yearlyPaymentsPercentageRange: raise ValidationError( "yearlyPaymentsPercentage should be greater than 0 and less than {}" .format(tender.yearlyPaymentsPercentageRange))
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_yearlyPaymentsPercentage(self, data, value): tender = get_tender(data['__parent__']) if tender.fundingKind == 'other' and value < Decimal('0.8'): raise ValidationError( 'yearlyPaymentsPercentage should be greater than 0.8 and less than 1' ) if tender.fundingKind == 'budget': if tender.lots: lots = [ i for i in tender.lots if i.id == data['__parent__']['relatedLot'] ] if lots and value > lots[0].yearlyPaymentsPercentageRange: raise ValidationError( 'yearlyPaymentsPercentage should be greater than 0 and less than {}' .format(lots[0].yearlyPaymentsPercentageRange)) else: if value > tender.yearlyPaymentsPercentageRange: raise ValidationError( 'yearlyPaymentsPercentage should be greater than 0 and less than {}' .format(tender.yearlyPaymentsPercentageRange))
def shouldStartAfter(self): if self.endDate: return tender = get_tender(self) lot = self.__parent__ if tender.status not in ['active.tendering', 'active.auction' ] or lot.status != 'active': return if tender.status == 'active.auction' and lot.numberOfBids < 2: return if self.startDate and get_now() > calc_auction_end_time( lot.numberOfBids, self.startDate): return calc_auction_end_time(lot.numberOfBids, self.startDate).isoformat() else: decision_dates = [ datetime.combine( complaint.dateDecision.date() + timedelta(days=3), time(0, tzinfo=complaint.dateDecision.tzinfo)) for complaint in tender.complaints if complaint.dateDecision ] decision_dates.append(tender.tenderPeriod.endDate) return max(decision_dates).isoformat()
def validate_relatedLot(self, data, relatedLot): parent = data["__parent__"] if isinstance(parent, Model) and parent.status not in self.skip: validate_relatedlot(get_tender(parent), relatedLot)
def validate_value(self, data, value): parent = data["__parent__"] if isinstance(parent, Bid) and parent.status not in self.skip: validate_lotvalue_value(get_tender(parent), data["relatedLot"], value)
def validate_id(self, data, lot_id): if lot_id and isinstance(data['__parent__'], Model) and lot_id not in [i.id for i in get_tender(data['__parent__']).lots]: raise ValidationError(u"id should be one of lots")
def validate_value(self, data, value): if value and isinstance(data['__parent__'], Bid) and ( data['__parent__'].status not in ('invalid', 'deleted', 'draft')) and data['relatedLot']: validate_LotValue_value(get_tender(data['__parent__']), data['relatedLot'], value)
def validate_id(self, data, lot_id): parent = data["__parent__"] if lot_id and isinstance(parent, Model) and lot_id not in [ lot.id for lot in get_tender(parent).lots if lot ]: raise ValidationError(u"id should be one of lots")
def validate_quantity(self, data, value): tender = get_tender(data["__parent__"]) validation_date = get_first_revision_date(tender, default=get_now()) if validation_date >= UNIT_PRICE_REQUIRED_FROM and value is None: raise ValidationError(BaseType.MESSAGES["required"])
def validate_id(self, data, lot_id): if lot_id and isinstance(data['__parent__'], Model) and lot_id not in [ i.id for i in get_tender(data['__parent__']).lots ]: raise ValidationError(u"id should be one of lots")