in lib/zuora-core/src/main/scala/com/gu/zuora/subscription/RatePlanChargeBillingSchedule.scala [157:198]
private def apply(
ratePlanStartDate: LocalDate,
ratePlanEndDate: Option[LocalDate],
billingPeriod: BillingPeriod,
): RatePlanChargeBillingSchedule = {
new RatePlanChargeBillingSchedule {
override def isDateCoveredBySchedule(date: LocalDate): Boolean = {
(date == ratePlanStartDate || date.isAfter(ratePlanStartDate)) &&
ratePlanEndDate
.map(endDate => date == endDate || date.isBefore(endDate))
.getOrElse(true)
}
override def billDatesCoveringDate(date: LocalDate): Either[ZuoraApiFailure, BillDates] = {
if (isDateCoveredBySchedule(date)) {
billDatesCoveringDate(date, ratePlanStartDate, 0)
} else {
ZuoraApiFailure(s"Billing schedule does not cover date $date").asLeft
}
}
@tailrec
private def billDatesCoveringDate(
date: LocalDate,
startDate: LocalDate,
billingPeriodIndex: Int,
): Either[ZuoraApiFailure, BillDates] = {
val currentPeriod = BillDates(
startDate.plus(billingPeriod.multiple.toLong * billingPeriodIndex, billingPeriod.unit),
startDate.plus(billingPeriod.multiple.toLong * (billingPeriodIndex + 1), billingPeriod.unit).minusDays(1),
)
if (currentPeriod.startDate.isAfter(date)) {
ZuoraApiFailure(s"Billing schedule does not cover date $date").asLeft
} else if (!currentPeriod.endDate.isBefore(date)) {
currentPeriod.asRight
} else {
billDatesCoveringDate(date, startDate, billingPeriodIndex + 1)
}
}
}
}