killbill-aplcache

Merge branch 'inv-ent-integration' of git@github.com:ning/killbill

2/4/2012 12:23:49 AM

Details

diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
index ed43c33..e708803 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/inv_ent/TestBasic.java
@@ -176,7 +176,7 @@ public class TestBasic {
         testBasePlanComplete(clock.getUTCNow().minusDays(1).getDayOfMonth());
     }
 
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testBasePlanCompleteWithBillingDayPresent() throws Exception {
         testBasePlanComplete(clock.getUTCNow().getDayOfMonth());
     }
@@ -189,7 +189,7 @@ public class TestBasic {
     private void testBasePlanComplete(int billingDay) throws Exception {
         long DELAY = 5000 * 10;
 
-        Account account = accountUserApi.createAccount(getAccountData(), null, null);
+        Account account = accountUserApi.createAccount(getAccountData(billingDay), null, null);
         assertNotNull(account);
 
         SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever");
@@ -207,7 +207,6 @@ public class TestBasic {
                 new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null);
         assertNotNull(subscription);
 
-
         assertTrue(busHandler.isCompleted(DELAY));
         log.info("testSimple passed first busHandler checkpoint.");
 
@@ -242,6 +241,9 @@ public class TestBasic {
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
         clock.setDeltaFromReality(AT_LEAST_ONE_MONTH_MS);
 
+        Thread.sleep(600000);
+        assertTrue(busHandler.isCompleted(DELAY));
+
         //
         // CHANGE PLAN EOT AND EXPECT NOTHING
         //
@@ -297,7 +299,7 @@ public class TestBasic {
     public void testHappyPath() throws AccountApiException, EntitlementUserApiException {
         long DELAY = 5000 * 10;
 
-        Account account = accountUserApi.createAccount(getAccountData(), null, null);
+        Account account = accountUserApi.createAccount(getAccountData(3), null, null);
         assertNotNull(account);
 
         SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever");
@@ -331,7 +333,7 @@ public class TestBasic {
     }
 
 
-    protected AccountData getAccountData() {
+    protected AccountData getAccountData(final int billingDay) {
         AccountData accountData = new AccountData() {
             @Override
             public String getName() {
@@ -355,7 +357,7 @@ public class TestBasic {
             }
             @Override
             public int getBillCycleDay() {
-                return 1;
+                return billingDay;
             }
             @Override
             public Currency getCurrency() {
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index 898b7df..7356d74 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -202,8 +202,8 @@ Use Cases to do:
 			<initialPhases>
 				<phase type="TRIAL">
 					<duration>
-						<unit>DAYS</unit>
-						<number>30</number>
+						<unit>MONTHS</unit>
+						<number>1</number>
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<fixedPrice> <!-- empty price implies $0 -->
@@ -227,10 +227,10 @@ Use Cases to do:
 			<initialPhases>
 				<phase type="TRIAL">
 					<duration>
-						<unit>DAYS</unit>
-						<number>30</number>
+						<unit>MONTHS</unit>
+						<number>1</number>
 					</duration>
-					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
                         <price><currency>GBP</currency><value>29.95</value></price>
                         <price><currency>EUR</currency><value>29.95</value></price>
@@ -257,8 +257,8 @@ Use Cases to do:
 			<initialPhases>
 				<phase type="TRIAL">
 					<duration>
-						<unit>DAYS</unit>
-						<number>30</number>
+						<unit>MONTHS</unit>
+						<number>1</number>
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 31424ba..19eaad5 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -136,6 +136,8 @@ public class DefaultInvoiceDao implements InvoiceDao {
         invoiceSqlDao.inTransaction(new Transaction<Void, InvoiceSqlDao>() {
             @Override
             public Void inTransaction(final InvoiceSqlDao invoiceDao, final TransactionStatus status) throws Exception {
+
+                // STEPH this seems useless
                 Invoice currentInvoice = invoiceDao.getById(invoice.getId().toString());
 
                 if (currentInvoice == null) {
@@ -148,6 +150,8 @@ public class DefaultInvoiceDao implements InvoiceDao {
                     notifyOfFutureBillingEvents(invoiceSqlDao, invoiceItems);
                     setChargedThroughDates(invoiceSqlDao, invoiceItems);
 
+
+                    // STEPH Why do we need that? Are the payments not always null at this point?
                     List<InvoicePayment> invoicePayments = invoice.getPayments();
                     InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
                     invoicePaymentSqlDao.create(invoicePayments);
@@ -188,7 +192,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
     public BigDecimal getAccountBalance(final UUID accountId) {
         return invoiceSqlDao.getAccountBalance(accountId.toString());
     }
-    
+
     @Override
     public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
         invoicePaymentSqlDao.notifyOfPaymentAttempt(invoicePayment);
@@ -211,6 +215,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     @Override
     public boolean lockAccount(final UUID accountId) {
+        /*
         try {
             invoiceSqlDao.lockAccount(accountId.toString());
             return true;
@@ -218,16 +223,21 @@ public class DefaultInvoiceDao implements InvoiceDao {
             log.error("Ouch! I broke", e);
             return false;
         }
+        */
+        return true;
     }
 
     @Override
     public boolean releaseAccount(final UUID accountId) {
+        /*
         try {
             invoiceSqlDao.releaseAccount(accountId.toString());
             return true;
         } catch (Exception e) {
             return false;
         }
+        */
+        return true;
     }
 
     @Override
@@ -264,19 +274,19 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     private void notifyOfFutureBillingEvents(final InvoiceSqlDao dao, final List<InvoiceItem> invoiceItems) {
         for (final InvoiceItem item : invoiceItems) {
-            if (item.getRecurringRate() != null) {
-                if (item.getRecurringAmount().compareTo(BigDecimal.ZERO) > 0) {
-                    notifier.insertNextBillingNotification(dao, item.getSubscriptionId(), item.getEndDate());
-                }
+            if ((item.getEndDate() != null) &&
+                    (item.getRecurringAmount() == null || item.getRecurringAmount().compareTo(BigDecimal.ZERO) >= 0)) {
+                notifier.insertNextBillingNotification(dao, item.getSubscriptionId(), item.getEndDate());
             }
         }
     }
 
     private void setChargedThroughDates(final InvoiceSqlDao dao, final Collection<InvoiceItem> invoiceItems) {
-        for (InvoiceItem invoiceItem : invoiceItems) {
-            if (invoiceItem.getEndDate() != null) {
-                log.info("Setting CTD for invoice item {} to {}", invoiceItem.getId().toString(), invoiceItem.getEndDate().toString());
-                entitlementBillingApi.setChargedThroughDateFromTransaction(dao, invoiceItem.getSubscriptionId(), invoiceItem.getEndDate());
+        for (InvoiceItem item : invoiceItems) {
+            if ((item.getEndDate() != null) &&
+                    (item.getRecurringAmount() == null || item.getRecurringAmount().compareTo(BigDecimal.ZERO) >= 0)) {
+                log.info("Setting CTD for invoice item {} to {}", item.getId().toString(), item.getEndDate().toString());
+                entitlementBillingApi.setChargedThroughDateFromTransaction(dao, item.getSubscriptionId(), item.getEndDate());
             }
         }
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
index de018be..174b44d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -42,6 +42,7 @@ import com.ning.billing.invoice.model.BillingEventSet;
 import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.invoice.model.InvoiceItemList;
 import com.ning.billing.invoice.notification.NextBillingDateEvent;
+import com.ning.billing.util.clock.Clock;
 
 public class InvoiceListener {
     private final static Logger log = LoggerFactory.getLogger(InvoiceListener.class);
@@ -50,17 +51,20 @@ public class InvoiceListener {
     private final EntitlementBillingApi entitlementBillingApi;
     private final AccountUserApi accountUserApi;
     private final InvoiceDao invoiceDao;
+    private final Clock clock;
 
     private final static boolean VERBOSE_OUTPUT = false;
 
     @Inject
     public InvoiceListener(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
                            final EntitlementBillingApi entitlementBillingApi,
-                           final InvoiceDao invoiceDao) {
+                           final InvoiceDao invoiceDao,
+                           final Clock clock) {
         this.generator = generator;
         this.entitlementBillingApi = entitlementBillingApi;
         this.accountUserApi = accountUserApi;
         this.invoiceDao = invoiceDao;
+        this.clock = clock;
     }
 
     @Subscribe
@@ -70,7 +74,8 @@ public class InvoiceListener {
 
     @Subscribe
     public void handleNextBillingDateEvent(final NextBillingDateEvent event) {
-        processSubscription(event.getSubscriptionId(), new DateTime());
+        // STEPH should we use the date of the event instead?
+        processSubscription(event.getSubscriptionId(), clock.getUTCNow());
     }
 
     private void processSubscription(final SubscriptionTransition transition) {
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 a4203d0..a8b7c88 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
@@ -75,6 +75,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             currentItems.add(new DefaultInvoiceItem(item, invoiceId));
         }
 
+        // STEPH why clone? Why cast?
         InvoiceItemList existingItems = (InvoiceItemList) existingInvoiceItems.clone();
 
         Collections.sort(currentItems);
@@ -86,6 +87,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             // see if there are any existing items that are covered by the current item
             while (it.hasNext()) {
                 InvoiceItem existingItem = it.next();
+                // STEPH this is more like 'contained' that 'duplicates'
                 if (currentItem.duplicates(existingItem)) {
                     currentItem.subtract(existingItem);
                     it.remove();
@@ -98,6 +100,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
         // add existing items that aren't covered by current items as credit items
         for (final InvoiceItem existingItem : existingItems) {
+            // STEPH do we really want to credit if that has not been paid yet?
             currentItems.add(existingItem.asCredit(existingItem.getInvoiceId()));
         }
 
@@ -119,7 +122,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             BillingEvent thisEvent = events.get(i);
             BillingEvent nextEvent = events.get(i + 1);
 
-            if (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) {
+
+            if (thisEvent.getSubscription().getId().equals(nextEvent.getSubscription().getId())) {
                 processEvents(invoiceId, thisEvent, nextEvent, items, targetDate, targetCurrency);
             } else {
                 processEvent(invoiceId, thisEvent, items, targetDate, targetCurrency);
@@ -137,6 +141,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private void processEvent(final UUID invoiceId, final BillingEvent event, final InvoiceItemList items,
                               final DateTime targetDate, final Currency targetCurrency) {
     	try {
+    	    // STEPH should not that check apply to next method as well?
             if (event.getEffectiveDate().compareTo(targetDate) > 0) {
                 return;
             }
@@ -158,10 +163,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             }
 
             BigDecimal effectiveFixedPrice = items.hasInvoiceItemForPhase(event.getPlanPhase().getName()) ? null : fixedPrice;
+
+            // STEPH don't we also need to check for if (Days.daysBetween(firstEvent.getEffectiveDate(), billThroughDate).getDays() > 0)
             addInvoiceItem(invoiceId, items, event, billThroughDate, recurringAmount, recurringRate, effectiveFixedPrice, targetCurrency);
     	} catch (CatalogApiException e) {
-            log.error(String.format("Encountered a catalog error processing invoice %s for billing event on date %s", 
-                    invoiceId.toString(), 
+    	    // STEPH same remark for catalog exception.
+            log.error(String.format("Encountered a catalog error processing invoice %s for billing event on date %s",
+                    invoiceId.toString(),
                     ISODateTimeFormat.basicDateTime().print(event.getEffectiveDate())), e);
         }
     }
@@ -191,6 +199,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                 addInvoiceItem(invoiceId, items, firstEvent, billThroughDate, recurringAmount, recurringRate, effectiveFixedPrice, targetCurrency);
             }
     	} catch (CatalogApiException e) {
+
+    	    // STEPH That needs to be thrown so we stop that invoice generation
     		log.error(String.format("Encountered a catalog error processing invoice %s for billing event on date %s",
                     invoiceId.toString(),
                     ISODateTimeFormat.basicDateTime().print(firstEvent.getEffectiveDate())), e);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
index 0d5b261..b8f5c42 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
@@ -20,6 +20,7 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import org.joda.time.DateTime;
 import org.joda.time.Days;
 import org.joda.time.Months;
+import org.joda.time.MutableDateTime;
 
 import java.math.BigDecimal;
 
@@ -50,24 +51,23 @@ public class InAdvanceBillingMode extends BillingModeBase {
     protected DateTime calculateBillingCycleDateOnOrAfter(final DateTime date, final int billingCycleDay) {
         int lastDayOfMonth = date.dayOfMonth().getMaximumValue();
 
-        DateTime proposedDate;
+
+        MutableDateTime tmp = date.toMutableDateTime();
         if (billingCycleDay > lastDayOfMonth) {
-            proposedDate = new DateTime(date.getYear(), date.getMonthOfYear(), lastDayOfMonth,
-                                        date.getHourOfDay(), date.getMinuteOfHour(),
-                                        date.getSecondOfMinute(), date.getMillisOfSecond());
+            tmp.setDayOfMonth(lastDayOfMonth);
         } else {
-            proposedDate = new DateTime(date.getYear(), date.getMonthOfYear(), billingCycleDay,
-                                        date.getHourOfDay(), date.getMinuteOfHour(),
-                                        date.getSecondOfMinute(), date.getMillisOfSecond());
+            tmp.setDayOfMonth(billingCycleDay);
         }
+        DateTime proposedDate = tmp.toDateTime();
 
         while (proposedDate.isBefore(date)) {
+            // STEPH could be an annual ?
             proposedDate = proposedDate.plusMonths(1);
         }
-
         return proposedDate;
     }
 
+    @Override
     protected DateTime calculateBillingCycleDateAfter(final DateTime date, final DateTime billingCycleDate, final int billingCycleDay, final BillingPeriod billingPeriod) {
         DateTime proposedDate = billingCycleDate;