private[productmove] def runWithEnvironment()

in handlers/product-move-api/src/main/scala/com/gu/productmove/endpoint/available/AvailableProductMovesEndpoint.scala [130:221]


  private[productmove] def runWithEnvironment(
      subscriptionName: SubscriptionName,
  ): RIO[GetSubscription with GetCatalogue with GetAccount with Stage, OutputBody] = {
    val output = for {
      stage <- ZIO.service[Stage]
      monthlyContributionRatePlanId =
        if (stage == Stage.CODE) "2c92c0f85a6b134e015a7fcd9f0c7855" else "2c92a0fc5aacfadd015ad24db4ff5e97"

      _ <- ZIO.log("subscription name: " + subscriptionName)

      // Kick off catalogue fetch in parallel
      zuoraProductCatalogueFetch <- GetCatalogue.get.fork
      subscription <- GetSubscription.get(
        subscriptionName,
      ) // TODO add code to return 404 rather than 500 if it's not found

      ratePlan <- getSingleOrNotEligible(subscription.ratePlans, s"Subscription: ${subscriptionName.value} , ratePlan")
      _ <- succeedIfEligible(
        ratePlan.productRatePlanId == monthlyContributionRatePlanId,
        s"Subscription: ${subscriptionName.value} is not a monthly contribution",
      )
      charge <- getSingleOrNotEligible(
        ratePlan.ratePlanCharges,
        s"Subscription: ${subscriptionName.value} , ratePlan charge for ratePlan $ratePlan",
      )

      // Next payment date
      chargedThroughDate <- ZIO.fromOption(charge.chargedThroughDate).orElse {
        for {
          _ <- ZIO.log(s"chargedThroughDate is null for subscription ${subscriptionName.value}.")
          resp <- ZIO.fail(AvailableMoves(List()))
        } yield resp
      }

      account <- GetAccount.get(subscription.accountNumber)

      creditCardExpirationDate <- ZIO
        .fromOption(account.basicInfo.defaultPaymentMethod.creditCardExpirationDate)
        .orElse {
          ZIO
            .log(s"Payment method is not a card for subscription ${subscriptionName.value}.")
            .flatMap(_ => ZIO.fail(AvailableMoves(List())))
        }

      paymentMethod <- GetAccount
        .getPaymentMethod(account.basicInfo.defaultPaymentMethod.id)

      today <- Clock.currentDateTime.map(_.toLocalDate)

      /*
      Only show the switch if:
        credit card is not expired (according to zuora)
        User is not in payment failure or has unpaid invoices
        Currency is GBP (initially on day 1 only?)
        Monthly contribution
        Account balance is 0
       */
      accountIsEligible <-
        (for {
          _ <- succeedIfEligible(
            account.subscriptions.length == 1,
            s"More than one subscription for account for subscription: ${subscriptionName.value}",
          )
          _ <- succeedIfEligible(
            account.basicInfo.currency == Currency.GBP,
            s"Subscription: ${subscriptionName.value} not in GBP",
          )
          _ <- succeedIfEligible(
            paymentMethod.NumConsecutiveFailures == 0,
            s"User is in payment failure with subscription: ${subscriptionName.value}",
          )
          _ <- succeedIfEligible(
            creditCardExpirationDate.isAfter(today),
            s"card expired for subscription: ${subscriptionName.value}",
          )
          _ <- succeedIfEligible(
            account.basicInfo.balance == 0,
            s"Account balance is not zero for subscription: ${subscriptionName.value}",
          )
        } yield ()).isSuccess

      _ <- if (accountIsEligible) ZIO.succeed(()) else ZIO.fail(AvailableMoves(List()))

      zuoraProductCatalogue <- zuoraProductCatalogueFetch.join

      productRatePlans = getAvailableSwitchRatePlans(zuoraProductCatalogue, List("Digital Pack"))
      moveToProduct <- ZIO.foreach(productRatePlans) { productRatePlan =>
        MoveToProduct.buildResponseFromRatePlan(subscriptionName, productRatePlan, chargedThroughDate)
      }

      _ <- ZIO.log("done")
    } yield AvailableMoves(moveToProduct)