def updateDirectDebit()

in membership-attribute-service/app/controllers/PaymentUpdateController.scala [131:215]


  def updateDirectDebit(subscriptionName: String): Action[AnyContent] =
    AuthorizeForRecentLoginAndScopes(Return401IfNotSignedInRecently, requiredScopes = List(readSelf, updateSelf)).async { implicit request =>
      import request.logPrefix
      metrics.measureDuration("POST /user-attributes/me/update-direct-debit/:subscriptionName") {
        // TODO - refactor to use the Zuora-only based lookup, like in AttributeController.pickAttributes - https://trello.com/c/RlESb8jG

        val updateForm = Form {
          tuple(
            "accountName" -> nonEmptyText,
            "accountNumber" -> nonEmptyText,
            "sortCode" -> nonEmptyText,
            "gatewayOwner" -> optional(text).transform[GatewayOwner](
              GatewayOwner.fromString,
              _.value,
            ),
          )
        }

        val services = request.touchpoint
        val user = request.user
        val userId = user.identityId

        logger.info(s"Attempting to update direct debit")

        (for {
          directDebitDetails <- SimpleEitherT.fromEither(updateForm.bindFromRequest().value.toRight("no direct debit details submitted with request"))
          (bankAccountName, bankAccountNumber, bankSortCode, paymentGatewayOwner) = directDebitDetails
          contact <- SimpleEitherT(services.contactRepository.get(userId).map(_.toEither.flatMap(_.toRight(s"no SF user for $userId"))))
          subscription <- SimpleEitherT(
            services.subscriptionService
              .current(contact)
              .map(subs => subscriptionSelector(memsub.Subscription.SubscriptionNumber(subscriptionName), s"the sfUser $contact", subs)),
          )
          account <- SimpleEitherT(
            annotateFailableFuture(services.zuoraSoapService.getAccount(subscription.accountId), s"get account with id ${subscription.accountId}"),
          )
          billToContact <- SimpleEitherT(
            annotateFailableFuture(services.zuoraSoapService.getContact(account.billToId), s"get billTo contact with id ${account.billToId}"),
          )
          bankTransferPaymentMethod = BankTransfer(
            accountHolderName = bankAccountName,
            accountNumber = bankAccountNumber,
            sortCode = bankSortCode,
            firstName = billToContact.firstName,
            lastName = billToContact.lastName,
            countryCode = "GB",
          )
          paymentGatewayToUse = paymentGatewayOwner match {
            case GatewayOwner.TortoiseMedia => GoCardlessTortoiseMediaGateway
            case _ => GoCardlessGateway
          }
          createPaymentMethod = CreatePaymentMethod(
            accountId = subscription.accountId,
            paymentMethod = bankTransferPaymentMethod,
            paymentGateway = paymentGatewayToUse,
            billtoContact = billToContact,
          )
          _ <- SimpleEitherT(
            annotateFailableFuture(
              services.zuoraSoapService.createPaymentMethod(createPaymentMethod),
              s"create direct debit payment method using ${paymentGatewayToUse.gatewayName}",
            ),
          )
          freshAccount <- SimpleEitherT(
            annotateFailableFuture(
              services.zuoraSoapService.getAccount(subscription.accountId),
              s"get fresh account with id ${subscription.accountId}",
            ),
          )
          freshDefaultPaymentMethodOption <- SimpleEitherT(
            annotateFailableFuture(services.paymentService.getPaymentMethod(freshAccount.defaultPaymentMethodId), "get fresh default payment method"),
          )
          catalog <- SimpleEitherT.rightT(services.futureCatalog)
          productType = subscription.plan(catalog).productType(catalog)
          _ <- sendPaymentMethodChangedEmail(user.primaryEmailAddress, contact, DirectDebit, productType)
        } yield checkDirectDebitUpdateResult(freshDefaultPaymentMethodOption, bankAccountName, bankAccountNumber, bankSortCode)).run
          .map(_.toEither)
          .map {
            case Left(message) =>
              logger.error(scrub"Failed to update direct debit due to $message")
              InternalServerError("")
            case Right(result) => result
          }
      }
    }