killbill-memoizeit

Additional code review for #98 Add new test to test behavior

10/10/2013 9:07:11 PM

Details

diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 1be626e..dd02b20 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -205,9 +205,105 @@ public class TestOverdueIntegration extends TestOverdueBase {
         assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
     }
 
+    @Test(groups = "slow", description="Test overdue stages and return to clear on CTD")
+    public void testOverdueStages2() throws Exception {
+        clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
+
+        // Set next invoice to fail and create subscription
+        paymentPlugin.makeAllInvoicesFailWithError(true);
+        final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.INVOICE);
+        bundle = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
+
+        invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
+
+        // 2012, 5, 31 => DAY 30 have to get out of trial {I0, P0}
+        addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+
+        invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
+
+        // 2012, 6, 8 => Retry P0
+        addDaysAndCheckForCompletion(8, NextEvent.PAYMENT_ERROR);
+        checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
+
+        // 2012, 6, 16 => Retry P0
+        addDaysAndCheckForCompletion(8, NextEvent.PAYMENT_ERROR);
+        checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
+
+        // 2012, 6, 24 => Retry P0
+        addDaysAndCheckForCompletion(8, NextEvent.PAYMENT_ERROR);
+        checkODState(DefaultBlockingState.CLEAR_STATE_NAME);
+
+        // 2012, 6, 31 => P1 (We se 6/31 instead of 6/30 because invoice might happen later in that day)
+        addDaysAndCheckForCompletion(7, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR);
+        checkODState("OD1");
+        checkChangePlanWithOverdueState(baseEntitlement, true, true);
+        invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 7, 31), callContext);
+
+        // 2012, 7, 2 => Retry P0
+        addDaysAndCheckForCompletion(1, NextEvent.PAYMENT_ERROR);
+        checkODState("OD1");
+
+        // 2012, 7, 9 => Retry P1
+        addDaysAndCheckForCompletion(7, NextEvent.PAYMENT_ERROR);
+        checkODState("OD1");
+
+        // 2012, 7, 10 => Retry P0
+        //
+        // This is the first stage that will block the billing (and entitlement). The overdue system will notify invoice which will in turn
+        // will adjust (repair) the previous invoice for the part that was blocked
+        //
+        addDaysAndCheckForCompletion(1, NextEvent.INVOICE_ADJUSTMENT, NextEvent.PAYMENT_ERROR);
+        checkODState("OD2");
+
+        invoiceChecker.checkInvoice(account.getId(), 3,
+                                    callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")),
+                                    // Repair for the part that was blocked
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 10), new LocalDate(2012, 7, 31), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-166.64")));
+
+        // 2012, 7, 17 => Retry P1
+        addDaysAndCheckForCompletion(7, NextEvent.PAYMENT_ERROR);
+        checkODState("OD2");
+
+        // 2012, 7, 18 => Retry P0
+        addDaysAndCheckForCompletion(1, NextEvent.PAYMENT_ERROR);
+        checkODState("OD2");
+
+        // 2012, 7, 23 => Should be 20 but notficationQ event occurs on 23...
+        addDaysAndCheckForCompletion(5);
+        checkODState("OD3");
+
+        // 2012, 7, 25 => Retry P0
+        addDaysAndCheckForCompletion(2, NextEvent.PAYMENT_ERROR);
+        // 2012, 7, 26 => Retry P0
+        addDaysAndCheckForCompletion(1, NextEvent.PAYMENT_ERROR);
+
+        // 2012, 7, 31 => No NEW INVOICE because OD2 -> still blocked
+        addDaysAndCheckForCompletion(5);
+        invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 7, 31), callContext);
+
+        allowPaymentsAndResetOverdueToClearByPayingAllUnpaidInvoices();
+
+        invoiceChecker.checkInvoice(account.getId(), 4, callContext,
+                                    // New invoice for the partial period since we unblocked on the 1st and so are missing the 31 july
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 31), new LocalDate(2012, 8, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+
+        // Move one month ahead, and check if we get the next invoice
+        addDaysAndCheckForCompletion(31, NextEvent.INVOICE, NextEvent.PAYMENT);
+
+        invoiceChecker.checkInvoice(account.getId(), 5, callContext,
+                                    // New invoice for the partial period since we unblocked on the 1st and so are missing the 31 july
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 8, 31), new LocalDate(2012, 9, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
+
+        // Verify the account balance is now 0
+        assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
+    }
+
 
     @Test(groups = "slow", description="Test overdue stages and return to clear after CTD")
-    public void testOverdueStages2() throws Exception {
+    public void testOverdueStages3() throws Exception {
         clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
 
         // Set next invoice to fail and create subscription
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
index 3b34ed5..34f5d07 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -72,8 +72,6 @@ public class OverdueStateApplicator {
 
     private static final Logger log = LoggerFactory.getLogger(OverdueStateApplicator.class);
 
-    private static final Period ONE_DAY = new Period(24, 0, 0, 0);
-
     private final BlockingInternalApi blockingApi;
     private final Clock clock;
     private final OverdueCheckPoster poster;
@@ -126,18 +124,21 @@ public class OverdueStateApplicator {
             log.debug("OverdueStateApplicator:apply <enter> : time = " + clock.getUTCNow() + ", previousState = " + previousOverdueState.getName() + ", nextState = " + nextOverdueState);
 
             final OverdueState firstOverdueState = overdueStateSet.getFirstState();
-            final Period initialReevaluationPeriod = overdueStateSet.getInitialReevaluationInterval() != null ?
-                                                     overdueStateSet.getInitialReevaluationInterval() : ONE_DAY;
-
             final boolean conditionForNextNotfication = !nextOverdueState.isClearState() ||
                                                         // We did not reach the first state yet but we have an unpaid invoice
                                                         (firstOverdueState != null && billingState != null && billingState.getDateOfEarliestUnpaidInvoice() != null);
 
             if (conditionForNextNotfication) {
-                final Period reevaluationInterval = nextOverdueState.isClearState() ? initialReevaluationPeriod : nextOverdueState.getReevaluationInterval();
-                createFutureNotification(account, clock.getUTCNow().plus(reevaluationInterval), context);
+                final Period reevaluationInterval = nextOverdueState.isClearState() ? overdueStateSet.getInitialReevaluationInterval() : nextOverdueState.getReevaluationInterval();
+                // If there is no configuration in the config, we assume this is because the overdue conditions are not time based and so there is nothing to retry
+                if (reevaluationInterval == null) {
+                    log.debug("OverdueStateApplicator <notificationQ> : Missing InitialReevaluationInterval from config, NOT inserting notification for account " +  account.getId());
+
+                } else {
+                    log.debug("OverdueStateApplicator <notificationQ> : inserting notification for account " + account.getId() + ", time = " + clock.getUTCNow().plus(reevaluationInterval));
+                    createFutureNotification(account, clock.getUTCNow().plus(reevaluationInterval), context);
+                }
 
-                log.debug("OverdueStateApplicator <notificationQ> : inserting notification for time = " + clock.getUTCNow().plus(reevaluationInterval));
             } else if (nextOverdueState.isClearState()) {
                 clearFutureNotification(account, context);
             }