in membership-attribute-service/app/controllers/ExistingPaymentOptionsController.scala [75:144]
def cardThatWontBeExpiredOnFirstTransaction(cardDetails: PaymentCardDetails): Boolean =
new LocalDate(cardDetails.expiryYear, cardDetails.expiryMonth, 1).isAfter(now.plusMonths(1))
def existingPaymentOptions(currencyFilter: Option[String]): Action[AnyContent] =
AuthorizeForRecentLogin(ContinueRegardlessOfSignInRecency, requiredScopes = List(completeReadSelf)).async { implicit request =>
import request.logPrefix
metrics.measureDuration("GET /user-attributes/me/existing-payment-options") {
implicit val tp: TouchpointComponents = request.touchpoint
val maybeUserId = request.redirectAdvice.userId
val isSignedInRecently = request.redirectAdvice.signInStatus == SignedInRecently
val eligibilityDate = now.minusMonths(3)
val defaultMandateIdIfApplicable = "CLEARED"
def paymentMethodStillValid(paymentMethodOption: Option[PaymentMethod]) = paymentMethodOption match {
case Some(card: PaymentCard) => card.isReferenceTransaction && card.paymentCardDetails.exists(cardThatWontBeExpiredOnFirstTransaction)
case Some(dd: GoCardless) =>
dd.mandateId != defaultMandateIdIfApplicable // i.e. mandateId a real reference and hasn't been cleared in Zuora because of mandate failure
case _ => false
}
def paymentMethodHasNoFailures(paymentMethodOption: Option[PaymentMethod]) =
!paymentMethodOption.flatMap(_.numConsecutiveFailures).exists(_ > 0)
def paymentMethodIsActive(paymentMethodOption: Option[PaymentMethod]) =
!paymentMethodOption.flatMap(_.paymentMethodStatus).contains("Closed")
def currencyMatchesFilter(accountCurrency: Option[Currency]) =
(accountCurrency.map(_.iso), currencyFilter) match {
case (Some(accountCurrencyISO), Some(currencyFilterValue)) => accountCurrencyISO == currencyFilterValue
case (None, Some(_)) => false // if the account has no currency but there is filter the account is not eligible
case _ => true
}
logger.info(s"Attempting to retrieve existing payment options for identity user: ${maybeUserId.mkString}")
val futureEitherListExistingPaymentOption = (for {
groupedSubsList <- ListTEither.fromEitherT(
allSubscriptionsSince(eligibilityDate, maybeUserId, tp.contactRepository, tp.subscriptionService).map(_.toList),
)
(accountId, subscriptions) = groupedSubsList
objectAccount <- ListTEither.singleDisjunction(tp.zuoraRestService.getObjectAccount(accountId).recover { case x =>
-\/[String, ObjectAccount](s"error receiving OBJECT account with account id $accountId. Reason: $x")
}) if currencyMatchesFilter(objectAccount.currency) &&
objectAccount.defaultPaymentMethodId.isDefined
account <- ListTEither.singleRightT(tp.zuoraSoapService.getAccount(accountId))
paymentMethodOption <- ListTEither.single(
tp.paymentService
.getPaymentMethod(account.defaultPaymentMethodId, Some(defaultMandateIdIfApplicable))
.map(Right(_))
.recover { case x => Left(s"error retrieving payment method for account: $accountId. Reason: $x") },
)
if paymentMethodStillValid(paymentMethodOption) &&
paymentMethodHasNoFailures(paymentMethodOption) &&
paymentMethodIsActive(paymentMethodOption)
} yield ExistingPaymentOption(isSignedInRecently, objectAccount, paymentMethodOption, subscriptions)).run.run.map(_.toEither)
for {
catalog <- tp.futureCatalog
result <- futureEitherListExistingPaymentOption.map {
case Right(existingPaymentOptions) =>
logger.info(s"Successfully retrieved eligible existing payment options for identity user: ${maybeUserId.mkString}")
Ok(Json.toJson(consolidatePaymentMethod(existingPaymentOptions.toList).map(_.toJson(catalog))))
case Left(message) =>
logger.warn(s"Unable to retrieve eligible existing payment options for identity user ${maybeUserId.mkString} due to $message")
InternalServerError("Failed to retrieve eligible existing payment options due to an internal error")
}
} yield result
}