killbill-memoizeit

junction: fix BillingEvent for invoice Make invoice ignore

8/27/2012 6:03:43 PM

Details

diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 1721788..c1c3154 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
 import org.mockito.Mockito;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -37,6 +38,7 @@ import com.ning.billing.catalog.MockPlan;
 import com.ning.billing.catalog.MockPlanPhase;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.dbi.MysqlTestingHelper;
@@ -45,6 +47,8 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.invoice.api.InvoiceNotifier;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.generator.InvoiceGenerator;
@@ -95,6 +99,9 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
     private Clock clock;
 
     private CallContext context;
+    private AccountUserApi accountUserApi;
+    private Account account;
+    private Subscription subscription;
 
     @BeforeSuite(groups = "slow")
     public void setup() throws Exception {
@@ -104,6 +111,21 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
         context = new DefaultCallContextFactory(clock).createCallContext("Miracle Max", CallOrigin.TEST, UserType.TEST);
 
         busService.getBus().start();
+
+        accountUserApi = Mockito.mock(AccountUserApi.class);
+        account = Mockito.mock(Account.class);
+
+        final UUID accountId = UUID.randomUUID();
+        Mockito.when(accountUserApi.getAccountById(accountId)).thenReturn(account);
+        Mockito.when(account.getCurrency()).thenReturn(Currency.USD);
+        Mockito.when(account.getId()).thenReturn(accountId);
+        Mockito.when(account.isNotifiedForInvoices()).thenReturn(true);
+        Mockito.when(account.getBillCycleDay()).thenReturn(new MockBillCycleDay(30));
+
+        subscription = Mockito.mock(Subscription.class);
+        final UUID subscriptionId = UUID.randomUUID();
+        Mockito.when(subscription.getId()).thenReturn(subscriptionId);
+        Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
     }
 
     @AfterClass(groups = "slow")
@@ -118,21 +140,8 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
 
     @Test(groups = "slow")
     public void testDryRunInvoice() throws InvoiceApiException, AccountApiException {
-        final UUID accountId = UUID.randomUUID();
-        final UUID subscriptionId = UUID.randomUUID();
-
-        final AccountUserApi accountUserApi = Mockito.mock(AccountUserApi.class);
-        final Account account = Mockito.mock(Account.class);
-
-        Mockito.when(accountUserApi.getAccountById(accountId)).thenReturn(account);
-        Mockito.when(account.getCurrency()).thenReturn(Currency.USD);
-        Mockito.when(account.getId()).thenReturn(accountId);
-        Mockito.when(account.isNotifiedForInvoices()).thenReturn(true);
-        Mockito.when(account.getBillCycleDay()).thenReturn(new MockBillCycleDay(30));
+        final UUID accountId = account.getId();
 
-        final Subscription subscription = Mockito.mock(Subscription.class);
-        Mockito.when(subscription.getId()).thenReturn(subscriptionId);
-        Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
         final BillingEventSet events = new MockBillingEventSet();
         final Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
         final PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
@@ -170,7 +179,77 @@ public class TestInvoiceDispatcher extends InvoicingTestBase {
 
         invoices = invoiceDao.getInvoicesByAccount(accountId);
         Assert.assertEquals(invoices.size(), 1);
+    }
 
+    @Test(groups = "slow")
+    public void testWithOverdueEvents() throws Exception {
+        final BillingEventSet events = new MockBillingEventSet();
+
+        // Initial trial
+        final MockPlan bicycleTrialEvergreen1USD = MockPlan.createBicycleTrialEvergreen1USD();
+        events.add(createMockBillingEvent(account, subscription, new DateTime("2012-05-01T00:03:42.000Z"), bicycleTrialEvergreen1USD,
+                                          new MockPlanPhase(bicycleTrialEvergreen1USD, PhaseType.TRIAL), BigDecimal.ZERO, null, account.getCurrency(), BillingPeriod.NO_BILLING_PERIOD,
+                                          31, 31, BillingModeType.IN_ADVANCE, "CREATE", 1L, SubscriptionTransitionType.CREATE));
+        // Phase change to evergreen
+        events.add(createMockBillingEvent(account, subscription, new DateTime("2012-05-31T00:03:42.000Z"), bicycleTrialEvergreen1USD,
+                                          new MockPlanPhase(bicycleTrialEvergreen1USD, PhaseType.EVERGREEN), null, new BigDecimal("249.95"), account.getCurrency(), BillingPeriod.MONTHLY,
+                                          31, 31, BillingModeType.IN_ADVANCE, "PHASE", 2L, SubscriptionTransitionType.PHASE));
+        // Overdue period
+        events.add(createMockBillingEvent(account, subscription, new DateTime("2012-07-15T00:00:00.000Z"), bicycleTrialEvergreen1USD,
+                                          new MockPlanPhase(bicycleTrialEvergreen1USD, PhaseType.EVERGREEN), null, null, account.getCurrency(), BillingPeriod.NO_BILLING_PERIOD,
+                                          31, 31, BillingModeType.IN_ADVANCE, "", 0L, SubscriptionTransitionType.START_BILLING_DISABLED));
+        events.add(createMockBillingEvent(account, subscription, new DateTime("2012-07-25T00:00:00.000Z"), bicycleTrialEvergreen1USD,
+                                          new MockPlanPhase(bicycleTrialEvergreen1USD, PhaseType.EVERGREEN), null, new BigDecimal("249.95"), account.getCurrency(), BillingPeriod.MONTHLY,
+                                          31, 31, BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.END_BILLING_DISABLED));
+        // Upgrade after the overdue period
+        final MockPlan jetTrialEvergreen1000USD = MockPlan.createJetTrialEvergreen1000USD();
+        events.add(createMockBillingEvent(account, subscription, new DateTime("2012-07-25T00:04:00.000Z"), jetTrialEvergreen1000USD,
+                                          new MockPlanPhase(jetTrialEvergreen1000USD, PhaseType.EVERGREEN), null, new BigDecimal("1000"), account.getCurrency(), BillingPeriod.MONTHLY,
+                                          31, 31, BillingModeType.IN_ADVANCE, "CHANGE", 3L, SubscriptionTransitionType.CHANGE));
+
+        Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(account.getId())).thenReturn(events);
+        final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
+        final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, billingApi, invoiceDao,
+                                                                   invoiceNotifier, locker, busService.getBus(), clock);
+
+        final Invoice invoice = dispatcher.processAccount(account.getId(), new DateTime("2012-07-31T00:00:00.000Z"), false, context);
+        Assert.assertNotNull(invoice);
+
+        final List<InvoiceItem> invoiceItems = invoice.getInvoiceItems();
+        Assert.assertEquals(invoiceItems.size(), 4);
+        Assert.assertEquals(invoiceItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
+        Assert.assertEquals(invoiceItems.get(0).getStartDate(), new LocalDate("2012-05-01"));
+        Assert.assertNull(invoiceItems.get(0).getEndDate());
+        Assert.assertEquals(invoiceItems.get(0).getAmount(), BigDecimal.ZERO);
+        Assert.assertNull(invoiceItems.get(0).getRate());
+
+        Assert.assertEquals(invoiceItems.get(1).getInvoiceItemType(), InvoiceItemType.RECURRING);
+        Assert.assertEquals(invoiceItems.get(1).getStartDate(), new LocalDate("2012-05-31"));
+        Assert.assertEquals(invoiceItems.get(1).getEndDate(), new LocalDate("2012-06-30"));
+        Assert.assertEquals(invoiceItems.get(1).getAmount(), new BigDecimal("249.95"));
+        Assert.assertEquals(invoiceItems.get(1).getRate(), new BigDecimal("249.95"));
+
+        Assert.assertEquals(invoiceItems.get(2).getInvoiceItemType(), InvoiceItemType.RECURRING);
+        Assert.assertEquals(invoiceItems.get(2).getStartDate(), new LocalDate("2012-06-30"));
+        Assert.assertEquals(invoiceItems.get(2).getEndDate(), new LocalDate("2012-07-15"));
+        Assert.assertEquals(invoiceItems.get(2).getAmount(), new BigDecimal("124.98"));
+        Assert.assertEquals(invoiceItems.get(2).getRate(), new BigDecimal("249.95"));
+
+        Assert.assertEquals(invoiceItems.get(3).getInvoiceItemType(), InvoiceItemType.RECURRING);
+        Assert.assertEquals(invoiceItems.get(3).getStartDate(), new LocalDate("2012-07-25"));
+        Assert.assertEquals(invoiceItems.get(3).getEndDate(), new LocalDate("2012-07-31"));
+        Assert.assertEquals(invoiceItems.get(3).getAmount(), new BigDecimal("193.50"));
+        Assert.assertEquals(invoiceItems.get(3).getRate(), new BigDecimal("1000"));
+
+        // Verify common fields
+        for (final InvoiceItem item : invoiceItems) {
+            Assert.assertEquals(item.getAccountId(), account.getId());
+            Assert.assertEquals(item.getBundleId(), subscription.getBundleId());
+            Assert.assertEquals(item.getCurrency(), account.getCurrency());
+            Assert.assertEquals(item.getInvoiceId(), invoice.getId());
+            Assert.assertNull(item.getLinkedItemId());
+            Assert.assertEquals(item.getSubscriptionId(), subscription.getId());
+        }
     }
 
     //MDW add a test to cover when the account auto-invoice-off tag is present
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
index 1262b20..191d8fb 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -197,12 +197,16 @@ public class BlockingCalculator {
         final DateTime effectiveDate = odEventTime;
         final PlanPhase planPhase = previousEvent.getPlanPhase();
         final Plan plan = previousEvent.getPlan();
-        final BigDecimal fixedPrice = BigDecimal.ZERO;
-        final BigDecimal recurringPrice = BigDecimal.ZERO;
+
+        // Make sure to set the fixed price to null and the billing period to NO_BILLING_PERIOD,
+        // which makes invoice disregard this event
+        final BigDecimal fixedPrice = null;
+        final BigDecimal recurringPrice = null;
+        final BillingPeriod billingPeriod = BillingPeriod.NO_BILLING_PERIOD;
+
         final Currency currency = previousEvent.getCurrency();
         final String description = "";
         final BillingModeType billingModeType = previousEvent.getBillingMode();
-        final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
         final SubscriptionTransitionType type = SubscriptionTransitionType.START_BILLING_DISABLED;
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
         final DateTimeZone tz = previousEvent.getTimeZone();
@@ -214,6 +218,7 @@ public class BlockingCalculator {
     }
 
     protected BillingEvent createNewReenableEvent(final DateTime odEventTime, final BillingEvent previousEvent) {
+        // All fields are populated with the event state from before the blocking period, for invoice to resume invoicing
         final Account account = previousEvent.getAccount();
         final BillCycleDay billCycleDay = previousEvent.getBillCycleDay();
         final Subscription subscription = previousEvent.getSubscription();
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
index 82dde85..19af867 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
@@ -41,6 +41,7 @@ import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.MockCatalog;
 import com.ning.billing.catalog.MockCatalogService;
 import com.ning.billing.catalog.api.BillingAlignment;
+import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
@@ -408,7 +409,7 @@ public class TestBillingApi extends JunctionTestSuite {
         final Iterator<BillingEvent> it = events.iterator();
 
         checkEvent(it.next(), nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
-        checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(1), nextPhase, SubscriptionTransitionType.START_BILLING_DISABLED.toString(), new MockPrice("0"), new MockPrice("0"));
+        checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(1), nextPhase, SubscriptionTransitionType.START_BILLING_DISABLED.toString(), null, null);
         checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(2), nextPhase, SubscriptionTransitionType.END_BILLING_DISABLED.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
     }
 
@@ -522,7 +523,9 @@ public class TestBillingApi extends JunctionTestSuite {
         Assert.assertEquals(time.getDayOfMonth(), event.getEffectiveDate().getDayOfMonth());
         Assert.assertEquals(nextPhase, event.getPlanPhase());
         Assert.assertEquals(nextPlan, event.getPlan());
-        Assert.assertEquals(nextPhase.getBillingPeriod(), event.getBillingPeriod());
+        if (!SubscriptionTransitionType.START_BILLING_DISABLED.equals(event.getTransitionType())) {
+            Assert.assertEquals(nextPhase.getBillingPeriod(), event.getBillingPeriod());
+        }
         Assert.assertEquals(BillingModeType.IN_ADVANCE, event.getBillingMode());
         Assert.assertEquals(desc, event.getTransitionType().toString());
     }
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 03c8422..acd17e0 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -348,7 +348,9 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(results.first().getFixedPrice());
+        assertNull(results.first().getRecurringPrice());
+        assertEquals(results.first().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
     }
 
@@ -368,7 +370,9 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
         assertEquals(results.size(), 1);
         assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(results.first().getFixedPrice());
+        assertNull(results.first().getRecurringPrice());
+        assertEquals(results.first().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
     }
 
@@ -403,7 +407,9 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(results.first().getFixedPrice());
+        assertNull(results.first().getRecurringPrice());
+        assertEquals(results.first().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
@@ -426,7 +432,9 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(results.first().getFixedPrice());
+        assertNull(results.first().getRecurringPrice());
+        assertEquals(results.first().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
@@ -450,7 +458,9 @@ public class TestBlockingCalculator extends JunctionTestSuite {
 
         assertEquals(results.size(), 2);
         assertEquals(results.first().getEffectiveDate(), now);
-        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(results.first().getFixedPrice());
+        assertNull(results.first().getRecurringPrice());
+        assertEquals(results.first().getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
         assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
@@ -587,12 +597,12 @@ public class TestBlockingCalculator extends JunctionTestSuite {
         assertEquals(result.getEffectiveDate(), now);
         assertEquals(result.getPlanPhase(), event.getPlanPhase());
         assertEquals(result.getPlan(), event.getPlan());
-        assertEquals(result.getFixedPrice(), BigDecimal.ZERO);
-        assertEquals(result.getRecurringPrice(), BigDecimal.ZERO);
+        assertNull(result.getFixedPrice());
+        assertNull(result.getRecurringPrice());
         assertEquals(result.getCurrency(), event.getCurrency());
         assertEquals(result.getDescription(), "");
         assertEquals(result.getBillingMode(), event.getBillingMode());
-        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+        assertEquals(result.getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
         assertEquals(result.getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
         // TODO - ugly, fragile
         assertEquals(result.getTotalOrdering(), (Long) (BlockingCalculator.getGlobalTotalOrder().get() - 1));