From 3a7d2855005be3ae4a03ace901e9a5a443440f31 Mon Sep 17 00:00:00 2001 From: "gu-scala-steward-public-repos[bot]" <108136057+gu-scala-steward-public-repos[bot]@users.noreply.github.com> Date: Thu, 27 Jul 2023 10:10:38 +0000 Subject: [PATCH 1/5] Update scalafmt-core to 3.7.11 --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 7b31ee4d..dcd6036c 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.7.10 +version = 3.7.11 runner.dialect = scala213 maxColumn = 120 From 701b378d30b266350a5029adc36e8d775609ac61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Honor=C3=A9?= Date: Sat, 29 Jul 2023 10:42:36 +0100 Subject: [PATCH 2/5] allow supporter plus amendment --- .../scala/pricemigrationengine/handlers/AmendmentHandler.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala index 6fe1f8b4..11c88de3 100644 --- a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala +++ b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala @@ -189,8 +189,7 @@ object AmendmentHandler extends CohortHandler { def handle(input: CohortSpec): ZIO[Logging, Failure, HandlerOutput] = { MigrationType(input) match { - case Membership2023Annuals => ZIO.succeed(HandlerOutput(isComplete = true)) - case SupporterPlus2023V1V2MA => ZIO.succeed(HandlerOutput(isComplete = true)) + case Membership2023Annuals => ZIO.succeed(HandlerOutput(isComplete = true)) case _ => main(input).provideSome[Logging]( EnvConfig.cohortTable.layer, From da4f291d985e37ba4390bdca7c35511591425a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Honor=C3=A9?= Date: Sat, 29 Jul 2023 12:22:17 +0100 Subject: [PATCH 3/5] Allow amendment for membership batch 3 --- .../handlers/AmendmentHandler.scala | 55 ++++++++++--------- .../handlers/AmendmentHandlerTest.scala | 9 ++- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala index 11c88de3..72f671ee 100644 --- a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala +++ b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala @@ -59,14 +59,12 @@ object AmendmentHandler extends CohortHandler { .filterOrFail(_.status != "Cancelled")(CancelledSubscriptionFailure(item.subscriptionName)) def checkExpirationTiming( + cohortSpec: CohortSpec, item: CohortItem, subscription: ZuoraSubscription ): Either[Failure, Unit] = { - // We check that the subscription's end of effective period is after the startDate, to avoid Zuora's error: - // ``` - // The Contract effective date should not be later than the term end date of the basic subscription - // ``` - // Note that this check will be duplicated in the estimation handler (this check in the Amendment handler came first) + // We check that the subscription's end of effective period is after the startDate, to avoid a Zuora's error + // Note that we do not make that check for digital products (notably: Membership2023Annuals and SupporterPlus2023V1V2MA) item.startDate match { case None => @@ -76,14 +74,21 @@ object AmendmentHandler extends CohortHandler { ) ) // This case won't really happen in practice, but item.startDate is an option case Some(startDate) => { - if (subscription.termEndDate.isAfter(startDate)) { - Right(()) - } else { - Left( - ExpiringSubscriptionFailure( - s"Cohort item: ${item.subscriptionName}. The item startDate (price increase date), ${item.startDate}, is after the subscription's end of effective period (${subscription.termEndDate.toString})" - ) - ) + MigrationType(cohortSpec) match { + case Membership2023Annuals => + Right(()) + case SupporterPlus2023V1V2MA => + Right(()) + case _ => + if (subscription.termEndDate.isAfter(startDate)) { + Right(()) + } else { + Left( + ExpiringSubscriptionFailure( + s"Cohort item: ${item.subscriptionName}. The item startDate (price increase date), ${item.startDate}, is after the subscription's end of effective period (${subscription.termEndDate.toString})" + ) + ) + } } } } @@ -109,7 +114,7 @@ object AmendmentHandler extends CohortHandler { subscriptionBeforeUpdate <- fetchSubscription(item) - _ <- ZIO.fromEither(checkExpirationTiming(item, subscriptionBeforeUpdate)) + _ <- ZIO.fromEither(checkExpirationTiming(cohortSpec, item, subscriptionBeforeUpdate)) account <- Zuora.fetchAccount(subscriptionBeforeUpdate.accountNumber, subscriptionBeforeUpdate.subscriptionNumber) @@ -188,18 +193,14 @@ object AmendmentHandler extends CohortHandler { } def handle(input: CohortSpec): ZIO[Logging, Failure, HandlerOutput] = { - MigrationType(input) match { - case Membership2023Annuals => ZIO.succeed(HandlerOutput(isComplete = true)) - case _ => - main(input).provideSome[Logging]( - EnvConfig.cohortTable.layer, - EnvConfig.zuora.layer, - EnvConfig.stage.layer, - DynamoDBZIOLive.impl, - DynamoDBClientLive.impl, - CohortTableLive.impl(input), - ZuoraLive.impl - ) - } + main(input).provideSome[Logging]( + EnvConfig.cohortTable.layer, + EnvConfig.zuora.layer, + EnvConfig.stage.layer, + DynamoDBZIOLive.impl, + DynamoDBClientLive.impl, + CohortTableLive.impl(input), + ZuoraLive.impl + ) } } diff --git a/lambda/src/test/scala/pricemigrationengine/handlers/AmendmentHandlerTest.scala b/lambda/src/test/scala/pricemigrationengine/handlers/AmendmentHandlerTest.scala index 9b641734..3f013c75 100644 --- a/lambda/src/test/scala/pricemigrationengine/handlers/AmendmentHandlerTest.scala +++ b/lambda/src/test/scala/pricemigrationengine/handlers/AmendmentHandlerTest.scala @@ -326,6 +326,9 @@ class AmendmentHandlerTest extends munit.FunSuite { } test("Check subscription's end date versus the cohort item's start (price increase) date") { + val cohortSpec = + CohortSpec("NAME", "Campaign1", LocalDate.of(2023, 7, 14), LocalDate.of(2023, 8, 21)) + // Stage 1 val subscription1 = Fixtures.subscriptionFromJson("Membership2023/Batch1/GBP/subscription.json") val item1 = @@ -333,13 +336,13 @@ class AmendmentHandlerTest extends munit.FunSuite { // subscription1.termEndDate is 2023-11-09 // item's startDate is LocalDate.of(2023, 4, 10) // This is the good case - assertEquals(checkExpirationTiming(item1, subscription1), Right(())) + assertEquals(checkExpirationTiming(cohortSpec, item1, subscription1), Right(())) // Stage 2 val subscription2 = Fixtures.subscriptionFromJson("Membership2023/Batch1/GBP/subscription.json") val item2 = CohortItem("SUBSCRIPTION-NUMBER", NotificationSendDateWrittenToSalesforce, None) // item's startDate is None, this triggers the AmendmentDataFailure - assertEquals(checkExpirationTiming(item2, subscription2).isLeft, true) + assertEquals(checkExpirationTiming(cohortSpec, item2, subscription2).isLeft, true) // Stage 3 val subscription3 = Fixtures.subscriptionFromJson("Membership2023/Batch1/GBP/subscription.json") @@ -348,7 +351,7 @@ class AmendmentHandlerTest extends munit.FunSuite { // subscription3.termEndDate is 2023-11-09 // item's startDate is LocalDate.of(2024, 1, 1) // This triggers the ExpiringSubscriptionFailure case - assertEquals(checkExpirationTiming(item3, subscription3).isLeft, true) + assertEquals(checkExpirationTiming(cohortSpec, item3, subscription3).isLeft, true) } test("SupporterPlus2023V1V2 Amendment (monthly standard)") { From 9389aa818f41b9e6e645880a23cfeeb0f2ae4c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Honor=C3=A9?= Date: Mon, 31 Jul 2023 14:51:17 +0100 Subject: [PATCH 4/5] Renewal before amendment when needed --- .../handlers/AmendmentHandler.scala | 13 +++++++++++++ .../scala/pricemigrationengine/model/Failure.scala | 1 + .../scala/pricemigrationengine/services/Zuora.scala | 5 +++++ .../pricemigrationengine/services/ZuoraLive.scala | 12 ++++++++++++ .../pricemigrationengine/service/MockZuora.scala | 5 +++++ 5 files changed, 36 insertions(+) diff --git a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala index 72f671ee..fb8570d3 100644 --- a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala +++ b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala @@ -94,6 +94,17 @@ object AmendmentHandler extends CohortHandler { } } + private def renewSubscriptionIfNeeded( + subscription: ZuoraSubscription, + startDate: LocalDate + ): ZIO[Zuora, Failure, Unit] = { + if (subscription.termEndDate.isBefore(startDate)) { + Zuora.renewSubscription(subscription.subscriptionNumber) + } else { + ZIO.succeed(()) + } + } + private def doAmendment( cohortSpec: CohortSpec, catalogue: ZuoraProductCatalogue, @@ -116,6 +127,8 @@ object AmendmentHandler extends CohortHandler { _ <- ZIO.fromEither(checkExpirationTiming(cohortSpec, item, subscriptionBeforeUpdate)) + _ <- renewSubscriptionIfNeeded(subscriptionBeforeUpdate, startDate) + account <- Zuora.fetchAccount(subscriptionBeforeUpdate.accountNumber, subscriptionBeforeUpdate.subscriptionNumber) invoicePreviewBeforeUpdate <- diff --git a/lambda/src/main/scala/pricemigrationengine/model/Failure.scala b/lambda/src/main/scala/pricemigrationengine/model/Failure.scala index 9a0b8551..fa0cdaa0 100644 --- a/lambda/src/main/scala/pricemigrationengine/model/Failure.scala +++ b/lambda/src/main/scala/pricemigrationengine/model/Failure.scala @@ -22,6 +22,7 @@ case class CohortUpdateFailure(reason: String) extends Failure case class ZuoraFailure(reason: String) extends Failure case class ZuoraFetchFailure(reason: String) extends Failure case class ZuoraUpdateFailure(reason: String) extends Failure +case class ZuoraRenewalFailure(reason: String) extends Failure case class AmendmentDataFailure(reason: String) extends Failure case class CancelledSubscriptionFailure(reason: String) extends Failure diff --git a/lambda/src/main/scala/pricemigrationengine/services/Zuora.scala b/lambda/src/main/scala/pricemigrationengine/services/Zuora.scala index 39b8798e..5a5ff1ef 100644 --- a/lambda/src/main/scala/pricemigrationengine/services/Zuora.scala +++ b/lambda/src/main/scala/pricemigrationengine/services/Zuora.scala @@ -19,6 +19,8 @@ trait Zuora { subscription: ZuoraSubscription, update: ZuoraSubscriptionUpdate ): ZIO[Any, ZuoraUpdateFailure, ZuoraSubscriptionId] + + def renewSubscription(subscriptionNumber: String): ZIO[Any, ZuoraRenewalFailure, Unit] } object Zuora { @@ -40,4 +42,7 @@ object Zuora { update: ZuoraSubscriptionUpdate ): ZIO[Zuora, ZuoraUpdateFailure, ZuoraSubscriptionId] = ZIO.environmentWithZIO(_.get.updateSubscription(subscription, update)) + + def renewSubscription(subscriptionNumber: String): ZIO[Zuora, ZuoraRenewalFailure, Unit] = + ZIO.environmentWithZIO(_.get.renewSubscription(subscriptionNumber)) } diff --git a/lambda/src/main/scala/pricemigrationengine/services/ZuoraLive.scala b/lambda/src/main/scala/pricemigrationengine/services/ZuoraLive.scala index 1af78e20..c0ffef7f 100644 --- a/lambda/src/main/scala/pricemigrationengine/services/ZuoraLive.scala +++ b/lambda/src/main/scala/pricemigrationengine/services/ZuoraLive.scala @@ -207,6 +207,18 @@ object ZuoraLive { response => response.subscriptionId ) ) <* logging.info(s"Updated subscription ${subscription.subscriptionNumber} with: $update") + + override def renewSubscription(subscriptionNumber: String): ZIO[Any, ZuoraRenewalFailure, Unit] = + retry( + put[Unit]( + path = s"subscriptions/${subscriptionNumber}/renew", + body = "{}" + ).mapBoth( + e => ZuoraRenewalFailure(s"Failed to renew subscription number ${subscriptionNumber}"), + response => () + ) + ) <* logging.info(s"renewed subscription ${subscriptionNumber}") + } ) } diff --git a/lambda/src/test/scala/pricemigrationengine/service/MockZuora.scala b/lambda/src/test/scala/pricemigrationengine/service/MockZuora.scala index 3bd6f55a..cfab3515 100644 --- a/lambda/src/test/scala/pricemigrationengine/service/MockZuora.scala +++ b/lambda/src/test/scala/pricemigrationengine/service/MockZuora.scala @@ -16,6 +16,8 @@ object MockZuora extends Mock[Zuora] { object UpdateSubscription extends Effect[(ZuoraSubscription, ZuoraSubscriptionUpdate), ZuoraUpdateFailure, ZuoraSubscriptionId] + object RenewSubscription extends Effect[String, ZuoraRenewalFailure, Unit] + val compose: URLayer[Proxy, Zuora] = ZLayer.fromZIO(ZIO.service[Proxy].map { proxy => new Zuora { @@ -35,6 +37,9 @@ object MockZuora extends Mock[Zuora] { override def updateSubscription(subscription: ZuoraSubscription, update: ZuoraSubscriptionUpdate) : ZIO[Any, ZuoraUpdateFailure, ZuoraSubscriptionId] = proxy(UpdateSubscription, subscription, update) + + override def renewSubscription(subscriptionNumber: String): ZIO[Any, ZuoraRenewalFailure, Unit] = + proxy(RenewSubscription, subscriptionNumber) } }) } From 48f1c58ff1cb1437a5e6a6441d03e9e38d231986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Honor=C3=A9?= Date: Mon, 31 Jul 2023 15:29:49 +0100 Subject: [PATCH 5/5] Set amendment handler batch size to 100 --- .../scala/pricemigrationengine/handlers/AmendmentHandler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala index fb8570d3..7bacadc0 100644 --- a/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala +++ b/lambda/src/main/scala/pricemigrationengine/handlers/AmendmentHandler.scala @@ -12,7 +12,7 @@ import java.time.LocalDate object AmendmentHandler extends CohortHandler { // TODO: move to config - private val batchSize = 150 + private val batchSize = 100 private def main(cohortSpec: CohortSpec): ZIO[Logging with CohortTable with Zuora, Failure, HandlerOutput] = for {