Skip to content

Commit

Permalink
Merge 2971a5d into f6d5699
Browse files Browse the repository at this point in the history
  • Loading branch information
Mario Galic committed Jul 26, 2019
2 parents f6d5699 + 2971a5d commit 4c7b107
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 62 deletions.
Expand Up @@ -16,36 +16,32 @@ object HolidayCreditUpdate {
def apply(
config: Config,
subscription: Subscription,
stoppedPublicationDate: LocalDate
stoppedPublicationDate: LocalDate,
nextInvoiceStartDate: LocalDate,
maybeExtendedTerm: Option[ExtendedTerm]
): Either[HolidayStopFailure, HolidayCreditUpdate] = {

subscription
.originalRatePlanCharge
.flatMap(_.chargedThroughDate)
.toRight(HolidayStopFailure("Original rate plan charge has no charged through date. A bill run is needed to fix this."))
.map { chargedThroughDate =>
val extendedTerm = ExtendedTerm(chargedThroughDate, subscription)
HolidayCreditUpdate(
currentTerm = extendedTerm.map(_.length),
currentTermPeriodType = extendedTerm.map(_.unit),
Seq(
Add(
productRatePlanId = config.holidayCreditProductRatePlanId,
contractEffectiveDate = chargedThroughDate,
customerAcceptanceDate = chargedThroughDate,
serviceActivationDate = chargedThroughDate,
chargeOverrides = Seq(
ChargeOverride(
productRatePlanChargeId = config.holidayCreditProductRatePlanChargeId,
HolidayStart__c = stoppedPublicationDate,
HolidayEnd__c = stoppedPublicationDate,
price = subscription.originalRatePlanCharge.map(HolidayCredit(_)).getOrElse(0)
)
Right(
HolidayCreditUpdate(
currentTerm = maybeExtendedTerm.map(_.length),
currentTermPeriodType = maybeExtendedTerm.map(_.unit),
Seq(
Add(
productRatePlanId = config.holidayCreditProductRatePlanId,
contractEffectiveDate = nextInvoiceStartDate,
customerAcceptanceDate = nextInvoiceStartDate,
serviceActivationDate = nextInvoiceStartDate,
chargeOverrides = Seq(
ChargeOverride(
productRatePlanChargeId = config.holidayCreditProductRatePlanChargeId,
HolidayStart__c = stoppedPublicationDate,
HolidayEnd__c = stoppedPublicationDate,
price = subscription.originalRatePlanCharge.map(HolidayCredit(_)).getOrElse(0)
)
)
)
)
}
)
)
}
}

Expand Down
Expand Up @@ -51,6 +51,9 @@ object HolidayStopProcess {
result.left.map(ProcessResult.fromOverallFailure).merge
}

/**
* This is the main business logic
*/
def processHolidayStop(
config: Config,
getSubscription: SubscriptionName => Either[HolidayStopFailure, Subscription],
Expand All @@ -59,7 +62,9 @@ object HolidayStopProcess {
for {
subscription <- getSubscription(stop.subscriptionName)
_ <- if (subscription.autoRenew) Right(()) else Left(HolidayStopFailure("Cannot currently process non-auto-renewing subscription"))
holidayCreditUpdate <- HolidayCreditUpdate(config, subscription, stop.stoppedPublicationDate)
nextInvoiceStartDate <- NextBillingPeriodStartDate(subscription)
maybeExtendedTerm = ExtendedTerm(nextInvoiceStartDate, subscription)
holidayCreditUpdate <- HolidayCreditUpdate(config, subscription, stop.stoppedPublicationDate, nextInvoiceStartDate, maybeExtendedTerm)
_ <- if (subscription.hasHolidayStop(stop)) Right(()) else updateSubscription(subscription, holidayCreditUpdate)
updatedSubscription <- getSubscription(stop.subscriptionName)
addedCharge <- updatedSubscription.ratePlanCharge(stop).toRight(HolidayStopFailure("Failed to add charge to subscription"))
Expand Down
@@ -0,0 +1,30 @@
package com.gu.holidaystopprocessor

import java.time.LocalDate

/**
* Holiday credit is applied to the next invoice on the first day of the next billing period.
*
* 'Invoiced period' or `billing period that has already been invoiced` is defined as
* [processedThroughDate, chargedThroughDate) meaning
* - from processedThroughDate inclusive
* - to chargedThroughDate exclusive
*
* Hence chargedThroughDate represents the first day of the next billing period. For quarterly
* billing period this would be the first day of the next quarter, whilst for annual this would be
* the first day of the next year.
*
* Note chargedThroughDate is an API concept. The UI and the actual invoice use the term 'Service Period'
* where from and to dates are both inclusive.
*
* Note nextBillingPeriodStartDate represents a specific date yyyy-mm-dd unlike billingPeriod (quarterly)
* or billingPeriodStartDay (1st of month).
*/
object NextBillingPeriodStartDate {
def apply(subscription: Subscription): Either[HolidayStopFailure, LocalDate] = {
subscription
.originalRatePlanCharge
.flatMap(_.chargedThroughDate)
.toRight(HolidayStopFailure("Original rate plan charge has no charged through date. A bill run is needed to fix this."))
}
}
Expand Up @@ -8,16 +8,22 @@ import org.scalatest.{FlatSpec, Matchers}
class SubscriptionUpdateTest extends FlatSpec with Matchers {

"holidayCreditToAdd" should "generate update correctly" in {
val subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 12),
termEndDate = LocalDate.of(2020, 7, 12),
price = 42.1,
billingPeriod = "Quarter",
chargedThroughDate = Some(LocalDate.of(2019, 9, 12))
)
val nextInvoiceStartDate = NextBillingPeriodStartDate(subscription)
val maybeExtendedTerm = ExtendedTerm(nextInvoiceStartDate.right.get, subscription)

val update = HolidayCreditUpdate(
config,
subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 12),
termEndDate = LocalDate.of(2020, 7, 12),
price = 42.1,
billingPeriod = "Quarter",
chargedThroughDate = Some(LocalDate.of(2019, 9, 12))
),
stoppedPublicationDate = LocalDate.of(2019, 5, 18)
subscription = subscription,
stoppedPublicationDate = LocalDate.of(2019, 5, 18),
nextInvoiceStartDate = nextInvoiceStartDate.right.get,
maybeExtendedTerm = maybeExtendedTerm
)
update shouldBe Right(HolidayCreditUpdate(
currentTerm = None,
Expand All @@ -42,33 +48,35 @@ class SubscriptionUpdateTest extends FlatSpec with Matchers {
}

it should "fail to generate an update when there's no charged-through date" in {
val update = HolidayCreditUpdate(
config,
subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 12),
termEndDate = LocalDate.of(2020, 7, 12),
price = 42.1,
billingPeriod = "Quarter",
chargedThroughDate = None
),
stoppedPublicationDate = LocalDate.of(2019, 5, 18)
val subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 12),
termEndDate = LocalDate.of(2020, 7, 12),
price = 42.1,
billingPeriod = "Quarter",
chargedThroughDate = None
)
update shouldBe Left(HolidayStopFailure(
"Original rate plan charge has no charged through date. A bill run is needed to fix this."
val nextInvoiceStartDate = NextBillingPeriodStartDate(subscription)
nextInvoiceStartDate shouldBe Left(HolidayStopFailure(
"Original rate plan charge has no charged through date. A bill run is needed to fix this."
))
}

it should "generate an update with an extended term when charged-through date of subscription is after its term-end date" in {
val subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 23),
termEndDate = LocalDate.of(2020, 7, 23),
price = 150,
billingPeriod = "Annual",
chargedThroughDate = Some(LocalDate.of(2020, 8, 2))
)
val nextInvoiceStartDate = NextBillingPeriodStartDate(subscription)
val maybeExtendedTerm = ExtendedTerm(nextInvoiceStartDate.right.get, subscription)
val update = HolidayCreditUpdate(
config,
subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 23),
termEndDate = LocalDate.of(2020, 7, 23),
price = 150,
billingPeriod = "Annual",
chargedThroughDate = Some(LocalDate.of(2020, 8, 2))
),
stoppedPublicationDate = LocalDate.of(2019, 8, 6)
subscription = subscription,
stoppedPublicationDate = LocalDate.of(2019, 8, 6),
nextInvoiceStartDate = nextInvoiceStartDate.right.get,
maybeExtendedTerm = maybeExtendedTerm
)
update shouldBe Right(HolidayCreditUpdate(
currentTerm = Some(376),
Expand All @@ -91,16 +99,21 @@ class SubscriptionUpdateTest extends FlatSpec with Matchers {
}

it should "generate an update without an extended term when charged-through date of subscription is on its term-end date" in {
val subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 23),
termEndDate = LocalDate.of(2020, 7, 23),
price = 150,
billingPeriod = "Annual",
chargedThroughDate = Some(LocalDate.of(2020, 7, 23))
)
val nextInvoiceStartDate = NextBillingPeriodStartDate(subscription)
val maybeExtendedTerm = ExtendedTerm(nextInvoiceStartDate.right.get, subscription)
val update = HolidayCreditUpdate(
config,
subscription = Fixtures.mkSubscription(
termStartDate = LocalDate.of(2019, 7, 23),
termEndDate = LocalDate.of(2020, 7, 23),
price = 150,
billingPeriod = "Annual",
chargedThroughDate = Some(LocalDate.of(2020, 7, 23))
),
stoppedPublicationDate = LocalDate.of(2019, 8, 6)
subscription = subscription,
stoppedPublicationDate = LocalDate.of(2019, 8, 6),
nextInvoiceStartDate = nextInvoiceStartDate.right.get,
maybeExtendedTerm = maybeExtendedTerm
)
update shouldBe Right(HolidayCreditUpdate(
currentTerm = None,
Expand Down

0 comments on commit 4c7b107

Please sign in to comment.