in membership-attribute-service/app/services/zuora/rest/SimpleClientZuoraRestService.scala [51:85]
def cancelSubscription(
subscriptionNumber: SubscriptionNumber,
termEndDate: LocalDate,
maybeChargedThroughDate: Option[
LocalDate,
], // FIXME: Optionality should probably be removed and semantics changed to cancellationEffectiveDate (see comments bellow)
)(implicit ex: ExecutionContext, logPrefix: LogPrefix): Future[String \/ Unit] = {
// FIXME: Not always safe assumption. There are multiple scenarios to consider
// 1. Free trial should be explicitly handled: val cancellationEffectiveDate = if(sub.startDate <= today && sub.acceptanceDate > today) LocalDate.now
// 2. If outside trial, and invoiced, ChargedThroughDate should always exist: val cancellationEffectiveDate = ChargedThroughDate
// 3. If outside trial, and invoiced, but ChargedThroughDate does not exist, then it is a likely logic error. Investigate ASAP!. Currently it happens after Contributions amount change.
val cancellationEffectiveDate =
maybeChargedThroughDate.getOrElse(LocalDate.now) // immediate cancellation for subs which aren't yet invoiced (e.g. during digipack trial)
val extendTermIfNeeded = maybeChargedThroughDate
.filter(_.isAfter(termEndDate)) // we need to extend the term if they've paid past their term end date, otherwise cancel call will fail
.map(_ =>
EitherT(
simpleRest.put[RenewSubscriptionCommand, ZuoraResponse](s"subscriptions/${subscriptionNumber.getNumber}/renew", RenewSubscriptionCommand()),
),
)
.getOrElse(EitherT.right[String, Future, ZuoraResponse](ZuoraResponse(success = true)))
val cancelCommand = CancelSubscriptionCommand(cancellationEffectiveDate)
val restResponse = for {
_ <- extendTermIfNeeded
cancelResponse <- EitherT(
simpleRest.put[CancelSubscriptionCommand, ZuoraResponse](s"subscriptions/${subscriptionNumber.getNumber}/cancel", cancelCommand),
)
} yield cancelResponse
unsuccessfulResponseToLeft(restResponse).map(_ => ()).run
}