killbill-aplcache

fixed price work

2/2/2012 5:35:49 PM

Details

diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
index 95308be..7b5476e 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
@@ -82,7 +82,7 @@ public interface InvoiceItemSqlDao extends EntityDao<InvoiceItem> {
                         q.bind("planName", item.getPlanName());
                         q.bind("phaseName", item.getPhaseName());
                         q.bind("startDate", item.getStartDate().toDate());
-                        q.bind("endDate", item.getEndDate() == null ? null : item.getEndDate().toDate());
+                        q.bind("endDate", item.getEndDate().toDate());
                         q.bind("recurringAmount", item.getRecurringAmount());
                         q.bind("recurringRate", item.getRecurringRate());
                         q.bind("fixedAmount", item.getFixedAmount());
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
index 1467249..89c94d0 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
@@ -134,6 +134,10 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private void processEvent(final UUID invoiceId, final BillingEvent event, final InvoiceItemList items,
                               final DateTime targetDate, final Currency targetCurrency) {
     	try {
+            if (event.getEffectiveDate().compareTo(targetDate) > 0) {
+                return;
+            }
+
             BigDecimal recurringRate = event.getRecurringPrice() == null ? null : event.getRecurringPrice().getPrice(targetCurrency);
             BigDecimal fixedPrice = event.getFixedPrice() == null ? null : event.getFixedPrice().getPrice(targetCurrency);
 
@@ -165,9 +169,12 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
             BigDecimal numberOfBillingPeriods;
             BigDecimal recurringAmount = null;
-            DateTime billThroughDate = null;
+            DateTime billThroughDate;
 
-            if (recurringRate != null) {
+            if (recurringRate == null) {
+                // since it's fixed price only, the following event dictates the end date, regardless of when it takes place
+                billThroughDate = secondEvent.getEffectiveDate();
+            } else {
                 numberOfBillingPeriods = calculateNumberOfBillingPeriods(firstEvent, secondEvent, targetDate);
                 recurringAmount = numberOfBillingPeriods.multiply(recurringRate);
                 BillingMode billingMode = getBillingMode(firstEvent.getBillingMode());
@@ -187,7 +194,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                                 final DateTime billThroughDate, final BigDecimal amount, final BigDecimal rate,
                                 final BigDecimal fixedAmount, final Currency currency) {
         DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, event.getSubscription().getId(),
-                                  event.getPlan().getName(), event.getPlanPhase().getName(),  event.getEffectiveDate(),
+                                  event.getPlan().getName(), event.getPlanPhase().getName(), event.getEffectiveDate(),
                                   billThroughDate, amount, rate, fixedAmount, currency);
         items.add(item);
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
index b65907e..b03fa6f 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
@@ -165,15 +165,6 @@ public class DefaultInvoiceItem implements InvoiceItem {
     // TODO: deal with error cases
     @Override
     public void subtract(InvoiceItem that) {
-        if (this.endDate == null) {
-            // this is a fixed price item; set the fixed amount to null
-            if (this.fixedAmount.compareTo(that.getFixedAmount()) == 0) {
-                this.fixedAmount = null;
-            }
-
-            return;
-        }
-
         if (this.startDate.equals(that.getStartDate()) && this.endDate.equals(that.getEndDate())) {
             this.startDate = this.endDate;
                 this.recurringAmount = safeSubtract(this.recurringAmount, that.getRecurringAmount());
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index 59920c0..bb9f562 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -6,7 +6,7 @@ CREATE TABLE invoice_items (
   plan_name varchar(50) NOT NULL,
   phase_name varchar(50) NOT NULL,
   start_date datetime NOT NULL,
-  end_date datetime NULL,
+  end_date datetime NOT NULL,
   recurring_amount numeric(10,4) NULL,
   recurring_rate numeric(10,4) NULL,
   fixed_amount numeric(10,4) NULL,
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 8cd47ff..11f8d62 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -449,98 +449,97 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
     }
 
     @Test
-    public void testDuplicatesEventBusIssues() {
-        Subscription subscription = new MockSubscription();
-        InternationalPrice zeroPrice = new MockInternationalPrice(new DefaultPrice(ZERO, Currency.USD));
-        int billCycleDay = 1;
-        BillingEventSet events = new BillingEventSet();
-
-        Plan shotgun = new MockPlan();
-        PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
-        BillingEvent event1 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:04.000Z"),
-                                                      shotgun, shotgunMonthly,
-                                                      zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
-                                                      BillingModeType.IN_ADVANCE, "Test Event 1", SubscriptionTransitionType.CREATE);
-        events.add(event1);
-
-
-        Plan assaultRifle = new MockPlan();
-        PlanPhase assaultRifleMonthly = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
-        BillingEvent event2 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:04.000Z"),
-                                                      assaultRifle, assaultRifleMonthly,
-                                                      zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
-                                                      BillingModeType.IN_ADVANCE, "Test Event 2", SubscriptionTransitionType.CREATE);
-        events.add(event2);
-
-        Plan pistol = new MockPlan();
-        PlanPhase pistolMonthlyTrial = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
-        BigDecimal pistolMonthlyCost = new BigDecimal("29.95");
-        PlanPhase pistolMonthlyEvergreen = createMockMonthlyPlanPhase(pistolMonthlyCost, null, PhaseType.EVERGREEN);
-        InternationalPrice pistolEvergreenPrice = new MockInternationalPrice(new DefaultPrice(pistolMonthlyCost, Currency.USD));
-        BillingEvent event3 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:05.000Z"),
-                                                      pistol, pistolMonthlyTrial,
-                                                      zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
-                                                      BillingModeType.IN_ADVANCE, "Test Event 3", SubscriptionTransitionType.CREATE);
-        events.add(event3);
-
-
-        BillingEvent event4 = new DefaultBillingEvent(subscription, new DateTime("2012-03-01T00:02:04.000Z"),
-                                                      pistol, pistolMonthlyEvergreen,
-                                                      null, pistolEvergreenPrice, BillingPeriod.MONTHLY, billCycleDay,
-                                                      BillingModeType.IN_ADVANCE, "Test Event 4",SubscriptionTransitionType.CREATE);
-        events.add(event4);
-
-        InvoiceItemList items = new InvoiceItemList();
-        UUID subscriptionId = UUID.randomUUID();
-        InvoiceItem item1 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, shotgun.getName(), shotgunMonthly.getName(), new DateTime("2012-01-30T16:02:04.000-08:00"), new DateTime("2012-01-30T16:02:04.000-08:00"), ZERO, ZERO, ZERO, Currency.USD);
-        InvoiceItem item2 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, assaultRifle.getName(), assaultRifleMonthly.getName(), new DateTime("2012-02-29T16:02:04.000-08:00"), new DateTime("2012-02-29T16:02:04.000-08:00"), ZERO, new BigDecimal("249.95"), ZERO, Currency.USD);
-        InvoiceItem item3 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, pistol.getName(), pistolMonthlyTrial.getName(), new DateTime("2012-01-30T16:02:04.000-08:00"), new DateTime("2012-01-30T16:02:04.000-08:00"), ZERO, ZERO, ZERO, Currency.USD);
-        items.add(item1);
-        items.add(item2);
-        items.add(item3);
-
-        InvoiceGenerator generator= new DefaultInvoiceGenerator();
-        Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, items, new DateTime(), Currency.USD);
-        assertNotNull(invoice);
-        assertTrue(invoice.getNumberOfItems() > 0);
-    }
-
-    @Test
     public void testImmediateChange() {
         UUID accountId = UUID.randomUUID();
         Subscription subscription = new MockSubscription();
         Plan plan1 = new MockPlan("plan 1");
-        PlanPhase phase1 = new MockPlanPhase(plan1, PhaseType.TRIAL);
+        PlanPhase plan1phase1 = new MockPlanPhase(plan1, PhaseType.TRIAL);
+        PlanPhase plan1phase2 = new MockPlanPhase(plan1, PhaseType.DISCOUNT);
+
         Plan plan2 = new MockPlan("plan 2");
-        PlanPhase phase2 = new MockPlanPhase(plan2, PhaseType.TRIAL);
+        PlanPhase plan2phase1 = new MockPlanPhase(plan2, PhaseType.TRIAL);
+        PlanPhase plan2phase2 = new MockPlanPhase(plan2, PhaseType.DISCOUNT);
+
         InternationalPrice zeroPrice = new MockInternationalPrice(new DefaultPrice(ZERO, Currency.USD));
+        InternationalPrice cheapPrice = new MockInternationalPrice(new DefaultPrice(ONE, Currency.USD));
+        InternationalPrice lessCheapPrice = new MockInternationalPrice(new DefaultPrice(FOUR, Currency.USD));
+
         BillingEventSet events = new BillingEventSet();
 
         BillingEvent event1 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:04.000Z"),
-                                                      plan1, phase1,
+                                                      plan1, plan1phase1,
                                                       zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, 1,
                                                       BillingModeType.IN_ADVANCE, "Test Event 1",
                                                       SubscriptionTransitionType.CREATE);
+        BillingEvent event2 = new DefaultBillingEvent(subscription, new DateTime("2012-04-30T00:02:04.000Z"),
+                                                      plan1, plan1phase2,
+                                                      null, cheapPrice, BillingPeriod.MONTHLY, 1,
+                                                      BillingModeType.IN_ADVANCE, "Test Event 2",
+                                                      SubscriptionTransitionType.PHASE);
         events.add(event1);
+        events.add(event2);
 
         Invoice invoice1 = generator.generateInvoice(accountId, events, null, new DateTime("2012-01-31T00:02:04.000Z"), Currency.USD);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
 
-        BillingEvent event2 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:04.000Z"),
-                                                      plan2, phase2,
+        BillingEvent event3 = new DefaultBillingEvent(subscription, new DateTime("2012-01-31T00:02:04.000Z"),
+                                                      plan2, plan2phase1,
                                                       zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, 1,
-                                                      BillingModeType.IN_ADVANCE, "Test Event 2",
+                                                      BillingModeType.IN_ADVANCE, "Test Event 3",
                                                       SubscriptionTransitionType.CHANGE);
-        events.add(event2);
+        BillingEvent event4 = new DefaultBillingEvent(subscription, new DateTime("2012-04-30T00:02:04.000Z"),
+                                                      plan2, plan2phase2,
+                                                      null, lessCheapPrice, BillingPeriod.MONTHLY, 1,
+                                                      BillingModeType.IN_ADVANCE, "Test Event 4",
+                                                      SubscriptionTransitionType.PHASE);
+
+        events.add(event3);
+        events.add(event4);
+
         InvoiceItemList items = new InvoiceItemList(invoice1.getInvoiceItems());
         Invoice invoice2 = generator.generateInvoice(accountId, events, items, new DateTime("2012-01-31T00:02:04.000Z"), Currency.USD);
 
         assertNotNull(invoice2);
-        assertEquals(invoice2.getNumberOfItems(), 1);
+        assertEquals(invoice2.getNumberOfItems(), 2);
         assertEquals(invoice2.getInvoiceItems().get(0).getPlanName(), plan2.getName());
     }
 
+    @Test
+    private void testFixedPriceLifeCycle() {
+        UUID accountId = UUID.randomUUID();
+        Subscription subscription = new MockSubscription();
+        Plan plan = new MockPlan("plan 1");
+        MockInternationalPrice zeroPrice = new MockInternationalPrice(new DefaultPrice(ZERO, Currency.USD));
+        MockInternationalPrice cheapPrice = new MockInternationalPrice(new DefaultPrice(ONE, Currency.USD));
+
+        PlanPhase phase1 = new MockPlanPhase(null, zeroPrice, BillingPeriod.NO_BILLING_PERIOD, PhaseType.TRIAL);
+        PlanPhase phase2 = new MockPlanPhase(cheapPrice, null, BillingPeriod.MONTHLY, PhaseType.DISCOUNT);
+
+        DateTime changeDate = new DateTime("2012-04-1T00:00:00.000-08:00");
+
+        BillingEventSet events = new BillingEventSet();
+
+        BillingEvent event1 = new DefaultBillingEvent(subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
+                                                      plan, phase1,
+                                                      zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                      BillingModeType.IN_ADVANCE, "Test Event 1",
+                                                      SubscriptionTransitionType.CREATE);
+
+        BillingEvent event2 = new DefaultBillingEvent(subscription, changeDate,
+                                                      plan, phase2,
+                                                      zeroPrice, null, BillingPeriod.NO_BILLING_PERIOD, 1,
+                                                      BillingModeType.IN_ADVANCE, "Test Event 2",
+                                                      SubscriptionTransitionType.PHASE);
+
+        events.add(event2);
+        events.add(event1);
+        Invoice invoice1 = generator.generateInvoice(accountId, events, null, new DateTime("2012-02-01T00:01:00.000-08:00"), Currency.USD);
+        assertNotNull(invoice1);
+        assertEquals(invoice1.getNumberOfItems(), 1);
+        assertEquals(invoice1.getInvoiceItems().get(0).getEndDate().compareTo(changeDate), 0);
+   }
+
     private MockPlanPhase createMockMonthlyPlanPhase() {
         return new MockPlanPhase(null, null, BillingPeriod.MONTHLY);
     }