diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 3a14ae9..4f2ba05 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -1,5 +1,6 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014 Groupon, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -502,6 +503,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
protected DefaultEntitlement changeEntitlementAndCheckForCompletion(final Entitlement entitlement,
final String productName,
final BillingPeriod billingPeriod,
+ final String priceList,
final BillingActionPolicy billingPolicy,
final NextEvent... events) {
return (DefaultEntitlement) doCallAndCheckForCompletion(new Function<Void, Entitlement>() {
@@ -511,9 +513,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
// Need to fetch again to get latest CTD updated from the system
Entitlement refreshedEntitlement = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
if (billingPolicy == null) {
- refreshedEntitlement = refreshedEntitlement.changePlan(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, callContext);
+ refreshedEntitlement = refreshedEntitlement.changePlan(productName, billingPeriod, priceList, callContext);
} else {
- refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, clock.getUTCNow().toLocalDate(), billingPolicy, callContext);
+ refreshedEntitlement = refreshedEntitlement.changePlanOverrideBillingPolicy(productName, billingPeriod, priceList, clock.getUTCNow().toLocalDate(), billingPolicy, callContext);
}
return refreshedEntitlement;
} catch (EntitlementApiException e) {
@@ -524,6 +526,15 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
}, events);
}
+
+ protected DefaultEntitlement changeEntitlementAndCheckForCompletion(final Entitlement entitlement,
+ final String productName,
+ final BillingPeriod billingPeriod,
+ final BillingActionPolicy billingPolicy,
+ final NextEvent... events) {
+ return changeEntitlementAndCheckForCompletion(entitlement, productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, billingPolicy, events);
+ }
+
protected DefaultEntitlement cancelEntitlementAndCheckForCompletion(final Entitlement entitlement,
final DateTime requestedDate,
final NextEvent... events) {
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index da39b52..a44456c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -1,5 +1,6 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014 Groupon, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -114,4 +115,57 @@ public class TestSubscription extends TestIntegrationBase {
invoiceChecker.checkInvoice(invoices.get(3).getId(), callContext, toBeChecked);
}
+
+ @Test(groups = "slow")
+ public void testChangeOfPlan() throws Exception {
+ // We take april as it has 30 days (easier to play with BCD)
+ final LocalDate today = new LocalDate(2012, 4, 1);
+ final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
+
+ // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
+ clock.setDeltaFromReality(today.toDateTimeAtCurrentTime(DateTimeZone.UTC).getMillis() - clock.getUTCNow().getMillis());
+
+ final String productName = "Shotgun";
+ final BillingPeriod term = BillingPeriod.ANNUAL;
+ final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+ //
+ // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
+ //
+
+ final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, BillingPeriod.ANNUAL, NextEvent.CREATE, NextEvent.INVOICE);
+ assertNotNull(bpEntitlement);
+ assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), callContext).size(), 1);
+
+ assertEquals(bpEntitlement.getSubscriptionBase().getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.ANNUAL);
+
+ // Move out of trials for interesting invoices adjustments
+ busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
+ clock.addDays(40);
+ assertListenerStatus();
+
+ List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+ assertEquals(invoices.size(), 2);
+ ImmutableList<ExpectedInvoiceItemCheck> toBeChecked = ImmutableList.<ExpectedInvoiceItemCheck>of(
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2013, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
+ invoiceChecker.checkInvoice(invoices.get(1).getId(), callContext, toBeChecked);
+
+ //
+ // FORCE AN IMMEDIATE CHANGE TO TEST THE CHANGE_OF_PLAN ALIGNMENT
+ // (Note that, the catalog is configured to use CHANGE_OF_PLAN when moving to that plan and Not CHANGE_OF_PRICELIST which has not been implement;
+ // this is a bit misleading since we are changing pricelist, but in that case pricelist change has no effect)
+ changeEntitlementAndCheckForCompletion(bpEntitlement, "Assault-Rifle", BillingPeriod.ANNUAL, "rescue", BillingActionPolicy.IMMEDIATE, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.INVOICE_ADJUSTMENT, NextEvent.PAYMENT);
+ invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
+ assertEquals(invoices.size(), 3);
+ toBeChecked = ImmutableList.<ExpectedInvoiceItemCheck>of(
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2013, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("2399.95")),
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2013, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-2334.20")),
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2012, 5, 11), InvoiceItemType.CBA_ADJ, new BigDecimal("2334.20")));
+ invoiceChecker.checkInvoice(invoices.get(1).getId(), callContext, toBeChecked);
+
+ toBeChecked = ImmutableList.<ExpectedInvoiceItemCheck>of(
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2013, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("5835.57")),
+ new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 11), new LocalDate(2012, 5, 11), InvoiceItemType.CBA_ADJ, new BigDecimal("-2334.20")));
+ invoiceChecker.checkInvoice(invoices.get(2).getId(), callContext, toBeChecked);
+ }
}
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 32199b0..a75c96a 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -1,5 +1,6 @@
/*
* Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014 Groupon, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -377,10 +378,10 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
final List<SubscriptionBaseEvent> changeEvents = new ArrayList<SubscriptionBaseEvent>();
// Only add the PHASE if it does not coincide with the CHANGE, if not this is 'just' a CHANGE.
+ changeEvents.add(changeEvent);
if (nextPhaseEvent != null && !nextPhaseEvent.getEffectiveDate().equals(changeEvent.getEffectiveDate())) {
changeEvents.add(nextPhaseEvent);
}
- changeEvents.add(changeEvent);
final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
dao.changePlan(subscription, changeEvents, internalCallContext);