membership-attribute-service/app/services/subscription/CancelSubscription.scala (44 lines of code) (raw):
package services.subscription
import com.gu.memsub
import com.gu.memsub.Subscription.SubscriptionNumber
import com.gu.memsub.subsv2.services.SubscriptionService
import com.gu.monitoring.SafeLogger.LogPrefix
import models.ApiError
import org.joda.time.LocalDate
import scalaz.{EitherT, Monad}
import services.zuora.rest.ZuoraRestService
import utils.SimpleEitherT
import utils.SimpleEitherT.SimpleEitherT
import scala.concurrent.{ExecutionContext, Future}
class CancelSubscription(subscriptionService: SubscriptionService[Future], zuoraRestService: ZuoraRestService)(implicit m: Monad[Future]) {
def cancel(
subscriptionNumber: SubscriptionNumber,
cancellationEffectiveDate: Option[LocalDate],
reason: Option[String],
accountId: memsub.Subscription.AccountId,
endOfTermDate: LocalDate,
)(implicit ec: ExecutionContext, logPrefix: LogPrefix): EitherT[ApiError, Future, Option[LocalDate]] =
(for {
_ <- disableAutoPayOnlyIfAccountHasOneSubscription(accountId).leftMap(message => s"Failed to disable AutoPay: $message")
_ <- reason match {
case Some(r) =>
EitherT(zuoraRestService.updateCancellationReason(subscriptionNumber, r)).leftMap(message =>
s"Failed to update cancellation reason: $message",
)
case None => EitherT.rightT[String, Future, Unit](Future.successful(()))
}
_ <- EitherT(zuoraRestService.cancelSubscription(subscriptionNumber, endOfTermDate, cancellationEffectiveDate)).leftMap(message =>
s"Failed to execute Zuora cancellation proper: $message",
)
} yield cancellationEffectiveDate).leftMap(ApiError(_, "", 500))
/** If user has multiple subscriptions within the same billing account, then disabling auto-pay on the account would stop collecting payments for
* all subscriptions including the non-cancelled ones. In this case debt would start to accumulate in the form of positive Zuora account balance,
* and if at any point auto-pay is switched back on, then payment for the entire amount would be attempted.
*/
def disableAutoPayOnlyIfAccountHasOneSubscription(
accountId: memsub.Subscription.AccountId,
)(implicit ec: ExecutionContext, logPrefix: LogPrefix): SimpleEitherT[Unit] = {
EitherT(subscriptionService.subscriptionsForAccountId(accountId)).flatMap { currentSubscriptions =>
if (currentSubscriptions.size <= 1)
SimpleEitherT(zuoraRestService.disableAutoPay(accountId).map(_.toEither))
else // do not disable auto pay
SimpleEitherT.right({})
}
}
}