private def doUpdate()

in handlers/product-move-api/src/main/scala/com/gu/productmove/endpoint/move/switchtype/RecurringContributionToSupporterPlus.scala [150:307]


  private def doUpdate(
      subscriptionName: SubscriptionName,
      account: GetAccountResponse,
      price: BigDecimal,
      previousAmount: BigDecimal,
      ratePlanCharge: RatePlanCharge,
      currency: Currency,
      currentRatePlan: GetSubscription.RatePlan,
      subscription: GetSubscription.GetSubscriptionResponse,
      csrUserId: Option[String],
      caseId: Option[String],
  ): Task[OutputBody] = {
    import ratePlanCharge.billingPeriod
    for {
      _ <- ZIO.log(
        s"Performing product move update with switch type ${SwitchType.RecurringContributionToSupporterPlus.id}",
      )

      today <- Clock.currentDateTime.map(_.toLocalDate)
      billingPeriod <- ZIO
        .fromOption(ratePlanCharge.billingPeriod)
        .orElseFail(
          new Throwable(
            s"Missing billing period on rate plan charge in rate plan $currentRatePlan ",
          ),
        )
      supporterPlusRatePlanIds <- getRatePlans.getSupporterPlusRatePlanIds(billingPeriod)

      // To avoid problems with charges not aligning correctly with the term and resulting in unpredictable
      // billing dates and amounts, we need to start a new term subscriptions which are switched on any day other
      // than a term start date.
      termStartedToday = subscription.termStartDate.isEqual(today)
      invoiceId <-
        if (termStartedToday)
          updateWithExistingTerm(
            subscriptionName,
            billingPeriod,
            currency,
            currentRatePlan.id,
            price,
          )
        else
          updateWithTermRenewal(
            today,
            subscription.termStartDate,
            subscriptionName,
            billingPeriod,
            currency,
            currentRatePlan.id,
            price,
          )

      // Get the amount of the invoice with which was created by the product switch
      _ <- ZIO.log(s"Invoice generated by update has id of $invoiceId")
      invoiceBalance <- getInvoice.get(invoiceId).map(_.balance)

      /*
        If the amount payable today is less than 0.50, we don't want to collect payment because Stripe has a minimum
        charge of 50 cents. Instead we write-off the invoices in the `adjustNonCollectedInvoices` function.
       */
      paidAmount <-
        if (invoiceBalance == 0) {
          ZIO.succeed(BigDecimal(0))
        } else if (invoiceBalance < 0 || invoiceBalance >= 0.5) {
          // not clear why we would want to create a negative payment, but this logic was already in place
          import account._
          createPayment
            .create(
              basicInfo.id,
              invoiceId,
              basicInfo.defaultPaymentMethod.id,
              invoiceBalance,
              today,
            )
            .as(invoiceBalance)
        } else {
          adjustNonCollectedInvoice(
            invoiceId,
            supporterPlusRatePlanIds,
            subscriptionName,
            invoiceBalance,
          ).as(BigDecimal(0))
        }

      _ <- ZIO.log(s"The amount paid on switch by the customer was $paidAmount")

      identityId <- ZIO
        .fromOption(account.basicInfo.IdentityId__c)
        .orElseFail(new Throwable(s"identityId is null for subscription name ${subscriptionName.value}"))

      emailFuture <- sqs
        .sendEmail(
          message = EmailMessage(
            EmailPayload(
              Address = Some(account.billToContact.workEmail),
              ContactAttributes = EmailPayloadContactAttributes(
                SubscriberAttributes = RCtoSPEmailPayloadProductSwitchAttributes(
                  first_name = account.billToContact.firstName,
                  last_name = account.billToContact.lastName,
                  currency = account.basicInfo.currency.symbol,
                  price = price.setScale(2, BigDecimal.RoundingMode.FLOOR).toString,
                  first_payment_amount = paidAmount.setScale(2, BigDecimal.RoundingMode.FLOOR).toString,
                  date_of_first_payment = today.format(DateTimeFormatter.ofPattern("d MMMM uuuu")),
                  payment_frequency = stringFor(billingPeriod),
                  subscription_id = subscriptionName.value,
                ),
              ),
            ),
            "SV_RCtoSP_Switch",
            account.basicInfo.sfContactId__c,
            Some(identityId),
          ),
        )
        .fork

      salesforceTrackingFuture <- sqs
        .queueSalesforceTracking(
          SalesforceRecordInput(
            subscriptionName.value,
            previousAmount,
            price,
            currentRatePlan.productName,
            currentRatePlan.ratePlanName,
            "Supporter Plus",
            today,
            today,
            paidAmount,
            csrUserId,
            caseId,
          ),
        )
        .fork

      amendSupporterProductDynamoTableFuture <- dynamo
        .writeItem(
          SupporterRatePlanItem(
            subscriptionName.value,
            identityId = identityId.rawIdentityId,
            gifteeIdentityId = None,
            productRatePlanId = supporterPlusRatePlanIds.ratePlanId,
            productRatePlanName = "product-move-api added Supporter Plus Monthly",
            termEndDate = today.plusDays(7),
            contractEffectiveDate = today,
            contributionAmount = None,
          ),
        )
        .fork

      requests = emailFuture
        .zip(salesforceTrackingFuture)
        .zip(amendSupporterProductDynamoTableFuture)

      _ <- requests.join

    } yield Success(
      s"Product move completed successfully with subscription number ${subscriptionName.value} and switch type ${SwitchType.RecurringContributionToSupporterPlus.id}",
    )
  }