killbill-aplcache

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
index 442d316..2402ed2 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
@@ -30,8 +30,11 @@ import org.killbill.billing.account.api.Account;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
+import org.killbill.billing.entitlement.api.Entitlement;
 import org.killbill.billing.invoice.api.DryRunArguments;
 import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
@@ -325,4 +328,38 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
         assertEquals(accountPayments.get(2).getPurchasedAmount(), new BigDecimal("10.00"));
     }
 
+
+    @Test(groups = "slow", description= "See https://github.com/killbill/killbill/issues/127#issuecomment-292445089")
+    public void testIntegrationWithBCDLargerThanEndMonth() throws Exception {
+
+        final int billingDay = 31;
+        final DateTime initialCreationDate = new DateTime(2017, 01, 31, 0, 0, 0, 0, testTimeZone);
+        // set clock to the initial start date
+        clock.setTime(initialCreationDate);
+
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+        assertListenerStatus();
+
+        // 2017-02-28
+        busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        clock.addMonths(1);
+        assertListenerStatus();
+
+        // 2017-03-31
+        busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        clock.addMonths(1);
+        clock.addDays(3);
+        assertListenerStatus();
+
+        // 2017-04-30
+        busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        clock.addMonths(1);
+        assertListenerStatus();
+    }
+
+
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
index ea26fcc..ed9f1bb 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/BillingIntervalDetail.java
@@ -198,6 +198,7 @@ public class BillingIntervalDetail {
         proposedDate = proposedDate.minus(billingPeriod.getPeriod());
         proposedDate = BillCycleDayCalculator.alignProposedBillCycleDate(proposedDate, billingCycleDay, billingPeriod);
 
+
         if (proposedDate.isBefore(firstBillingCycleDate)) {
             // Make sure not to go too far in the past
             lastBillingCycleDate = firstBillingCycleDate;
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInAdvanceBillingIntervalDetail.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInAdvanceBillingIntervalDetail.java
index 121ff05..c3fd724 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInAdvanceBillingIntervalDetail.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestInAdvanceBillingIntervalDetail.java
@@ -25,6 +25,8 @@ import org.killbill.billing.invoice.InvoiceTestSuiteNoDB;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import static org.killbill.billing.invoice.generator.InvoiceDateUtils.calculateNumberOfWholeBillingPeriods;
+
 public class TestInAdvanceBillingIntervalDetail extends InvoiceTestSuiteNoDB {
 
     /*
@@ -196,4 +198,21 @@ public class TestInAdvanceBillingIntervalDetail extends InvoiceTestSuiteNoDB {
         final LocalDate effectiveEndDate = billingIntervalDetail.getEffectiveEndDate();
         Assert.assertEquals(effectiveEndDate, new LocalDate("2012-05-31"));
     }
+
+
+    @Test(groups = "fast", description= "See https://github.com/killbill/killbill/issues/127#issuecomment-292445089")
+    public void testWithBCDLargerThanEndMonth() throws Exception {
+        final LocalDate startDate = new LocalDate("2017-01-31");
+        final LocalDate endDate = null;
+        final LocalDate targetDate = new LocalDate("2017-03-31");
+        int BCD = 31;
+        final BillingIntervalDetail billingIntervalDetail = new BillingIntervalDetail(startDate, endDate, targetDate, BCD, BillingPeriod.MONTHLY, BillingMode.IN_ADVANCE);
+
+        final LocalDate firstBillingCycleDate = billingIntervalDetail.getFirstBillingCycleDate();
+        final LocalDate lastBillingCycleDate = billingIntervalDetail.getLastBillingCycleDate();
+
+        final int numberOfWholeBillingPeriods = calculateNumberOfWholeBillingPeriods(firstBillingCycleDate, lastBillingCycleDate, BillingPeriod.MONTHLY);
+        Assert.assertEquals(numberOfWholeBillingPeriods, 3);
+    }
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
index 7b002a3..90373da 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
@@ -69,7 +69,7 @@ public class InvoiceJson extends JsonBase {
                        @JsonProperty("invoiceNumber") final String invoiceNumber,
                        @JsonProperty("balance") final BigDecimal balance,
                        @JsonProperty("accountId") final String accountId,
-                       @JsonProperty("externalBundleKeys") final String bundleKeys,
+                       @JsonProperty("bundleKeys") final String bundleKeys,
                        @JsonProperty("credits") final List<CreditJson> credits,
                        @JsonProperty("items") final List<InvoiceItemJson> items,
                        @JsonProperty("isParentInvoice") final Boolean isParentInvoice,
diff --git a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
index 80fda69..aaa544b 100644
--- a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
+++ b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
@@ -60,8 +60,12 @@ public abstract class BillCycleDayCalculator {
         }
         final int lastDayOfMonth = proposedDate.dayOfMonth().getMaximumValue();
         int proposedBillCycleDate = proposedDate.getDayOfMonth();
-        if (proposedBillCycleDate < billingCycleDay && billingCycleDay <= lastDayOfMonth) {
-            proposedBillCycleDate = billingCycleDay;
+        if (proposedBillCycleDate < billingCycleDay) {
+            if (billingCycleDay <= lastDayOfMonth) {
+                proposedBillCycleDate = billingCycleDay;
+            } else {
+                proposedBillCycleDate = lastDayOfMonth;
+            }
         }
         return new LocalDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), proposedBillCycleDate, proposedDate.getChronology());
     }