def alertAvailableFor()

in membership-attribute-service/app/services/PaymentFailureAlerter.scala [86:125]


  def alertAvailableFor(
      account: AccountObject,
      subscription: Subscription,
      paymentMethodGetter: PaymentMethodId => Future[Either[String, PaymentMethodResponse]],
      catalog: Catalog,
  )(implicit ec: ExecutionContext): Future[Boolean] = {
    def isAlertableProduct = !nonAlertableProducts.contains(subscription.plan(catalog).product(catalog))

    def creditCard(paymentMethodResponse: PaymentMethodResponse) =
      paymentMethodResponse.paymentMethodType == "CreditCardReferenceTransaction" || paymentMethodResponse.paymentMethodType == "CreditCard"

    val stillFreshInDays = 27
    def recentEnough(lastInvoiceDateTime: DateTime) = lastInvoiceDateTime.plusDays(stillFreshInDays).isAfterNow
    val isActionablePaymentGateway = account.PaymentGateway.exists(gw => gw == StripeUKMembershipGateway || gw == StripeAUMembershipGateway)

    def hasFailureForCreditCardPaymentMethod(paymentMethodId: PaymentMethodId): Future[Either[String, Boolean]] = {
      val eventualPaymentMethod: Future[Either[String, PaymentMethodResponse]] = paymentMethodGetter(paymentMethodId)
      eventualPaymentMethod map { maybePaymentMethod: Either[String, PaymentMethodResponse] =>
        maybePaymentMethod.map { pm: PaymentMethodResponse =>
          creditCard(pm) && pm.numConsecutiveFailures > 0
        }
      }
    }

    val alertAvailable = for {
      invoiceDate: DateTime <- account.LastInvoiceDate
      paymentMethodId: PaymentMethodId <- account.DefaultPaymentMethodId
    } yield {
      if (
        isAlertableProduct &&
        account.Balance > 0 &&
        isActionablePaymentGateway &&
        !subscription.isCancelled &&
        recentEnough(invoiceDate)
      ) hasFailureForCreditCardPaymentMethod(paymentMethodId)
      else Future.successful(Right(false))
    }.map(_.getOrElse(false))

    alertAvailable.getOrElse(Future.successful(false))
  }