def nextServiceStartDate()

in lambda/src/main/scala/pricemigrationengine/model/AmendmentData.scala [50:86]


  def nextServiceStartDate(
      invoiceList: ZuoraInvoiceList,
      subscription: ZuoraSubscription,
      onOrAfter: LocalDate
  ): Either[Failure, LocalDate] =
    ZuoraInvoiceItem
      .itemsForSubscription(invoiceList, subscription)
      .map(_.serviceStartDate)
      .sortBy(_.toEpochDay)
      .dropWhile(_.isBefore(onOrAfter))
      .headOption
      .toRight(DataExtractionFailure(s"Cannot determine next billing date on or after $onOrAfter from $invoiceList"))

  def hasNotPriceAndDiscount(ratePlanCharge: ZuoraRatePlanCharge): Boolean =
    ratePlanCharge.price.isDefined ^ ratePlanCharge.discountPercentage.exists(_ > 0)

  def ratePlanCharge(
      subscription: ZuoraSubscription,
      invoiceItem: ZuoraInvoiceItem
  ): Either[Failure, ZuoraRatePlanCharge] =
    ZuoraRatePlanCharge
      .matchingRatePlanCharge(subscription, invoiceItem)
      .filterOrElse(
        hasNotPriceAndDiscount,
        DataExtractionFailure(s"Rate plan charge '${invoiceItem.chargeNumber}' has price and discount")
      )

  def ratePlanChargesOrFail(
      subscription: ZuoraSubscription,
      invoiceItems: Seq[ZuoraInvoiceItem]
  ): Either[DataExtractionFailure, Seq[ZuoraRatePlanCharge]] = {
    val ratePlanCharges = invoiceItems.map(item => ratePlanCharge(subscription, item))
    val failures = ratePlanCharges.collect { case Left(failure) => failure }

    if (failures.isEmpty) Right(ratePlanCharges.collect { case Right(charge) => charge })
    else Left(DataExtractionFailure(failures.map(_.reason).mkString(", ")))
  }