killbill-aplcache

improvements to entitlement mocking; remove * imports; add

1/31/2012 3:05:42 PM

Changes

Details

diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index 2e264c0..7bc323d 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -36,18 +36,18 @@ import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.dao.TagStoreSqlDao;
 
 public class DefaultAccountDao implements AccountDao {
-    private final AccountSqlDao accountDao;
+    private final AccountSqlDao accountSqlDao;
     private final Bus eventBus;
 
     @Inject
     public DefaultAccountDao(IDBI dbi, Bus eventBus) {
         this.eventBus = eventBus;
-        this.accountDao = dbi.onDemand(AccountSqlDao.class);
+        this.accountSqlDao = dbi.onDemand(AccountSqlDao.class);
     }
 
     @Override
     public Account getAccountByKey(final String key) {
-        return accountDao.inTransaction(new Transaction<Account, AccountSqlDao>() {
+        return accountSqlDao.inTransaction(new Transaction<Account, AccountSqlDao>() {
             @Override
             public Account inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws Exception {
                 Account account = accountSqlDao.getAccountByKey(key);
@@ -65,35 +65,30 @@ public class DefaultAccountDao implements AccountDao {
         if (externalKey == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_CANNOT_MAP_NULL_KEY, "");
         }
-        return accountDao.getIdFromKey(externalKey);
+        return accountSqlDao.getIdFromKey(externalKey);
     }
 
     @Override
     public Account getById(final String id) {
-        return accountDao.inTransaction(new Transaction<Account, AccountSqlDao>() {
-            @Override
-            public Account inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws Exception {
-                Account account = accountSqlDao.getById(id);
-                if (account != null) {
-                    setCustomFieldsFromWithinTransaction(account, accountSqlDao);
-                    setTagsFromWithinTransaction(account, accountSqlDao);
-                }
-                return account;
-            }
-        });
+        Account account = accountSqlDao.getById(id);
+        if (account != null) {
+            setCustomFieldsFromWithinTransaction(account, accountSqlDao);
+            setTagsFromWithinTransaction(account, accountSqlDao);
+        }
+        return account;
     }
 
 
     @Override
     public List<Account> get() {
-        return accountDao.get();
+        return accountSqlDao.get();
     }
 
     @Override
     public void create(final Account account) throws AccountApiException {
         final String key = account.getExternalKey();
         try {
-            accountDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
+            accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
                 @Override
                 public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
                     Account currentAccount = accountSqlDao.getAccountByKey(key);
@@ -122,7 +117,7 @@ public class DefaultAccountDao implements AccountDao {
     @Override
     public void update(final Account account) throws AccountApiException {
         try {
-            accountDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
+            accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
                 @Override
                 public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
                     String accountId = account.getId().toString();
@@ -160,7 +155,7 @@ public class DefaultAccountDao implements AccountDao {
     @Override
 	public void deleteByKey(final String externalKey) throws AccountApiException {
     	try {
-            accountDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
+            accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
                 @Override
                 public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
 
@@ -180,7 +175,7 @@ public class DefaultAccountDao implements AccountDao {
 
     @Override
     public void test() {
-        accountDao.test();
+        accountSqlDao.test();
     }
 
     private void setCustomFieldsFromWithinTransaction(final Account account, final AccountSqlDao transactionalDao) {
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
index baacad8..71e3402 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
@@ -17,7 +17,14 @@
 package com.ning.billing.analytics;
 
 import com.ning.billing.analytics.utils.Rounder;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.catalog.api.TimeUnit;
 import com.ning.billing.entitlement.api.user.Subscription;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionBinder.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionBinder.java
index 9db1b75..374f296 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionBinder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessSubscriptionTransitionBinder.java
@@ -23,7 +23,11 @@ import org.skife.jdbi.v2.sqlobject.Binder;
 import org.skife.jdbi.v2.sqlobject.BinderFactory;
 import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.sql.Types;
 
 @BindingAnnotation(BusinessSubscriptionTransitionBinder.BstBinderFactory.class)
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index 368b8c1..c17cdd4 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -16,9 +16,21 @@
 
 package com.ning.billing.analytics.dao;
 
-import com.ning.billing.analytics.*;
+import com.ning.billing.analytics.BusinessAccount;
+import com.ning.billing.analytics.BusinessSubscription;
+import com.ning.billing.analytics.BusinessSubscriptionEvent;
+import com.ning.billing.analytics.BusinessSubscriptionTransition;
+import com.ning.billing.analytics.MockDuration;
+import com.ning.billing.analytics.MockPhase;
+import com.ning.billing.analytics.MockPlan;
+import com.ning.billing.analytics.MockProduct;
 import com.ning.billing.analytics.utils.Rounder;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.user.Subscription;
 import org.apache.commons.io.IOUtils;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockPhase.java b/analytics/src/test/java/com/ning/billing/analytics/MockPhase.java
index 3f11c0e..663ed78 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockPhase.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockPhase.java
@@ -16,10 +16,16 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Price;
 
 import java.math.BigDecimal;
-import java.util.Date;
 
 public class MockPhase implements PlanPhase
 {
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
index 7bad790..470263e 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -16,7 +16,12 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
index 6c38854..55c73ad 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscription.java
@@ -16,7 +16,12 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -94,7 +99,7 @@ public class TestBusinessSubscription
         Assert.assertEquals(subscription, subscription);
         Assert.assertTrue(subscription.equals(subscription));
 
-        final Subscription otherIsubscription = new MockSubscription(Subscription.SubscriptionState.CANCELLED, plan, phase);
-        Assert.assertTrue(!subscription.equals(new BusinessSubscription(otherIsubscription, USD)));
+        final Subscription otherSubscription = new MockSubscription(Subscription.SubscriptionState.CANCELLED, plan, phase);
+        Assert.assertTrue(!subscription.equals(new BusinessSubscription(otherSubscription, USD)));
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionEvent.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionEvent.java
index 5ea1950..a3ca56c 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionEvent.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionEvent.java
@@ -16,7 +16,11 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransition.java b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransition.java
index 592d20d..a8a954c 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransition.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestBusinessSubscriptionTransition.java
@@ -16,7 +16,11 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
index dc13776..ee5bd3e 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.entitlement.api.billing;
 
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.Currency;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -130,4 +132,37 @@ public class DefaultBillingEvent implements BillingEvent {
     public InternationalPrice getRecurringPrice() {
         return recurringPrice;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("BillingEvent {subscriptionId = ").append(subscription.getId().toString()).append(", ");
+        sb.append("plan = ").append(plan.getName()).append(", ");
+        sb.append("phase = ").append(planPhase.getName()).append(", ");
+        sb.append("effectiveDate = ").append(effectiveDate.toString()).append(", ");
+        sb.append("billCycleDay = ").append(billCycleDay).append(", ");
+        sb.append("recurringPrice(USD) = ");
+
+        try {
+            sb.append(recurringPrice.getPrice(Currency.USD).toString());
+        } catch (Exception e) {
+            sb.append("null");
+        }
+
+        sb.append(", ");
+        sb.append("fixedPrice(USD) = ");
+
+        try {
+            sb.append(fixedPrice.getPrice(Currency.USD).toString());
+        } catch (Exception e) {
+            sb.append("null");
+        }
+
+        sb.append(", ");
+
+        sb.append("billingPeriod = ").append(billingPeriod.toString());
+        sb.append("}");
+
+        return sb.toString();
+    }
 }
\ No newline at end of file
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
index 87075a9..8a07355 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
@@ -31,7 +31,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 
@@ -153,7 +157,6 @@ public class DefaultLifecycle implements Lifecycle {
         return methodsInService;
     }
 
-
     private final class LifecycleHandler<T> {
         private final T target;
         private final Method method;
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 9753d7f..c65bbef 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
@@ -161,7 +161,6 @@ public class TestBasic {
         });
     }
 
-
     private DateTime checkAndGetCTD(UUID subscriptionId) {
         SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
         DateTime ctd = subscription.getChargedThroughDate();
@@ -170,8 +169,9 @@ public class TestBasic {
         return ctd;
     }
 
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testSimple() throws Exception {
+        long DELAY = 5000;
 
         Account account = accountUserApi.createAccount(getAccountData(), null, null);
         assertNotNull(account);
@@ -190,7 +190,7 @@ public class TestBasic {
         SubscriptionData subscription = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
                 new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null);
         assertNotNull(subscription);
-        assertTrue(busHandler.isCompleted(5000));
+        assertTrue(busHandler.isCompleted(DELAY));
         log.info("testSimple passed first busHandler checkpoint.");
 
         //
@@ -208,7 +208,7 @@ public class TestBasic {
         String newPlanSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
         String newProductName = "Assault-Rifle";
         subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
-        assertTrue(busHandler.isCompleted(5000));
+        assertTrue(busHandler.isCompleted(DELAY));
         log.info("testSimple passed second busHandler checkpoint.");
 
         //
@@ -223,7 +223,7 @@ public class TestBasic {
         newPlanSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
         newProductName = "Pistol";
         subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
-
+        log.info("testSimple has passed third busHandler checkpoint (no events)");
         //
         // MOVE TIME AFTER CTD AND EXPECT BOTH EVENTS : NextEvent.CHANGE NextEvent.INVOICE
         //
@@ -231,8 +231,8 @@ public class TestBasic {
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
         clock.setDeltaFromReality(ctd.getMillis() - clock.getUTCNow().getMillis());
         //clock.setDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
-        assertTrue(busHandler.isCompleted(5000));
-        log.info("testSimple passed third busHandler checkpoint.");
+        assertTrue(busHandler.isCompleted(DELAY));
+        log.info("testSimple passed fourth busHandler checkpoint.");
 
         //
         // MOVE TIME AFTER NEXT BILL CYCLE DAY AND EXPECT EVENT : NextEvent.INVOICE
@@ -242,8 +242,7 @@ public class TestBasic {
         do {
             clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
             busHandler.pushExpectedEvent(NextEvent.INVOICE);
-            busHandler.pushExpectedEvent(NextEvent.INVOICE);
-            assertTrue(busHandler.isCompleted(5000));
+            assertTrue(busHandler.isCompleted(DELAY));
             lastCtd = checkAndGetCTD(subscription.getId());
         } while (maxCycles-- > 0);
 
@@ -257,7 +256,7 @@ public class TestBasic {
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
         Interval it = new Interval(lastCtd, clock.getUTCNow());
         clock.addDeltaFromReality(it.toDurationMillis());
-        assertTrue(busHandler.isCompleted(5000));
+        assertTrue(busHandler.isCompleted(DELAY));
     }
 
 
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
index 595a01b..9bf7c10 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/lifecycle/TestLifecycle.java
@@ -16,7 +16,11 @@
 
 package com.ning.billing.beatrix.lifecycle;
 
-import com.google.inject.*;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Stage;
 import com.ning.billing.lifecycle.KillbillService;
 import com.ning.billing.lifecycle.LifecycleHandlerType;
 import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
index adf9307..2df4f1f 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPlanPhase.java
@@ -17,7 +17,13 @@
 package com.ning.billing.catalog;
 
 import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationError;
 import com.ning.billing.util.config.ValidationErrors;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
index 48de5d4..aba447d 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
@@ -23,7 +23,13 @@ import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationError;
 import com.ning.billing.util.config.ValidationErrors;
 
-import javax.xml.bind.annotation.*;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlIDREF;
 
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implements PriceList  {
@@ -36,8 +42,7 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
 	private Boolean retired = false;
 	
 	@XmlElementWrapper(name="plans", required=true)
-	@XmlElement(name="plan", required=true)
-	@XmlIDREF
+	@XmlIDREF @XmlElement(name="plan", required=true)
     private DefaultPlan[] plans;
 	
 	public DefaultPriceList(){}
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
index bf8cfd4..ff3868c 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
@@ -21,15 +21,20 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationErrors;
 
-import javax.xml.bind.annotation.*;
-
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlIDREF;
 import java.net.URI;
 
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultProduct extends ValidatingConfig<StandaloneCatalog> implements Product {
 	private static final DefaultProduct[] EMPTY_PRODUCT_LIST = new DefaultProduct[0];
 	
-	@XmlAttribute (required=true)
+	@XmlAttribute(required=true)
 	@XmlID
     private String name;
 
@@ -42,7 +47,7 @@ public class DefaultProduct extends ValidatingConfig<StandaloneCatalog> implemen
 	@XmlElementWrapper(name="included", required=false)
 	@XmlIDREF @XmlElement(name="addonProduct", required=true)
     private DefaultProduct[] included = EMPTY_PRODUCT_LIST;
-	
+
 	@XmlElementWrapper(name="available", required=false)
 	@XmlIDREF @XmlElement(name="addonProduct", required=true)
     private DefaultProduct[] available = EMPTY_PRODUCT_LIST;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/rules/CaseChange.java b/catalog/src/main/java/com/ning/billing/catalog/rules/CaseChange.java
index f101ef1..963dc2f 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/rules/CaseChange.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/rules/CaseChange.java
@@ -19,7 +19,12 @@ package com.ning.billing.catalog.rules;
 import com.ning.billing.catalog.DefaultPriceList;
 import com.ning.billing.catalog.DefaultProduct;
 import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationErrors;
 
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
index 765d4bd..cb6a887 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -19,7 +19,11 @@ package com.ning.billing.catalog;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.catalog.rules.*;
+import com.ning.billing.catalog.rules.CaseCancelPolicy;
+import com.ning.billing.catalog.rules.CaseChangePlanAlignment;
+import com.ning.billing.catalog.rules.CaseChangePlanPolicy;
+import com.ning.billing.catalog.rules.CaseCreateAlignment;
+import com.ning.billing.catalog.rules.PlanRules;
 
 import java.util.Date;
 
diff --git a/catalog/src/test/java/com/ning/billing/catalog/rules/TestCaseChange.java b/catalog/src/test/java/com/ning/billing/catalog/rules/TestCaseChange.java
index f684503..ef1eb17 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/rules/TestCaseChange.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/rules/TestCaseChange.java
@@ -21,9 +21,14 @@ import com.ning.billing.catalog.DefaultPriceList;
 import com.ning.billing.catalog.DefaultProduct;
 import com.ning.billing.catalog.MockCatalog;
 import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.*;
-import com.ning.billing.catalog.rules.TestCase.CaseResult;
 
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.ProductCategory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -39,10 +44,10 @@ public class TestCaseChange {
 		private Result result;
 
 		public CaseChangeResult(DefaultProduct from, DefaultProduct to, 
-				ProductCategory fromProductCategory, ProductCategory toProductCategory, 
-				BillingPeriod fromBP, BillingPeriod toBP, 
+				ProductCategory fromProductCategory, ProductCategory toProductCategory,
+				BillingPeriod fromBP, BillingPeriod toBP,
 				DefaultPriceList fromPriceList, DefaultPriceList toPriceList,
-				PhaseType fromType, 
+				PhaseType fromType,
 				Result result) {
 			setFromProduct(from);
 			setToProduct(to);
@@ -63,7 +68,7 @@ public class TestCaseChange {
 		}
 	}
 	@Test(enabled=true)
-	public void testBasic() throws CatalogApiException{
+	public void testBasic() throws CatalogApiException {
 		MockCatalog cat = new MockCatalog();
 
 		DefaultProduct product1 = cat.getCurrentProducts()[0];
@@ -1043,8 +1048,8 @@ public class TestCaseChange {
 				String fromPriceListName, String toPriceListName,
 				PhaseType phaseType, StandaloneCatalog cat){
 	        try{
-	        	cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType), 
-						new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName),cat);	
+	        	cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType),
+						new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName),cat);
 	        	Assert.fail("Expecting an exception");
 	        } catch (CatalogApiException e) {
 	        	Assert.assertEquals(e.getCode(), ErrorCode.CAT_PRICE_LIST_NOT_FOUND.getCode());
diff --git a/catalog/src/test/java/com/ning/billing/catalog/rules/TestCasePhase.java b/catalog/src/test/java/com/ning/billing/catalog/rules/TestCasePhase.java
index 02f7ab5..1b28da7 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/rules/TestCasePhase.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/rules/TestCasePhase.java
@@ -21,7 +21,11 @@ import com.ning.billing.catalog.DefaultPriceList;
 import com.ning.billing.catalog.DefaultProduct;
 import com.ning.billing.catalog.MockCatalog;
 import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.ProductCategory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -195,7 +199,7 @@ public class TestCasePhase {
 	}
 	
 	@Test(enabled=true)
-	public void testOrder() throws CatalogApiException{
+	public void testOrder() throws CatalogApiException {
 		MockCatalog cat = new MockCatalog();
 
 		DefaultProduct product = cat.getCurrentProducts()[0];
diff --git a/catalog/src/test/java/com/ning/billing/catalog/rules/TestPlanRules.java b/catalog/src/test/java/com/ning/billing/catalog/rules/TestPlanRules.java
index 7ac9cc0..e9617ea 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/rules/TestPlanRules.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/rules/TestPlanRules.java
@@ -19,8 +19,17 @@ package com.ning.billing.catalog.rules;
 import com.ning.billing.catalog.DefaultPriceList;
 import com.ning.billing.catalog.DefaultProduct;
 import com.ning.billing.catalog.MockCatalog;
-import com.ning.billing.catalog.api.*;
 
+import com.ning.billing.catalog.api.ActionPolicy;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.IllegalPlanChange;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanAlignmentChange;
+import com.ning.billing.catalog.api.PlanChangeResult;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index 4c5e0af..efda54c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -20,7 +20,14 @@ import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.catalog.api.*;
+import com.ning.billing.catalog.api.BillingAlignment;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
@@ -33,7 +40,13 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
 
 public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
 	private static final Logger log = LoggerFactory.getLogger(DefaultEntitlementBillingApi.class);
@@ -60,7 +73,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
             subscriptions.addAll(dao.getSubscriptions(bundle.getId()));
         }
 
-        SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();        
+        SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
         for (final Subscription subscription: subscriptions) {
         	for (final SubscriptionTransition transition : subscription.getAllTransitions()) {
         		try {
@@ -89,14 +102,16 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
     	PlanPhase phase = transition.getNextPhase();
     	
     	BillingAlignment alignment = catalog.billingAlignment(
-    			new PlanPhaseSpecifier(product.getName(), 
+    			new PlanPhaseSpecifier(product.getName(),
     					product.getCategory(), 
     					phase.getBillingPeriod(), 
     					transition.getNextPriceList(), 
     					phase.getPhaseType()), 
     					transition.getRequestedTransitionTime());
     	int result = 0;
-    	Account account = accountApi.getAccountById(accountId);
+
+        Account account = accountApi.getAccountById(accountId);
+
     	switch (alignment) {
     		case ACCOUNT : 
     			result = account.getBillCycleDay();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 272f234..8d7592f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -30,7 +30,12 @@ import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
 
 public class SubscriptionData implements Subscription {
 
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 ec42757..e12adc3 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -50,6 +50,8 @@ public class InvoiceListener {
     private final AccountUserApi accountUserApi;
     private final InvoiceDao invoiceDao;
 
+    private final static boolean VERBOSE_OUTPUT = true;
+
     @Inject
     public InvoiceListener(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
                            final EntitlementBillingApi entitlementBillingApi,
@@ -107,7 +109,19 @@ public class InvoiceListener {
         InvoiceItemList invoiceItemList = new InvoiceItemList(items);
         Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
 
-        if (invoice != null) {
+        if (invoice == null) {
+            log.info("Generated null invoice.");
+            if (VERBOSE_OUTPUT) {
+                for (BillingEvent event : events) {
+                    log.info(event.toString());
+                }
+                for (InvoiceItem item : invoiceItemList) {
+                    log.info(item.toString());
+                }
+            }
+        } else {
+            log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
+
             if (invoice.getNumberOfItems() > 0) {
                 invoiceDao.create(invoice);
             }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/BillingModeBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/BillingModeBase.java
index d7235c7..ffdf806 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/BillingModeBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/BillingModeBase.java
@@ -60,10 +60,6 @@ public abstract class BillingModeBase implements BillingMode {
         return precedingProRation.add(numberOfBillingPeriods);
     }
 
-    DateTime buildDate(final int year, final int month, final int day) {
-        return new DateTime(year, month, day, 0, 0, 0, 0);
-    }
-
     boolean isNotBetween(DateTime targetDate, DateTime startDate, DateTime endDate) {
         return (targetDate.isBefore(startDate) || !targetDate.isBefore(endDate));
     }
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 47f5d67..0e2c2e5 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
@@ -44,8 +44,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     public Invoice generateInvoice(final UUID accountId, final BillingEventSet events,
                                    @Nullable final InvoiceItemList existingItems, final DateTime targetDate,
                                    final Currency targetCurrency) {
-        if (events == null) {return null;}
-        if (events.size() == 0) {return null;}
+        if (events == null) {
+            return null;
+        }
+
+        if (events.size() == 0) {
+            return null;
+        }
 
         DefaultInvoice invoice = new DefaultInvoice(accountId, targetDate, targetCurrency);
         InvoiceItemList currentItems = generateInvoiceItems(events, invoice.getId(), targetDate, targetCurrency);
@@ -61,7 +66,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
     private InvoiceItemList reconcileInvoiceItems(final UUID invoiceId, final InvoiceItemList currentInvoiceItems,
                                                   final InvoiceItemList existingInvoiceItems) {
-        if (existingInvoiceItems == null) {
+        if ((existingInvoiceItems == null) || (existingInvoiceItems.size() == 0)) {
             return currentInvoiceItems;
         }
 
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 136967c..84a3632 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
@@ -239,4 +239,20 @@ public class DefaultInvoiceItem implements InvoiceItem {
         if ((value1 == null) ^ (value2 == null)) {return false;}
         return (value1.add(value2).compareTo(BigDecimal.ZERO) == 0);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("InvoiceItem = {").append("id = ").append(id.toString()).append(", ");
+        sb.append("invoiceId = ").append(invoiceId.toString()).append(", ");
+        sb.append("subscriptionId = ").append(subscriptionId.toString()).append(", ");
+        sb.append("startDate = ").append(startDate.toString()).append(", ");
+        sb.append("endDate = ").append(startDate.toString()).append(", ");
+        sb.append("recurringAmount = ") .append(recurringAmount.toString()).append(", ");
+        sb.append("recurringRate = ").append(recurringRate.toString()).append(", ");
+        sb.append("fixedAmount = ").append(fixedAmount.toString());
+
+        sb.append("}");
+        return sb.toString();
+    }
 }
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 3ad4f50..0d5b261 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
@@ -52,9 +52,13 @@ public class InAdvanceBillingMode extends BillingModeBase {
 
         DateTime proposedDate;
         if (billingCycleDay > lastDayOfMonth) {
-            proposedDate = buildDate(date.getYear(), date.getMonthOfYear(), lastDayOfMonth);
+            proposedDate = new DateTime(date.getYear(), date.getMonthOfYear(), lastDayOfMonth,
+                                        date.getHourOfDay(), date.getMinuteOfHour(),
+                                        date.getSecondOfMinute(), date.getMillisOfSecond());
         } else {
-            proposedDate = buildDate(date.getYear(), date.getMonthOfYear(), billingCycleDay);
+            proposedDate = new DateTime(date.getYear(), date.getMonthOfYear(), billingCycleDay,
+                                        date.getHourOfDay(), date.getMinuteOfHour(),
+                                        date.getSecondOfMinute(), date.getMillisOfSecond());
         }
 
         while (proposedDate.isBefore(date)) {
@@ -74,9 +78,13 @@ public class InAdvanceBillingMode extends BillingModeBase {
                 int lastDayOfMonth = proposedDate.dayOfMonth().getMaximumValue();
 
                 if (lastDayOfMonth < billingCycleDay) {
-                    proposedDate = buildDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), lastDayOfMonth);
+                    proposedDate = new DateTime(proposedDate.getYear(), proposedDate.getMonthOfYear(), lastDayOfMonth,
+                                                proposedDate.getHourOfDay(), proposedDate.getMinuteOfHour(),
+                                                proposedDate.getSecondOfMinute(), proposedDate.getMillisOfSecond());
                 } else {
-                    proposedDate = buildDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), billingCycleDay);
+                    proposedDate = new DateTime(proposedDate.getYear(), proposedDate.getMonthOfYear(), billingCycleDay,
+                                                proposedDate.getHourOfDay(), proposedDate.getMinuteOfHour(),
+                                                proposedDate.getSecondOfMinute(), proposedDate.getMillisOfSecond());
                 }
             }
         }
@@ -100,9 +108,13 @@ public class InAdvanceBillingMode extends BillingModeBase {
         if (proposedDate.dayOfMonth().get() < billingCycleDay) {
             int lastDayOfTheMonth = proposedDate.dayOfMonth().getMaximumValue();
             if (lastDayOfTheMonth < billingCycleDay) {
-                return buildDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), lastDayOfTheMonth);
+                return new DateTime(proposedDate.getYear(), proposedDate.getMonthOfYear(), lastDayOfTheMonth,
+                                    proposedDate.getHourOfDay(), proposedDate.getMinuteOfHour(),
+                                    proposedDate.getSecondOfMinute(), proposedDate.getMillisOfSecond());
             } else {
-                return buildDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), billingCycleDay);
+                return new DateTime(proposedDate.getYear(), proposedDate.getMonthOfYear(), billingCycleDay,
+                                    proposedDate.getHourOfDay(), proposedDate.getMinuteOfHour(),
+                                    proposedDate.getSecondOfMinute(), proposedDate.getMillisOfSecond());
             }
         } else {
             return proposedDate;
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 702801b..4b7a679 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
@@ -22,6 +22,7 @@ import com.ning.billing.catalog.MockPlan;
 import com.ning.billing.catalog.MockPlanPhase;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.InternationalPrice;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
@@ -33,6 +34,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.dao.MockSubscription;
 import com.ning.billing.invoice.model.BillingEventSet;
 import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
 import com.ning.billing.invoice.model.DefaultInvoiceItem;
@@ -49,6 +51,8 @@ import java.util.UUID;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 @Test(groups = {"fast", "invoicing", "invoiceGenerator"})
 public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
@@ -415,6 +419,93 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 10, 10), 1, expectedAmount);
     }
 
+    @Test
+    public void testZeroDollarEvents() {
+        Plan plan = new MockPlan();
+        PlanPhase planPhase = createMockMonthlyPlanPhase(ZERO);
+        BillingEventSet events = new BillingEventSet();
+        DateTime targetDate = buildDateTime(2011, 1, 1);
+        events.add(createBillingEvent(UUID.randomUUID(), targetDate, plan, planPhase, 1));
+
+        InvoiceGenerator invoiceGenerator = new DefaultInvoiceGenerator();
+        Invoice invoice = invoiceGenerator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+
+        assertEquals(invoice.getNumberOfItems(), 1);
+    }
+
+    @Test
+    public void testEndDateIsCorrect() {
+        Plan plan = new MockPlan();
+        PlanPhase planPhase = createMockMonthlyPlanPhase(ZERO);
+        BillingEventSet events = new BillingEventSet();
+        DateTime targetDate = new DateTime();
+        events.add(createBillingEvent(UUID.randomUUID(), targetDate, plan, planPhase, targetDate.getDayOfMonth()));
+
+        InvoiceGenerator invoiceGenerator = new DefaultInvoiceGenerator();
+        Invoice invoice = invoiceGenerator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+        InvoiceItem item = invoice.getInvoiceItems().get(0);
+
+        // end date of the invoice item should be equal to exactly one month later
+        assertEquals(item.getEndDate().compareTo(targetDate.plusMonths(1)), 0);
+    }
+
+    @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");
+        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");
+        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");
+        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 3");
+        events.add(event4);
+
+        InvoiceItemList items = new InvoiceItemList();
+        UUID subscriptionId = UUID.randomUUID();
+        InvoiceItem item1 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, new DateTime("2012-01-30T16:02:04.000-08:00"), new DateTime("2012-01-30T16:02:04.000-08:00"), "1", ZERO, ZERO, ZERO, Currency.USD);
+        InvoiceItem item2 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, new DateTime("2012-02-29T16:02:04.000-08:00"), new DateTime("2012-02-29T16:02:04.000-08:00"), "2", ZERO, new BigDecimal("249.95"), ZERO, Currency.USD);
+        InvoiceItem item3 = new DefaultInvoiceItem(UUID.randomUUID(), subscriptionId, new DateTime("2012-01-30T16:02:04.000-08:00"), new DateTime("2012-01-30T16:02:04.000-08:00"), "3", 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);
+    }
+
     private MockPlanPhase createMockMonthlyPlanPhase() {
         return new MockPlanPhase(null, null, BillingPeriod.MONTHLY);
     }
@@ -424,6 +515,13 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
                                  null, BillingPeriod.MONTHLY);
     }
 
+    private MockPlanPhase createMockMonthlyPlanPhase(@Nullable final BigDecimal recurringRate,
+                                                     final BigDecimal fixedRate, PhaseType phaseType) {
+        return new MockPlanPhase(new MockInternationalPrice(new DefaultPrice(recurringRate, Currency.USD)),
+                                 new MockInternationalPrice(new DefaultPrice(fixedRate, Currency.USD)),
+                                 BillingPeriod.MONTHLY, phaseType);
+    }
+
     private MockPlanPhase createMockMonthlyPlanPhase(final BigDecimal recurringRate, final PhaseType phaseType) {
         return new MockPlanPhase(new MockInternationalPrice(new DefaultPrice(recurringRate, Currency.USD)),
                                  null, BillingPeriod.MONTHLY, phaseType);