killbill-aplcache

Details

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
index af66de0..f6726f6 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
@@ -50,6 +50,7 @@ import org.killbill.billing.util.currency.KillBillMoney;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.Inject;
 
 import static org.killbill.billing.invoice.generator.InvoiceDateUtils.calculateNumberOfWholeBillingPeriods;
@@ -90,12 +91,12 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
         return accountItemTree.getResultingItemList();
     }
 
-    private List<InvoiceItem> processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
+    private void processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events,
                                                             final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems,
                                                             final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate) throws InvoiceApiException {
 
         if (events.size() == 0) {
-            return proposedItems;
+            return;
         }
 
         // Pretty-print the generated invoice items from the junction events
@@ -121,10 +122,11 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
 
         log.info(logStringBuilder.toString());
 
-        return proposedItems;
+        return;
     }
 
-    private List<InvoiceItem> processFixedBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events, final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems) {
+    @VisibleForTesting
+    void processFixedBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events, final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems) {
 
         final AccountDateAndTimeZoneContext dateAndTimeZoneContext = events.getAccountDateAndTimeZoneContext();
 
@@ -144,11 +146,10 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
         if (prevItem != null) {
             proposedItems.add(prevItem);
         }
-        return proposedItems;
     }
 
-
-    private boolean isSameDayAndSameSubscription(final InvoiceItem prevComputedFixedItem, final BillingEvent currentBillingEvent, final AccountDateAndTimeZoneContext dateAndTimeZoneContext) {
+    @VisibleForTesting
+    boolean isSameDayAndSameSubscription(final InvoiceItem prevComputedFixedItem, final BillingEvent currentBillingEvent, final AccountDateAndTimeZoneContext dateAndTimeZoneContext) {
         final LocalDate curLocalEffectiveDate = dateAndTimeZoneContext.computeLocalDateFromFixedAccountOffset(currentBillingEvent.getEffectiveDate());
         if (prevComputedFixedItem != null && /* If we have computed a previous item */
             prevComputedFixedItem.getStartDate().compareTo(curLocalEffectiveDate) == 0 && /* The current billing event happens at the same date */
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java
new file mode 100644
index 0000000..fc2d83a
--- /dev/null
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestFixedAndRecurringInvoiceItemGenerator.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.generator;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.catalog.DefaultPrice;
+import org.killbill.billing.catalog.MockInternationalPrice;
+import org.killbill.billing.catalog.MockPlan;
+import org.killbill.billing.catalog.MockPlanPhase;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.PhaseType;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.invoice.InvoiceTestSuiteNoDB;
+import org.killbill.billing.invoice.MockBillingEventSet;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
+import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.junction.BillingEventSet;
+import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.util.AccountDateAndTimeZoneContext;
+import org.killbill.billing.util.timezone.DefaultAccountDateAndTimeZoneContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+public class TestFixedAndRecurringInvoiceItemGenerator extends InvoiceTestSuiteNoDB {
+
+    private Account account;
+    private SubscriptionBase subscription;
+    private AccountDateAndTimeZoneContext dateAndTimeZoneContext;
+
+    @Override
+    @BeforeMethod(groups = "fast")
+    public void beforeMethod() {
+        super.beforeMethod();
+
+        try {
+            account = invoiceUtil.createAccount(callContext);
+            subscription = invoiceUtil.createSubscription();
+            dateAndTimeZoneContext = new DefaultAccountDateAndTimeZoneContext(new DateTime("2016-01-08T03:01:01.000Z"), DateTimeZone.UTC);
+        } catch (final Exception e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    @Test(groups = "fast")
+    public void testIsSameDayAndSameSubscriptionWithNullPrevEvent() {
+
+        final Plan plan = new MockPlan("my-plan");
+
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final InvoiceItem prevInvoiceItem = null;
+
+        final BillingEvent event = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-02-01"),
+                                                                      plan, phase,
+                                                                      fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                      BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                      SubscriptionBaseTransitionType.CREATE);
+
+        assertFalse(fixedAndRecurringInvoiceItemGenerator.isSameDayAndSameSubscription(prevInvoiceItem, event, dateAndTimeZoneContext));
+    }
+
+    @Test(groups = "fast")
+    public void testIsSameDayAndSameSubscriptionWithDifferentSubscriptionId() {
+
+        final Plan plan = new MockPlan("my-plan");
+
+        final LocalDate invoiceItemDate = new LocalDate("2016-01-08");
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final UUID invoiceId = UUID.randomUUID();
+        final InvoiceItem prevInvoiceItem = new FixedPriceInvoiceItem(invoiceId, account.getId(), UUID.randomUUID(), UUID.randomUUID(), plan.getName(),
+                                                                      phase.getName(), invoiceItemDate, fixedPriceAmount, Currency.USD);
+
+        final BillingEvent event = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                      plan, phase,
+                                                                      fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                      BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                      SubscriptionBaseTransitionType.CREATE);
+
+        assertFalse(fixedAndRecurringInvoiceItemGenerator.isSameDayAndSameSubscription(prevInvoiceItem, event, dateAndTimeZoneContext));
+    }
+
+    @Test(groups = "fast")
+    public void testIsSameDayAndSameSubscriptionWithDifferentDate() {
+
+        final Plan plan = new MockPlan("my-plan");
+
+        final LocalDate invoiceItemDate = new LocalDate("2016-01-08");
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final UUID invoiceId = UUID.randomUUID();
+        final InvoiceItem prevInvoiceItem = new FixedPriceInvoiceItem(invoiceId, account.getId(), subscription.getBundleId(), subscription.getId(), plan.getName(),
+                                                                      phase.getName(), invoiceItemDate, fixedPriceAmount, Currency.USD);
+
+        final BillingEvent event = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-02-01"),
+                                                                      plan, phase,
+                                                                      fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                      BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                      SubscriptionBaseTransitionType.CREATE);
+
+        assertFalse(fixedAndRecurringInvoiceItemGenerator.isSameDayAndSameSubscription(prevInvoiceItem, event, dateAndTimeZoneContext));
+    }
+
+    @Test(groups = "fast")
+    public void testIsSameDayAndSameSubscriptionWithSameDateAndSubscriptionId() {
+
+        final Plan plan = new MockPlan("my-plan");
+
+        final LocalDate invoiceItemDate = new LocalDate("2016-01-08");
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final UUID invoiceId = UUID.randomUUID();
+        final InvoiceItem prevInvoiceItem = new FixedPriceInvoiceItem(invoiceId, account.getId(), subscription.getBundleId(), subscription.getId(), plan.getName(),
+                                                                      phase.getName(), invoiceItemDate, fixedPriceAmount, Currency.USD);
+
+        final BillingEvent event = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                      plan, phase,
+                                                                      fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                      BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                      SubscriptionBaseTransitionType.CREATE);
+
+        assertTrue(fixedAndRecurringInvoiceItemGenerator.isSameDayAndSameSubscription(prevInvoiceItem, event, dateAndTimeZoneContext));
+    }
+
+    @Test(groups = "fast")
+    public void testProcessFixedBillingEventsWithCancellationOnSameDay() {
+
+        final LocalDate targetDate = new LocalDate("2016-01-08");
+
+        final UUID invoiceId = UUID.randomUUID();
+        final BillingEventSet events = new MockBillingEventSet();
+
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final Plan plan = new MockPlan("my-plan");
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final BillingEvent event1 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan, phase,
+                                                                       fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                       SubscriptionBaseTransitionType.CREATE);
+        events.add(event1);
+
+
+        final BillingEvent event2 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan, phase,
+                                                                       null, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 2L,
+                                                                       SubscriptionBaseTransitionType.CANCEL);
+        events.add(event2);
+
+        final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
+        fixedAndRecurringInvoiceItemGenerator.processFixedBillingEvents(invoiceId, account.getId(), events, targetDate, Currency.USD, proposedItems);
+        assertTrue(proposedItems.isEmpty());
+    }
+
+    @Test(groups = "fast")
+    public void testProcessFixedBillingEventsWithCancellationOnNextDay() {
+
+        final LocalDate targetDate = new LocalDate("2016-01-08");
+
+        final UUID invoiceId = UUID.randomUUID();
+        final BillingEventSet events = new MockBillingEventSet();
+
+        final BigDecimal fixedPriceAmount = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount, Currency.USD));
+        final Plan plan = new MockPlan("my-plan");
+        final PlanPhase phase = new MockPlanPhase(null, fixedPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final BillingEvent event1 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan, phase,
+                                                                       fixedPriceAmount, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                       SubscriptionBaseTransitionType.CREATE);
+        events.add(event1);
+
+
+        final BillingEvent event2 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-09"),
+                                                                       plan, phase,
+                                                                       null, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 2L,
+                                                                       SubscriptionBaseTransitionType.CANCEL);
+        events.add(event2);
+
+        final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
+        fixedAndRecurringInvoiceItemGenerator.processFixedBillingEvents(invoiceId, account.getId(), events, targetDate, Currency.USD, proposedItems);
+        assertEquals(proposedItems.size(), 1);
+        assertEquals(proposedItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
+        assertEquals(proposedItems.get(0).getAmount(), fixedPriceAmount);
+    }
+
+
+    @Test(groups = "fast")
+    public void testProcessFixedBillingEventsWithMultipleChangeOnSameDay() {
+
+        final LocalDate targetDate = new LocalDate("2016-01-08");
+
+        final UUID invoiceId = UUID.randomUUID();
+        final BillingEventSet events = new MockBillingEventSet();
+
+        final BigDecimal fixedPriceAmount1 = BigDecimal.TEN;
+        final MockInternationalPrice fixedPrice1 = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount1, Currency.USD));
+        final Plan plan1 = new MockPlan("my-plan1");
+        final PlanPhase planPhase1 = new MockPlanPhase(null, fixedPrice1, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final BillingEvent event1 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan1, planPhase1,
+                                                                       fixedPriceAmount1, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 1L,
+                                                                       SubscriptionBaseTransitionType.CREATE);
+        events.add(event1);
+
+
+
+        final BigDecimal fixedPriceAmount2 = null;
+        final MockInternationalPrice fixedPrice2 = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount2, Currency.USD));
+        final Plan plan2 = new MockPlan("my-plan2");
+        final PlanPhase planPhase2 = new MockPlanPhase(null, fixedPrice2, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final BillingEvent event2 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan2, planPhase2,
+                                                                       fixedPriceAmount2, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 2L,
+                                                                       SubscriptionBaseTransitionType.CHANGE);
+        events.add(event2);
+
+
+        final BigDecimal fixedPriceAmount3 = BigDecimal.ONE;
+        final MockInternationalPrice fixedPrice3 = new MockInternationalPrice(new DefaultPrice(fixedPriceAmount3, Currency.USD));
+        final Plan plan3 = new MockPlan("my-plan3");
+        final PlanPhase planPhase3 = new MockPlanPhase(null, fixedPrice3, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+
+        final BillingEvent event3 = invoiceUtil.createMockBillingEvent(account, subscription, new DateTime("2016-01-08"),
+                                                                       plan3, planPhase3,
+                                                                       fixedPriceAmount3, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                                       BillingMode.IN_ADVANCE, "Billing Event Desc", 3L,
+                                                                       SubscriptionBaseTransitionType.CHANGE);
+        events.add(event3);
+
+        final List<InvoiceItem> proposedItems = new ArrayList<InvoiceItem>();
+        fixedAndRecurringInvoiceItemGenerator.processFixedBillingEvents(invoiceId, account.getId(), events, targetDate, Currency.USD, proposedItems);
+        assertEquals(proposedItems.size(), 1);
+        assertEquals(proposedItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
+        assertEquals(proposedItems.get(0).getAmount(), fixedPriceAmount3);
+    }
+
+}
\ No newline at end of file
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
index 10c58c2..a2f5751 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModuleNoDB.java
@@ -34,6 +34,7 @@ import org.killbill.billing.currency.api.CurrencyConversionException;
 import org.killbill.billing.currency.api.Rate;
 import org.killbill.billing.invoice.dao.InvoiceDao;
 import org.killbill.billing.invoice.dao.MockInvoiceDao;
+import org.killbill.billing.mock.api.MockAccountUserApi;
 import org.killbill.billing.mock.glue.MockNonEntityDaoModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.mockito.Mockito;
@@ -55,7 +56,7 @@ public class TestInvoiceModuleNoDB extends TestInvoiceModule {
         install(new MockNonEntityDaoModule(configSource));
 
         bind(AccountInternalApi.class).toInstance(Mockito.mock(AccountInternalApi.class));
-        bind(AccountUserApi.class).toInstance(Mockito.mock(AccountUserApi.class));
+        bind(AccountUserApi.class).to(MockAccountUserApi.class);
 
         installCurrencyConversionApi();
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index c360655..4e2d5f6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -224,8 +224,10 @@ public class TestInvoiceHelper {
 
     public SubscriptionBase createSubscription() throws SubscriptionBaseApiException {
         final UUID uuid = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
         final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
         Mockito.when(subscription.getId()).thenReturn(uuid);
+        Mockito.when(subscription.getBundleId()).thenReturn(bundleId);
         Mockito.when(subscriptionApi.getSubscriptionFromId(Mockito.<UUID>any(), Mockito.<InternalTenantContext>any())).thenReturn(subscription);
         return subscription;
     }
@@ -329,7 +331,6 @@ public class TestInvoiceHelper {
 
         final Account mockAccount = Mockito.mock(Account.class);
         Mockito.when(mockAccount.getTimeZone()).thenReturn(DateTimeZone.UTC);
-        final Account accountOrMockAcount = account != null ? account : mockAccount;
         return new BillingEvent() {
             @Override
             public int getBillCycleDayLocal() {