killbill-aplcache

Merge branch 'integration' of github.com:ning/killbill

4/17/2012 6:53:42 PM

Changes

analytics/pom.xml 23(+23 -0)

bin/cleanAndInstall 23(+23 -0)

bin/db-helper 3(+1 -2)

catalog/pom.xml 6(+6 -0)

ne/pom.xml 120(+120 -0)

overdue/pom.xml 133(+133 -0)

pom.xml 17(+17 -0)

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index d6752e9..efeb07d 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -256,7 +256,7 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
 
     @Override
 	public MutableAccountData toMutableAccountData() {
-	    return new MutableAccountData(this);
+	    return new DefaultMutableAccountData(this);
 	}
     
 	@Override
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultMutableAccountData.java b/account/src/main/java/com/ning/billing/account/api/DefaultMutableAccountData.java
new file mode 100644
index 0000000..4476130
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultMutableAccountData.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.account.api;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.tag.TagStore;
+
+public class DefaultMutableAccountData implements AccountData, MutableAccountData {
+    private String externalKey;
+    private String email;
+    private String name;
+    private int firstNameLength;
+    private Currency currency;
+    private int billCycleDay;
+    private String paymentProviderName;
+    private DateTimeZone timeZone;
+    private String locale;
+    private String address1;
+    private String address2;
+    private String companyName;
+    private String city;
+    private String stateOrProvince;
+    private String country;
+    private String postalCode;
+    private String phone;
+    
+    public DefaultMutableAccountData(String externalKey, String email, String name,
+            int firstNameLength, Currency currency, int billCycleDay,
+            String paymentProviderName, TagStore tags, DateTimeZone timeZone,
+            String locale, String address1, String address2,
+            String companyName, String city, String stateOrProvince,
+            String country, String postalCode, String phone,
+            DateTime createdDate, DateTime updatedDate) {
+        super();
+        this.externalKey = externalKey;
+        this.email = email;
+        this.name = name;
+        this.firstNameLength = firstNameLength;
+        this.currency = currency;
+        this.billCycleDay = billCycleDay;
+        this.paymentProviderName = paymentProviderName;
+        this.timeZone = timeZone;
+        this.locale = locale;
+        this.address1 = address1;
+        this.address2 = address2;
+        this.companyName = companyName;
+        this.city = city;
+        this.stateOrProvince = stateOrProvince;
+        this.country = country;
+        this.postalCode = postalCode;
+        this.phone = phone;
+    }
+    
+    public DefaultMutableAccountData(AccountData accountData) {
+        super();
+        this.externalKey = accountData.getExternalKey();
+        this.email = accountData.getEmail();
+        this.name = accountData.getName();
+        this.firstNameLength = accountData.getFirstNameLength();
+        this.currency = accountData.getCurrency();
+        this.billCycleDay = accountData.getBillCycleDay();
+        this.paymentProviderName = accountData.getPaymentProviderName();
+        this.timeZone = accountData.getTimeZone();
+        this.locale = accountData.getLocale();
+        this.address1 = accountData.getAddress1();
+        this.address2 = accountData.getAddress2();
+        this.companyName = accountData.getCompanyName();
+        this.city = accountData.getCity();
+        this.stateOrProvince = accountData.getStateOrProvince();
+        this.country = accountData.getCountry();
+        this.postalCode = accountData.getPostalCode();
+        this.phone = accountData.getPhone();
+    }
+
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getExternalKey()
+     */
+    @Override
+    public String getExternalKey() {
+        return externalKey;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getEmail()
+     */
+    @Override
+    public String getEmail() {
+        return email;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getName()
+     */
+    @Override
+    public String getName() {
+        return name;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getFirstNameLength()
+     */
+    @Override
+    public int getFirstNameLength() {
+        return firstNameLength;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getCurrency()
+     */
+    @Override
+    public Currency getCurrency() {
+        return currency;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getBillCycleDay()
+     */
+    @Override
+    public int getBillCycleDay() {
+        return billCycleDay;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getPaymentProviderName()
+     */
+    @Override
+    public String getPaymentProviderName() {
+        return paymentProviderName;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getTimeZone()
+     */
+    @Override
+    public DateTimeZone getTimeZone() {
+        return timeZone;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getLocale()
+     */
+    @Override
+    public String getLocale() {
+        return locale;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getAddress1()
+     */
+    @Override
+    public String getAddress1() {
+        return address1;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getAddress2()
+     */
+    @Override
+    public String getAddress2() {
+        return address2;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getCompanyName()
+     */
+    @Override
+    public String getCompanyName() {
+        return companyName;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getCity()
+     */
+    @Override
+    public String getCity() {
+        return city;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getStateOrProvince()
+     */
+    @Override
+    public String getStateOrProvince() {
+        return stateOrProvince;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getCountry()
+     */
+    @Override
+    public String getCountry() {
+        return country;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getPostalCode()
+     */
+    @Override
+    public String getPostalCode() {
+        return postalCode;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#getPhone()
+     */
+    @Override
+    public String getPhone() {
+        return phone;
+    }
+    
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setExternalKey(java.lang.String)
+     */
+    @Override
+    public void setExternalKey(String externalKey) {
+        this.externalKey = externalKey;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setEmail(java.lang.String)
+     */
+    @Override
+    public void setEmail(String email) {
+        this.email = email;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setName(java.lang.String)
+     */
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setFirstNameLength(int)
+     */
+    @Override
+    public void setFirstNameLength(int firstNameLength) {
+        this.firstNameLength = firstNameLength;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setCurrency(com.ning.billing.catalog.api.Currency)
+     */
+    @Override
+    public void setCurrency(Currency currency) {
+        this.currency = currency;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setBillCycleDay(int)
+     */
+    @Override
+    public void setBillCycleDay(int billCycleDay) {
+        this.billCycleDay = billCycleDay;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setPaymentProviderName(java.lang.String)
+     */
+    @Override
+    public void setPaymentProviderName(String paymentProviderName) {
+        this.paymentProviderName = paymentProviderName;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setTimeZone(org.joda.time.DateTimeZone)
+     */
+    @Override
+    public void setTimeZone(DateTimeZone timeZone) {
+        this.timeZone = timeZone;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setLocale(java.lang.String)
+     */
+    @Override
+    public void setLocale(String locale) {
+        this.locale = locale;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setAddress1(java.lang.String)
+     */
+    @Override
+    public void setAddress1(String address1) {
+        this.address1 = address1;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setAddress2(java.lang.String)
+     */
+    @Override
+    public void setAddress2(String address2) {
+        this.address2 = address2;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setCompanyName(java.lang.String)
+     */
+    @Override
+    public void setCompanyName(String companyName) {
+        this.companyName = companyName;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setCity(java.lang.String)
+     */
+    @Override
+    public void setCity(String city) {
+        this.city = city;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setStateOrProvince(java.lang.String)
+     */
+    @Override
+    public void setStateOrProvince(String stateOrProvince) {
+        this.stateOrProvince = stateOrProvince;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setCountry(java.lang.String)
+     */
+    @Override
+    public void setCountry(String country) {
+        this.country = country;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setPostalCode(java.lang.String)
+     */
+    @Override
+    public void setPostalCode(String postalCode) {
+        this.postalCode = postalCode;
+    }
+    /* (non-Javadoc)
+     * @see com.ning.billing.account.api.MutableAccountData#setPhone(java.lang.String)
+     */
+    @Override
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+
+}
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index ad186fd..f35a5eb 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -30,6 +30,7 @@ import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.MigrationAccountData;
+import com.ning.billing.account.api.DefaultMutableAccountData;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;

analytics/pom.xml 23(+23 -0)

diff --git a/analytics/pom.xml b/analytics/pom.xml
index a92d088..f3bae99 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -65,11 +65,34 @@
         <dependency>
             <groupId>com.ning.billing</groupId>
             <artifactId>killbill-catalog</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+         <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-entitlement</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.ning.billing</groupId>
             <artifactId>killbill-entitlement</artifactId>
+             <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+             <type>test-jar</type>
             <scope>test</scope>
         </dependency>
         <dependency>
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 71e3402..ddcc9c7 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
@@ -91,7 +91,7 @@ public class BusinessSubscription
      */
     BusinessSubscription(final Subscription subscription, final Currency currency)
     {
-        this(subscription.getCurrentPriceList(), subscription.getCurrentPlan(), subscription.getCurrentPhase(), currency, subscription.getStartDate(), subscription.getState(), subscription.getId(), subscription.getBundleId());
+        this(subscription.getCurrentPriceList() == null ? null : subscription.getCurrentPriceList().getName(), subscription.getCurrentPlan(), subscription.getCurrentPhase(), currency, subscription.getStartDate(), subscription.getState(), subscription.getId(), subscription.getBundleId());
     }
 
     public BusinessSubscription(final String priceList, final Plan currentPlan, final PlanPhase currentPhase, final Currency currency, final DateTime startDate, final SubscriptionState state, final UUID subscriptionId, final UUID bundleId)
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
index 2bb02ea..82457ef 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscriptionTransitionRecorder.java
@@ -115,7 +115,7 @@ public class BusinessSubscriptionTransitionRecorder
             prevSubscription = null;
         }
         else {
-            prevSubscription = new BusinessSubscription(transition.getPreviousPriceList(), transition.getPreviousPlan(), transition.getPreviousPhase(), currency, previousEffectiveTransitionTime, transition.getPreviousState(), transition.getSubscriptionId(), transition.getBundleId());
+            prevSubscription = new BusinessSubscription(transition.getPreviousPriceList() == null ? null : transition.getPreviousPriceList().getName(), transition.getPreviousPlan(), transition.getPreviousPhase(), currency, previousEffectiveTransitionTime, transition.getPreviousState(), transition.getSubscriptionId(), transition.getBundleId());
         }
         final BusinessSubscription nextSubscription;
 
@@ -124,7 +124,7 @@ public class BusinessSubscriptionTransitionRecorder
             nextSubscription = null;
         }
         else {
-            nextSubscription = new BusinessSubscription(transition.getNextPriceList(), transition.getNextPlan(), transition.getNextPhase(), currency, transition.getEffectiveTransitionTime(), transition.getNextState(), transition.getSubscriptionId(), transition.getBundleId());
+            nextSubscription = new BusinessSubscription(transition.getNextPriceList() == null ? null : transition.getNextPriceList().getName(), transition.getNextPlan(), transition.getNextPhase(), currency, transition.getEffectiveTransitionTime(), transition.getNextState(), transition.getSubscriptionId(), transition.getBundleId());
         }
 
         record(transition.getId(), transitionKey, accountKey, transition.getRequestedTransitionTime(), event, prevSubscription, nextSubscription);
diff --git a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
index 1aafa7c..1d1b1ad 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/AnalyticsTestModule.java
@@ -16,25 +16,22 @@
 
 package com.ning.billing.analytics;
 
-import com.ning.billing.invoice.glue.InvoiceModule;
-import com.ning.billing.payment.setup.PaymentModule;
-import com.ning.billing.util.glue.CallContextModule;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
 import org.skife.jdbi.v2.IDBI;
+
 import com.ning.billing.account.glue.AccountModule;
 import com.ning.billing.analytics.setup.AnalyticsModule;
-import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.glue.EntitlementModule;
-
+import com.ning.billing.invoice.glue.InvoiceModule;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+import com.ning.billing.payment.setup.PaymentModule;
 import com.ning.billing.util.glue.BusModule;
-
+import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.ClockModule;
+import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
-
-import java.lang.reflect.Field;
+import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
 
 public class AnalyticsTestModule extends AnalyticsModule
 {
@@ -49,9 +46,9 @@ public class AnalyticsTestModule extends AnalyticsModule
         install(new FieldStoreModule());
         install(new TagStoreModule());
         install(new AccountModule());
-        install(new CatalogModule());
         install(new BusModule());
         install(new EntitlementModule());
+        install(new MockOverdueAccessModule());
         install(new InvoiceModule());
         install(new PaymentModule());
         install(new TagStoreModule());
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index ac25c74..71cbeb1 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -26,11 +26,6 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.testng.Assert;
@@ -56,10 +51,13 @@ import com.ning.billing.analytics.MockPlan;
 import com.ning.billing.analytics.MockProduct;
 import com.ning.billing.analytics.dao.BusinessAccountDao;
 import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionDao;
+import com.ning.billing.catalog.MockCatalogModule;
+import com.ning.billing.catalog.MockPriceList;
 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.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.dbi.MysqlTestingHelper;
@@ -71,6 +69,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.user.DefaultInvoiceCreationNotification;
 import com.ning.billing.invoice.dao.InvoiceDao;
@@ -81,6 +80,10 @@ import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.tag.DefaultTagDefinition;
@@ -88,7 +91,7 @@ import com.ning.billing.util.tag.DescriptiveTag;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
 
-@Guice(modules = AnalyticsTestModule.class)
+@Guice(modules = {AnalyticsTestModule.class, MockCatalogModule.class})
 public class TestAnalyticsService {
     private static final UUID ID = UUID.randomUUID();
     private static final String KEY = "12345";
@@ -208,7 +211,7 @@ public class TestAnalyticsService {
         final UUID subscriptionId = UUID.randomUUID();
         final DateTime effectiveTransitionTime = clock.getUTCNow();
         final DateTime requestedTransitionTime = clock.getUTCNow();
-        final String priceList = "something";
+        final PriceList priceList = new MockPriceList().setName("something");
 
         transition = new SubscriptionTransitionData(
                 ID,
@@ -237,7 +240,7 @@ public class TestAnalyticsService {
                 requestedTransitionTime,
                 BusinessSubscriptionEvent.subscriptionCreated(plan),
                 null,
-                new BusinessSubscription(priceList, plan, phase, ACCOUNT_CURRENCY, effectiveTransitionTime, Subscription.SubscriptionState.ACTIVE, subscriptionId, bundle.getId())
+                new BusinessSubscription(priceList.getName(), plan, phase, ACCOUNT_CURRENCY, effectiveTransitionTime, Subscription.SubscriptionState.ACTIVE, subscriptionId, bundle.getId())
         );
     }
 
@@ -248,7 +251,7 @@ public class TestAnalyticsService {
     private void createInvoiceAndPaymentCreationEvents(final Account account) {
         final DefaultInvoice invoice = new DefaultInvoice(account.getId(), clock.getUTCNow(), clock.getUTCNow(), ACCOUNT_CURRENCY);
         final FixedPriceInvoiceItem invoiceItem = new FixedPriceInvoiceItem(
-                UUID.randomUUID(), invoice.getId(), account.getId(), UUID.randomUUID(), "somePlan", "somePhase", clock.getUTCNow(), clock.getUTCNow().plusDays(1),
+                UUID.randomUUID(), invoice.getId(), account.getId(), UUID.randomUUID(), UUID.randomUUID(), "somePlan", "somePhase", clock.getUTCNow(), clock.getUTCNow().plusDays(1),
                 INVOICE_AMOUNT, ACCOUNT_CURRENCY, context.getUserName(), clock.getUTCNow());
         invoice.addInvoiceItem(invoiceItem);
 
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
index 4942118..5e94f15 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
@@ -19,13 +19,13 @@ package com.ning.billing.analytics;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.MutableAccountData;
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockDuration.java b/analytics/src/test/java/com/ning/billing/analytics/MockDuration.java
index f10ff2f..e2fa1a2 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockDuration.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockDuration.java
@@ -20,6 +20,7 @@ import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.TimeUnit;
 import org.apache.commons.lang.NotImplementedException;
 import org.joda.time.DateTime;
+import org.joda.time.Period;
 
 public class MockDuration
 {
@@ -43,6 +44,10 @@ public class MockDuration
             public DateTime addToDateTime(DateTime dateTime) {
                 throw new NotImplementedException();
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
     }
 
@@ -66,6 +71,10 @@ public class MockDuration
             public DateTime addToDateTime(DateTime dateTime) {
                 throw new NotImplementedException();
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
     }
 
@@ -89,6 +98,10 @@ public class MockDuration
             public DateTime addToDateTime(DateTime dateTime) {
                 throw new NotImplementedException();
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
index 06e3d79..1fe60e7 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockEntitlementUserApi.java
@@ -21,14 +21,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
+
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
-
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.util.callcontext.CallContext;
 
 public class MockEntitlementUserApi implements EntitlementUserApi
 {
@@ -72,6 +73,11 @@ public class MockEntitlementUserApi implements EntitlementUserApi
             {
                 return key;
             }
+
+            @Override
+            public OverdueState<SubscriptionBundle> getOverdueState() {
+                throw new UnsupportedOperationException();
+            }
         };
     }
 
@@ -119,4 +125,9 @@ public class MockEntitlementUserApi implements EntitlementUserApi
 	public DateTime getNextBillingDate(UUID account) {
 		throw new UnsupportedOperationException();
 	}
+
+    @Override
+    public Subscription getBaseSubscription(UUID bundleId) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
index 6a83560..306bf90 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
@@ -16,24 +16,26 @@
 
 package com.ning.billing.analytics;
 
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
 import com.ning.billing.catalog.api.BillingPeriod;
 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.PriceList;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
-
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 
-import java.util.List;
-import java.util.UUID;
 
 public class MockSubscription implements Subscription
 {
@@ -118,7 +120,7 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public String getCurrentPriceList()
+    public PriceList getCurrentPriceList()
     {
         return null;
     }
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 15ebf67..037b9b5 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/TestAnalyticsListener.java
@@ -16,24 +16,27 @@
 
 package com.ning.billing.analytics;
 
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
 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.PriceList;
 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;
 import com.ning.billing.entitlement.events.user.ApiEventType;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
 
 public class TestAnalyticsListener
 {
@@ -47,7 +50,7 @@ public class TestAnalyticsListener
     private final Product product = new MockProduct("platinium", "subscription", ProductCategory.BASE);
     private final Plan plan = new MockPlan("platinum-monthly", product);
     private final PlanPhase phase = new MockPhase(PhaseType.EVERGREEN, plan, MockDuration.UNLIMITED(), 25.95);
-    private final String priceList = null;
+    private final PriceList priceList = null;
 
     private AnalyticsListener listener;
 
diff --git a/api/src/main/java/com/ning/billing/account/api/Account.java b/api/src/main/java/com/ning/billing/account/api/Account.java
index 3f1e383..b7f6337 100644
--- a/api/src/main/java/com/ning/billing/account/api/Account.java
+++ b/api/src/main/java/com/ning/billing/account/api/Account.java
@@ -16,12 +16,12 @@
 
 package com.ning.billing.account.api;
 
-import com.ning.billing.util.entity.UpdatableEntity;
-
+import com.ning.billing.overdue.config.api.Overdueable;
 import com.ning.billing.util.customfield.Customizable;
+import com.ning.billing.util.entity.UpdatableEntity;
 import com.ning.billing.util.tag.Taggable;
 
-public interface Account extends AccountData, Customizable, UpdatableEntity, Taggable {
+public interface Account extends AccountData, Customizable, UpdatableEntity, Taggable, Overdueable{ 
     public static String ObjectType = "account";
     
     public MutableAccountData toMutableAccountData();    
diff --git a/api/src/main/java/com/ning/billing/account/api/MutableAccountData.java b/api/src/main/java/com/ning/billing/account/api/MutableAccountData.java
index 2909b2d..78dad92 100644
--- a/api/src/main/java/com/ning/billing/account/api/MutableAccountData.java
+++ b/api/src/main/java/com/ning/billing/account/api/MutableAccountData.java
@@ -16,182 +16,78 @@
 
 package com.ning.billing.account.api;
 
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.util.tag.TagStore;
-
-public class MutableAccountData implements AccountData {
-    private String externalKey;
-    private String email;
-    private String name;
-    private int firstNameLength;
-    private Currency currency;
-    private int billCycleDay;
-    private String paymentProviderName;
-    private DateTimeZone timeZone;
-    private String locale;
-    private String address1;
-    private String address2;
-    private String companyName;
-    private String city;
-    private String stateOrProvince;
-    private String country;
-    private String postalCode;
-    private String phone;
-    
-    public MutableAccountData(String externalKey, String email, String name,
-            int firstNameLength, Currency currency, int billCycleDay,
-            String paymentProviderName, TagStore tags, DateTimeZone timeZone,
-            String locale, String address1, String address2,
-            String companyName, String city, String stateOrProvince,
-            String country, String postalCode, String phone,
-            DateTime createdDate, DateTime updatedDate) {
-        super();
-        this.externalKey = externalKey;
-        this.email = email;
-        this.name = name;
-        this.firstNameLength = firstNameLength;
-        this.currency = currency;
-        this.billCycleDay = billCycleDay;
-        this.paymentProviderName = paymentProviderName;
-        this.timeZone = timeZone;
-        this.locale = locale;
-        this.address1 = address1;
-        this.address2 = address2;
-        this.companyName = companyName;
-        this.city = city;
-        this.stateOrProvince = stateOrProvince;
-        this.country = country;
-        this.postalCode = postalCode;
-        this.phone = phone;
-    }
-    
-    public MutableAccountData(AccountData accountData) {
-        super();
-        this.externalKey = accountData.getExternalKey();
-        this.email = accountData.getEmail();
-        this.name = accountData.getName();
-        this.firstNameLength = accountData.getFirstNameLength();
-        this.currency = accountData.getCurrency();
-        this.billCycleDay = accountData.getBillCycleDay();
-        this.paymentProviderName = accountData.getPaymentProviderName();
-        this.timeZone = accountData.getTimeZone();
-        this.locale = accountData.getLocale();
-        this.address1 = accountData.getAddress1();
-        this.address2 = accountData.getAddress2();
-        this.companyName = accountData.getCompanyName();
-        this.city = accountData.getCity();
-        this.stateOrProvince = accountData.getStateOrProvince();
-        this.country = accountData.getCountry();
-        this.postalCode = accountData.getPostalCode();
-        this.phone = accountData.getPhone();
-    }
-
-    public String getExternalKey() {
-        return externalKey;
-    }
-    public String getEmail() {
-        return email;
-    }
-    public String getName() {
-        return name;
-    }
-    public int getFirstNameLength() {
-        return firstNameLength;
-    }
-    public Currency getCurrency() {
-        return currency;
-    }
-    public int getBillCycleDay() {
-        return billCycleDay;
-    }
-    public String getPaymentProviderName() {
-        return paymentProviderName;
-    }
-    public DateTimeZone getTimeZone() {
-        return timeZone;
-    }
-    public String getLocale() {
-        return locale;
-    }
-    public String getAddress1() {
-        return address1;
-    }
-    public String getAddress2() {
-        return address2;
-    }
-    public String getCompanyName() {
-        return companyName;
-    }
-    public String getCity() {
-        return city;
-    }
-    public String getStateOrProvince() {
-        return stateOrProvince;
-    }
-    public String getCountry() {
-        return country;
-    }
-    public String getPostalCode() {
-        return postalCode;
-    }
-    public String getPhone() {
-        return phone;
-    }
-    
-    public void setExternalKey(String externalKey) {
-        this.externalKey = externalKey;
-    }
-    public void setEmail(String email) {
-        this.email = email;
-    }
-    public void setName(String name) {
-        this.name = name;
-    }
-    public void setFirstNameLength(int firstNameLength) {
-        this.firstNameLength = firstNameLength;
-    }
-    public void setCurrency(Currency currency) {
-        this.currency = currency;
-    }
-    public void setBillCycleDay(int billCycleDay) {
-        this.billCycleDay = billCycleDay;
-    }
-    public void setPaymentProviderName(String paymentProviderName) {
-        this.paymentProviderName = paymentProviderName;
-    }
-    public void setTimeZone(DateTimeZone timeZone) {
-        this.timeZone = timeZone;
-    }
-    public void setLocale(String locale) {
-        this.locale = locale;
-    }
-    public void setAddress1(String address1) {
-        this.address1 = address1;
-    }
-    public void setAddress2(String address2) {
-        this.address2 = address2;
-    }
-    public void setCompanyName(String companyName) {
-        this.companyName = companyName;
-    }
-    public void setCity(String city) {
-        this.city = city;
-    }
-    public void setStateOrProvince(String stateOrProvince) {
-        this.stateOrProvince = stateOrProvince;
-    }
-    public void setCountry(String country) {
-        this.country = country;
-    }
-    public void setPostalCode(String postalCode) {
-        this.postalCode = postalCode;
-    }
-    public void setPhone(String phone) {
-        this.phone = phone;
-    }
-
-
-}
+
+public interface MutableAccountData extends AccountData {
+
+    public String getExternalKey();
+
+    public String getEmail();
+
+    public String getName();
+
+    public int getFirstNameLength();
+
+    public Currency getCurrency();
+
+    public int getBillCycleDay();
+
+    public String getPaymentProviderName();
+
+    public DateTimeZone getTimeZone();
+
+    public String getLocale();
+
+    public String getAddress1();
+
+    public String getAddress2();
+
+    public String getCompanyName();
+
+    public String getCity();
+
+    public String getStateOrProvince();
+
+    public String getCountry();
+
+    public String getPostalCode();
+
+    public String getPhone();
+
+    public void setExternalKey(String externalKey);
+
+    public void setEmail(String email);
+
+    public void setName(String name);
+
+    public void setFirstNameLength(int firstNameLength);
+
+    public void setCurrency(Currency currency);
+
+    public void setBillCycleDay(int billCycleDay);
+
+    public void setPaymentProviderName(String paymentProviderName);
+
+    public void setTimeZone(DateTimeZone timeZone);
+
+    public void setLocale(String locale);
+
+    public void setAddress1(String address1);
+
+    public void setAddress2(String address2);
+
+    public void setCompanyName(String companyName);
+
+    public void setCity(String city);
+
+    public void setStateOrProvince(String stateOrProvince);
+
+    public void setCountry(String country);
+
+    public void setPostalCode(String postalCode);
+
+    public void setPhone(String phone);
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/catalog/api/Catalog.java b/api/src/main/java/com/ning/billing/catalog/api/Catalog.java
index 2b3609a..924a5e4 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/Catalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/Catalog.java
@@ -56,6 +56,11 @@ public interface Catalog {
     public abstract PlanPhase findPhase(String name, DateTime requestedDate, DateTime subscriptionStartDate) throws CatalogApiException;
 
     //
+    // Find a priceList
+    //  
+    public abstract PriceList findPriceList(String name, DateTime requestedDate) throws CatalogApiException;
+
+    //
     // Rules
     //
 	public abstract ActionPolicy planChangePolicy(PlanPhaseSpecifier from,
@@ -74,7 +79,5 @@ public interface Catalog {
 			PlanSpecifier to, DateTime requestedDate) throws CatalogApiException;
 
     public abstract boolean canCreatePlan(PlanSpecifier specifier, DateTime requestedDate) throws CatalogApiException;
-	
-	
-	
+		
 }
diff --git a/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java b/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java
new file mode 100644
index 0000000..8525d91
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/catalog/api/OverdueActions.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog.api;
+
+public enum OverdueActions  {
+	CANCEL,
+	PAYMENT_RETRY
+}
diff --git a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
index c93fde8..d9b0053 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/StaticCatalog.java
@@ -18,6 +18,10 @@ package com.ning.billing.catalog.api;
 
 import java.util.Date;
 
+import com.ning.billing.account.api.Account;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+
 
 public interface StaticCatalog {
     //
@@ -48,10 +52,15 @@ public interface StaticCatalog {
     //
     // Find a phase
     //
-    public abstract PlanPhase findCurrentPhase(String name) throws CatalogApiException;
+    public abstract  PlanPhase findCurrentPhase(String name) throws CatalogApiException;
+    
+    //
+    // Find a pricelist
+    //
+    public abstract PriceList findCurrentPricelist(String name) throws CatalogApiException;
     
     //
-    // Rules
+    //  
     //
 	public abstract ActionPolicy planChangePolicy(PlanPhaseSpecifier from,
 			PlanSpecifier to) throws CatalogApiException;
@@ -71,6 +80,4 @@ public interface StaticCatalog {
 
     public abstract boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException;
 
-
-	
 }
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/config/CatalogConfig.java b/api/src/main/java/com/ning/billing/config/CatalogConfig.java
index 97f4957..73ffd9a 100644
--- a/api/src/main/java/com/ning/billing/config/CatalogConfig.java
+++ b/api/src/main/java/com/ning/billing/config/CatalogConfig.java
@@ -22,7 +22,7 @@ import org.skife.config.Default;
 public interface CatalogConfig extends KillbillConfig {
 
     @Config("killbill.catalog.uri")
-    @Default("jar:///com/ning/billing/irs/catalog/NingCatalog.xml")
+    @Default("jar:///com/ning/billing/irs/catalog/Catalog.xml")
     String getCatalogURI();
 
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
index 4f2e0d9..d59701a 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/BillingEvent.java
@@ -16,21 +16,26 @@
 
 package com.ning.billing.entitlement.api.billing;
 
-import com.ning.billing.catalog.api.Currency;
+import java.math.BigDecimal;
+
 import org.joda.time.DateTime;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 
-import java.math.BigDecimal;
-
 public interface BillingEvent extends Comparable<BillingEvent> {
 
     /**
+     * @return the account that this billing event is associated with
+     */
+    public Account getAccount();
+
+    /**
      *
      * @return the billCycleDay as seen for that subscription at that time
      *
@@ -109,4 +114,4 @@ public interface BillingEvent extends Comparable<BillingEvent> {
 	 */
 	public Long getTotalOrdering();
 
-}
+ }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
index 0d87399..90572b3 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
@@ -33,7 +33,7 @@ public interface EntitlementBillingApi {
      * @return an ordered list of billing event for the given accounts
      *
      */
-    public SortedSet<BillingEvent> getBillingEventsForAccount(UUID accountId);
+    public SortedSet<BillingEvent> getBillingEventsForAccountAndUpdateAccountBCD(UUID accountId);
 
     public UUID getAccountIdFromSubscriptionId(UUID subscriptionId);
 
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 205f256..66091e2 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
@@ -37,6 +37,8 @@ public interface EntitlementUserApi {
     public List<Subscription> getSubscriptionsForBundle(UUID bundleId);
 
     public List<Subscription> getSubscriptionsForKey(String bundleKey);
+    
+    public Subscription getBaseSubscription(UUID bundleId);
 
     public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleKey, CallContext context)
         throws EntitlementUserApiException;
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
index 5515898..da8ad47 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/Subscription.java
@@ -16,17 +16,18 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
 import com.ning.billing.catalog.api.BillingPeriod;
 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.PriceList;
 import com.ning.billing.catalog.api.ProductCategory;
-
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.entity.ExtendedEntity;
-import org.joda.time.DateTime;
-
-import java.util.UUID;
 
 
 public interface Subscription extends ExtendedEntity {
@@ -58,7 +59,7 @@ public interface Subscription extends ExtendedEntity {
 
     public Plan getCurrentPlan();
 
-    public String getCurrentPriceList();
+    public PriceList getCurrentPriceList();
 
     public PlanPhase getCurrentPhase();
 
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
index f7c2e84..8794856 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
@@ -16,11 +16,14 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 
-import java.util.UUID;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
 
-public interface SubscriptionBundle {
+public interface SubscriptionBundle extends Overdueable {
 
     public UUID getAccountId();
 
@@ -29,4 +32,6 @@ public interface SubscriptionBundle {
     public DateTime getStartDate();
 
     public String getKey();
+
+    public OverdueState<SubscriptionBundle> getOverdueState();
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEventTransition.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEventTransition.java
index b1efaad..e0de69d 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEventTransition.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionEventTransition.java
@@ -16,13 +16,15 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.util.bus.BusEvent;
-import org.joda.time.DateTime;
-
-import java.util.UUID;
 
 public interface SubscriptionEventTransition extends BusEvent {
 
@@ -53,7 +55,7 @@ public interface SubscriptionEventTransition extends BusEvent {
 
     Plan getPreviousPlan();
 
-    String getPreviousPriceList();
+    PriceList getPreviousPriceList();
 
     PlanPhase getPreviousPhase();
 
@@ -63,7 +65,7 @@ public interface SubscriptionEventTransition extends BusEvent {
 
     SubscriptionState getNextState();
 
-    String getNextPriceList();
+    PriceList getNextPriceList();
     
     Integer getRemainingEventsForUserOperation();
 }
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 57ea8d9..db73376 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -56,6 +56,9 @@ public enum ErrorCode {
     ENT_GET_NO_BUNDLE_FOR_SUBSCRIPTION(1080, "Could not find a bundle for subscription %s"),
     ENT_GET_INVALID_BUNDLE_ID(1081, "Could not find a bundle matching id %s"),
     ENT_INVALID_SUBSCRIPTION_ID(1082, "Unknown subscription %s"),
+    
+    ENT_BUNDLE_IS_OVERDUE_BLOCKED(1090, "Changes to this bundle are blocked by overdue enforcement (%s :  %s)"),
+    ENT_ACCOUNT_IS_OVERDUE_BLOCKED(1091, "Changes to this account are blocked by overdue enforcement (%s)"),
     /*
     *
     * Range 2000 : CATALOG
@@ -107,7 +110,12 @@ public enum ErrorCode {
      * Billing Alignment
      */
     CAT_INVALID_BILLING_ALIGNMENT(2060, "Invalid billing alignment '%s'"),
-
+    /*
+     * Overdue
+     */
+    CAT_NO_SUCH_OVEDUE_STATE(2070, "No such overdue state '%s'"),
+    CAT_MISSING_CLEAR_STATE(2071, "Missing a clear state"),
+    CAT_NO_OVERDUEABLE_TYPE(2072, "No such overdueable type: "),
    /*
     *
     * Range 3000 : ACCOUNT
@@ -150,7 +158,17 @@ public enum ErrorCode {
     INVOICE_INVALID_TRANSITION(4002, "Transition did not contain a subscription id."),
     INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID(4003, "No account id was retrieved for subscription id %s"),
     INVOICE_INVALID_DATE_SEQUENCE(4004, "Date sequence was invalid. Start Date: %s; End Date: %s; Target Date: %s"),
-    INVOICE_TARGET_DATE_TOO_FAR_IN_THE_FUTURE(4005, "The target date was too far in the future. Target Date: %s")
+    INVOICE_TARGET_DATE_TOO_FAR_IN_THE_FUTURE(4005, "The target date was too far in the future. Target Date: %s"),
+    
+    /*
+     * 
+     * Range 5000: Overdue system
+     * 
+     */
+    OVERDUE_OVERDUEABLE_NOT_SUPPORTED(5001, "The Overdueable type '%s' is not supported"), 
+    OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered on Overdueable: id='%s', type='%s'"),  
+    
+    
     ;
 
     private int code;
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
index abbc3f1..b7ab8b1 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
@@ -28,6 +28,8 @@ public interface InvoiceItem extends Entity, Comparable<InvoiceItem> {
 
     UUID getAccountId();
 
+    UUID getBundleId();
+
     UUID getSubscriptionId();
 
     String getPlanName();
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/BillingState.java b/api/src/main/java/com/ning/billing/overdue/config/api/BillingState.java
new file mode 100644
index 0000000..2afa40a
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/BillingState.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.util.tag.Tag;
+
+public class BillingState<T extends Overdueable> {
+	private final UUID objectId;
+	private final int numberOfUnpaidInvoices;
+	private final BigDecimal balanceOfUnpaidInvoices;
+	private final DateTime dateOfEarliestUnpaidInvoice;
+	private final PaymentResponse responseForLastFailedPayment;
+	private final Tag[] tags;
+	
+	public BillingState(UUID id, int numberOfUnpaidInvoices, BigDecimal balanceOfUnpaidInvoices,
+			DateTime dateOfEarliestUnpaidInvoice,
+			PaymentResponse responseForLastFailedPayment,
+			Tag[] tags) {
+		super();
+		this.objectId = id;
+		this.numberOfUnpaidInvoices = numberOfUnpaidInvoices;
+		this.balanceOfUnpaidInvoices = balanceOfUnpaidInvoices;
+		this.dateOfEarliestUnpaidInvoice = dateOfEarliestUnpaidInvoice;
+		this.responseForLastFailedPayment = responseForLastFailedPayment;
+		this.tags = tags;
+	}
+
+	public UUID getObjectId() {
+		return objectId;
+	}
+	
+	public int getNumberOfUnpaidInvoices() {
+		return numberOfUnpaidInvoices;
+	}
+
+	public BigDecimal getBalanceOfUnpaidInvoices() {
+		return balanceOfUnpaidInvoices;
+	}
+
+	public DateTime getDateOfEarliestUnpaidInvoice() {
+		return dateOfEarliestUnpaidInvoice;
+	}
+	
+	public PaymentResponse getResponseForLastFailedPayment() {
+		return responseForLastFailedPayment;
+	}
+
+	public Tag[] getTags() {
+		return tags;
+	}
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/BillingStateBundle.java b/api/src/main/java/com/ning/billing/overdue/config/api/BillingStateBundle.java
new file mode 100644
index 0000000..15eebc8
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/BillingStateBundle.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.util.tag.Tag;
+
+public class BillingStateBundle extends BillingState<SubscriptionBundle> {
+    private final Product basePlanProduct;
+    private final BillingPeriod basePlanBillingPeriod;
+    private final PriceList basePlanPriceList;
+    private final PhaseType basePlanPhaseType;
+    
+	public BillingStateBundle(UUID id, int numberOfUnpaidInvoices, BigDecimal unpaidInvoiceBalance,
+			DateTime dateOfEarliestUnpaidInvoice,
+			PaymentResponse responseForLastFailedPayment,
+			Tag[] tags, 
+			Product basePlanProduct,
+			BillingPeriod basePlanBillingPeriod, 
+			PriceList basePlanPriceList, PhaseType basePlanPhaseType) {
+		super(id, numberOfUnpaidInvoices, unpaidInvoiceBalance, 
+				dateOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags);
+		
+		this.basePlanProduct = basePlanProduct;
+		this.basePlanBillingPeriod = basePlanBillingPeriod;
+		this.basePlanPriceList = basePlanPriceList;
+		this.basePlanPhaseType = basePlanPhaseType;
+	}
+	
+	public Product getBasePlanProduct() {
+		return basePlanProduct;
+	}
+	
+	public BillingPeriod getBasePlanBillingPeriod() {
+		return basePlanBillingPeriod;
+	}
+	
+	public PriceList getBasePlanPriceList() {
+		return basePlanPriceList;
+	}
+
+    public PhaseType getBasePlanPhaseType() {
+        return basePlanPhaseType;
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/Overdueable.java b/api/src/main/java/com/ning/billing/overdue/config/api/Overdueable.java
new file mode 100644
index 0000000..c32a43e
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/Overdueable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+import java.util.UUID;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public interface Overdueable {
+
+    public enum Type {
+        //Not currently supported
+        // ACCOUNT,
+        SUBSCRIPTION_BUNDLE;
+        
+        public static Type get(Overdueable o) throws CatalogApiException{
+            if (o instanceof SubscriptionBundle){
+                return SUBSCRIPTION_BUNDLE;
+            }
+            throw new CatalogApiException(ErrorCode.CAT_NO_OVERDUEABLE_TYPE , o.getClass().getName());
+        }
+        
+        public static Type get(String type) throws CatalogApiException {
+            if (type.equalsIgnoreCase(SUBSCRIPTION_BUNDLE.name())) {
+                return SUBSCRIPTION_BUNDLE;
+            }
+            throw new CatalogApiException(ErrorCode.CAT_NO_OVERDUEABLE_TYPE , type);
+        }
+
+    }
+
+    public UUID getId();
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/OverdueError.java b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueError.java
new file mode 100644
index 0000000..b71b299
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueError.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+
+public class OverdueError extends BillingExceptionBase {
+    private static final long serialVersionUID = 1L;
+
+    public OverdueError(Throwable cause, ErrorCode code, Object... args) {
+        super(cause, code, args);
+    }
+
+    public OverdueError(ErrorCode code, Object... args) {
+        super(code, args);
+    }
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/OverdueState.java b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueState.java
new file mode 100644
index 0000000..a7835fe
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+
+public interface OverdueState<T extends Overdueable> {
+
+    public String getName();
+
+    public String getExternalMessage();
+    
+    public int getDaysBetweenPaymentRetries();
+
+    public boolean disableEntitlementAndChangesBlocked();
+
+    public boolean blockChanges();
+    
+    public boolean isClearState();
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java
new file mode 100644
index 0000000..03c076c
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/OverdueStateSet.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.CatalogApiException;
+
+public interface OverdueStateSet<T extends Overdueable> {
+
+    public abstract OverdueState<T> findClearState() throws CatalogApiException;
+
+    public abstract OverdueState<T> findState(String stateName) throws CatalogApiException;
+
+    public abstract OverdueState<T> calculateOverdueState(BillingState<T> billingState, DateTime now) throws CatalogApiException;
+
+    public abstract DateTime dateOfNextCheck(BillingState<T> billingState, DateTime now);
+
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/ning/billing/overdue/config/api/PaymentResponse.java b/api/src/main/java/com/ning/billing/overdue/config/api/PaymentResponse.java
new file mode 100644
index 0000000..fb82d7c
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/config/api/PaymentResponse.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.api;
+
+public enum PaymentResponse {
+    // Card issues
+    INVALID_CARD("The card number, expiry date or cvc is invalid or incorrect"),
+	EXPIRED_CARD("The card has expired"),
+	LOST_OR_STOLEN_CARD("The card has been lost or stolen"),
+
+	// Account issues
+    DO_NOT_HONOR("Do not honor the card - usually a problem with account"),
+	INSUFFICIENT_FUNDS("The account had insufficient funds to fulfil the payment"),
+	DECLINE("Generic payment decline"),
+	
+	//Transaction
+	PROCESSING_ERROR("Error processing card"),
+	INVALID_AMOUNT("An invalid amount was entered"),
+	DUPLICATE_TRANSACTION("A transaction with identical amount and credit card information was submitted very recently."),
+
+	//Other
+	OTHER("Some other error");
+	
+	private String description;
+	
+	private PaymentResponse(String description) {
+	    this.description = description;
+	}
+	
+	public String getDescription() {
+	    return description;
+	}
+	
+//	 690118 | Approved
+//	 136956 | Do Not Honor
+//	 119640 | Insufficient Funds
+//	  68514 | Invalid Account Number
+//	  66824 | Declined: 10417-The transaction cannot complete successfully.  Instruct the customer to use an alternative payment
+//	  55473 | Declined: 10201-Agreement was canceled
+//	  30930 | Pick Up Card
+//	  29857 | Lost/Stolen Card
+//	  28197 | Declined
+//	  24830 | Declined: 10207-Transaction failed but user has alternate funding source
+//	  18445 | Generic Decline
+//	  18254 | Expired Card
+//	  16521 | Cardholder transaction not permitted
+//	  11576 | Restricted Card
+//	   7410 | Account Number Does Not Match Payment Type
+//	   7312 | Invalid merchant information: 10507-Payer's account is denied
+//	   6425 | Invalid Transaction
+//	   2825 | Declined: 10204-User's account is closed or restricted
+//	   2730 | Invalid account number
+//	   1331 | 
+//	   1240 | Field format error: 10561-There's an error with this transaction. Please enter a complete billing address.
+//	   1125 | Cardholder requested that recurring or installment payment be stopped
+//	   1060 | No such issuer
+//	   1047 | Issuer Unavailable
+//	    816 | Not signed up for this tender type
+//	    749 | Transaction not allowed at terminal
+//	    663 | Invalid expiration date: 0910
+//	    548 | Invalid expiration date: 1010
+//	    542 | Invalid expiration date:
+//	    500 | Invalid expiration date: 0810
+//	    492 | Invalid expiration date: 1110
+//	    410 | Invalid expiration date: 0710
+//	    388 | Exceeds Approval Amount Limit
+//	    362 | Generic processor error: 10001-Internal Error
+//	    313 | Exceeds per transaction limit: 10553-This transaction cannot be processed.
+//	    310 | Decline CVV2/CID Fail
+//	    309 | Generic processor error: 10201-Agreement was canceled
+//	    278 | Generic processor error: 10417-The transaction cannot complete successfully.  Instruct the customer to use an alte
+//	    246 | Call Issuer
+//	    237 | Generic processor error: 11091-The transaction was blocked as it would exceed the sending limit for this buyer.
+//	    202 | Failed to connect to host Input Server Uri = https://payflowpro.paypal.com:443
+//	    166 | Exceeds number of PIN entries
+//	    150 | Invalid Amount
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueAccessApi.java b/api/src/main/java/com/ning/billing/overdue/OverdueAccessApi.java
new file mode 100644
index 0000000..889c740
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueAccessApi.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue;
+
+import java.util.SortedSet;
+import java.util.UUID;
+
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+
+public interface OverdueAccessApi {
+    public static final String CLEAR_STATE_NAME = "__KILLBILL__CLEAR__OVERDUE_STATE__";
+
+    public String getOverdueStateNameFor(Overdueable overdueable);
+
+    public String getOverdueStateNameFor(UUID overdueableId, Overdueable.Type type);
+    
+    public SortedSet<OverdueEvent> getOverdueHistory(Overdueable overdueable);
+
+    public SortedSet<OverdueEvent> getOverdueHistory(UUID overdueableId, Overdueable.Type type);
+    
+    public <T extends Overdueable> void  setOverrideState(T overdueable, OverdueState<T> newOverdueState, Overdueable.Type type);
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java b/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java
new file mode 100644
index 0000000..7629abf
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueApiException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue;
+
+import com.ning.billing.BillingExceptionBase;
+import com.ning.billing.ErrorCode;
+
+public class OverdueApiException extends BillingExceptionBase {
+	private static final long serialVersionUID = 1L;
+
+	public OverdueApiException(Throwable cause, ErrorCode code, Object... args) {
+		super(cause, code, args);
+	}
+
+	public OverdueApiException(ErrorCode code, Object... args) {
+		super(code, args);
+	}
+
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueEvent.java b/api/src/main/java/com/ning/billing/overdue/OverdueEvent.java
new file mode 100644
index 0000000..22e3b10
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable.Type;
+
+public class OverdueEvent implements Comparable<OverdueEvent>{
+    private final UUID overdueableId;
+    private final String stateName;
+    private final Overdueable.Type type;
+    private final DateTime timestamp;
+    
+    public OverdueEvent(UUID overdueableId, String stateName, Type type,
+            DateTime timestamp) {
+        super();
+        this.overdueableId = overdueableId;
+        this.stateName = stateName;
+        this.type = type;
+        this.timestamp = timestamp;
+    }
+    
+    public UUID getOverdueableId() {
+        return overdueableId;
+    }
+    public String getStateName() {
+        return stateName;
+    }
+    public Overdueable.Type getType() {
+        return type;
+    }
+    public DateTime getTimestamp() {
+        return timestamp;
+    }
+
+    @Override
+    public int compareTo(OverdueEvent arg0) {
+        return timestamp.compareTo(arg0.getTimestamp());
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueService.java b/api/src/main/java/com/ning/billing/overdue/OverdueService.java
new file mode 100644
index 0000000..8841046
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue;
+
+import com.ning.billing.lifecycle.KillbillService;
+
+public interface OverdueService extends KillbillService {
+    public String getName();
+
+    public OverdueUserApi getUserApi();
+    
+}
diff --git a/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
new file mode 100644
index 0000000..a785679
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/overdue/OverdueUserApi.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue;
+
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+
+public interface OverdueUserApi {
+
+    public <T extends Overdueable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException;
+
+    public <T extends Overdueable> void setOverrideBillingStateForAccount(T overdueable, BillingState<T> state) throws OverdueError;
+
+    public <T extends Overdueable> OverdueState<T> getOverdueStateFor(T overdueable) throws OverdueError;
+}
diff --git a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
index 406ec54..9f4bb38 100644
--- a/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
+++ b/api/src/main/java/com/ning/billing/util/tag/ControlTagType.java
@@ -18,7 +18,8 @@ package com.ning.billing.util.tag;
 
 public enum ControlTagType {
     AUTO_PAY_OFF("Suspends payments until removed.", true, false),
-    AUTO_INVOICING_OFF("Suspends invoicing until removed.", false, true),
+    AUTO_INVOICING_OFF("Suspends invoicing until removed.", false, true), 
+    OVERDUE_ENFORCEMENT_OFF("Suspends overdue enforcement behaviour until removed.", false, false),
     WRITTEN_OFF("Indicated that an invoice is written off. No billing or payment effect.", false, false);
 
     private final String description;
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
index 447b5b7..1ad8ccb 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/MockModule.java
@@ -22,9 +22,6 @@ import java.io.IOException;
 import java.net.URL;
 import java.util.Set;
 
-import com.ning.billing.util.glue.CallContextModule;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.glue.TagStoreModule;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
@@ -49,12 +46,15 @@ import com.ning.billing.lifecycle.KillbillService;
 import com.ning.billing.payment.api.PaymentService;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
 import com.ning.billing.payment.setup.PaymentModule;
+import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.CallContextModule;
+import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
 
 
 public class MockModule extends AbstractModule {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index e334966..f081c29 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -631,7 +631,7 @@ public class TestIntegration {
         assertTrue(busHandler.isCompleted(DELAY));
         invoices = invoiceUserApi.getInvoicesByAccount(accountId);
         assertNotNull(invoices);
-        assertTrue(invoices.size() == 2);
+        assertEquals(invoices.size(),2);
 
         busHandler.pushExpectedEvent(NextEvent.PHASE);
         busHandler.pushExpectedEvent(NextEvent.INVOICE);
@@ -640,7 +640,7 @@ public class TestIntegration {
         assertTrue(busHandler.isCompleted(DELAY));
         invoices = invoiceUserApi.getInvoicesByAccount(accountId);
         assertNotNull(invoices);
-        assertTrue(invoices.size() == 3);
+        assertEquals(invoices.size(),3);
     }
 
     protected AccountData getAccountData(final int billingDay) {

bin/cleanAndInstall 23(+23 -0)

diff --git a/bin/cleanAndInstall b/bin/cleanAndInstall
new file mode 100755
index 0000000..fca07ad
--- /dev/null
+++ b/bin/cleanAndInstall
@@ -0,0 +1,23 @@
+#! /usr/bin/env bash
+
+###################################################################################
+#                                                                                 #
+#                   Copyright 2010-2011 Ning, Inc.                                #
+#                                                                                 #
+#      Ning 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.                                                         #
+#                                                                                 #
+###################################################################################
+
+bin/db-helper -a clean -d killbill; 
+bin/db-helper -a clean -d test_killbill; 
+mvn -Dcom.ning.billing.dbi.test.useLocalDb=true clean install 

bin/db-helper 3(+1 -2)

diff --git a/bin/db-helper b/bin/db-helper
index 3bd86ae..cc8b746 100755
--- a/bin/db-helper
+++ b/bin/db-helper
@@ -53,7 +53,6 @@ function get_modules() {
 }
 
 function find_test_ddl() {
-
     local modules=`get_modules`
     local ddl_test=
     
@@ -137,7 +136,7 @@ fi
 
 
 if [ $ACTION == "dump" ]; then
-    DDL_FILE=`create_ddl_file`
+     DDL_FILE=`create_ddl_file`
     cat $DDL_FILE
 fi
 

catalog/pom.xml 6(+6 -0)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 489aba0..6f6a8c5 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -33,6 +33,12 @@
             <artifactId>killbill-util</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
             <scope>test</scope>
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
index b824617..5c7b1e6 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultCatalogService.java
@@ -52,7 +52,6 @@ public class DefaultCatalogService implements KillbillService, Provider<Catalog>
     public synchronized void loadCatalog() throws ServiceException {
         if (!isInitialized) {
             try {
-            	System.out.println("Really really::" + config.getCatalogURI());
             	String url = config.getCatalogURI();
             	catalog = loader.load(url);
 
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 aba447d..c597dc0 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceList.java
@@ -107,10 +107,20 @@ public class DefaultPriceList extends ValidatingConfig<StandaloneCatalog> implem
         return count;
     }
 	
-	public DefaultPriceList setRetired(boolean retired) {
+	protected DefaultPriceList setRetired(boolean retired) {
 		this.retired = retired;
 		return this;
 	}
 
+	public DefaultPriceList setName(String name) {
+		this.name = name;
+		return this;
+	}
+
+	public DefaultPriceList setPlans(DefaultPlan[] plans) {
+		this.plans = plans;
+		return this;
+	}
+
 
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
index f0636dd..83d810b 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultPriceListSet.java
@@ -48,7 +48,7 @@ public class DefaultPriceListSet extends ValidatingConfig<StandaloneCatalog> {
 		this.childPriceLists = childPriceLists;
 	}
 
-	public DefaultPlan getPlanListFrom(String priceListName, Product product,
+	public DefaultPlan getPlanFrom(String priceListName, Product product,
 			BillingPeriod period) throws CatalogApiException {
 		DefaultPlan result = null;
 		DefaultPriceList pl = findPriceListFrom(priceListName);
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 ff3868c..6687c75 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/DefaultProduct.java
@@ -55,7 +55,6 @@ public class DefaultProduct extends ValidatingConfig<StandaloneCatalog> implemen
 	//Not included in XML
 	private String catalogName;
 	
-	
 	@Override
 	public String getCatalogName() {
 		return catalogName;
diff --git a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
index 029cdcd..a63645c 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
@@ -17,7 +17,6 @@
 package com.ning.billing.catalog;
 
 import java.net.URI;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 
@@ -40,6 +39,7 @@ import com.ning.billing.catalog.api.PlanChangeResult;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.StaticCatalog;
 import com.ning.billing.catalog.rules.PlanRules;
@@ -70,11 +70,11 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 	private PlanRules planRules;
 
 	@XmlElementWrapper(name="plans", required=true)
-	@XmlElement(name="plan", required=true)
+	@XmlElement(name="plan", required=true) 
 	private DefaultPlan[] plans;
 
-	@XmlElement(name="priceLists", required=true)
-	private DefaultPriceListSet priceLists;
+    @XmlElement(name="priceLists", required=true)
+    private DefaultPriceListSet priceLists;
 
 	public StandaloneCatalog() {}
 
@@ -142,7 +142,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 			throw new CatalogApiException(ErrorCode.CAT_PRICE_LIST_NOT_FOUND,priceListName);
 		}
 		Product product = findCurrentProduct(productName);
-		DefaultPlan result = priceLists.getPlanListFrom(priceListName, product, period);
+		DefaultPlan result = priceLists.getPlanFrom(priceListName, product, period);
 		if ( result == null) {
 			String periodString = (period == null) ? "NULL" :  period.toString();
 			throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND, productName, periodString, priceListName);
@@ -187,6 +187,16 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 		return plan.findPhase(name);
 	}
 
+    @Override
+    public PriceList findCurrentPricelist(String name)
+            throws CatalogApiException {
+        if (name == null || priceLists == null) {
+            throw new CatalogApiException(ErrorCode.CAT_PRICE_LIST_NOT_FOUND, name);
+        }
+        
+        return priceLists.findPriceListFrom(name);
+    }
+
 
 
 	//////////////////////////////////////////////////////////////////////////////
@@ -288,10 +298,10 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 		return this;
 	}
 
-	protected StandaloneCatalog setPriceLists(DefaultPriceListSet priceLists) {
-		this.priceLists = priceLists;
-		return this;
-	}
+    protected StandaloneCatalog setPriceLists(DefaultPriceListSet priceLists) {
+        this.priceLists = priceLists;
+        return this;
+    }
 
 	@Override
 	public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
@@ -303,4 +313,5 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 				(!plan.isRetired()) &&
 				(!priceList.isRetired());
 	}
+
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
index ef9b125..215b142 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -46,6 +46,7 @@ import com.ning.billing.catalog.api.PlanChangeResult;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.StaticCatalog;
 import com.ning.billing.util.clock.Clock;
@@ -160,6 +161,8 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
 		throw new CatalogApiException(ErrorCode.CAT_NO_CATALOG_FOR_GIVEN_DATE, requestedDate.toDate().toString());
 	}
 	
+	
+	
 	//
 	// Public methods not exposed in interface
 	//
@@ -270,6 +273,17 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
 		return plan.findPhase(phaseName);
 	}
 	
+	
+	//
+    // Find a price list
+    //
+    @Override
+    public PriceList findPriceList(String name, DateTime requestedDate)
+            throws CatalogApiException {
+        return versionForDate(requestedDate).findCurrentPriceList(name);
+    }
+
+ 
     //
     // Rules
     //
@@ -381,6 +395,13 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
 	public PlanPhase findCurrentPhase(String name) throws CatalogApiException {
 		return versionForDate(clock.getUTCNow()).findCurrentPhase(name);
 	}
+	
+
+    @Override
+    public PriceList findCurrentPricelist(String name)
+            throws CatalogApiException {
+        return versionForDate(clock.getUTCNow()).findCurrentPriceList(name);
+    }
 
 	@Override
 	public ActionPolicy planChangePolicy(PlanPhaseSpecifier from,
@@ -424,8 +445,4 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
 		return versionForDate(clock.getUTCNow()).canCreatePlan(specifier);
 	}
 
-	
-
-
- 
 }
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 244ca49..fa51ed1 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -34,8 +34,8 @@ public class MockCatalog extends StandaloneCatalog {
 		populateRules();
 		populatePriceLists();
 	}
-	
-	public void populateRules(){
+
+    public void populateRules(){
 		setPlanRules(new PlanRules());
 	}
 
@@ -47,6 +47,8 @@ public class MockCatalog extends StandaloneCatalog {
 			){
 		
 	}
+	
+	
 
 	public void populatePriceLists() {
 		DefaultPlan[] plans = getCurrentPlans();
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java b/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java
new file mode 100644
index 0000000..2aceb5b
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalogModule.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+
+public class MockCatalogModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+        ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog());
+        bind(CatalogService.class).toInstance(catalogService);
+    }
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java b/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
index deececb..45ea7d3 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
@@ -60,13 +60,21 @@ public class MockPlan extends DefaultPlan {
 				-1);
 	}
 
-	public static MockPlan createJetTrialFixedTermEvergreen1000USD() {
-		return new MockPlan("JetTrialEvergreen1000USD",
-				MockProduct.createJet(),
-				new DefaultPlanPhase[]{ MockPlanPhase.create30DayTrial(), MockPlanPhase.createUSDMonthlyFixedTerm("500.00", null, 6) },
-				MockPlanPhase.create1USDMonthlyEvergreen(),
-				-1);
-	}
+    public static MockPlan createJetTrialFixedTermEvergreen1000USD() {
+        return new MockPlan("JetTrialEvergreen1000USD",
+                MockProduct.createJet(),
+                new DefaultPlanPhase[]{ MockPlanPhase.create30DayTrial(), MockPlanPhase.createUSDMonthlyFixedTerm("500.00", null, 6) },
+                MockPlanPhase.create1USDMonthlyEvergreen(),
+                -1);
+    }
+
+    public static MockPlan createHornMonthlyNoTrial1USD() {
+        return new MockPlan("Horn1USD",
+                MockProduct.createHorn(),
+                new DefaultPlanPhase[]{ },
+                MockPlanPhase.create1USDMonthlyEvergreen(),
+                -1);
+    }
 
 	public MockPlan() {
 		this("BicycleTrialEvergreen1USD",
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java b/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java
new file mode 100644
index 0000000..9b672ba
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockPriceList.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.catalog;
+
+import com.ning.billing.catalog.api.PriceListSet;
+
+public class MockPriceList extends DefaultPriceList {
+
+	public MockPriceList() {
+		setName(PriceListSet.DEFAULT_PRICELIST_NAME);
+		setRetired(false);
+		setPlans(MockPlan.createAll());
+	}
+}
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestPriceListSet.java b/catalog/src/test/java/com/ning/billing/catalog/TestPriceListSet.java
index 3cb8d2f..a26ce10 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestPriceListSet.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestPriceListSet.java
@@ -50,10 +50,10 @@ public class TestPriceListSet {
 		};
 		DefaultPriceListSet set = new DefaultPriceListSet(defaultPriceList, childPriceLists);
 		
-		Assert.assertEquals(set.getPlanListFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
-		Assert.assertEquals(set.getPlanListFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
-		Assert.assertEquals(set.getPlanListFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
-		Assert.assertEquals(set.getPlanListFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
+		Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
 	}
 	
 	public void testForNullBillingPeriod() throws CatalogApiException {
@@ -76,10 +76,10 @@ public class TestPriceListSet {
 		};
 		DefaultPriceListSet set = new DefaultPriceListSet(defaultPriceList, childPriceLists);
 		
-		Assert.assertEquals(set.getPlanListFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
-		Assert.assertEquals(set.getPlanListFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
-		Assert.assertEquals(set.getPlanListFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
-		Assert.assertEquals(set.getPlanListFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.DISCOUNT);
+		Assert.assertEquals(set.getPlanFrom("child", foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.ANNUAL).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
+		Assert.assertEquals(set.getPlanFrom(PriceListSet.DEFAULT_PRICELIST_NAME, foo, BillingPeriod.MONTHLY).getFinalPhase().getPhaseType(), PhaseType.EVERGREEN);
 	}
 
 }
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index c21aac1..ca17050 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -67,8 +67,7 @@
             </createAlignmentCase>
         </createAlignment>
 	</rules>
-
-
+ 
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index f7ae066..ccbd964 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -68,7 +68,6 @@
         </createAlignment>
 	</rules>
 
-
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 3d36b9d..4a895b0 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -169,8 +169,8 @@ Use Cases to do:
 				<toPriceList>DEFAULT</toPriceList>
 			</priceListCase>
 		</priceList>
-	</rules>
-
+	</rules> 
+	
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
index a982a26..5517eb8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -133,7 +133,7 @@ public class PlanAligner  {
                         subscription.getBundleStartDate(),
                         lastPlanTransition.getNextPlan(),
                         lastPlanTransition.getNextPhase().getPhaseType(),
-                        lastPlanTransition.getNextPriceList(),
+                        lastPlanTransition.getNextPriceList().getName(),
                         requestedDate);
                 return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
             // If we went through Plan changes, borrow the logics for changePlan alignement
@@ -142,9 +142,9 @@ public class PlanAligner  {
                         subscription.getBundleStartDate(),
                         lastPlanTransition.getPreviousPhase(),
                         lastPlanTransition.getPreviousPlan(),
-                        lastPlanTransition.getPreviousPriceList(),
+                        lastPlanTransition.getPreviousPriceList().getName(),
                         lastPlanTransition.getNextPlan(),
-                        lastPlanTransition.getNextPriceList(),
+                        lastPlanTransition.getNextPriceList().getName(),
                         requestedDate,
                         effectiveDate,
                         WhichPhase.NEXT);
@@ -192,7 +192,7 @@ public class PlanAligner  {
                 subscription.getBundleStartDate(),
                 subscription.getCurrentPhase(),
                 subscription.getCurrentPlan(),
-                subscription.getCurrentPriceList(),
+                subscription.getCurrentPriceList().getName(),
                 nextPlan,
                 nextPriceList,
                 requestedDate,
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
new file mode 100644
index 0000000..0fb0518
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/BillCycleDayCalculator.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.billing;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+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.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
+
+public class BillCycleDayCalculator {
+	private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
+	
+	private final CatalogService catalogService;
+	private final EntitlementUserApi entitlementApi;
+
+	@Inject
+	public BillCycleDayCalculator(final CatalogService catalogService, final EntitlementUserApi entitlementApi) {
+		super();
+		this.catalogService = catalogService;
+		this.entitlementApi = entitlementApi;
+	}
+
+	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionEventTransition transition, final Account account) throws CatalogApiException, AccountApiException {
+		Catalog catalog = catalogService.getFullCatalog();
+		Plan plan =  (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
+				transition.getNextPlan() : transition.getPreviousPlan();
+				Product product = plan.getProduct();
+				PlanPhase phase = (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
+						transition.getNextPhase() : transition.getPreviousPhase();
+
+						BillingAlignment alignment = catalog.billingAlignment(
+								new PlanPhaseSpecifier(product.getName(),
+										product.getCategory(),
+										phase.getBillingPeriod(),
+										transition.getNextPriceList().getName(),
+										phase.getPhaseType()),
+										transition.getRequestedTransitionTime());
+						int result = -1;
+
+						switch (alignment) {
+						case ACCOUNT :
+							result = account.getBillCycleDay();
+							if(result == 0) {
+								result = calculateBcdFromSubscription(subscription, plan, account);
+							}
+							break;
+						case BUNDLE :
+						    Subscription baseSub = entitlementApi.getBaseSubscription(bundle.getId());
+							result = calculateBcdFromSubscription(baseSub, plan, account);
+							break;
+						case SUBSCRIPTION :
+							result = calculateBcdFromSubscription(subscription, plan, account);
+							break;
+						}
+						if(result == -1) {
+							throw new CatalogApiException(ErrorCode.CAT_INVALID_BILLING_ALIGNMENT, alignment.toString());
+						}
+						return result;
+
+	}
+
+	private int calculateBcdFromSubscription(Subscription subscription, Plan plan, Account account) throws AccountApiException {
+		DateTime date = plan.dateOfFirstRecurringNonZeroCharge(subscription.getStartDate());
+		return date.toDateTime(account.getTimeZone()).getDayOfMonth();
+	}
+
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
index bc89040..646155b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
@@ -16,10 +16,13 @@
 
 package com.ning.billing.entitlement.api.billing;
 
-import com.ning.billing.catalog.api.CatalogApiException;
+import java.math.BigDecimal;
+
 import org.joda.time.DateTime;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
@@ -28,9 +31,8 @@ import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 
-import java.math.BigDecimal;
-
 public class DefaultBillingEvent implements BillingEvent {
+    final private Account account;
     final private int billCycleDay;
     final private Subscription subscription;
     final private DateTime effectiveDate;
@@ -45,7 +47,8 @@ public class DefaultBillingEvent implements BillingEvent {
     final private SubscriptionTransitionType type;
     final private Long totalOrdering;
 
-    public DefaultBillingEvent(SubscriptionEventTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+    public DefaultBillingEvent(Account account, SubscriptionEventTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+        this.account = account;
         this.billCycleDay = billCycleDay;
         this.subscription = subscription;
         effectiveDate = transition.getEffectiveTransitionTime();
@@ -68,11 +71,11 @@ public class DefaultBillingEvent implements BillingEvent {
         totalOrdering = ((SubscriptionTransitionData) transition).getTotalOrdering();
     }
 
-    // Intended for test only
-    public DefaultBillingEvent(Subscription subscription, DateTime effectiveDate, Plan plan, PlanPhase planPhase,
+    public DefaultBillingEvent(Account account, Subscription subscription, DateTime effectiveDate, Plan plan, PlanPhase planPhase,
                                BigDecimal fixedPrice, BigDecimal recurringPrice, Currency currency,
                                BillingPeriod billingPeriod, int billCycleDay, BillingModeType billingModeType,
                                String description, long totalOrdering, SubscriptionTransitionType type) {
+        this.account = account;
         this.subscription = subscription;
         this.effectiveDate = effectiveDate;
         this.plan = plan;
@@ -103,6 +106,11 @@ public class DefaultBillingEvent implements BillingEvent {
     }
 
     @Override
+    public Account getAccount() {
+         return account;
+    }
+
+    @Override
     public int getBillCycleDay() {
          return billCycleDay;
     }
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 8c3e83f..b73de3b 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
@@ -22,69 +22,57 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.CallContextFactory;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
-import com.ning.billing.ErrorCode;
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.account.api.MutableAccountData;
-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.Currency;
-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;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
-import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.SubscriptionSqlDao;
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.audit.dao.AuditSqlDao;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.UserType;
 
 public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
 	private static final Logger log = LoggerFactory.getLogger(DefaultEntitlementBillingApi.class);
     private static final String API_USER_NAME = "Entitlement Billing Api";
-
     private final CallContextFactory factory;
     private final EntitlementDao entitlementDao;
     private final AccountUserApi accountApi;
-    private final CatalogService catalogService;
+    private final BillCycleDayCalculator bcdCalculator;
     private final SubscriptionFactory subscriptionFactory;
+  
     private static final String SUBSCRIPTION_TABLE_NAME = "subscriptions";
 
     @Inject
-    public DefaultEntitlementBillingApi(final CallContextFactory factory, final SubscriptionFactory subscriptionFactory, final EntitlementDao dao, final AccountUserApi accountApi, final CatalogService catalogService) {
+    public DefaultEntitlementBillingApi(final CallContextFactory factory, final SubscriptionFactory subscriptionFactory, final EntitlementDao dao, final AccountUserApi accountApi, final BillCycleDayCalculator bcdCalculator) {
         super();
         this.factory = factory;
         this.subscriptionFactory = subscriptionFactory;
         this.entitlementDao = dao;
         this.accountApi = accountApi;
-        this.catalogService = catalogService;
+        this.bcdCalculator = bcdCalculator;
     }
 
     @Override
-    public SortedSet<BillingEvent> getBillingEventsForAccount(final UUID accountId) {
+    public SortedSet<BillingEvent> getBillingEventsForAccountAndUpdateAccountBCD(
+            final UUID accountId) {
         Account account = accountApi.getAccountById(accountId);
-        Currency currency = account.getCurrency();
+        CallContext context = factory.createCallContext(API_USER_NAME, CallOrigin.INTERNAL, UserType.SYSTEM);
 
         List<SubscriptionBundle> bundles = entitlementDao.getSubscriptionBundleForAccount(accountId);
         SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
@@ -94,7 +82,15 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         	for (final Subscription subscription: subscriptions) {
         		for (final SubscriptionEventTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
         			try {
-        				BillingEvent event = new DefaultBillingEvent(transition, subscription, calculateBcd(bundle, subscription, transition, accountId), currency);
+        			    int bcd = bcdCalculator.calculateBcd(bundle, subscription, transition, account);
+        			    
+        			    if(account.getBillCycleDay() == 0) {
+        			        MutableAccountData modifiedData = account.toMutableAccountData();
+        			        modifiedData.setBillCycleDay(bcd);
+                            accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
+        			    }
+
+        				BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcd, account.getCurrency());
         				result.add(event);
         			} catch (CatalogApiException e) {
         				log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
@@ -105,6 +101,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         		}
         	}
         }
+              
         return result;
     }
 
@@ -113,79 +110,6 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         return entitlementDao.getAccountIdFromSubscriptionId(subscriptionId);
     }
 
-    private int calculateBcd(final SubscriptionBundle bundle, final Subscription subscription,
-                             final SubscriptionEventTransition transition, final UUID accountId) throws CatalogApiException, AccountApiException {
-    	Catalog catalog = catalogService.getFullCatalog();
-    	Plan plan =  (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
-    	        transition.getNextPlan() : transition.getPreviousPlan();
-    	Product product = plan.getProduct();
-    	PlanPhase phase = (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
-    	        transition.getNextPhase() : transition.getPreviousPhase();
-
-    	BillingAlignment alignment = catalog.billingAlignment(
-    			new PlanPhaseSpecifier(product.getName(),
-    					product.getCategory(),
-    					phase.getBillingPeriod(),
-    					transition.getNextPriceList(),
-    					phase.getPhaseType()),
-    					transition.getRequestedTransitionTime());
-    	int result = -1;
-
-		Account account = accountApi.getAccountById(accountId);
-		switch (alignment) {
-    		case ACCOUNT :
-    			result = account.getBillCycleDay();
-
-    			if(result == 0) {
-                    // in this case, we're making an internal call from the entitlement API to set the BCD for the account
-                    CallContext context = factory.createCallContext(API_USER_NAME, CallOrigin.INTERNAL, UserType.SYSTEM);
-    				result = calculateBcdFromSubscription(subscription, plan, account, context);
-    			}
-    		break;
-    		case BUNDLE :
-    			result = bundle.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
-    		break;
-    		case SUBSCRIPTION :
-    			result = subscription.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
-    		break;
-    	}
-    	if(result == -1) {
-    		throw new CatalogApiException(ErrorCode.CAT_INVALID_BILLING_ALIGNMENT, alignment.toString());
-    	}
-    	return result;
-
-    }
-
-   	private int calculateBcdFromSubscription(Subscription subscription, Plan plan, Account account,
-                                             final CallContext context) throws AccountApiException {
-		int result = account.getBillCycleDay();
-        if(result != 0) {
-            return result;
-        }
-        result = new DateTime(account.getTimeZone()).getDayOfMonth();
-
-        try {
-        	result = billCycleDay(subscription.getStartDate(),account.getTimeZone(), plan);
-        } catch (CatalogApiException e) {
-            log.error("Unexpected catalog error encountered when updating BCD",e);
-        }
-
-        MutableAccountData modifiedData = account.toMutableAccountData();
-        modifiedData.setBillCycleDay(result);
-
-        accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
-        return result;
-    }
-
-    private int billCycleDay(DateTime requestedDate, DateTimeZone timeZone,
-    		Plan plan) throws CatalogApiException {
-
-        DateTime date = plan.dateOfFirstRecurringNonZeroCharge(requestedDate);
-        return date.toDateTime(timeZone).getDayOfMonth();
-
-    }
-
-
     @Override
     public void setChargedThroughDate(final UUID subscriptionId, final DateTime ctd, CallContext context) {
         SubscriptionData subscription = (SubscriptionData) entitlementDao.getSubscriptionFromId(subscriptionFactory, subscriptionId);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index 5554c9c..59040be 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -19,11 +19,11 @@ package com.ning.billing.entitlement.api.user;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.catalog.api.Catalog;
-import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
+
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
+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;
@@ -36,6 +36,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBui
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
 
@@ -90,6 +91,11 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     }
 
     @Override
+    public Subscription getBaseSubscription(UUID bundleId) {
+        return dao.getBaseSubscription(subscriptionFactory, bundleId);
+    }
+    
+
     public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleName, CallContext context)
     throws EntitlementUserApiException {
         SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId);
@@ -157,7 +163,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
             }
 
             SubscriptionData subscription = apiService.createPlan(new SubscriptionBuilder()
-                .setId(UUID.randomUUID())
+                 .setId(UUID.randomUUID())
                 .setBundleId(bundleId)
                 .setCategory(plan.getProduct().getCategory())
                 .setBundleStartDate(bundleStartDate)
@@ -172,7 +178,7 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
 
 
     private void checkAddonCreationRights(SubscriptionData baseSubscription, Plan targetAddOnPlan)
-        throws EntitlementUserApiException, CatalogApiException {
+            throws EntitlementUserApiException, CatalogApiException {
 
         if (baseSubscription.getState() != SubscriptionState.ACTIVE) {
             throw new EntitlementUserApiException(ErrorCode.ENT_CREATE_AO_BP_NON_ACTIVE, targetAddOnPlan.getName());
@@ -190,20 +196,20 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
         }
     }
 
-	@Override
-	public DateTime getNextBillingDate(UUID accountId) {
-		List<SubscriptionBundle> bundles = getBundlesForAccount(accountId);
-		DateTime result = null;
-		for(SubscriptionBundle bundle : bundles) {
-			List<Subscription> subscriptions = getSubscriptionsForBundle(bundle.getId());
-			for(Subscription subscription : subscriptions) {
-				DateTime chargedThruDate = subscription.getChargedThroughDate();
-				if(result == null ||
-						(chargedThruDate != null && chargedThruDate.isBefore(result))) {
-					result = subscription.getChargedThroughDate();
-				}
-			}
-		}
-		return result;
-	}
+    @Override
+    public DateTime getNextBillingDate(UUID accountId) {
+        List<SubscriptionBundle> bundles = getBundlesForAccount(accountId);
+        DateTime result = null;
+        for(SubscriptionBundle bundle : bundles) {
+            List<Subscription> subscriptions = getSubscriptionsForBundle(bundle.getId());
+            for(Subscription subscription : subscriptions) {
+                DateTime chargedThruDate = subscription.getChargedThroughDate();
+                if(result == null ||
+                        (chargedThruDate != null && chargedThruDate.isBefore(result))) {
+                    result = subscription.getChargedThroughDate();
+                }
+            }
+        }
+        return result;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
index 1187273..563cc80 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionApiService.java
@@ -16,9 +16,26 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.joda.time.DateTime;
+
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-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.CatalogService;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanChangeResult;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PlanSpecifier;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
@@ -27,15 +44,17 @@ import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEventData;
-import com.ning.billing.entitlement.events.user.*;
+import com.ning.billing.entitlement.events.user.ApiEvent;
+import com.ning.billing.entitlement.events.user.ApiEventBuilder;
+import com.ning.billing.entitlement.events.user.ApiEventCancel;
+import com.ning.billing.entitlement.events.user.ApiEventChange;
+import com.ning.billing.entitlement.events.user.ApiEventCreate;
+import com.ning.billing.entitlement.events.user.ApiEventReCreate;
+import com.ning.billing.entitlement.events.user.ApiEventUncancel;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-
-import java.util.ArrayList;
-import java.util.List;
 
 public class SubscriptionApiService {
 
@@ -55,13 +74,16 @@ public class SubscriptionApiService {
     public SubscriptionData createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
             String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
             CallContext context)
-    throws EntitlementUserApiException {
-
+        throws EntitlementUserApiException {
         SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+
+
+        
         createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false, context);
         return subscription;
     }
 
+
     public boolean recreatePlan(SubscriptionData subscription, PlanPhaseSpecifier spec, DateTime requestedDate, CallContext context)
     throws EntitlementUserApiException {
 
@@ -97,6 +119,7 @@ public class SubscriptionApiService {
             boolean reCreate, CallContext context)
     throws EntitlementUserApiException {
 
+
         try {
             TimedPhase [] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
 
@@ -150,7 +173,7 @@ public class SubscriptionApiService {
             PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
                     currentPlan.getProduct().getCategory(),
                     subscription.getCurrentPlan().getBillingPeriod(),
-                    subscription.getCurrentPriceList(),
+                    subscription.getCurrentPriceList().getName(),
                     subscription.getCurrentPhase().getPhaseType());
 
             ActionPolicy policy = catalogService.getFullCatalog().planCancelPolicy(planPhase, requestedDate);
@@ -208,6 +231,7 @@ public class SubscriptionApiService {
 
     public boolean changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
             String priceList, DateTime requestedDate, CallContext context)
+
     throws EntitlementUserApiException {
 
         try {
@@ -216,7 +240,7 @@ public class SubscriptionApiService {
             requestedDate = (requestedDate != null) ? DefaultClock.truncateMs(requestedDate) : now;
             validateRequestedDate(subscription, now, requestedDate);
 
-            String currentPriceList = subscription.getCurrentPriceList();
+            PriceList currentPriceList = subscription.getCurrentPriceList();
 
             SubscriptionState currentState = subscription.getState();
             if (currentState != SubscriptionState.ACTIVE) {
@@ -234,7 +258,7 @@ public class SubscriptionApiService {
                 PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
                         currentPlan.getProduct().getCategory(),
                         currentPlan.getBillingPeriod(),
-                        currentPriceList, subscription.getCurrentPhase().getPhaseType());
+                        currentPriceList.getName(), subscription.getCurrentPhase().getPhaseType());
                 PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
                         destProduct.getCategory(),
                         term,
@@ -283,6 +307,7 @@ public class SubscriptionApiService {
         }
     }
 
+
     public void commitCustomFields(SubscriptionData subscription, CallContext context) {
         dao.saveCustomFields(subscription, context);
     }
@@ -300,4 +325,6 @@ public class SubscriptionApiService {
                     requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
         }
     }
+    
+
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
index 8cc2573..0fac2c8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundleData.java
@@ -16,9 +16,11 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 
-import java.util.UUID;
+import com.ning.billing.overdue.config.api.OverdueState;
 
 public class SubscriptionBundleData implements SubscriptionBundle {
 
@@ -26,17 +28,19 @@ public class SubscriptionBundleData implements SubscriptionBundle {
     private final String key;
     private final UUID accountId;
     private final DateTime startDate;
+    private final OverdueState<SubscriptionBundle> overdueState;
 
     public SubscriptionBundleData(String name, UUID accountId) {
-        this(UUID.randomUUID(), name, accountId, null);
+        this(UUID.randomUUID(), name, accountId, null, null);
     }
 
-    public SubscriptionBundleData(UUID id, String key, UUID accountId, DateTime startDate) {
+    public SubscriptionBundleData(UUID id, String key, UUID accountId, DateTime startDate, OverdueState<SubscriptionBundle> overdueState) {
         super();
         this.id = id;
         this.key = key;
         this.accountId = accountId;
         this.startDate = startDate;
+        this.overdueState = overdueState;
     }
 
     @Override
@@ -60,4 +64,9 @@ public class SubscriptionBundleData implements SubscriptionBundle {
     public DateTime getStartDate() {
         return startDate;
     }
+
+    @Override
+    public OverdueState<SubscriptionBundle> getOverdueState() {
+        return overdueState;
+    }
 }
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 103860f..feae851 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
@@ -16,6 +16,18 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Catalog;
@@ -23,6 +35,7 @@ import com.ning.billing.catalog.api.CatalogApiException;
 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.PriceList;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
@@ -38,18 +51,7 @@ import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.customfield.CustomField;
-
 import com.ning.billing.util.entity.ExtendedEntityBase;
-import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
 
 public class SubscriptionData extends ExtendedEntityBase implements Subscription {
 
@@ -148,7 +150,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
     }
 
     @Override
-    public String getCurrentPriceList() {
+    public PriceList getCurrentPriceList() {
         return (getPreviousTransition() == null) ? null : getPreviousTransition().getNextPriceList();
     }
 
@@ -336,11 +338,11 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
         SubscriptionState nextState = null;
         String nextPlanName = null;
         String nextPhaseName = null;
-        String nextPriceList = null;
+        String nextPriceListName = null; 
         UUID nextUserToken = null;
         
         SubscriptionState previousState = null;
-        String previousPriceList = null;
+        PriceList previousPriceList = null;
 
         transitions = new LinkedList<SubscriptionTransitionData>();
         Plan previousPlan = null;
@@ -381,12 +383,12 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
                     nextState = SubscriptionState.ACTIVE;
                     nextPlanName = userEV.getEventPlan();
                     nextPhaseName = userEV.getEventPlanPhase();
-                    nextPriceList = userEV.getPriceList();
+                    nextPriceListName = userEV.getPriceList();
                     break;
                 case CHANGE:
                     nextPlanName = userEV.getEventPlan();
                     nextPhaseName = userEV.getEventPlanPhase();
-                    nextPriceList = userEV.getPriceList();
+                    nextPriceListName = userEV.getPriceList();
                     break;
                 case CANCEL:
                     nextState = SubscriptionState.CANCELLED;
@@ -408,9 +410,12 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
 
             Plan nextPlan = null;
             PlanPhase nextPhase = null;
+            PriceList nextPriceList = null;
+
             try {
                 nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getRequestedDate(), getStartDate()) : null;
                 nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getRequestedDate(), getStartDate()) : null;
+                nextPriceList = (nextPriceListName != null) ? catalog.findPriceList(nextPriceListName, cur.getRequestedDate()) : null;
             } catch (CatalogApiException e) {
                 log.error(String.format("Failed to build transition for subscription %s", id), e);
             }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index 80990cb..3e52a2e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -16,17 +16,17 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
-import com.ning.billing.util.bus.BusEvent.BusEventType;
-
-import org.joda.time.DateTime;
-
-import java.util.UUID;
 
 public class SubscriptionTransitionData implements SubscriptionEventTransition {
 
@@ -40,11 +40,11 @@ public class SubscriptionTransitionData implements SubscriptionEventTransition {
     private final DateTime requestedTransitionTime;
     private final DateTime effectiveTransitionTime;
     private final SubscriptionState previousState;
-    private final String previousPriceList;
+    private final PriceList previousPriceList;
     private final Plan previousPlan;
     private final PlanPhase previousPhase;
     private final SubscriptionState nextState;
-    private final String nextPriceList;
+    private final PriceList nextPriceList;
     private final Plan nextPlan;
     private final PlanPhase nextPhase;
     private final boolean isFromDisk;
@@ -53,8 +53,8 @@ public class SubscriptionTransitionData implements SubscriptionEventTransition {
 
     public SubscriptionTransitionData(UUID eventId, UUID subscriptionId, UUID bundleId, EventType eventType,
             ApiEventType apiEventType, DateTime requestedTransitionTime, DateTime effectiveTransitionTime,
-            SubscriptionState previousState, Plan previousPlan, PlanPhase previousPhase, String previousPriceList,
-            SubscriptionState nextState, Plan nextPlan, PlanPhase nextPhase, String nextPriceList,
+            SubscriptionState previousState, Plan previousPlan, PlanPhase previousPhase, PriceList previousPriceList,
+            SubscriptionState nextState, Plan nextPlan, PlanPhase nextPhase, PriceList nextPriceList,
             long totalOrdering, UUID userToken, boolean isFromDisk) {
         super();
         this.eventId = eventId;
@@ -155,12 +155,12 @@ public class SubscriptionTransitionData implements SubscriptionEventTransition {
 
 
     @Override
-    public String getPreviousPriceList() {
+    public PriceList getPreviousPriceList() {
         return previousPriceList;
     }
 
     @Override
-    public String getNextPriceList() {
+    public PriceList getNextPriceList() {
         return nextPriceList;
     }
     
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
index bccd559..f6f5497 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
@@ -16,12 +16,11 @@
 
 package com.ning.billing.entitlement.engine.dao;
 
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.dao.BinderBase;
-import com.ning.billing.util.dao.MapperBase;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -36,10 +35,12 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.UUID;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.MapperBase;
 
 @ExternalizedSqlViaStringTemplate3()
 public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Transmogrifier {
@@ -71,6 +72,7 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Tran
     }
 
     public static class ISubscriptionBundleSqlMapper extends MapperBase implements ResultSetMapper<SubscriptionBundle> {
+        
         @Override
         public SubscriptionBundle map(int arg, ResultSet r,
                 StatementContext ctx) throws SQLException {
@@ -79,7 +81,7 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Tran
             String name = r.getString("name");
             UUID accountId = UUID.fromString(r.getString("account_id"));
             DateTime startDate = getDate(r, "start_dt");
-            SubscriptionBundleData bundle = new SubscriptionBundleData(id, name, accountId, startDate);
+            SubscriptionBundleData bundle = new SubscriptionBundleData(id, name, accountId, startDate, null);
             return bundle;
         }
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 55238f5..89d2b1e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -24,10 +24,8 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
@@ -40,6 +38,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
@@ -62,16 +61,18 @@ import com.ning.billing.entitlement.events.user.ApiEventCancel;
 import com.ning.billing.entitlement.events.user.ApiEventChange;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.audit.dao.AuditSqlDao;
+import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
 import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService.NoSuchNotificationQueue;
 
-import javax.annotation.Nullable;
-
 public class EntitlementSqlDao implements EntitlementDao {
 
     private final static Logger log = LoggerFactory.getLogger(EntitlementSqlDao.class);
@@ -86,7 +87,9 @@ public class EntitlementSqlDao implements EntitlementDao {
     private final NotificationQueueService notificationQueueService;
     private final AddonUtils addonUtils;
     private final CustomFieldDao customFieldDao;
+    private final CatalogService catalogService;
 
+    
     //
     // We are not injecting SubscriptionFactory since that creates circular dependencies--
     // Guice would still work, but this is playing with fire.
@@ -95,8 +98,9 @@ public class EntitlementSqlDao implements EntitlementDao {
     //
     @Inject
     public EntitlementSqlDao(final IDBI dbi, final Clock clock,
-            final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
-            final CustomFieldDao customFieldDao) {
+                             final AddonUtils addonUtils, final NotificationQueueService notificationQueueService,
+                             final CustomFieldDao customFieldDao,
+                             final CatalogService catalogService) {
         this.clock = clock;
         this.subscriptionsDao = dbi.onDemand(SubscriptionSqlDao.class);
         this.eventsDao = dbi.onDemand(EventSqlDao.class);
@@ -104,6 +108,7 @@ public class EntitlementSqlDao implements EntitlementDao {
         this.notificationQueueService = notificationQueueService;
         this.addonUtils = addonUtils;
         this.customFieldDao = customFieldDao;
+        this.catalogService = catalogService;
     }
 
     @Override
@@ -613,4 +618,5 @@ public class EntitlementSqlDao implements EntitlementDao {
             subscription.setFields(fields);
         }
     }
+ 
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
index e167807..dea0aea 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/EntitlementModule.java
@@ -45,7 +45,7 @@ public class EntitlementModule extends AbstractModule {
     protected void installEntitlementDao() {
         bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
     }
-
+    
     protected void installEntitlementCore() {
     	bind(SubscriptionFactory.class).asEagerSingleton();
         bind(SubscriptionApiService.class).asEagerSingleton();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
index 0c16089..24affef 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultBillingEvent.java
@@ -133,7 +133,7 @@ public class TestDefaultBillingEvent {
 		Plan shotgun = new MockPlan();
 		PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, BigDecimal.ZERO, PhaseType.TRIAL);
 
-		return new DefaultBillingEvent(sub , effectiveDate,
+		return new DefaultBillingEvent(null, sub , effectiveDate,
 				shotgun, shotgunMonthly,
 				BigDecimal.ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
 				BillingModeType.IN_ADVANCE, "Test Event 1", totalOrdering, type);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index d6648a1..f184638 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -25,9 +25,6 @@ import java.util.List;
 import java.util.SortedSet;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.glue.CallContextModule;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.testng.Assert;
@@ -46,9 +43,11 @@ import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.entitlement.api.TestApiBase;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
@@ -63,7 +62,10 @@ import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.lifecycle.KillbillService.ServiceException;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.ClockModule;
 
 public class TestDefaultEntitlementBillingApi {
@@ -79,7 +81,6 @@ public class TestDefaultEntitlementBillingApi {
 
 	private Clock clock;
 	private SubscriptionData subscription;
-    private CallContextFactory factory;
 	private DateTime subscriptionStartDate;
 
 	@BeforeSuite(groups={"fast", "slow"})
@@ -89,7 +90,6 @@ public class TestDefaultEntitlementBillingApi {
 
         catalogService = g.getInstance(CatalogService.class);
         clock = g.getInstance(Clock.class);
-        factory = g.getInstance(CallContextFactory.class);
 
         ((DefaultCatalogService)catalogService).loadCatalog();
 	}
@@ -97,7 +97,7 @@ public class TestDefaultEntitlementBillingApi {
 	@BeforeMethod(groups={"fast", "slow"})
 	public void setupEveryTime() {
 		bundles = new ArrayList<SubscriptionBundle>();
-		final SubscriptionBundle bundle = new SubscriptionBundleData( zeroId,"TestKey", oneId,  clock.getUTCNow().minusDays(4));
+		final SubscriptionBundle bundle = new SubscriptionBundleData( zeroId,"TestKey", oneId,  clock.getUTCNow().minusDays(4), null);
 		bundles.add(bundle);
 
 
@@ -127,7 +127,6 @@ public class TestDefaultEntitlementBillingApi {
 
     @Test(enabled=true, groups="fast")
 	public void testBillingEventsEmpty() {
-
         dao = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementDao.class);
         ((ZombieControl) dao).addResult("getSubscriptionBundleForAccount", new ArrayList<SubscriptionBundle>());
 
@@ -135,12 +134,15 @@ public class TestDefaultEntitlementBillingApi {
         Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
         ((ZombieControl) account).addResult("getId", accountId).addResult("getCurrency", Currency.USD);
 
-		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         ((ZombieControl) accountApi).addResult("getAccountById", account);
 
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
-		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, catalogService);
-		SortedSet<BillingEvent> events = api.getBillingEventsForAccount(new UUID(0L,0L));
+		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, bcdCalculator);
+		SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
 		Assert.assertEquals(events.size(), 0);
 	}
 
@@ -150,19 +152,25 @@ public class TestDefaultEntitlementBillingApi {
 		DateTime then = now.minusDays(1);
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-annual", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[0]; // The trial has no billing period
-		String nextPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 		SubscriptionEventTransition t = new SubscriptionTransitionData(
 				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
 
+
         AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
         ((ZombieControl)account).addResult("getBillCycleDay", 32);
         ((ZombieControl)account).addResult("getCurrency", Currency.USD);
         ((ZombieControl)accountApi).addResult("getAccountById", account);
 		       
-		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, catalogService);
-		SortedSet<BillingEvent> events = api.getBillingEventsForAccount(new UUID(0L,0L));
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, bcdCalculator);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
 		checkFirstEvent(events, nextPlan, 32, oneId, now, nextPhase, ApiEventType.CREATE.toString());
 	}
 
@@ -172,7 +180,7 @@ public class TestDefaultEntitlementBillingApi {
 		DateTime then = now.minusDays(1);
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-annual", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
-		String nextPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+		PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 		SubscriptionEventTransition t = new SubscriptionTransitionData(
 				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
@@ -185,9 +193,13 @@ public class TestDefaultEntitlementBillingApi {
 		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
 		((ZombieControl)accountApi).addResult("getAccountById", account);
 
+		EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
-		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, catalogService);
-		SortedSet<BillingEvent> events = api.getBillingEventsForAccount(new UUID(0L,0L));
+        DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, bcdCalculator);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
 		checkFirstEvent(events, nextPlan, subscription.getStartDate().getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
 	}
 
@@ -197,7 +209,7 @@ public class TestDefaultEntitlementBillingApi {
 		DateTime then = now.minusDays(1);
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("shotgun-monthly", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
-		String nextPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 		SubscriptionEventTransition t = new SubscriptionTransitionData(
 				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
@@ -208,8 +220,13 @@ public class TestDefaultEntitlementBillingApi {
         ((ZombieControl)account).addResult("getCurrency", Currency.USD);
         ((ZombieControl)accountApi).addResult("getAccountById", account);
 
-        DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao,accountApi,catalogService);
-		SortedSet<BillingEvent> events = api.getBillingEventsForAccount(new UUID(0L,0L));
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, bcdCalculator);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
 		checkFirstEvent(events, nextPlan, 32, oneId, now, nextPhase, ApiEventType.CREATE.toString());
 	}
 
@@ -219,7 +236,7 @@ public class TestDefaultEntitlementBillingApi {
 		DateTime then = now.minusDays(1);
 		Plan nextPlan = catalogService.getFullCatalog().findPlan("laser-scope-monthly", now);
 		PlanPhase nextPhase = nextPlan.getAllPhases()[0];
-		String nextPriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
 		SubscriptionEventTransition t = new SubscriptionTransitionData(
 				zeroId, oneId, twoId, EventType.API_USER, ApiEventType.CREATE, then, now, null, null, null, null, SubscriptionState.ACTIVE, nextPlan, nextPhase, nextPriceList, 1, null, true);
 		transitions.add(t);
@@ -228,13 +245,18 @@ public class TestDefaultEntitlementBillingApi {
 		((ZombieControl)account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC);
         ((ZombieControl)account).addResult("getCurrency", Currency.USD);
 
-		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
-		((ZombieControl)accountApi).addResult("getAccountById", account);
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+        ((ZombieControl) entitlementApi).addResult("getBaseSubscription", subscription);
 
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
-		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, catalogService);
-		SortedSet<BillingEvent> events = api.getBillingEventsForAccount(new UUID(0L,0L));
-		checkFirstEvent(events, nextPlan, bundles.get(0).getStartDate().getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
+        DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, null, dao, accountApi, bcdCalculator);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+		checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
 	}
 
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
new file mode 100644
index 0000000..febf63c
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.billing;
+
+
+public class TestOverdueEventCalculator {
+
+    //TODO MDW refactoring
+//    private static final String DISABLED_BUNDLE = "disabled-bundle";
+//    private static final String CLEAR_BUNDLE = "clear-bundle";
+//    
+//    
+//    private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false); 
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+//
+//    private OverdueAccessApi overdueAccessApi;
+//    private Account account;
+//    private Subscription subscription1;
+//    private Subscription subscription2;
+//    private Subscription subscription3;
+//    private Subscription subscription4;
+//    private UUID bundleId1 = UUID.randomUUID();
+//    private UUID bundleId2 = UUID.randomUUID();
+//    private Clock clock;
+//    private OverdueEventCalculator odc;
+//
+//    @BeforeClass
+//    public void setUpBeforeClass() throws Exception {
+//
+//        @SuppressWarnings("unchecked")
+//        final OverdueStatesBundle bundleODS =  new MockOverdueStatesBundle(new DefaultOverdueState[] {
+//                CLEAR_BUNDLE_STATE, DISABLED_BUNDLE_STATE    });
+//
+//        clock = new ClockMock();
+//        
+//        Injector i = Guice.createInjector(new AbstractModule() {
+//
+//            @Override
+//            protected void configure() {
+//                overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+//                account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+//                subscription1 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription2 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription3 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                subscription4 = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class, Comparable.class);
+//                ((ZombieControl) subscription1).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription2).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription3).addResult("getBundleId", bundleId1);
+//                ((ZombieControl) subscription4).addResult("getBundleId", bundleId2);
+//                ((ZombieControl) subscription1).addResult("compareTo", 1);
+//                ((ZombieControl) subscription2).addResult("compareTo", 1);
+//                ((ZombieControl) subscription3).addResult("compareTo", 1);
+//                ((ZombieControl) subscription4).addResult("compareTo", 1);
+//                ((ZombieControl) subscription1).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription2).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription3).addResult("getId", UUID.randomUUID());
+//                ((ZombieControl) subscription4).addResult("getId", UUID.randomUUID());
+//         
+//              //  bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+//                CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+//                ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+//
+//                    @Override
+//                    public void setOverdueRules() {
+//                         OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);                       
+//                        setOverdueRules(overdueRules);  
+//                    }
+//                    
+//                });
+//                bind(CatalogService.class).toInstance(catalogService);
+//                               
+//               
+//                bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+//                bind(OverdueAccessApi.class).toInstance(overdueAccessApi);              
+//                              
+//            }
+//            
+//        });
+//        odc = i.getInstance(OverdueEventCalculator.class);
+//
+//    }
+//
+//    @Test
+//    // S1-S2-S3 subscriptions in B1
+//    // B1 -----[--------]
+//    // S1 --A-------------------------------------
+//    // S2 --B------C------------------------------
+//    // S3 ------------------D---------------------
+//    
+//
+//    //Result
+//    // S1 --A--[-------]--------------------------
+//    // S2 --B--[-------]--------------------------
+//    // S3 ------------------D---------------------
+//    
+//    public void testInsertOverdueEvents() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent A = createRealEvent(now.minusDays(1).minusHours(1), subscription1);
+//        BillingEvent B = createRealEvent(now.minusDays(1), subscription2);
+//        BillingEvent C = createRealEvent(now.plusDays(1), subscription2);
+//        BillingEvent D = createRealEvent(now.plusDays(3), subscription3);
+//        billingEvents.add(A);
+//        billingEvents.add(B);
+//        billingEvents.add(C);
+//        billingEvents.add(D);
+//
+//        SortedSet<OverdueEvent> overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(bundleId1,DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now));
+//        overdueBundleEvents.add(new OverdueEvent(bundleId1,CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now.plusDays(2)));
+//        
+//        ((ZombieControl)overdueAccessApi).addResult("getOverdueHistory", overdueBundleEvents);
+//        
+//        
+//        odc.insertOverdueEvents(billingEvents);
+//        
+//        assertEquals(billingEvents.size(), 7);
+//        
+//        SortedSet<BillingEvent> s1Events = odc.filter(billingEvents, subscription1);
+//        Iterator<BillingEvent> it1 = s1Events.iterator();
+//        assertEquals(it1.next(), A);
+//        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(it1.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//        
+//        SortedSet<BillingEvent> s2Events = odc.filter(billingEvents, subscription2);
+//        Iterator<BillingEvent> it2 = s2Events.iterator();       
+//        assertEquals(it2.next(), B);
+//        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(it2.next().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//                
+//        SortedSet<BillingEvent> s3Events = odc.filter(billingEvents, subscription3);
+//        Iterator<BillingEvent> it3 = s3Events.iterator();       
+//        assertEquals(it3.next(),D);
+//    }
+//
+//    // Open ended duration with a previous event
+//    // --X--[----------------------------------
+//   @Test
+//    public void testEventsToRemoveOpenPrev() {
+//       DateTime now = clock.getUTCNow();
+//       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//       
+//       disabledDuration.add(new DisabledDuration(now, null));
+//       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//       
+//       SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//       
+//       assertEquals(results.size(), 0);
+//   }
+//
+//   // Open with previous and following events
+//   // --X--[----Y-----------------------------
+//    @Test
+//    public void testEventsToRemoveOpenPrevFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e1);
+//        billingEvents.add(e2);
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Open with no previous event (only following)
+//    // -----[----X-----------------------------
+//    @Test
+//    public void testEventsToRemoveOpenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        BillingEvent e1  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e1);
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e1);
+//   }
+//
+//    // Closed duration with a single previous event
+//    // --X--[------------]---------------------
+//        @Test
+//    public void testEventsToRemoveClosedPrev() {
+//            DateTime now = clock.getUTCNow();
+//            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//            
+//            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//            BillingEvent e1  = createRealEvent(now.minusDays(1), subscription1);
+//            billingEvents.add(e1);
+//            
+//            SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents,  subscription1);
+//            
+//            assertEquals(results.size(), 0);
+//    }
+//
+//    // Closed duration with a previous event and in-between event
+//    // --X--[------Y-----]---------------------
+//    @Test
+//    public void testEventsToRemoveClosedPrevBetw() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event and following
+//    // --X--[------Y-----]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedPrevBetwNext() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        BillingEvent e1 = createRealEvent(now.minusDays(1), subscription1);
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//        billingEvents.add(e1);
+//        billingEvents.add(e2);        
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//   }
+//
+//    // Closed with no previous event but in-between events
+//    // -----[------Y-----]---------------------
+//    @Test
+//    public void testEventsToRemoveClosedBetwn() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        billingEvents.add(e2);        
+//      
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Closed with no previous event but in-between events and following
+//    // -----[------Y-----]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedBetweenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//
+//        BillingEvent e2  = createRealEvent(now.plusDays(1), subscription1);
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//        billingEvents.add(e2);        
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first(), e2);
+//    }
+//
+//    // Closed duration with only following
+//    // -----[------------]-------Z-------------
+//    @Test
+//    public void testEventsToRemoveClosedFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//
+//        BillingEvent e3  = createRealEvent(now.plusDays(3), subscription1);
+//       
+//        billingEvents.add(e3);        
+//        
+//        SortedSet<BillingEvent> results = odc.eventsToRemove( disabledDuration, billingEvents, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//     }
+//    
+//    // Open ended duration with a previous event
+//    // --X--[----------------------------------
+//   @Test
+//    public void testCreateNewEventsOpenPrev() {
+//       DateTime now = clock.getUTCNow();
+//       List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//       SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//       
+//       disabledDuration.add(new DisabledDuration(now, null));
+//       billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//       
+//       SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//       
+//       assertEquals(results.size(), 1);
+//       assertEquals(results.first().getEffectiveDate(), now);
+//       assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//       assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//   }
+//
+//   // Open with previous and following events
+//   // --X--[----Y-----------------------------
+//    @Test
+//    public void testCreateNewEventsOpenPrevFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//    }
+//
+//    // Open with no previous event (only following)
+//    // -----[----X-----------------------------
+//    @Test
+//    public void testCreateNewEventsOpenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, null));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//   }
+//
+//    // Closed duration with a single previous event
+//    // --X--[------------]---------------------
+//        @Test
+//    public void testCreateNewEventsClosedPrev() {
+//            DateTime now = clock.getUTCNow();
+//            List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//            SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//            
+//            disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//            billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//            
+//            SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//            
+//            assertEquals(results.size(), 2);
+//            assertEquals(results.first().getEffectiveDate(), now);
+//            assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//            assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//            assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//            assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//            assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event
+//    // --X--[------Y-----]---------------------
+//    @Test
+//    public void testCreateNewEventsClosedPrevBetw() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with a previous event and in-between event and following
+//    // --X--[------Y-----]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedPrevBetwNext() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.minusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 2);
+//        assertEquals(results.first().getEffectiveDate(), now);
+//        assertEquals(results.first().getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(results.first().getTransitionType(), SubscriptionTransitionType.CANCEL);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//   }
+//
+//    // Closed with no previous event but in-between events
+//    // -----[------Y-----]---------------------
+//    @Test
+//    public void testCreateNewEventsClosedBetwn() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed with no previous event but in-between events and following
+//    // -----[------Y-----]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedBetweenFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 1);
+//        assertEquals(results.last().getEffectiveDate(), now.plusDays(2));
+//        assertEquals(results.last().getRecurringPrice(), billingEvents.first().getRecurringPrice());
+//        assertEquals(results.last().getTransitionType(), SubscriptionTransitionType.RE_CREATE);
+//    }
+//
+//    // Closed duration with only following
+//    // -----[------------]-------Z-------------
+//    @Test
+//    public void testCreateNewEventsClosedFollow() {
+//        DateTime now = clock.getUTCNow();
+//        List<DisabledDuration> disabledDuration = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+//        SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+//        
+//        disabledDuration.add(new DisabledDuration(now, now.plusDays(2)));
+//        billingEvents.add(createRealEvent(now.plusDays(3), subscription1));
+//        
+//        SortedSet<BillingEvent> results = odc.createNewEvents( disabledDuration, billingEvents,  account, subscription1);
+//        
+//        assertEquals(results.size(), 0);
+//     }
+//
+//    @Test
+//    public void testPrecedingBillingEventForSubscription() {
+//        DateTime now = new DateTime();
+//        
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//
+//        events.add(createRealEvent(now.minusDays(10), subscription1));
+//        events.add(createRealEvent(now.minusDays(6), subscription1));
+//        events.add(createRealEvent(now.minusDays(5), subscription1));
+//        events.add(createRealEvent(now.minusDays(1), subscription1));
+//        
+//        BillingEvent minus11 = odc.precedingBillingEventForSubscription(now.minusDays(11), events, subscription1);
+//        assertNull(minus11);
+//        
+//        BillingEvent minus5andAHalf= odc.precedingBillingEventForSubscription(now.minusDays(5).minusHours(12), events, subscription1);
+//        assertNotNull(minus5andAHalf);
+//        assertEquals(minus5andAHalf.getEffectiveDate(), now.minusDays(6));
+//      
+//        
+//    }
+//    
+//    protected BillingEvent createRealEvent(DateTime effectiveDate, Subscription subscription) {
+//        final Account account = this.account;
+//        final int billCycleDay = 1;
+//        final PlanPhase planPhase = new MockPlanPhase();
+//        final Plan plan = new MockPlan();
+//        final BigDecimal fixedPrice = BigDecimal.TEN;
+//        final BigDecimal recurringPrice = BigDecimal.TEN;
+//        final Currency currency = Currency.USD;
+//        final String description = "";
+//        final BillingModeType billingModeType = BillingModeType.IN_ADVANCE;
+//        final BillingPeriod billingPeriod = BillingPeriod.MONTHLY;
+//        final SubscriptionTransitionType type = SubscriptionTransitionType.CHANGE;
+//        final Long totalOrdering = 0L; //TODO
+//
+//        return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+//                fixedPrice, recurringPrice, currency,
+//                billingPeriod, billCycleDay, billingModeType,
+//                description, totalOrdering, type);
+//    }
+//
+//
+//    @Test
+//    public void testFilter() {
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//        
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription2));
+//        
+//        SortedSet<BillingEvent> result1 = odc.filter(events, subscription1);
+//        SortedSet<BillingEvent> result2 = odc.filter(events, subscription2);
+//        SortedSet<BillingEvent> result3 = odc.filter(events, subscription3);
+//        
+//        assertEquals(result1.size(), 3);
+//        assertEquals(result1.first().getSubscription(), subscription1);
+//        assertEquals(result1.last().getSubscription(), subscription1);
+//        assertEquals(result2.size(), 1);
+//        assertEquals(result2.first().getSubscription(), subscription2);
+//        assertEquals(result3.size(), 0);
+//    }
+//
+//    @Test
+//    public void testCreateNewDisableEvent() {
+//        DateTime now = clock.getUTCNow();
+//        BillingEvent event = new MockBillingEvent();
+//        
+//        BillingEvent result = odc.createNewDisableEvent(now, event);
+//        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+//        assertEquals(result.getEffectiveDate(), now);
+//        assertEquals(result.getPlanPhase(), event.getPlanPhase());
+//        assertEquals(result.getPlan(), event.getPlan());
+//        assertEquals(result.getFixedPrice(),BigDecimal.ZERO);
+//        assertEquals(result.getRecurringPrice(), BigDecimal.ZERO);
+//        assertEquals(result.getCurrency(), event.getCurrency());
+//        assertEquals(result.getDescription(), "");
+//        assertEquals(result.getBillingMode(), event.getBillingMode());
+//        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+//        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.CANCEL);
+//        assertEquals(result.getTotalOrdering(), new Long(0));
+//    }
+//
+//    @Test
+//    public void testCreateNewReenableEvent() {
+//        DateTime now = clock.getUTCNow();
+//        BillingEvent event = new MockBillingEvent();
+//        
+//        BillingEvent result = odc.createNewReenableEvent(now, event);
+//        assertEquals(result.getBillCycleDay(),event.getBillCycleDay());
+//        assertEquals(result.getEffectiveDate(), now);
+//        assertEquals(result.getPlanPhase(), event.getPlanPhase());
+//        assertEquals(result.getPlan(), event.getPlan());
+//        assertEquals(result.getFixedPrice(),event.getFixedPrice());
+//        assertEquals(result.getRecurringPrice(), event.getRecurringPrice());
+//        assertEquals(result.getCurrency(), event.getCurrency());
+//        assertEquals(result.getDescription(), "");
+//        assertEquals(result.getBillingMode(), event.getBillingMode());
+//        assertEquals(result.getBillingPeriod(), event.getBillingPeriod());
+//        assertEquals(result.getTransitionType(),  SubscriptionTransitionType.RE_CREATE);
+//        assertEquals(result.getTotalOrdering(), new Long(0));
+//    }
+//    
+//    private class MockBillingEvent extends DefaultBillingEvent {
+//        public MockBillingEvent() {
+//            super(account, subscription1, clock.getUTCNow(), null, null, BigDecimal.ZERO, BigDecimal.TEN, Currency.USD, BillingPeriod.ANNUAL,
+//                    4, BillingModeType.IN_ADVANCE, "", 3L, SubscriptionTransitionType.CREATE);
+//        }        
+//    }
+//
+//    @Test
+//    public void testCreateBundleSubscriptionMap() {
+//        SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
+//        events.add(createBillingEvent(subscription1));
+//        events.add(createBillingEvent(subscription2));
+//        events.add(createBillingEvent(subscription3));
+//        events.add(createBillingEvent(subscription4));
+//        
+//        Hashtable<UUID,Set<Subscription>> map = odc.createBundleSubscriptionMap(events);
+//        
+//        assertNotNull(map);
+//        assertEquals(map.keySet().size(),2);
+//        assertEquals(map.get(bundleId1).size(), 3);
+//        assertEquals(map.get(bundleId2).size(), 1);
+//        
+//    }
+//
+//    private BillingEvent createBillingEvent(Subscription subscription) {
+//        BillingEvent result =  BrainDeadProxyFactory.createBrainDeadProxyFor(BillingEvent.class, Comparable.class);
+//        ((ZombieControl)result).addResult("getSubscription", subscription);
+//        ((ZombieControl)result).addResult("compareTo", 1);
+//        return result;
+//    }
+//
+//    @Test
+//    public void testCreateDisablePairs() {
+//        SortedSet<OverdueEvent> overdueBundleEvents;
+//        UUID ovdId = UUID.randomUUID();
+//        DateTime now = clock.getUTCNow();
+//        
+//        //simple events open clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        
+//        List<DisabledDuration> pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNull(pairs.get(0).getEnd());
+//        
+//        //simple events closed clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+//
+//        //simple BUNDLE events closed clear -> disabled
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(2));
+//        
+//        
+//        //two or more disableds in a row
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(3));
+//
+//       
+//        overdueBundleEvents = new TreeSet<OverdueEvent>();
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(1)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(2)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(3)));
+//        overdueBundleEvents.add(new OverdueEvent(ovdId,CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE,now.plusDays(4)));
+//        
+//        pairs = odc.createDisablePairs(overdueBundleEvents);
+//        assertEquals(pairs.size(), 1);
+//        assertNotNull(pairs.get(0).getStart());
+//        assertEquals(pairs.get(0).getStart(),now.plusDays(1));
+//        assertNotNull(pairs.get(0).getEnd());
+//        assertEquals(pairs.get(0).getEnd(),now.plusDays(4));
+//  
+//    }
+//
+//    @Test
+//    public void testIsDisableEvent() {
+//       DateTime now = clock.getUTCNow();
+//           assertTrue(!odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), CLEAR_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+//       assertTrue(odc.isDisableEvent(new OverdueEvent(new UUID(0L,0L), DISABLED_BUNDLE, Overdueable.Type.SUBSCRIPTION_BUNDLE, now)));
+//    }
+//
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index 1d679a9..3e1b421 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -69,7 +69,7 @@ public abstract class TestMigration extends TestApiBase {
             Subscription subscription = subscriptions.get(0);
             assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
             assertEquals(subscription.getEndDate(), null);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-annual");
@@ -103,7 +103,7 @@ public abstract class TestMigration extends TestApiBase {
                     subscriptions.get(0) : subscriptions.get(1);
             assertDateWithin(baseSubscription.getStartDate(), beforeMigration, afterMigration);
             assertEquals(baseSubscription.getEndDate(), null);
-            assertEquals(baseSubscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(baseSubscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(baseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(baseSubscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(baseSubscription.getCurrentPlan().getName(), "shotgun-annual");
@@ -113,7 +113,7 @@ public abstract class TestMigration extends TestApiBase {
                     subscriptions.get(0) : subscriptions.get(1);
             assertEquals(aoSubscription.getStartDate(), initalAddonStart);
             assertEquals(aoSubscription.getEndDate(), null);
-            assertEquals(aoSubscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(aoSubscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(aoSubscription.getCurrentPhase().getPhaseType(), PhaseType.DISCOUNT);
             assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(aoSubscription.getCurrentPlan().getName(), "telescopic-scope-monthly");
@@ -146,7 +146,7 @@ public abstract class TestMigration extends TestApiBase {
             assertEquals(subscriptions.size(), 1);
             Subscription subscription = subscriptions.get(0);
             assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-annual");
@@ -161,7 +161,7 @@ public abstract class TestMigration extends TestApiBase {
             assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
             assertNotNull(subscription.getEndDate());
             assertTrue(subscription.getEndDate().isAfterNow());
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase(), null);
             assertEquals(subscription.getState(), SubscriptionState.CANCELLED);
             assertNull(subscription.getCurrentPlan());
@@ -191,7 +191,7 @@ public abstract class TestMigration extends TestApiBase {
 
             assertEquals(subscription.getStartDate(), trialDate);
             assertEquals(subscription.getEndDate(), null);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.TRIAL);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
@@ -205,7 +205,7 @@ public abstract class TestMigration extends TestApiBase {
 
             assertEquals(subscription.getStartDate(), trialDate);
             assertEquals(subscription.getEndDate(), null);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
@@ -236,7 +236,7 @@ public abstract class TestMigration extends TestApiBase {
             Subscription subscription = subscriptions.get(0);
             assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
             assertEquals(subscription.getEndDate(), null);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
             assertEquals(subscription.getCurrentPlan().getName(), "assault-rifle-monthly");
@@ -248,7 +248,7 @@ public abstract class TestMigration extends TestApiBase {
 
             assertDateWithin(subscription.getStartDate(), beforeMigration, afterMigration);
             assertEquals(subscription.getEndDate(), null);
-            assertEquals(subscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(subscription.getCurrentPriceList().getName(), PriceListSet.DEFAULT_PRICELIST_NAME);
 
             assertEquals(subscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
             assertEquals(subscription.getState(), SubscriptionState.ACTIVE);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index 0a65693..53b5199 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
@@ -31,6 +31,7 @@ import com.ning.billing.util.callcontext.TestCallContext;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.joda.time.Period;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -74,6 +75,7 @@ import com.ning.billing.entitlement.events.user.ApiEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.bus.Bus.EventBusException;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.BusService;
 
@@ -185,7 +187,7 @@ public abstract class TestApiBase {
     }
 
     @BeforeMethod(alwaysRun = true)
-    public void setupTest() {
+    public void setupTest() throws Exception {
 
         log.warn("RESET TEST FRAMEWORK\n\n");
 
@@ -261,7 +263,6 @@ public abstract class TestApiBase {
         }
     }
 
-
     protected void assertDateWithin(DateTime in, DateTime lower, DateTime upper) {
         assertTrue(in.isEqual(lower) || in.isAfter(lower));
         assertTrue(in.isEqual(upper) || in.isBefore(upper));
@@ -282,6 +283,10 @@ public abstract class TestApiBase {
             public DateTime addToDateTime(DateTime dateTime) {
                 return null;
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
         return result;
     }
@@ -301,6 +306,10 @@ public abstract class TestApiBase {
             public DateTime addToDateTime(DateTime dateTime) {
                 return null;  //To change body of implemented methods use File | Settings | File Templates.
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
         return result;
     }
@@ -321,6 +330,10 @@ public abstract class TestApiBase {
             public DateTime addToDateTime(DateTime dateTime) {
                 return null;  //To change body of implemented methods use File | Settings | File Templates.
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         };
         return result;
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index 14d6653..906af6f 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -21,7 +21,9 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
+import org.apache.commons.lang.NotImplementedException;
 import org.joda.time.DateTime;
+import org.joda.time.Period;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -38,8 +40,9 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
+import com.ning.billing.catalog.api.TimeUnit;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
 import com.ning.billing.util.clock.DefaultClock;
@@ -280,6 +283,7 @@ public class TestUserApiAddOn extends TestApiBase {
         }
     }
 
+    //TODO MDW - debugging reenable if you find this
     @Test(enabled=true, groups={"slow"})
     public void testAddonCreateWithSubscriptionAlign() {
 
@@ -352,7 +356,32 @@ public class TestUserApiAddOn extends TestApiBase {
            testListener.pushExpectedEvent(NextEvent.PHASE);
 
            // MOVE THROUGH TIME TO GO INTO EVERGREEN
-           someTimeLater = aoCurrentPhase.getDuration();
+           
+           // Talk with Stephane about this fix. It seemed that the add on phase change was not appearing in the queue
+           // hypothesis is that waiting a period that is exactly the duration of the phase might be an instant too short
+           // depending how the comparison works
+           //someTimeLater = aoCurrentPhase.getDuration();
+           someTimeLater = new Duration() {
+                @Override
+                public TimeUnit getUnit() {
+                   return TimeUnit.DAYS;
+                }
+
+                @Override
+                public int getNumber() {
+                   return 32;
+                }
+
+                @Override
+                public DateTime addToDateTime(DateTime dateTime) {
+                   throw new NotImplementedException();
+                }
+                @Override
+                public Period toJodaPeriod() {
+                    throw new UnsupportedOperationException();
+                }
+           };
+           
            clock.addDeltaFromReality(someTimeLater);
            assertTrue(testListener.isCompleted(5000));
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
index 55ad5e8..5a7d33e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
@@ -17,25 +17,23 @@
 package com.ning.billing.entitlement.api.user;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.assertFalse;
 
-import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
-import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
-import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 import org.testng.Assert;
 
-
 import com.ning.billing.catalog.api.BillingPeriod;
 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.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.api.TestApiBase;
-import java.util.List;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
+import com.ning.billing.util.clock.DefaultClock;
 
 public abstract class TestUserApiCancel extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
index 57e34e9..7eccbdd 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelMemory.java
@@ -16,12 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import org.testng.annotations.Test;
 
 public class TestUserApiCancelMemory extends TestUserApiCancel {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
index 469d374..6d02736 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancelSql.java
@@ -16,12 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import org.testng.annotations.Test;
 
 public class TestUserApiCancelSql extends TestUserApiCancel {
 
@@ -34,7 +35,7 @@ public class TestUserApiCancelSql extends TestUserApiCancel {
     }
 
     @Test(enabled= false, groups={"stress"})
-    public void stressTest() throws EntitlementBillingApiException {
+    public void stressTest() throws Exception {
         for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
             cleanupTest();
             setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index d8a34c9..98e495d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -29,14 +29,13 @@ import org.testng.Assert;
 
 import com.ning.billing.catalog.api.BillingPeriod;
 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.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.user.ApiEvent;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index f390cdb..8bbdd2d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
@@ -16,12 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import org.testng.annotations.Test;
 
 public class TestUserApiChangePlanMemory extends TestUserApiChangePlan {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
index 735099c..509b056 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanSql.java
@@ -16,12 +16,13 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import org.testng.annotations.Test;
 
 public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
 
@@ -33,7 +34,7 @@ public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
     }
 
     @Test(enabled= true, groups={"stress"})
-    public void stressTest() throws EntitlementBillingApiException {
+    public void stressTest() throws Exception {
         for (int i = 0; i < MAX_STRESS_ITERATIONS; i++) {
             cleanupTest();
             setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
index a8d6e0c..01ced07 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreate.java
@@ -22,19 +22,20 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
 import java.util.List;
+
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
 import com.ning.billing.catalog.api.BillingPeriod;
+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.PriceListSet;
-import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
 import com.ning.billing.util.clock.DefaultClock;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
index b674e34..7987d87 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
@@ -16,11 +16,12 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
-import org.testng.annotations.Test;
 
 public class TestUserApiCreateMemory extends TestUserApiCreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
index 6820fec..c890da7 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateSql.java
@@ -16,11 +16,12 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
-import org.testng.annotations.Test;
 
 public class TestUserApiCreateSql extends TestUserApiCreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
index 74fbef7..b21764d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -16,31 +16,33 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
-
 import com.ning.billing.catalog.api.BillingPeriod;
 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.PhaseType;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.TestApiBase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import static org.testng.Assert.*;
 
 public class TestUserApiDemos extends TestApiBase {
 
@@ -174,7 +176,7 @@ public class TestUserApiDemos extends TestApiBase {
 
         Plan currentPlan = subscription.getCurrentPlan();
         PlanPhase currentPhase = subscription.getCurrentPhase();
-        String priceList = subscription.getCurrentPriceList();
+        String priceList = subscription.getCurrentPriceList().getName();
         System.out.println("");
         System.out.println("\t CURRENT TIME = " + clock.getUTCNow());
         System.out.println("");
@@ -190,7 +192,7 @@ public class TestUserApiDemos extends TestApiBase {
     }
 
     @Test(enabled= true, groups={"stress"})
-    public void stressTest() throws EntitlementBillingApiException {
+    public void stressTest() throws Exception {
         for (int i = 0; i < 100; i++) {
             cleanupTest();
             setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index 11103ba..440b780 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -16,6 +16,18 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
@@ -24,20 +36,10 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
 
 public class TestUserApiError extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
index 7dbc802..91aaf02 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreate.java
@@ -25,11 +25,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
-import com.google.inject.Injector;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 
 public abstract class TestUserApiRecreate extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
index 1ece406..08f1ac1 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
@@ -16,6 +16,14 @@
 
 package com.ning.billing.entitlement.api.user;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
@@ -23,17 +31,11 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhase;
-
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApiException;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
 import com.ning.billing.util.clock.DefaultClock;
-import org.joda.time.DateTime;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
 
 public class TestUserApiScenarios extends TestApiBase {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
index bbfd42a..afc5591 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserCustomFieldsSql.java
@@ -16,16 +16,11 @@
 
 package com.ning.billing.entitlement.api.user;
 
-import java.util.List;
-
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.DefaultClock;
+import java.util.List;
+
 import org.joda.time.DateTime;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -35,9 +30,14 @@ import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
+import com.ning.billing.entitlement.api.TestApiBase;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.customfield.CustomField;
 
 
@@ -51,7 +51,7 @@ public class TestUserCustomFieldsSql extends TestApiBase {
     }
 
     @Test(enabled=false, groups={"slow"})
-    public void stress() {
+    public void stress() throws Exception {
         cleanupTest();
         for (int i = 0; i < 20; i++) {
             setupTest();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index 1872305..5bb0fb5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -24,7 +24,6 @@ import java.util.List;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
 import org.apache.commons.lang.NotImplementedException;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -50,6 +49,7 @@ import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
 import com.ning.billing.entitlement.events.user.ApiEvent;
 import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.notificationq.NotificationKey;
 import com.ning.billing.util.notificationq.NotificationQueue;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 4733f4a..8deaef6 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -16,8 +16,6 @@
 
 package com.ning.billing.entitlement.engine.dao;
 
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.tag.dao.TagDao;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
@@ -26,9 +24,10 @@ import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 
 import com.google.inject.Inject;
-import com.ning.billing.entitlement.api.user.SubscriptionFactory;
+import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 
 public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEntitlementDao {
@@ -37,8 +36,9 @@ public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEnti
 
     @Inject
     public MockEntitlementDaoSql(IDBI dbi, Clock clock, AddonUtils addonUtils, NotificationQueueService notificationQueueService,
-                                 CustomFieldDao customFieldDao) {
-        super(dbi, clock, addonUtils, notificationQueueService, customFieldDao);
+                                 CustomFieldDao customFieldDao, 
+                                 final CatalogService catalogService) {
+        super(dbi, clock, addonUtils, notificationQueueService, customFieldDao, catalogService);
         this.resetDao = dbi.onDemand(ResetSqlDao.class);
     }
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index acb1a2a..c795ca5 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
@@ -25,6 +25,7 @@ import com.ning.billing.util.glue.CallContextModule;
 
 public class MockEngineModule extends EntitlementModule {
 
+   
     @Override
     protected void configure() {
         super.configure();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
index f774e58..a1744ca 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModuleSql.java
@@ -16,19 +16,17 @@
 
 package com.ning.billing.entitlement.glue;
 
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.IDBI;
+
 import com.ning.billing.dbi.DBIProvider;
 import com.ning.billing.dbi.DbiConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.MockEntitlementDaoSql;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 
-import org.skife.config.ConfigurationObjectFactory;
-import org.skife.jdbi.v2.IDBI;
-
 public class MockEngineModuleSql extends MockEngineModule {
 
 
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 beadd47..f6ba4a5 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
@@ -384,9 +384,11 @@ public class DefaultInvoiceDao implements InvoiceDao {
         addInvoiceItemsToChargeThroughDates(chargeThroughDates, recurringItems);
 
         for (UUID subscriptionId : chargeThroughDates.keySet()) {
-            DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
-            log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
-            entitlementBillingApi.setChargedThroughDateFromTransaction(dao, subscriptionId, chargeThroughDate, context);
+            if(subscriptionId != null) {
+                DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
+                log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
+                entitlementBillingApi.setChargedThroughDateFromTransaction(dao, subscriptionId, chargeThroughDate, context);
+            }
         }
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
index f564658..b89c68b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
@@ -16,12 +16,17 @@
 
 package com.ning.billing.invoice.dao;
 
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.InvoiceItem;
-import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
+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.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -36,16 +41,12 @@ import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-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.math.BigDecimal;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.UUID;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.entity.EntityDao;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper(FixedPriceInvoiceItemSqlDao.FixedPriceInvoiceItemMapper.class)
@@ -78,9 +79,10 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
                 return new Binder<FixedPriceInvoiceItemBinder, FixedPriceInvoiceItem>() {
                     public void bind(SQLStatement q, FixedPriceInvoiceItemBinder bind, FixedPriceInvoiceItem item) {
                         q.bind("id", item.getId().toString());
-                        q.bind("invoiceId", item.getInvoiceId().toString());
                         q.bind("accountId", item.getAccountId().toString());
-                        q.bind("subscriptionId", item.getSubscriptionId().toString());
+                        q.bind("invoiceId", item.getInvoiceId().toString());
+                        q.bind("bundleId", item.getBundleId() == null ? null : item.getBundleId().toString());
+                        q.bind("subscriptionId", item.getSubscriptionId() == null ? null : item.getSubscriptionId().toString());
                         q.bind("planName", item.getPlanName());
                         q.bind("phaseName", item.getPhaseName());
                         q.bind("startDate", item.getStartDate().toDate());
@@ -99,7 +101,8 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             UUID id = UUID.fromString(result.getString("id"));
             UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
             UUID accountId = UUID.fromString(result.getString("account_id"));
-            UUID subscriptionId = UUID.fromString(result.getString("subscription_id"));
+            UUID bundleId = result.getString("bundle_id") == null ? null :UUID.fromString(result.getString("bundle_id"));
+            UUID subscriptionId = result.getString("subscription_id") == null ? null : UUID.fromString(result.getString("subscription_id"));
             String planName = result.getString("plan_name");
             String phaseName = result.getString("phase_name");
             DateTime startDate = new DateTime(result.getTimestamp("start_date"));
@@ -109,7 +112,7 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             String createdBy = result.getString("created_by");
             DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
 
-            return new FixedPriceInvoiceItem(id, invoiceId, accountId, subscriptionId, planName, phaseName,
+            return new FixedPriceInvoiceItem(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
                                             startDate, endDate, amount, currency, createdBy, createdDate);
         }
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
index 29dfb9e..46c5153 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
@@ -16,12 +16,17 @@
 
 package com.ning.billing.invoice.dao;
 
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.InvoiceItem;
-import com.ning.billing.invoice.model.RecurringInvoiceItem;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
+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.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -36,16 +41,12 @@ import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-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.math.BigDecimal;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.UUID;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.model.RecurringInvoiceItem;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.entity.EntityDao;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper(RecurringInvoiceItemSqlDao.RecurringInvoiceItemMapper.class)
@@ -79,7 +80,8 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
                         q.bind("id", item.getId().toString());
                         q.bind("invoiceId", item.getInvoiceId().toString());
                         q.bind("accountId", item.getAccountId().toString());
-                        q.bind("subscriptionId", item.getSubscriptionId().toString());
+                        q.bind("bundleId", item.getBundleId() == null ? null : item.getBundleId().toString());
+                        q.bind("subscriptionId", item.getSubscriptionId() == null ? null : item.getSubscriptionId().toString());
                         q.bind("planName", item.getPlanName());
                         q.bind("phaseName", item.getPhaseName());
                         q.bind("startDate", item.getStartDate().toDate());
@@ -100,7 +102,8 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             UUID id = UUID.fromString(result.getString("id"));
             UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
             UUID accountId = UUID.fromString(result.getString("account_id"));
-            UUID subscriptionId = UUID.fromString(result.getString("subscription_id"));
+            UUID subscriptionId = result.getString("subscription_id") == null ? null : UUID.fromString(result.getString("subscription_id"));
+            UUID bundleId = result.getString("bundle_id") == null ? null : UUID.fromString(result.getString("bundle_id"));
             String planName = result.getString("plan_name");
             String phaseName = result.getString("phase_name");
             DateTime startDate = new DateTime(result.getTimestamp("start_date"));
@@ -113,8 +116,9 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             String createdBy = result.getString("created_by");
             DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
 
-            return new RecurringInvoiceItem(id, invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate,
+            return new RecurringInvoiceItem(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
                     amount, rate, currency, reversedItemId, createdBy, createdDate);
+
         }
     }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 7d1253c..043c670 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -148,7 +148,7 @@ public class InvoiceDispatcher {
             return null;    
         }
 
-        SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccount(accountId);
+        SortedSet<BillingEvent> events = entitlementBillingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId);
         BillingEventSet billingEvents = new BillingEventSet(events);
 
         Currency targetCurrency = account.getCurrency();
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/BillingEventSet.java b/invoice/src/main/java/com/ning/billing/invoice/model/BillingEventSet.java
index da95559..8cf1e1e 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/BillingEventSet.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/BillingEventSet.java
@@ -28,7 +28,10 @@ public class BillingEventSet extends ArrayList<BillingEvent> {
 
     public BillingEventSet(Collection<BillingEvent> events) {
         super();
-        addAll(events);
+        if(events != null) {
+            addAll(events);
+            
+        }
     }
 
     public boolean isLast(final BillingEvent event) {
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 389010c..627a7be 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
@@ -16,6 +16,18 @@
 
 package com.ning.billing.invoice.model;
 
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.Months;
+
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -28,16 +40,6 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.util.clock.Clock;
-import org.joda.time.DateTime;
-import org.joda.time.Months;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.UUID;
-import javax.annotation.Nullable;
 
 public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private static final int ROUNDING_MODE = InvoicingConfiguration.getRoundingMode();
@@ -211,7 +213,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                     if (rate != null) {
                         BigDecimal amount = itemDatum.getNumberOfCycles().multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_MODE);
 
-                        RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId, accountId,
+                        RecurringInvoiceItem recurringItem = new RecurringInvoiceItem(invoiceId, 
+                                accountId,
+                                thisEvent.getSubscription().getBundleId(), 
                                 thisEvent.getSubscription().getId(),
                                 thisEvent.getPlan().getName(),
                                 thisEvent.getPlanPhase().getName(),
@@ -246,7 +250,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                 Duration duration = thisEvent.getPlanPhase().getDuration();
                 DateTime endDate = duration.addToDateTime(thisEvent.getEffectiveDate());
 
-                return new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getId(),
+                return new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(),
+                                                 thisEvent.getSubscription().getId(),
                                                  thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
                                                  thisEvent.getEffectiveDate(), endDate, fixedPrice, currency);
             } else {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
index 91e49fa..8c2398b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
@@ -16,23 +16,25 @@
 
 package com.ning.billing.invoice.model;
 
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.InvoiceItem;
-import org.joda.time.DateTime;
-
 import java.math.BigDecimal;
 import java.util.UUID;
 
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoiceItem;
+
 public class FixedPriceInvoiceItem extends InvoiceItemBase {
-    public FixedPriceInvoiceItem(UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+
+    public FixedPriceInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                  DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
-        super(invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+        super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
     }
 
-    public FixedPriceInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+    public FixedPriceInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                  DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
                                  String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
     }
 
     @Override
@@ -49,6 +51,7 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
     public int hashCode() {
         int result = accountId.hashCode();
         result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
         result = 31 * result + (planName != null ? planName.hashCode() : 0);
         result = 31 * result + (phaseName != null ? phaseName.hashCode() : 0);
         result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
@@ -66,12 +69,17 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
 
         FixedPriceInvoiceItem that = (FixedPriceInvoiceItem) item;
         int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0) {
-            int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
-            if (compareSubscriptions == 0) {
-                return getStartDate().compareTo(that.getStartDate());
+        if (compareAccounts == 0 && bundleId != null) {
+            int compareBundles = getBundleId().compareTo(that.getBundleId());
+            if (compareBundles == 0 && subscriptionId != null) {
+                int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
+                if (compareSubscriptions == 0) {
+                    return getStartDate().compareTo(that.getStartDate());
+                } else {
+                    return compareSubscriptions;
+                }
             } else {
-                return compareSubscriptions;
+                return compareBundles;
             }
         } else {
             return compareAccounts;
@@ -84,7 +92,8 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
         sb.append("InvoiceItem = {").append("id = ").append(id.toString()).append(", ");
         sb.append("invoiceId = ").append(invoiceId.toString()).append(", ");
         sb.append("accountId = ").append(accountId.toString()).append(", ");
-        sb.append("subscriptionId = ").append(subscriptionId.toString()).append(", ");
+        sb.append("subscriptionId = ").append(subscriptionId == null ? null : subscriptionId.toString()).append(", ");
+        sb.append("bundleId = ").append(bundleId == null ? null : bundleId.toString()).append(", ");
         sb.append("planName = ").append(planName).append(", ");
         sb.append("phaseName = ").append(phaseName).append(", ");
         sb.append("startDate = ").append(startDate.toString()).append(", ");
@@ -110,6 +119,8 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
         if (accountId.compareTo(that.accountId) != 0) return false;
         if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null)
             return false;
+        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null)
+            return false;
         if (amount != null ? amount.compareTo(that.amount) != 0 : that.amount != null) return false;
         if (currency != that.currency) return false;
         if (startDate != null ? startDate.compareTo(that.startDate) != 0 : that.startDate != null) return false;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
index 2f16468..175a08e 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
@@ -29,6 +29,7 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     protected final UUID invoiceId;
     protected final UUID accountId;
     protected final UUID subscriptionId;
+    protected final UUID bundleId;
     protected final String planName;
     protected final String phaseName;
     protected final DateTime startDate;
@@ -36,19 +37,21 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     protected final BigDecimal amount;
     protected final Currency currency;
 
-    public InvoiceItemBase(UUID invoiceId, UUID accountId, @Nullable UUID subscriptionId, String planName, String phaseName,
-                           DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
-        this(UUID.randomUUID(), invoiceId, accountId,  subscriptionId, planName, phaseName,
+    public InvoiceItemBase(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+            DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
+        this(UUID.randomUUID(), invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
                 startDate, endDate, amount, currency, null, null);
     }
 
-    public InvoiceItemBase(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID subscriptionId, String planName, String phaseName,
-                           DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
-                           @Nullable String createdBy, @Nullable DateTime createdDate) {
+
+    public InvoiceItemBase(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId, @Nullable UUID subscriptionId, String planName, String phaseName,
+            DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
+            @Nullable String createdBy, @Nullable DateTime createdDate) {
         super(id, createdBy, createdDate);
         this.invoiceId = invoiceId;
         this.accountId = accountId;
         this.subscriptionId = subscriptionId;
+        this.bundleId = bundleId;
         this.planName = planName;
         this.phaseName = phaseName;
         this.startDate = startDate;
@@ -72,6 +75,10 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     }
 
     @Override
+    public UUID getBundleId() {
+        return bundleId;
+    }
+    
     public UUID getAccountId() {
         return accountId;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/MigrationInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/MigrationInvoiceItem.java
index 01c1296..ec0962b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/MigrationInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/MigrationInvoiceItem.java
@@ -25,10 +25,9 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.MigrationPlan;
 
 public class MigrationInvoiceItem extends FixedPriceInvoiceItem {
-	private final static UUID MIGRATION_SUBSCRIPTION_ID = UUID.fromString("ed25f954-3aa2-4422-943b-c3037ad7257c"); //new UUID(0L,0L);
 
 	public MigrationInvoiceItem(UUID invoiceId, UUID accountId, DateTime startDate, BigDecimal amount, Currency currency) {
-		super(invoiceId, accountId, MIGRATION_SUBSCRIPTION_ID, MigrationPlan.MIGRATION_PLAN_NAME, MigrationPlan.MIGRATION_PLAN_PHASE_NAME,
+		super(invoiceId, accountId, null, null, MigrationPlan.MIGRATION_PLAN_NAME, MigrationPlan.MIGRATION_PLAN_PHASE_NAME,
               startDate, startDate, amount, currency);
 	}
 }
\ No newline at end of file
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
index f63599d..683a610 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
@@ -27,43 +27,41 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
     private final BigDecimal rate;
     private final UUID reversedItemId;
 
-    public RecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
-                                Currency currency) {
-        super(invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+                                Currency currency) { 
+        super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
         this.rate = rate;
         this.reversedItemId = null;
     }
 
-    public RecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
                                 Currency currency, UUID reversedItemId) {
-        super(invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate,
+        super(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
                 amount, currency);
         this.rate = rate;
         this.reversedItemId = reversedItemId;
     }
 
-    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
                                 Currency currency,
                                 String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
-
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
         this.rate = rate;
         this.reversedItemId = null;
     }
 
-    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
                                 Currency currency, UUID reversedItemId,
                                 String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
-
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
         this.rate = rate;
         this.reversedItemId = reversedItemId;
     }
@@ -71,7 +69,8 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
     @Override
     public InvoiceItem asCredit() {
         BigDecimal amountNegated = amount == null ? null : amount.negate();
-        return new RecurringInvoiceItem(invoiceId, accountId, subscriptionId, planName, phaseName, startDate, endDate,
+
+        return new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
                 amountNegated, rate, currency, id);
     }
 
@@ -103,17 +102,23 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
 
         RecurringInvoiceItem that = (RecurringInvoiceItem) item;
         int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0) {
-            int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
-            if (compareSubscriptions == 0) {
-                int compareStartDates = getStartDate().compareTo(that.getStartDate());
-                if (compareStartDates == 0) {
-                    return getEndDate().compareTo(that.getEndDate());
+        if (compareAccounts == 0 && bundleId != null) {
+            int compareBundles = getBundleId().compareTo(that.getBundleId());
+            if (compareBundles == 0 && subscriptionId != null) {
+
+                int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
+                if (compareSubscriptions == 0) {
+                    int compareStartDates = getStartDate().compareTo(that.getStartDate());
+                    if (compareStartDates == 0) {
+                        return getEndDate().compareTo(that.getEndDate());
+                    } else {
+                        return compareStartDates;
+                    }
                 } else {
-                    return compareStartDates;
+                    return compareSubscriptions;
                 }
             } else {
-                return compareSubscriptions;
+                return compareBundles;
             }
         } else {
             return compareAccounts;
@@ -137,7 +142,10 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
         if (rate.compareTo(that.rate) != 0) return false;
         if (reversedItemId != null ? !reversedItemId.equals(that.reversedItemId) : that.reversedItemId != null)
             return false;
-        if (!subscriptionId.equals(that.subscriptionId)) return false;
+        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null)
+            return false;
+        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null)
+            return false;
 
         return true;
     }
@@ -146,6 +154,7 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
     public int hashCode() {
         int result = accountId.hashCode();
         result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
         result = 31 * result + planName.hashCode();
         result = 31 * result + phaseName.hashCode();
         result = 31 * result + startDate.hashCode();
@@ -165,6 +174,8 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
         sb.append(startDate.toString()).append(", ");
         sb.append(endDate.toString()).append(", ");
         sb.append(amount.toString()).append(", ");
+        sb.append("subscriptionId = ").append(subscriptionId == null ? null : subscriptionId.toString()).append(", ");
+        sb.append("bundleId = ").append(bundleId == null ? null : bundleId.toString()).append(", ");
 
         return sb.toString();
     }
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
index 100182f..659d876 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
@@ -4,6 +4,7 @@ fields(prefix) ::= <<
   <prefix>id,
   <prefix>invoice_id,
   <prefix>account_id,
+  <prefix>bundle_id,
   <prefix>subscription_id,
   <prefix>plan_name,
   <prefix>phase_name,
@@ -42,13 +43,13 @@ getInvoiceItemsBySubscription() ::= <<
 
 create() ::= <<
   INSERT INTO fixed_invoice_items(<fields()>)
-  VALUES(:id, :invoiceId, :accountId, :subscriptionId, :planName, :phaseName,
+  VALUES(:id, :invoiceId, :accountId, :bundleId, :subscriptionId, :planName, :phaseName,
          :startDate, :endDate, :amount, :currency, :userName, :createdDate);
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO fixed_invoice_items(<fields()>)
-  VALUES(:id, :invoiceId, :accountId, :subscriptionId, :planName, :phaseName,
+  VALUES(:id, :invoiceId, :accountId, :bundleId, :subscriptionId, :planName, :phaseName,
          :startDate, :endDate, :amount, :currency, :userName, :createdDate);
 >>
 
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
index 6b5f504..7573ef3 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
@@ -4,6 +4,7 @@ fields(prefix) ::= <<
   <prefix>id,
   <prefix>invoice_id,
   <prefix>account_id,
+  <prefix>bundle_id,
   <prefix>subscription_id,
   <prefix>plan_name,
   <prefix>phase_name,
@@ -44,13 +45,13 @@ getInvoiceItemsBySubscription() ::= <<
 
 create() ::= <<
   INSERT INTO recurring_invoice_items(<fields()>)
-  VALUES(:id, :invoiceId, :accountId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
+  VALUES(:id, :invoiceId, :accountId, :bundleId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
          :amount, :rate, :currency, :reversedItemId, :userName, :createdDate);
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO recurring_invoice_items(<fields()>)
-  VALUES(:id, :invoiceId, :accountId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
+  VALUES(:id, :invoiceId, :accountId, :bundleId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
          :amount, :rate, :currency, :reversedItemId, :userName, :createdDate);
 >>
 
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 3adb40e..d04806a 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -4,7 +4,8 @@ CREATE TABLE recurring_invoice_items (
   id char(36) NOT NULL,
   invoice_id char(36) NOT NULL,
   account_id char(36) NOT NULL,
-  subscription_id char(36) NOT NULL,
+  bundle_id char(36),
+  subscription_id char(36),
   plan_name varchar(50) NOT NULL,
   phase_name varchar(50) NOT NULL,
   start_date datetime NOT NULL,
@@ -25,7 +26,8 @@ CREATE TABLE fixed_invoice_items (
   id char(36) NOT NULL,
   invoice_id char(36) NOT NULL,
   account_id char(36) NOT NULL,
-  subscription_id char(36) NOT NULL,
+  bundle_id char(36),
+  subscription_id char(36),
   plan_name varchar(50) NOT NULL,
   phase_name varchar(50) NOT NULL,
   start_date datetime NOT NULL,
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
index 4701bc8..300313c 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/MockModuleNoEntitlement.java
@@ -32,7 +32,8 @@ public class MockModuleNoEntitlement extends MockModule {
 	@Override
 	protected void installEntitlementModule() {
 		EntitlementBillingApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementBillingApi.class);
-		((ZombieControl)entitlementApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+        ((ZombieControl)entitlementApi).addResult("setChargedThroughDateFromTransaction", BrainDeadProxyFactory.ZOMBIE_VOID);
+        ((ZombieControl)entitlementApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", BrainDeadProxyFactory.ZOMBIE_VOID);
 		bind(EntitlementBillingApi.class).toInstance(entitlementApi);
 		bind(EntitlementDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementDao.class));
 
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index 512f559..3aee83d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -110,7 +110,7 @@ public class TestDefaultInvoiceMigrationApi {
 
     private final Clock clock = new ClockMock();
 
-	@BeforeClass(alwaysRun = true)
+	@BeforeClass(groups={"slow"})
 	public void setup() throws Exception
 	{
 		log.info("Starting set up");
@@ -133,7 +133,7 @@ public class TestDefaultInvoiceMigrationApi {
 		regularInvoiceId = generateRegularInvoice();
 	}
 
-	@AfterClass(alwaysRun = true)
+	@AfterClass(groups={"slow"})
 	public void tearDown() {
 		try {
 			((DefaultBusService) busService).stopBus();
@@ -171,20 +171,20 @@ public class TestDefaultInvoiceMigrationApi {
 		((ZombieControl)account).addResult("getId", accountId);
 
 		Subscription subscription =  BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
-		((ZombieControl)subscription).addResult("getId", subscriptionId);
+        ((ZombieControl)subscription).addResult("getId", subscriptionId);
+        ((ZombieControl)subscription).addResult("getBundleId", new UUID(0L,0L));
 		SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
 		Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
 		PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
 		DateTime effectiveDate = new DateTime().minusDays(1);
 		Currency currency = Currency.USD;
 		BigDecimal fixedPrice = null;
-		events.add(new DefaultBillingEvent(subscription, effectiveDate,plan, planPhase,
+		events.add(new DefaultBillingEvent(account, subscription, effectiveDate,plan, planPhase,
 				fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
 				BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
 
 		EntitlementBillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementBillingApi.class);
-		((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccount", events);
-
+        ((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
 		InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountUserApi, entitlementBillingApi, invoiceDao, locker, busService.getBus(), clock);
 
         CallContext context = new DefaultCallContextFactory(clock).createCallContext("Migration test", CallOrigin.TEST, UserType.TEST);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 96aeab5..fbb77dd 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -17,33 +17,32 @@
 package com.ning.billing.invoice.dao;
 
 import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
 
 import java.io.IOException;
 
-import com.ning.billing.config.InvoiceConfig;
-import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
-import com.ning.billing.invoice.model.InvoiceGenerator;
-import com.ning.billing.invoice.tests.InvoicingTestBase;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.Clock;
 import org.apache.commons.io.IOUtils;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.TransactionCallback;
 import org.skife.jdbi.v2.TransactionStatus;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
 
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
+import com.ning.billing.config.InvoiceConfig;
 import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
+import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
+import com.ning.billing.invoice.model.InvoiceGenerator;
+import com.ning.billing.invoice.tests.InvoicingTestBase;
 import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.bus.DefaultBusService;
-import org.testng.annotations.BeforeMethod;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
 
 public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
     protected InvoiceDao invoiceDao;
@@ -69,7 +68,6 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
 
     @BeforeClass(alwaysRun = true)
     protected void setup() throws IOException {
-        try {
             module = new InvoiceModuleWithEmbeddedDb();
             final String invoiceDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
             final String entitlementDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
@@ -94,10 +92,7 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
             ((DefaultBusService) busService).startBus();
 
             assertTrue(true);
-        }
-        catch (Throwable t) {
-            fail(t.toString());
-        }
+       
     }
 
     @BeforeMethod(alwaysRun = true)
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 907c8e3..a3b8888 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -84,11 +84,12 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         Invoice invoice = new DefaultInvoice(accountId, clock.getUTCNow(), clock.getUTCNow(), Currency.USD);
         UUID invoiceId = invoice.getId();
         UUID subscriptionId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime startDate = new DateTime(2010, 1, 1, 0, 0, 0, 0);
         DateTime endDate = new DateTime(2010, 4, 1, 0, 0, 0, 0);
-        InvoiceItem invoiceItem = new RecurringInvoiceItem(invoiceId, accountId, subscriptionId,
-                "test plan", "test phase", startDate, endDate,
+        InvoiceItem invoiceItem = new RecurringInvoiceItem(invoiceId, accountId, bundleId,subscriptionId, "test plan", "test phase", startDate, endDate,
                 new BigDecimal("21.00"), new BigDecimal("7.00"), Currency.USD);
+
         invoice.addInvoiceItem(invoiceItem);
         invoiceDao.create(invoice, context);
 
@@ -155,6 +156,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     @Test
     public void testGetInvoicesBySubscription() {
         UUID accountId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
 
         UUID subscriptionId1 = UUID.randomUUID();
         BigDecimal rate1 = new BigDecimal("17.0");
@@ -177,19 +179,20 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
         DateTime endDate = startDate.plusMonths(1);
 
-        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoiceId1, accountId, subscriptionId1, "test plan", "test A", startDate, endDate,
+
+        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId,subscriptionId1, "test plan", "test A", startDate, endDate,
                 rate1, rate1, Currency.USD);
         recurringInvoiceItemDao.create(item1, context);
 
-        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoiceId1, accountId, subscriptionId2, "test plan", "test B", startDate, endDate,
+        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId,subscriptionId2, "test plan", "test B", startDate, endDate,
                 rate2, rate2, Currency.USD);
         recurringInvoiceItemDao.create(item2, context);
 
-        RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoiceId1, accountId, subscriptionId3, "test plan", "test C", startDate, endDate,
+        RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId,subscriptionId3, "test plan", "test C", startDate, endDate,
                 rate3, rate3, Currency.USD);
         recurringInvoiceItemDao.create(item3, context);
 
-        RecurringInvoiceItem item4 = new RecurringInvoiceItem(invoiceId1, accountId, subscriptionId4, "test plan", "test D", startDate, endDate,
+        RecurringInvoiceItem item4 = new RecurringInvoiceItem(invoiceId1, accountId, bundleId,subscriptionId4, "test plan", "test D", startDate, endDate,
                 rate4, rate4, Currency.USD);
         recurringInvoiceItemDao.create(item4, context);
 
@@ -202,15 +205,16 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         startDate = endDate;
         endDate = startDate.plusMonths(1);
 
-        RecurringInvoiceItem item5 = new RecurringInvoiceItem(invoiceId2, accountId, subscriptionId1, "test plan", "test phase A", startDate, endDate,
+
+        RecurringInvoiceItem item5 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId,subscriptionId1, "test plan", "test phase A", startDate, endDate,
                 rate1, rate1, Currency.USD);
         recurringInvoiceItemDao.create(item5, context);
 
-        RecurringInvoiceItem item6 = new RecurringInvoiceItem(invoiceId2, accountId, subscriptionId2, "test plan", "test phase B", startDate, endDate,
+        RecurringInvoiceItem item6 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId,subscriptionId2, "test plan", "test phase B", startDate, endDate,
                 rate2, rate2, Currency.USD);
         recurringInvoiceItemDao.create(item6, context);
 
-        RecurringInvoiceItem item7 = new RecurringInvoiceItem(invoiceId2, accountId, subscriptionId3, "test plan", "test phase C", startDate, endDate,
+        RecurringInvoiceItem item7 = new RecurringInvoiceItem(invoiceId2, accountId, bundleId,subscriptionId3, "test plan", "test phase C", startDate, endDate,
                 rate3, rate3, Currency.USD);
         recurringInvoiceItemDao.create(item7, context);
 
@@ -260,6 +264,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     @Test
     public void testAccountBalance() {
         UUID accountId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime targetDate1 = new DateTime(2011, 10, 6, 0, 0, 0, 0);
         Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1, Currency.USD);
         invoiceDao.create(invoice1, context);
@@ -270,11 +275,11 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase A", startDate,
+        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId,UUID.randomUUID(), "test plan", "test phase A", startDate,
                 endDate, rate1, rate1, Currency.USD);
         recurringInvoiceItemDao.create(item1, context);
 
-        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase B", startDate,
+        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId,UUID.randomUUID(), "test plan", "test phase B", startDate,
                 endDate, rate2, rate2, Currency.USD);
         recurringInvoiceItemDao.create(item2, context);
 
@@ -289,6 +294,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     @Test
     public void testAccountBalanceWithNoPayments() {
         UUID accountId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime targetDate1 = new DateTime(2011, 10, 6, 0, 0, 0, 0);
         Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1, Currency.USD);
         invoiceDao.create(invoice1, context);
@@ -299,11 +305,11 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
+        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
                 rate1, rate1, Currency.USD);
         recurringInvoiceItemDao.create(item1, context);
 
-        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
+        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
                 rate2, rate2, Currency.USD);
         recurringInvoiceItemDao.create(item2, context);
 
@@ -329,6 +335,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     @Test
     public void testGetUnpaidInvoicesByAccountId() {
         UUID accountId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime targetDate1 = new DateTime(2011, 10, 6, 0, 0, 0, 0);
         Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate1, Currency.USD);
         invoiceDao.create(invoice1, context);
@@ -339,11 +346,12 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
+
+        RecurringInvoiceItem item1 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase A", startDate, endDate,
                 rate1, rate1, Currency.USD);
         recurringInvoiceItemDao.create(item1, context);
 
-        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
+        RecurringInvoiceItem item2 = new RecurringInvoiceItem(invoice1.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase B", startDate, endDate,
                 rate2, rate2, Currency.USD);
         recurringInvoiceItemDao.create(item2, context);
 
@@ -367,7 +375,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         BigDecimal rate3 = new BigDecimal("21.0");
 
-        RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoice2.getId(), accountId, UUID.randomUUID(), "test plan", "test phase C", startDate2, endDate2,
+        RecurringInvoiceItem item3 = new RecurringInvoiceItem(invoice2.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test phase C", startDate2, endDate2,
                 rate3, rate3, Currency.USD);
         recurringInvoiceItemDao.create(item3, context);
 
@@ -402,7 +410,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
 
         DateTime effectiveDate1 = new DateTime(2011, 2, 1, 0, 0, 0, 0);
-        BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan1, phase1, null,
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan1, phase1, null,
                 recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
                 "testEvent1", 1L, SubscriptionTransitionType.CREATE);
 
@@ -420,7 +428,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         MockPlan plan2 = new MockPlan(phase2);
 
         DateTime effectiveDate2 = new DateTime(2011, 2, 15, 0, 0, 0, 0);
-        BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan2, phase2, null,
+        BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan2, phase2, null,
                 recurringPrice2.getPrice(currency), currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
                 "testEvent2", 2L, SubscriptionTransitionType.CREATE);
         events.add(event2);
@@ -453,7 +461,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
         DateTime effectiveDate = buildDateTime(2011, 1, 1);
 
-        BillingEvent event = new DefaultBillingEvent(subscription, effectiveDate, plan, phase, null,
+        BillingEvent event = new DefaultBillingEvent(null, subscription, effectiveDate, plan, phase, null,
                 recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 15, BillingModeType.IN_ADVANCE,
                 "testEvent", 1L, SubscriptionTransitionType.CREATE);
         BillingEventSet events = new BillingEventSet();
@@ -486,7 +494,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
         DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
 
-        BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1, fixedPrice.getPrice(currency),
                 null, currency, BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
                 "testEvent1", 1L, SubscriptionTransitionType.CREATE);
         BillingEventSet events = new BillingEventSet();
@@ -502,7 +510,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         invoiceList.add(invoice1);
 
         DateTime effectiveDate2 = effectiveDate1.plusDays(30);
-        BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan, phase2, null,
+        BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
                 recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                 "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
         events.add(event2);
@@ -546,7 +554,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
         DateTime effectiveDate1 = buildDateTime(2011, 1, 1);
 
-        BillingEvent event1 = new DefaultBillingEvent(subscription, effectiveDate1, plan, phase1,
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, effectiveDate1, plan, phase1,
                 fixedPrice.getPrice(currency), null, currency,
                 BillingPeriod.MONTHLY, 1, BillingModeType.IN_ADVANCE,
                 "testEvent1", 1L, SubscriptionTransitionType.CREATE);
@@ -554,7 +562,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         events.add(event1);
 
         DateTime effectiveDate2 = effectiveDate1.plusDays(30);
-        BillingEvent event2 = new DefaultBillingEvent(subscription, effectiveDate2, plan, phase2, null,
+        BillingEvent event2 = new DefaultBillingEvent(null, subscription, effectiveDate2, plan, phase2, null,
                 recurringPrice.getPrice(currency), currency, BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                 "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
         events.add(event2);
@@ -593,7 +601,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BillingEventSet events = new BillingEventSet();
         List<Invoice> invoices = new ArrayList<Invoice>();
 
-        BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
                                                       TEN, currency,
                                                       BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                                                       "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
@@ -605,7 +613,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         invoice1 = invoiceDao.getById(invoice1.getId());
         assertNotNull(invoice1.getInvoiceNumber());
 
-        BillingEvent event2 = new DefaultBillingEvent(subscription, targetDate1, plan, phase2, null,
+        BillingEvent event2 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase2, null,
                                                       TWENTY, currency,
                                                       BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                                                       "testEvent2", 2L, SubscriptionTransitionType.CHANGE);
@@ -631,7 +639,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         Currency currency = Currency.USD;
 
         // create pseudo-random invoice
-        BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
                                                       TEN, currency,
                                                       BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                                                       "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
@@ -662,7 +670,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         Currency currency = Currency.USD;
 
         // create pseudo-random invoice
-        BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, targetDate1, plan, phase1, null,
                                                       TEN, currency,
                                                       BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
                                                       "testEvent1", 1L, SubscriptionTransitionType.CHANGE);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
index 464ef86..7ada46c 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
@@ -36,12 +36,13 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
     public void testInvoiceItemCreation() {
         UUID accountId = UUID.randomUUID();
         UUID invoiceId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         UUID subscriptionId = UUID.randomUUID();
         DateTime startDate = new DateTime(2011, 10, 1, 0, 0, 0, 0);
         DateTime endDate = new DateTime(2011, 11, 1, 0, 0, 0, 0);
         BigDecimal rate = new BigDecimal("20.00");
 
-        RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, subscriptionId, "test plan", "test phase", startDate, endDate,
+        RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, "test plan", "test phase", startDate, endDate,
                 rate, rate, Currency.USD);
         recurringInvoiceItemDao.create(item, context);
 
@@ -63,12 +64,14 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
     public void testGetInvoiceItemsBySubscriptionId() {
         UUID accountId = UUID.randomUUID();
         UUID subscriptionId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
         BigDecimal rate = new BigDecimal("20.00");
 
         for (int i = 0; i < 3; i++) {
             UUID invoiceId = UUID.randomUUID();
-            RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, subscriptionId,
+
+            RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId,
                     "test plan", "test phase", startDate.plusMonths(i), startDate.plusMonths(i + 1),
                     rate, rate, Currency.USD);
             recurringInvoiceItemDao.create(item, context);
@@ -82,13 +85,15 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
     public void testGetInvoiceItemsByInvoiceId() {
         UUID accountId = UUID.randomUUID();
         UUID invoiceId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
         BigDecimal rate = new BigDecimal("20.00");
 
         for (int i = 0; i < 5; i++) {
             UUID subscriptionId = UUID.randomUUID();
             BigDecimal amount = rate.multiply(new BigDecimal(i + 1));
-            RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, subscriptionId,
+
+            RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId,
                     "test plan", "test phase", startDate, startDate.plusMonths(1),
                     amount, amount, Currency.USD);
             recurringInvoiceItemDao.create(item, context);
@@ -101,6 +106,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
     @Test(groups = "slow")
     public void testGetInvoiceItemsByAccountId() {
         UUID accountId = UUID.randomUUID();
+        UUID bundleId = UUID.randomUUID();
         DateTime targetDate = new DateTime(2011, 5, 23, 0, 0, 0, 0);
         DefaultInvoice invoice = new DefaultInvoice(accountId, clock.getUTCNow(), targetDate, Currency.USD);
 
@@ -111,7 +117,8 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate = new BigDecimal("20.00");
 
         UUID subscriptionId = UUID.randomUUID();
-        RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, subscriptionId,
+
+        RecurringInvoiceItem item = new RecurringInvoiceItem(invoiceId, accountId, bundleId, subscriptionId,
                 "test plan", "test phase", startDate, startDate.plusMonths(1),
                 rate, rate, Currency.USD);
         recurringInvoiceItemDao.create(item, context);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index fd15171..368b74f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -16,11 +16,19 @@
 
 package com.ning.billing.invoice.glue;
 
+import static org.testng.Assert.assertNotNull;
+
 import java.io.IOException;
 import java.net.URL;
 
-import com.ning.billing.invoice.api.test.InvoiceTestApi;
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
+import com.ning.billing.invoice.api.test.InvoiceTestApi;
 import com.ning.billing.invoice.dao.InvoicePaymentSqlDao;
 import com.ning.billing.invoice.dao.RecurringInvoiceItemSqlDao;
 import com.ning.billing.invoice.notification.MockNextBillingDateNotifier;
@@ -30,23 +38,15 @@ import com.ning.billing.invoice.notification.NextBillingDatePoster;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.glue.GlobalLockerModule;
-import com.ning.billing.util.glue.TagStoreModule;
-import org.skife.jdbi.v2.IDBI;
-
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.dbi.MysqlTestingHelper;
-import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.FieldStoreModule;
+import com.ning.billing.util.glue.GlobalLockerModule;
+import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.billing.util.notificationq.MockNotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 
-import static org.testng.Assert.assertNotNull;
-
 public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
     private final MysqlTestingHelper helper = new MysqlTestingHelper();
     private IDBI dbi;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index 99f12b4..c062a06 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
@@ -16,10 +16,6 @@
 
 package com.ning.billing.invoice;
 
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.glue.FieldStoreModule;
-import com.ning.billing.util.glue.TagStoreModule;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
@@ -32,11 +28,15 @@ import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.invoice.glue.InvoiceModule;
 import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.glue.BusModule;
+import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
+import com.ning.billing.util.glue.TagStoreModule;
 
 
 public class MockModule extends AbstractModule {
@@ -74,7 +74,7 @@ public class MockModule extends AbstractModule {
     }
     
     protected void installEntitlementModule() {
-    	install(new EntitlementModule());
+        install(new EntitlementModule());
     }
 
     protected void installInvoiceModule() {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
index 26df2af..e70626f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/notification/TestNextBillingDateNotifier.java
@@ -24,23 +24,6 @@ import java.sql.SQLException;
 import java.util.UUID;
 import java.util.concurrent.Callable;
 
-import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.account.api.MockAccountUserApi;
-import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
-import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
-import com.ning.billing.invoice.InvoiceDispatcher;
-import com.ning.billing.invoice.dao.DefaultInvoiceDao;
-import com.ning.billing.invoice.dao.InvoiceDao;
-import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
-import com.ning.billing.invoice.model.InvoiceGenerator;
-import com.ning.billing.util.callcontext.CallContextFactory;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
-import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.globallocker.GlobalLocker;
-import com.ning.billing.util.globallocker.MySqlGlobalLocker;
-import com.ning.billing.util.tag.dao.AuditedTagDao;
-import com.ning.billing.util.tag.dao.TagDao;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.skife.config.ConfigurationObjectFactory;
@@ -56,28 +39,46 @@ import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.account.api.MockAccountUserApi;
 import com.ning.billing.catalog.DefaultCatalogService;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.config.CatalogConfig;
 import com.ning.billing.config.InvoiceConfig;
 import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
+import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.engine.dao.EntitlementSqlDao;
+import com.ning.billing.invoice.InvoiceDispatcher;
 import com.ning.billing.invoice.InvoiceListener;
+import com.ning.billing.invoice.dao.DefaultInvoiceDao;
+import com.ning.billing.invoice.dao.InvoiceDao;
+import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
+import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.lifecycle.KillbillService.ServiceException;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.InMemoryBus;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.globallocker.GlobalLocker;
+import com.ning.billing.util.globallocker.MySqlGlobalLocker;
 import com.ning.billing.util.notificationq.DefaultNotificationQueueService;
 import com.ning.billing.util.notificationq.DummySqlTest;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 import com.ning.billing.util.notificationq.dao.NotificationSqlDao;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
 
 public class TestNextBillingDateNotifier {
 	private Clock clock;
@@ -118,7 +119,7 @@ public class TestNextBillingDateNotifier {
 	public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
 		//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
         final Injector g = Guice.createInjector(Stage.PRODUCTION,  new AbstractModule() {
-			@Override
+			
             protected void configure() {
                 bind(Clock.class).to(ClockMock.class).asEagerSingleton();
                 bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
@@ -142,8 +143,8 @@ public class TestNextBillingDateNotifier {
                 bind(NextBillingDatePoster.class).to(DefaultNextBillingDatePoster.class).asEagerSingleton();
                 bind(AccountUserApi.class).to(MockAccountUserApi.class).asEagerSingleton();
                 bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
-                bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();                
-			}
+                bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();
+            }
         });
 
         clock = g.getInstance(Clock.class);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index b77f758..45f1db4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -23,11 +23,6 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.Clock;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
@@ -56,7 +51,6 @@ import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
-import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.invoice.notification.NextBillingDateNotifier;
@@ -64,6 +58,11 @@ import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.bus.DefaultBusService;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.globallocker.GlobalLocker;
 
 @Test(groups = "slow")
@@ -72,9 +71,6 @@ public class TestInvoiceDispatcher {
 	private Logger log = LoggerFactory.getLogger(TestInvoiceDispatcher.class);
 
 	@Inject
-	private InvoiceUserApi invoiceUserApi;
-
-	@Inject
 	private InvoiceGenerator generator;
 
 	@Inject
@@ -141,19 +137,20 @@ public class TestInvoiceDispatcher {
 		((ZombieControl)account).addResult("getId", accountId);
 
 		Subscription subscription =  BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
-		((ZombieControl)subscription).addResult("getId", subscriptionId);
+        ((ZombieControl)subscription).addResult("getId", subscriptionId);
+        ((ZombieControl)subscription).addResult("getBundleId", new UUID(0L,0L));
 		SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
 		Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
 		PlanPhase planPhase = MockPlanPhase.create1USDMonthlyEvergreen();
 		DateTime effectiveDate = new DateTime().minusDays(1);
 		Currency currency = Currency.USD;
 		BigDecimal fixedPrice = null;
-		events.add(new DefaultBillingEvent(subscription, effectiveDate,plan, planPhase,
+		events.add(new DefaultBillingEvent(account, subscription, effectiveDate,plan, planPhase,
 				fixedPrice, BigDecimal.ONE, currency, BillingPeriod.MONTHLY, 1,
 				BillingModeType.IN_ADVANCE, "", 1L, SubscriptionTransitionType.CREATE));
 
 		EntitlementBillingApi entitlementBillingApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementBillingApi.class);
-		((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccount", events);
+		((ZombieControl)entitlementBillingApi).addResult("getBillingEventsForAccountAndUpdateAccountBCD", events);
 
 		DateTime target = new DateTime();
 
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 da29ce7..1be0585 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
@@ -481,6 +481,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         UUID accountId = UUID.randomUUID();
         Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
         ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+        ((ZombieControl) subscription).addResult("getBundleId", UUID.randomUUID());
 
         Plan plan = new MockPlan("plan 1");
         MockInternationalPrice zeroPrice = new MockInternationalPrice(new DefaultPrice(ZERO, Currency.USD));
@@ -493,13 +494,13 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         BillingEventSet events = new BillingEventSet();
 
-        BillingEvent event1 = new DefaultBillingEvent(subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
+        BillingEvent event1 = new DefaultBillingEvent(null, subscription, new DateTime("2012-01-1T00:00:00.000-08:00"),
                                                       plan, phase1,
                                                       ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
                                                       BillingModeType.IN_ADVANCE, "Test Event 1", 1L,
                                                       SubscriptionTransitionType.CREATE);
 
-        BillingEvent event2 = new DefaultBillingEvent(subscription, changeDate,
+        BillingEvent event2 = new DefaultBillingEvent(null, subscription, changeDate,
                                                       plan, phase2,
                                                       ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, 1,
                                                       BillingModeType.IN_ADVANCE, "Test Event 2", 2L,
@@ -691,7 +692,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(subscriptionId));
         Currency currency = Currency.USD;
 
-        return new DefaultBillingEvent(sub, startDate, plan, planPhase,
+        return new DefaultBillingEvent(null, sub, startDate, plan, planPhase,
                                        planPhase.getFixedPrice() == null ? null : planPhase.getFixedPrice().getPrice(currency),
                                        planPhase.getRecurringPrice() == null ? null : planPhase.getRecurringPrice().getPrice(currency),
                                        currency, planPhase.getBillingPeriod(),
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
index 20b222c..0619020 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJson.java
@@ -23,7 +23,6 @@ import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonView;
 import org.joda.time.DateTime;
 
-import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.util.clock.DefaultClock;
 
@@ -245,7 +244,7 @@ public class SubscriptionJson {
         this.productName = data.getCurrentPlan().getProduct().getName();
         this.productCategory = data.getCurrentPlan().getProduct().getCategory().toString();
         this.billingPeriod = data.getCurrentPlan().getBillingPeriod().toString();
-        this.priceList = data.getCurrentPriceList();
+        this.priceList = data.getCurrentPriceList().getName();
         this.events = events;
         this.deletedEvents = deletedEvents;
         this.newEvents = newEvents;

ne/pom.xml 120(+120 -0)

diff --git a/ne/pom.xml b/ne/pom.xml
new file mode 100644
index 0000000..01c8700
--- /dev/null
+++ b/ne/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 Ning, Inc. ~ ~ Ning 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. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill</artifactId>
+        <version>0.1.11-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-ne</artifactId>
+    <name>killbill-ne</name>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.skife.config</groupId>
+            <artifactId>config-magic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.jdbi</groupId>
+            <artifactId>jdbi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj-db-files</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Strangely this is needed in order to run the tests in local db mode -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+           <scope>test</scope>
+         </dependency>
+ 
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <groups>fast,slow, stress</groups>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/ne/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java b/ne/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
new file mode 100644
index 0000000..0545df0
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.config.api.OverdueState;
+
+public class DefaultOverdueChecker implements OverdueChecker {
+
+    private final EntitlementUserApi entitlementApi;
+
+    @Inject
+    public DefaultOverdueChecker(EntitlementUserApi entitlementApi, OverdueAccessApi overdueApi) {
+        this.entitlementApi = entitlementApi;
+    }
+
+    @Override
+    public void checkBlocked(Subscription subscription) throws EntitlementUserApiException {
+        if(subscription.getBundleId() != null) {
+            SubscriptionBundle bundle = entitlementApi.getBundleFromId(subscription.getBundleId());
+            checkBlocked(bundle);
+        }
+    }
+
+    @Override
+    public void checkBlocked(SubscriptionBundle bundle) throws EntitlementUserApiException {
+        OverdueState<SubscriptionBundle> bundleState = bundle.getOverdueState();
+        if(bundleState != null && bundleState.blockChanges()) {
+            throw new EntitlementUserApiException(ErrorCode.ENT_BUNDLE_IS_OVERDUE_BLOCKED, bundle.getId(), bundle.getKey());
+        }
+    }
+
+ 
+}
diff --git a/ne/src/main/java/com/ning/billing/entitlement/api/overdue/OverdueChecker.java b/ne/src/main/java/com/ning/billing/entitlement/api/overdue/OverdueChecker.java
new file mode 100644
index 0000000..037401c
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/entitlement/api/overdue/OverdueChecker.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public interface OverdueChecker {
+
+    public void checkBlocked(Subscription subscription)  throws EntitlementUserApiException;
+
+    public void checkBlocked(SubscriptionBundle bundle) throws EntitlementUserApiException;
+}
diff --git a/ne/src/main/java/com/ning/billing/ne/api/billing/OverdueEventCalculator.java b/ne/src/main/java/com/ning/billing/ne/api/billing/OverdueEventCalculator.java
new file mode 100644
index 0000000..5c82383
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/ne/api/billing/OverdueEventCalculator.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ne.api.billing;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.entitlement.api.billing.BillingModeType;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionEventTransition.SubscriptionTransitionType;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.OverdueEvent;
+import com.ning.billing.overdue.config.api.Overdueable;
+
+public class OverdueEventCalculator {
+    private final OverdueAccessApi overdueApi;
+    private final CatalogService catalogService;
+
+    protected static class DisabledDuration {
+        private final DateTime start;
+        private final DateTime end;
+
+        public DisabledDuration(DateTime start,DateTime end) {
+            this.start = start;
+            this.end = end;
+        }
+        public DateTime getStart() {
+            return start;
+        }
+        public DateTime getEnd() {
+            return end;
+        }
+
+    }
+
+    protected static class MergeEvent extends OverdueEvent {
+
+        public MergeEvent(DateTime timestamp) {
+            super(null,  null, null, timestamp);
+        }
+
+    }
+
+    @Inject
+    public OverdueEventCalculator(OverdueAccessApi overdueApi, CatalogService catalogService) {
+        this.overdueApi = overdueApi;
+        this.catalogService = catalogService;
+    }
+
+    public void insertOverdueEvents(SortedSet<BillingEvent> billingEvents) {
+        if(billingEvents.size() <= 0) { return; }
+
+        Account account = billingEvents.first().getAccount();
+ 
+        Hashtable<UUID,Set<Subscription>> bundleMap = createBundleSubscriptionMap(billingEvents);
+
+        SortedSet<BillingEvent> billingEventsToAdd = new TreeSet<BillingEvent>();
+        SortedSet<BillingEvent> billingEventsToRemove = new TreeSet<BillingEvent>();
+
+        for(UUID bundleId : bundleMap.keySet()) {
+            SortedSet<OverdueEvent> overdueBundleEvents = overdueApi.getOverdueHistory(bundleId, Overdueable.Type.SUBSCRIPTION_BUNDLE);
+            List<DisabledDuration>  bundleDisablePairs  = createDisablePairs(overdueBundleEvents); 
+
+            for (Subscription subscription: bundleMap.get(bundleId)) {
+                billingEventsToAdd.addAll(createNewEvents( bundleDisablePairs, billingEvents, account, subscription));
+                billingEventsToRemove.addAll(eventsToRemove(bundleDisablePairs, billingEvents, subscription));
+            }
+        }
+
+        for(BillingEvent eventToAdd: billingEventsToAdd ) {
+            billingEvents.add(eventToAdd);
+        }
+
+        for(BillingEvent eventToRemove : billingEventsToRemove) {
+            billingEvents.remove(eventToRemove);
+        }
+
+    }
+
+    protected SortedSet<BillingEvent> eventsToRemove(List<DisabledDuration> disabledDuration,
+            SortedSet<BillingEvent> billingEvents, Subscription subscription) {
+        SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+
+        SortedSet<BillingEvent> filteredBillingEvents = filter(billingEvents, subscription);
+        for(DisabledDuration duration : disabledDuration) {
+            for(BillingEvent event : filteredBillingEvents) {
+                if(duration.getEnd() == null || event.getEffectiveDate().isBefore(duration.getEnd())) {
+                    if( event.getEffectiveDate().isAfter(duration.getStart()) ) { //between the pair
+                        result.add(event);
+                    }
+                } else { //after the last event of the pair no need to keep checking
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+     protected SortedSet<BillingEvent> createNewEvents( List<DisabledDuration> disabledDuration, SortedSet<BillingEvent> billingEvents, Account account, Subscription subscription) {
+        SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+        for(DisabledDuration duration : disabledDuration) {
+            BillingEvent precedingInitialEvent = precedingBillingEventForSubscription(duration.getStart(), billingEvents, subscription);
+            BillingEvent precedingFinalEvent = precedingBillingEventForSubscription(duration.getEnd(), billingEvents, subscription);
+
+            if(precedingInitialEvent != null) { // there is a preceding billing event
+                result.add(createNewDisableEvent(duration.getStart(), precedingInitialEvent));
+                if(duration.getEnd() != null) { // no second event in the pair means they are still disabled (no re-enable)
+                    result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent));
+                }
+
+            } else if(precedingFinalEvent != null) { // can happen - e.g. phase event
+                //
+                // TODO: check with Jeff that this is going to do something sensible
+                //
+                result.add(createNewReenableEvent(duration.getEnd(), precedingFinalEvent));
+
+            } 
+
+            // N.B. if there's no precedingInitial and no precedingFinal then there's nothing to do
+        }
+        return result;
+    }
+
+    protected BillingEvent precedingBillingEventForSubscription(DateTime datetime, SortedSet<BillingEvent> billingEvents, Subscription subscription) { 
+        if(datetime == null) { //second of a pair can be null if there's no re-enabling
+            return null;
+        }
+
+        SortedSet<BillingEvent> filteredBillingEvents = filter(billingEvents, subscription);
+        BillingEvent result = filteredBillingEvents.first();
+
+        if(datetime.isBefore(result.getEffectiveDate())) {
+            //This case can happen, for example, if we have an add on and the bundle goes into disabled before the add on is created
+            return null;
+        }
+
+        for(BillingEvent event : filteredBillingEvents) {
+            if(event.getEffectiveDate().isAfter(datetime)) { // found it its the previous event
+                return result;
+            } else { // still looking
+                result = event;
+            }
+        }
+        return result;
+    }
+
+    protected SortedSet<BillingEvent> filter(SortedSet<BillingEvent> billingEvents, Subscription subscription) {
+        SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+        for(BillingEvent event : billingEvents) {
+            if(event.getSubscription() == subscription) {
+                result.add(event);
+            }
+        }
+        return result;
+    }
+
+    protected BillingEvent createNewDisableEvent(DateTime odEventTime, BillingEvent previousEvent) {
+        final Account account = previousEvent.getAccount();
+        final int billCycleDay = previousEvent.getBillCycleDay();
+        final Subscription subscription = previousEvent.getSubscription();
+        final DateTime effectiveDate = odEventTime;
+        final PlanPhase planPhase = previousEvent.getPlanPhase();
+        final Plan plan = previousEvent.getPlan();
+        final BigDecimal fixedPrice = BigDecimal.ZERO;
+        final BigDecimal recurringPrice = BigDecimal.ZERO;
+        final Currency currency = previousEvent.getCurrency();
+        final String description = "";
+        final BillingModeType billingModeType = previousEvent.getBillingMode();
+        final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
+        final SubscriptionTransitionType type = SubscriptionTransitionType.CANCEL;
+        final Long totalOrdering = 0L; //TODO
+
+        return null;
+        
+        //TODO MDW
+//        new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+//                fixedPrice, recurringPrice, currency,
+//                billingPeriod, billCycleDay, billingModeType,
+//                description, totalOrdering, type);
+    }
+
+    protected BillingEvent createNewReenableEvent(DateTime odEventTime, BillingEvent previousEvent) {
+        final Account account = previousEvent.getAccount();
+        final int billCycleDay = previousEvent.getBillCycleDay();
+        final Subscription subscription = previousEvent.getSubscription();
+        final DateTime effectiveDate = odEventTime;
+        final PlanPhase planPhase = previousEvent.getPlanPhase();
+        final Plan plan = previousEvent.getPlan();
+        final BigDecimal fixedPrice = previousEvent.getFixedPrice();
+        final BigDecimal recurringPrice = previousEvent.getRecurringPrice();
+        final Currency currency = previousEvent.getCurrency();
+        final String description = "";
+        final BillingModeType billingModeType = previousEvent.getBillingMode();
+        final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
+        final SubscriptionTransitionType type = SubscriptionTransitionType.RE_CREATE;
+        final Long totalOrdering = 0L; //TODO
+
+        return null;
+        
+        //TODO MDW
+//        return new DefaultBillingEvent(account, subscription, effectiveDate, plan, planPhase,
+//                fixedPrice, recurringPrice, currency,
+//                billingPeriod, billCycleDay, billingModeType,
+//                description, totalOrdering, type);
+    }
+
+    protected Hashtable<UUID,Set<Subscription>> createBundleSubscriptionMap(SortedSet<BillingEvent> billingEvents) {
+        Hashtable<UUID,Set<Subscription>> result = new Hashtable<UUID,Set<Subscription>>();
+        for(BillingEvent event : billingEvents) {
+            UUID bundleId = event.getSubscription().getBundleId();
+            Set<Subscription> subs = result.get(bundleId);
+            if(subs == null) {
+                subs = new TreeSet<Subscription>();
+                result.put(bundleId,subs);
+            }
+            subs.add(event.getSubscription());        
+        }
+        return result;
+    }
+
+
+
+    protected List<DisabledDuration> createDisablePairs(SortedSet<OverdueEvent> overdueBundleEvents) {
+        List<DisabledDuration> result = new ArrayList<OverdueEventCalculator.DisabledDuration>();
+        OverdueEvent first = null;
+
+        for(OverdueEvent e : overdueBundleEvents) {
+            if(isDisableEvent(e) && first == null) { // found a transition to disabled
+                first = e;
+            } else if(first != null && !isDisableEvent(e)) { // found a transition from disabled
+                result.add(new DisabledDuration(first.getTimestamp(), e.getTimestamp()));
+                first = null;
+            }
+        }
+
+        if(first != null) { // found a transition to disabled with no terminating event
+            result.add(new DisabledDuration(first.getTimestamp(), null));
+        }
+
+        return result;
+    }
+
+    protected boolean isDisableEvent(OverdueEvent e) {
+        //TODO Martin refactoring 
+        return false;
+//        OverdueState<?> state = null;
+//        try {
+//            if (e.getType() == Overdueable.Type.SUBSCRIPTION_BUNDLE) {
+//                state = catalogService.getCurrentCatalog().currentBundleOverdueStateSet().findState(e.getStateName());
+//            }
+//        } catch (CatalogApiException exp) {
+//            throw new EntitlementError(exp);
+//        }
+//        if (state == null) {
+//            throw new EntitlementError("Unable to find an overdue state with name: " + e.getStateName());
+//        }
+//        return state.disableEntitlementAndChangesBlocked();
+    }
+
+}
diff --git a/ne/src/main/java/com/ning/billing/ne/glue/NEModule.java b/ne/src/main/java/com/ning/billing/ne/glue/NEModule.java
new file mode 100644
index 0000000..7159d87
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/ne/glue/NEModule.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ne.glue;
+
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.ning.billing.ne.override.dao.OverrideStateDao;
+import com.ning.billing.ne.override.dao.OverrideStateSqlDao;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.DefaultOverdueAcessApi;
+
+public class NEModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        bind(OverdueAccessApi.class).to(DefaultOverdueAcessApi.class);
+        bind(OverrideStateDao.class).toProvider(OverdueDaoProvider.class);
+    }
+
+    public static class OverdueDaoProvider implements Provider<OverrideStateDao>{
+        
+        private IDBI dbi;
+
+
+        @Inject
+        public OverdueDaoProvider(IDBI dbi){
+            this.dbi = dbi;
+        }
+        
+
+        @Override
+        public OverrideStateDao get() {
+            return dbi.onDemand(OverrideStateSqlDao.class);
+        }   
+    }
+}
diff --git a/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateDao.java b/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateDao.java
new file mode 100644
index 0000000..6e1418a
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateDao.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ne.override.dao;
+
+import java.util.SortedSet;
+import java.util.UUID;
+
+import com.ning.billing.overdue.OverdueEvent;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable.Type;
+import com.ning.billing.util.clock.Clock;
+
+public interface OverrideStateDao {
+
+    //Read
+    public String getOverdueStateFor(Overdueable overdueable);
+
+    public String getOverdueStateForIdAndType(UUID overdueableId, Type type);
+
+    public SortedSet<OverdueEvent> getOverdueHistoryFor(Overdueable overdueable);
+
+    public SortedSet<OverdueEvent> getOverdueHistoryForIdAndType(UUID overdueableId, Type type);
+
+    //Write
+    <T extends Overdueable> void  setOverdueState(T overdueable, OverdueState<T> newOverdueState, Overdueable.Type type, Clock clock);
+
+} 
\ No newline at end of file
diff --git a/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateSqlDao.java b/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateSqlDao.java
new file mode 100644
index 0000000..7041d84
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/ne/override/dao/OverrideStateSqlDao.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ne.override.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.OverdueEvent;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable.Type;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.MapperBase;
+
+@ExternalizedSqlViaStringTemplate3()
+public interface OverrideStateSqlDao extends OverrideStateDao, CloseMe, Transmogrifier {
+
+    @Override
+    @SqlUpdate
+    public abstract <T extends Overdueable> void setOverdueState(
+            @Bind(binder = OverdueableBinder.class) T overdueable, 
+            @Bind(binder = OverdueStateBinder.class) OverdueState<T> overdueState,
+            @Bind(binder = OverdueableTypeBinder.class) Overdueable.Type type,
+            @Bind(binder = CurrentTimeBinder.class) Clock clock) ;
+
+
+    @Override
+    @SqlQuery
+    @Mapper(OverdueStateSqlMapper.class)
+    public abstract String getOverdueStateFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+    
+    @Override
+    @SqlQuery
+    @Mapper(OverdueStateSqlMapper.class)
+    public abstract String getOverdueStateForIdAndType(@Bind(binder = UUIDBinder.class) UUID overdueableId, @Bind(binder = OverdueableTypeBinder.class)  Type type);
+
+    @Override
+    @SqlQuery
+    @Mapper(OverdueHistorySqlMapper.class)
+    public abstract SortedSet<OverdueEvent> getOverdueHistoryFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+    
+    @Override
+    @SqlQuery
+    @Mapper(OverdueHistorySqlMapper.class)
+    public abstract SortedSet<OverdueEvent> getOverdueHistoryForIdAndType(@Bind(binder = UUIDBinder.class) UUID overdueableId, @Bind(binder = OverdueableTypeBinder.class)  Type type);
+
+
+    public class OverdueHistorySqlMapper extends MapperBase implements ResultSetMapper<OverdueEvent> {
+
+        @Override
+        public OverdueEvent map(int index, ResultSet r, StatementContext ctx)
+                throws SQLException {
+            
+            DateTime timestamp;
+            UUID overdueableId;
+            String stateName;
+            Type type;
+            try {
+                timestamp = new DateTime(r.getDate("created_date"));
+                overdueableId = UUID.fromString(r.getString("id"));
+                stateName = r.getString("state") == null ? OverdueAccessApi.CLEAR_STATE_NAME : r.getString("state");
+                type = Type.get(r.getString("type"));
+            } catch (CatalogApiException e) {
+                throw new SQLException(e);
+            }
+            return new OverdueEvent(overdueableId, stateName, type, timestamp);
+        }    
+    }
+    
+    public static class OverdueStateSqlMapper extends MapperBase implements ResultSetMapper<String> {
+
+        @Override
+        public String map(int index, ResultSet r, StatementContext ctx)
+                throws SQLException {
+            return r.getString("state") == null ? OverdueAccessApi.CLEAR_STATE_NAME : r.getString("state");
+        }
+    }
+    
+    public static class UUIDBinder extends BinderBase implements Binder<Bind, UUID> {
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, UUID id) {
+            stmt.bind("id", id.toString());
+        }
+    }
+    public static class OverdueableBinder extends BinderBase implements Binder<Bind, Overdueable> {
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Overdueable overdueable) {
+            stmt.bind("id", overdueable.getId().toString());
+        }
+    }
+    
+    public static class OverdueStateBinder<T extends Overdueable> extends BinderBase implements Binder<Bind, OverdueState<T>> {
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, OverdueState<T> overdueState) {
+            stmt.bind("state", overdueState.getName());
+        }
+    }
+    
+    public class OverdueableTypeBinder extends BinderBase implements Binder<Bind, Overdueable.Type>{
+
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Type type) {
+            stmt.bind("type", type.name());
+        }
+
+    }
+
+    public static class CurrentTimeBinder extends BinderBase implements Binder<Bind, Clock> {
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Clock clock) {
+            stmt.bind("created_date", clock.getUTCNow().toDate());
+        }
+        
+    }
+
+}
diff --git a/ne/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java b/ne/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
new file mode 100644
index 0000000..a37d21c
--- /dev/null
+++ b/ne/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.overdue;
+
+import java.util.SortedSet;
+import java.util.UUID;
+
+import com.google.inject.Inject;
+import com.ning.billing.ne.override.dao.OverrideStateDao;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.OverdueEvent;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.Overdueable.Type;
+import com.ning.billing.util.clock.Clock;
+
+public class DefaultOverdueAcessApi implements OverdueAccessApi {
+    private OverrideStateDao dao;
+    private Clock clock;
+
+    @Inject
+    public DefaultOverdueAcessApi(OverrideStateDao dao, Clock clock) {
+        this.dao = dao;
+        this.clock = clock;
+    }
+    
+    @Override
+    public String getOverdueStateNameFor(Overdueable overdueable) {
+        return dao.getOverdueStateFor(overdueable);
+    }
+
+    @Override
+    public String getOverdueStateNameFor(UUID overdueableId, Type type) {
+        return dao.getOverdueStateForIdAndType(overdueableId, type);
+    }
+
+    @Override
+    public SortedSet<OverdueEvent> getOverdueHistory(Overdueable overdueable) {
+        return dao.getOverdueHistoryFor(overdueable); 
+    }
+
+    @Override
+    public SortedSet<OverdueEvent> getOverdueHistory(UUID overdueableId,
+            Type type) {
+        return dao.getOverdueHistoryForIdAndType(overdueableId, type);
+    }
+
+    @Override
+    public <T extends Overdueable> void setOverrideState(T overdueable, OverdueState<T> newOverdueState, Type type) {
+       dao.setOverdueState(overdueable, newOverdueState, type, clock);
+        
+    }
+
+}
diff --git a/ne/src/main/resources/com/ning/billing/ne/ddl.sql b/ne/src/main/resources/com/ning/billing/ne/ddl.sql
new file mode 100644
index 0000000..954a44f
--- /dev/null
+++ b/ne/src/main/resources/com/ning/billing/ne/ddl.sql
@@ -0,0 +1,9 @@
+
+DROP TABLE IF EXISTS overdue_states;
+CREATE TABLE overdue_states (
+  id char(36) NOT NULL,
+  state varchar(50) NOT NULL,
+  type varchar(20) NOT NULL,    
+  created_date datetime NOT NULL
+) ENGINE=innodb;
+CREATE INDEX overdue_states_by_id ON overdue_states (id);
\ No newline at end of file
diff --git a/ne/src/main/resources/com/ning/billing/ne/override/dao/OverrideStateSqlDao.sql.stg b/ne/src/main/resources/com/ning/billing/ne/override/dao/OverrideStateSqlDao.sql.stg
new file mode 100644
index 0000000..1a3bf1b
--- /dev/null
+++ b/ne/src/main/resources/com/ning/billing/ne/override/dao/OverrideStateSqlDao.sql.stg
@@ -0,0 +1,68 @@
+group OverrideStateSqlDao;
+
+getOverdueStateFor() ::= <<
+    select
+        id
+      , state
+      , type
+      , created_date   
+    from overdue_states
+    where id = :id 
+    order by created_date desc
+    limit 1
+    ;
+>>
+
+getOverdueStateForIdAndType() ::= <<
+    select
+        id
+      , state
+      , type
+      , created_date   
+    from overdue_states
+    where id = :id 
+    and type = :type
+    order by created_date desc
+    limit 1
+    ;
+>>
+
+
+getOverdueHistoryFor() ::= <<
+    select
+        id
+      , state
+      , type
+      , created_date   
+    from overdue_states
+    where id = :id 
+    order by created_date asc
+    ;
+>>
+
+getOverdueHistoryForIdAndType() ::= <<
+    select
+        id
+      , state
+      , type
+      , created_date   
+    from overdue_states
+    where id = :id 
+    and type = :type
+    order by created_date asc
+    ;
+>>
+
+setOverdueState() ::= <<
+    insert into overdue_states (
+        id
+      , state
+      , type
+      , created_date
+    ) values (
+        :id
+      , :state
+      , :type
+      , :created_date 
+    );
+>>
\ No newline at end of file
diff --git a/ne/src/test/java/com/ning/billing/entitlement/api/overdue/MockOverdueChecker.java b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/MockOverdueChecker.java
new file mode 100644
index 0000000..d306543
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/MockOverdueChecker.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public class MockOverdueChecker implements OverdueChecker {
+
+    @Override
+    public void checkBlocked(Subscription subscription)
+            throws EntitlementUserApiException {
+        //Intentionally blank
+
+    }
+
+    @Override
+    public void checkBlocked(SubscriptionBundle bundle)
+            throws EntitlementUserApiException {
+        //Intentionally blank
+    }
+
+}
diff --git a/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
new file mode 100644
index 0000000..9cffbba
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.entitlement.api.overdue;
+
+
+public class TestOverdueChecker {
+//
+//
+//    private static final String DISABLED_AND_BLOCKED_BUNDLE = "disabled-blocked-bundle";
+//    private static final String DISABLED_BUNDLE = "disabled-bundle";
+//    private static final String BLOCKED_BUNDLE = "blocked-bundle";
+//    private static final String CLEAR_BUNDLE = "clear-bundle";
+//    
+//        
+//    private static final DefaultOverdueState<SubscriptionBundle> CLEAR_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(CLEAR_BUNDLE, false, false); 
+//    private static final DefaultOverdueState<SubscriptionBundle> BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(BLOCKED_BUNDLE, true, false);
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_BUNDLE, false, true);
+//    private static final DefaultOverdueState<SubscriptionBundle> DISABLED_AND_BLOCKED_BUNDLE_STATE = new MockOverdueState<SubscriptionBundle>(DISABLED_AND_BLOCKED_BUNDLE, true, true) ;
+//   
+//    
+//    private OverdueChecker checker;
+//    private OverdueAccessApi overdueAccessApi;    
+//    private Subscription subscription;
+//    private SubscriptionBundle bundle;
+//    
+//    @BeforeClass(groups={"fast"})
+//    public void setup() {
+//        overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+//        subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+//        bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+//        ((ZombieControl) bundle).addResult("getAccountId", new UUID(0L,0L));
+//        ((ZombieControl) bundle).addResult("getId", new UUID(0L,0L));
+//        ((ZombieControl) bundle).addResult("getKey", "key");
+//        ((ZombieControl) subscription).addResult("getBundleId", new UUID(0L,0L));
+//       
+//        @SuppressWarnings("unchecked")
+//        final OverdueStatesBundle bundleODS =  new MockOverdueStatesBundle(new DefaultOverdueState[] {
+//                CLEAR_BUNDLE_STATE,BLOCKED_BUNDLE_STATE, DISABLED_BUNDLE_STATE, DISABLED_AND_BLOCKED_BUNDLE_STATE
+//        });
+//
+//        Injector i = Guice.createInjector(new AbstractModule() {
+//
+//            @Override
+//            protected void configure() {
+//                bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();
+//                CatalogService catalogService = BrainDeadProxyFactory.createBrainDeadProxyFor(CatalogService.class);
+//                ((ZombieControl) catalogService).addResult("getCurrentCatalog", new MockCatalog() {
+//
+//                    @Override
+//                    public void setOverdueRules() {
+//                         OverdueRules overdueRules = new MockOverdueRules().setOverdueStatesBundle(bundleODS);                       
+//                        setOverdueRules(overdueRules);  
+//                    }
+//                    
+//                });
+//                bind(CatalogService.class).toInstance(catalogService);
+//                
+//               
+//                bind(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+//                bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+//                
+//                
+//                EntitlementDao entitlementDao = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementDao.class);
+//                //((ZombieControl) entitlementDao).addResult("", result)
+//                bind(EntitlementDao.class).toInstance(entitlementDao);
+//                ((ZombieControl) entitlementDao).addResult("getSubscriptionBundleFromId",bundle);
+//                
+//            }
+//            
+//        });
+//        checker = i.getInstance(OverdueChecker.class);
+//    }
+//
+//
+//    private void setStateBundle(OverdueState<SubscriptionBundle> state) {
+//        ((ZombieControl) bundle).addResult("getOverdueState", state);
+//    }
+//
+//    @Test(groups={"fast"}, enabled = true)
+//    public void testSubscriptionChecker() throws EntitlementUserApiException {
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//
+//        //BLOCKED BUNDLE
+//        try {
+//            setStateBundle(BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//        //DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+// 
+//        try {
+//            setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(subscription);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//         setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(subscription);
+//        
+//    }
+//    
+//    @Test(groups={"fast"}, enabled = true)
+//    public void testBundleChecker() throws EntitlementUserApiException {
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//
+// 
+//        //BLOCKED BUNDLE
+//        try {
+//            setStateBundle(BLOCKED_BUNDLE_STATE);
+//            checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//        
+//       
+//        //DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_BUNDLE_STATE);
+//            checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//
+//        //BLOCKED AND DISABLED BUNDLE
+//        try {
+//            setStateBundle(DISABLED_AND_BLOCKED_BUNDLE_STATE);
+//             checker.checkBlocked(bundle);
+//            Assert.fail("The call should have been blocked!");
+//        } catch (EntitlementUserApiException e) {
+//            //Expected behavior
+//        }
+//
+//        setStateBundle(CLEAR_BUNDLE_STATE);
+//        checker.checkBlocked(bundle);
+//        
+//    }
+//    
+//
+//     
+}
diff --git a/ne/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java b/ne/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java
new file mode 100644
index 0000000..9a08f87
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.mock.overdue;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.ne.override.dao.OverrideStateDao;
+import com.ning.billing.overdue.OverdueAccessApi;
+
+public class MockOverdueAccessModule extends AbstractModule {
+    public static final String CLEAR_STATE="Clear";
+
+    @Override
+    protected void configure() {
+        OverdueAccessApi overdueAccessApi = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessApi.class);
+        ((ZombieControl) overdueAccessApi).addResult("getOverdueStateNameFor", MockOverdueAccessModule.CLEAR_STATE);
+        bind(OverrideStateDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverrideStateDao.class));
+        bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+    }
+}
diff --git a/ne/src/test/java/com/ning/billing/overdue/dao/MockModule.java b/ne/src/test/java/com/ning/billing/overdue/dao/MockModule.java
new file mode 100644
index 0000000..30adc91
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/overdue/dao/MockModule.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.dao;
+
+import org.skife.config.ConfigurationObjectFactory;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
+import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.dbi.DBIProvider;
+import com.ning.billing.dbi.DbiConfig;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+
+
+public class MockModule extends AbstractModule {
+    public static final String PLUGIN_NAME = "Booboo";
+
+    @Override
+    protected void configure() {
+        bind(Clock.class).to(ClockMock.class).asEagerSingleton();
+        bind(ClockMock.class).asEagerSingleton();
+        bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
+
+        final MysqlTestingHelper helper = new MysqlTestingHelper();
+        bind(MysqlTestingHelper.class).toInstance(helper);
+        if (helper.isUsingLocalInstance()) {
+            bind(IDBI.class).toProvider(DBIProvider.class).asEagerSingleton();
+            final DbiConfig config = new ConfigurationObjectFactory(System.getProperties()).build(DbiConfig.class);
+            bind(DbiConfig.class).toInstance(config);
+        } else {
+            final IDBI dbi = helper.getDBI(); 
+            bind(IDBI.class).toInstance(dbi);
+        }
+
+       install(new CatalogModule());
+    }
+    
+
+}
diff --git a/ne/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java b/ne/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
new file mode 100644
index 0000000..70b2a14
--- /dev/null
+++ b/ne/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.dao;
+
+import java.io.IOException;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.google.inject.Inject;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.ne.glue.NEModule;
+import com.ning.billing.ne.override.dao.OverrideStateDao;
+import com.ning.billing.overdue.OverdueEvent;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.clock.ClockMock;
+
+@Guice(modules = {MockModule.class,  NEModule.class})
+public class TestOverdueDao {
+    private Logger log = LoggerFactory.getLogger(TestOverdueDao.class);
+    
+    @Inject
+    private MysqlTestingHelper helper;
+    
+    @Inject
+    private OverrideStateDao dao;
+
+    @Inject
+    private OverrideStateDao accessDao;
+
+    @BeforeClass(groups={"slow"})
+    public void setup() throws IOException {
+        log.info("Starting set up");
+
+        final String utilDdl = IOUtils.toString(TestOverdueDao.class.getResourceAsStream("/com/ning/billing/ne/ddl.sql"));
+
+        helper.startMysql();
+        helper.initDb(utilDdl);
+
+    }
+    
+    
+    @Test(groups={"slow"}, enabled=true)
+    public void testDao() { 
+        ClockMock clock = new ClockMock();
+        SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+        UUID bundleId = UUID.randomUUID();
+        ((ZombieControl)bundle).addResult("getId", bundleId);
+        
+        String overdueStateName = "WayPassedItMan";
+        @SuppressWarnings("unchecked")
+        OverdueState<SubscriptionBundle> state = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueState.class);
+        ((ZombieControl)state).addResult("getName", overdueStateName);
+        
+        dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+        clock.setDeltaFromReality(1000 * 3600 * 24);
+        
+        String overdueStateName2 = "NoReallyThisCantGoOn";
+        ((ZombieControl)state).addResult("getName", overdueStateName2);
+        dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+        
+        Assert.assertEquals(accessDao.getOverdueStateFor(bundle), overdueStateName2);
+        Assert.assertEquals(accessDao.getOverdueStateForIdAndType(bundle.getId(), Overdueable.Type.SUBSCRIPTION_BUNDLE), overdueStateName2);
+        
+    }
+    
+    @Test(groups={"slow"}, enabled=true)
+    public void testDaoHistory() throws CatalogApiException { 
+        ClockMock clock = new ClockMock();
+        SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+        UUID bundleId = UUID.randomUUID();
+        ((ZombieControl)bundle).addResult("getId", bundleId);
+        
+        String overdueStateName = "WayPassedItMan";
+        @SuppressWarnings("unchecked")
+        OverdueState<SubscriptionBundle> state = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueState.class);
+        ((ZombieControl)state).addResult("getName", overdueStateName);
+        
+        dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+        clock.setDeltaFromReality(1000 * 3600 * 24);
+        
+        String overdueStateName2 = "NoReallyThisCantGoOn";
+        ((ZombieControl)state).addResult("getName", overdueStateName2);
+        dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
+        
+        SortedSet<OverdueEvent> history1 = accessDao.getOverdueHistoryFor(bundle);
+        SortedSet<OverdueEvent> history2 = accessDao.getOverdueHistoryForIdAndType(bundle.getId(), Overdueable.Type.get(bundle));
+        
+        Assert.assertEquals(history1.size(), 2);
+        Assert.assertEquals(history1.first().getStateName(), overdueStateName);
+        Assert.assertEquals(history1.last().getStateName(), overdueStateName2);
+        
+        Assert.assertEquals(history2.size(), 2);
+        Assert.assertEquals(history2.first().getStateName(), overdueStateName);
+        Assert.assertEquals(history2.last().getStateName(), overdueStateName2);
+       
+    }
+    
+}
diff --git a/ne/src/test/resources/log4j.xml b/ne/src/test/resources/log4j.xml
new file mode 100644
index 0000000..ac530a1
--- /dev/null
+++ b/ne/src/test/resources/log4j.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 Ning, Inc.
+  ~
+  ~ Ning 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.entitlement">
+        <level value="info"/>
+    </logger>
+
+    <logger name="com.ning.billing.util.notificationq">
+        <level value="info"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>
diff --git a/ne/src/test/resources/resource.properties b/ne/src/test/resources/resource.properties
new file mode 100644
index 0000000..d63334b
--- /dev/null
+++ b/ne/src/test/resources/resource.properties
@@ -0,0 +1,7 @@
+killbill.catalog.uri=file:src/test/resources/catalogSample.xml
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+user.timezone=UTC
+
+

overdue/pom.xml 133(+133 -0)

diff --git a/overdue/pom.xml b/overdue/pom.xml
new file mode 100644
index 0000000..d0a7413
--- /dev/null
+++ b/overdue/pom.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 Ning, Inc. ~ ~ Ning 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. -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.ning.billing</groupId>
+        <artifactId>killbill</artifactId>
+        <version>0.1.11-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>killbill-overdue</artifactId>
+    <name>killbill-overdue</name>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+        </dependency>
+          <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.skife.config</groupId>
+            <artifactId>config-magic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.jdbi</groupId>
+            <artifactId>jdbi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Check if we need this one -->
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+            <scope>test</scope>
+         </dependency>
+         <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-ne</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-util</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-catalog</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-mxj-db-files</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Strangely this is needed in order to run the tests in local db mode -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+           <scope>test</scope>
+         </dependency>
+ 
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <groups>fast,slow, stress</groups>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
new file mode 100644
index 0000000..a7f0627
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue.notification;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.config.InvoiceConfig;
+import com.ning.billing.config.NotificationConfig;
+import com.ning.billing.ovedue.OverdueProperties;
+import com.ning.billing.overdue.service.DefaultOverdueService;
+import com.ning.billing.util.notificationq.NotificationQueue;
+import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueAlreadyExists;
+import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
+
+public class DefaultOverdueCheckNotifier implements  OverdueCheckNotifier {
+
+    private final static Logger log = LoggerFactory.getLogger(DefaultOverdueCheckNotifier.class);
+
+    public static final String OVERDUE_CHECK_NOTIFIER_QUEUE = "overdue-check-queue";
+
+    private final NotificationQueueService notificationQueueService;
+	private final OverdueProperties config;
+
+    private NotificationQueue overdueQueue;
+	private final OverdueListener listener;
+
+    @Inject
+	public DefaultOverdueCheckNotifier(NotificationQueueService notificationQueueService,
+	        OverdueProperties config, OverdueListener listener){
+		this.notificationQueueService = notificationQueueService;
+		this.config = config;
+        this.listener = listener;
+	}
+
+    @Override
+    public void initialize() {
+		try {
+            overdueQueue = notificationQueueService.createNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
+            		OVERDUE_CHECK_NOTIFIER_QUEUE,
+                    new NotificationQueueHandler() {
+                @Override
+                public void handleReadyNotification(String notificationKey, DateTime eventDate) {
+                	try {
+                 		UUID key = UUID.fromString(notificationKey);
+                        processEvent(key , eventDate);
+                   	} catch (IllegalArgumentException e) {
+                		log.error("The key returned from the NextBillingNotificationQueue is not a valid UUID", e);
+                		return;
+                	}
+
+                }
+            },
+            new NotificationConfig() {
+                @Override
+                public boolean isNotificationProcessingOff() {
+                    return config.isNotificationProcessingOff();
+                }
+                @Override
+                public long getNotificationSleepTimeMs() {
+                    return config.getNotificationSleepTimeMs();
+                }
+                @Override
+                public int getDaoMaxReadyEvents() {
+                    return config.getDaoMaxReadyEvents();
+                }
+                @Override
+                public long getDaoClaimTimeMs() {
+                    return config.getDaoClaimTimeMs();
+                }
+            });
+        } catch (NotificationQueueAlreadyExists e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void start() {
+    	overdueQueue.startQueue();
+    }
+
+    @Override
+    public void stop() {
+        if (overdueQueue != null) {
+        	overdueQueue.stopQueue();
+        }
+    }
+
+    private void processEvent(UUID overdueableId, DateTime eventDateTime) {
+        listener.handleNextOverdueCheck(overdueableId, eventDateTime); 
+    }
+
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java
new file mode 100644
index 0000000..29aa528
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckPoster.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue.notification;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.service.DefaultOverdueService;
+import com.ning.billing.util.notificationq.NotificationKey;
+import com.ning.billing.util.notificationq.NotificationQueue;
+import com.ning.billing.util.notificationq.NotificationQueueService;
+import com.ning.billing.util.notificationq.NotificationQueueService.NoSuchNotificationQueue;
+
+public class DefaultOverdueCheckPoster implements OverdueCheckPoster {
+    private final static Logger log = LoggerFactory.getLogger(DefaultOverdueCheckNotifier.class);
+
+	private final NotificationQueueService notificationQueueService;
+
+	@Inject
+    public DefaultOverdueCheckPoster(
+			NotificationQueueService notificationQueueService) {
+		super();
+		this.notificationQueueService = notificationQueueService;
+	}
+
+	@Override
+	public void insertOverdueCheckNotification(final Transmogrifier transactionalDao, final Overdueable overdueable, final DateTime futureNotificationTime) {
+    	NotificationQueue checkOverdueQueue;
+		try {
+			checkOverdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
+					DefaultOverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
+			 log.info("Queuing overdue check notification. id: {}, timestamp: {}", overdueable.getId().toString(), futureNotificationTime.toString());
+
+	            checkOverdueQueue.recordFutureNotificationFromTransaction(transactionalDao, futureNotificationTime, new NotificationKey(){
+	                @Override
+	                public String toString() {
+	                    return overdueable.getId().toString();
+	                }
+	    	    });
+		} catch (NoSuchNotificationQueue e) {
+			log.error("Attempting to put items on a non-existent queue (DefaultOverdueCheck).", e);
+		}
+    }
+	
+	public void clearNotificationEventsFor(final Overdueable overdueable) {
+	    NotificationQueue checkOverdueQueue;
+        try {
+            checkOverdueQueue = notificationQueueService.getNotificationQueue(DefaultOverdueService.OVERDUE_SERVICE_NAME,
+                DefaultOverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE);
+            checkOverdueQueue.removeNotificationsByKey(overdueable.getId());
+        } catch (NoSuchNotificationQueue e) {
+            log.error("Attempting to clear items from a non-existent queue (DefaultOverdueCheck).", e);
+        }
+	}
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java
new file mode 100644
index 0000000..7ef6ab8
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckNotifier.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue.notification;
+
+
+public interface OverdueCheckNotifier {
+
+    public void initialize();
+
+    public void start();
+
+    public void stop();
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
new file mode 100644
index 0000000..8573436
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueCheckPoster.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue.notification;
+
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
+import com.ning.billing.overdue.config.api.Overdueable;
+
+public interface OverdueCheckPoster {
+
+	void insertOverdueCheckNotification(Transmogrifier transactionalDao,
+			Overdueable overdueable, DateTime futureNotificationTime);
+
+}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueListener.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueListener.java
new file mode 100644
index 0000000..e3ddcf3
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/OverdueListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue.notification;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+public class OverdueListener {
+
+    public void handleNextOverdueCheck(UUID subscriptionId, DateTime eventDateTime) {
+        //TODO
+        
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java b/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java
new file mode 100644
index 0000000..4b38c09
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/ovedue/OverdueProperties.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.ovedue;
+
+import org.skife.config.Config;
+import org.skife.config.Default;
+
+import com.ning.billing.config.KillbillConfig;
+import com.ning.billing.config.NotificationConfig;
+
+public interface OverdueProperties extends NotificationConfig, KillbillConfig  {
+
+    @Override
+    @Config("killbill.overdue.dao.claim.time")
+    @Default("60000")
+    public long getDaoClaimTimeMs();
+
+    @Override   
+    @Config("killbill.overdue.dao.ready.max")
+    @Default("10")
+    public int getDaoMaxReadyEvents();
+
+    @Override
+    @Config("killbill.overdue.engine.notifications.sleep")
+    @Default("500")
+    public long getNotificationSleepTimeMs();
+
+    @Override
+    @Config("killbill.notifications.off")
+    @Default("false")
+    public boolean isNotificationProcessingOff();
+
+    @Config("killbill.overdue.maxNumberOfMonthsInFuture")
+    @Default("36")
+    public int getNumberOfMonthsInFuture();
+
+    @Config("killbill.overdue.configUri")
+    @Default("jar:///com/ning/billing/irs/catalog/Catalog.xml")
+    public String getConfigURI();
+}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
new file mode 100644
index 0000000..9855b9e
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.api;
+
+import org.apache.commons.lang.NotImplementedException;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.service.ExtendedOverdueService;
+import com.ning.billing.overdue.wrapper.OverdueWrapper;
+import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
+
+public class DefaultOverdueUserApi implements OverdueUserApi{
+
+    
+    private final OverdueWrapperFactory factory;
+    private final OverdueAccessApi accessApi; 
+    private final OverdueConfig overdueConfig;
+   
+    @Inject
+    public DefaultOverdueUserApi(OverdueWrapperFactory factory,OverdueAccessApi accessApi, ExtendedOverdueService service,  CatalogService catalogService) {
+        this.factory = factory;
+        this.accessApi = accessApi;
+        this.overdueConfig = service.getOverdueConfig();
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Overdueable> OverdueState<T> getOverdueStateFor(T overdueable) throws OverdueError {
+        try {
+            String stateName = accessApi.getOverdueStateNameFor(overdueable);
+            OverdueStateSet<SubscriptionBundle> states = overdueConfig.getBundleStateSet();
+            return (OverdueState<T>) states.findState(stateName);
+        } catch (CatalogApiException e) {
+            throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED,overdueable.getId(), overdueable.getClass().getSimpleName());
+        }
+    }
+    
+    @Override
+    public <T extends Overdueable> OverdueState<T> refreshOverdueStateFor(T overdueable) throws OverdueError, CatalogApiException {
+        OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(overdueable);
+        return wrapper.refresh();
+    } 
+ 
+
+    @Override
+    public <T extends Overdueable> void setOverrideBillingStateForAccount(
+            T overdueable, BillingState<T> state) {
+        throw new NotImplementedException();
+    }
+    
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
new file mode 100644
index 0000000..5d40d67
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.applicator;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.clock.Clock;
+
+public class OverdueStateApplicator<T extends Overdueable>{
+
+    private final OverdueAccessApi accessApi;
+
+
+    @Inject
+    public OverdueStateApplicator(OverdueAccessApi accessApi) {
+        this.accessApi = accessApi;
+    }
+
+    public void apply(T overdueable, OverdueState<T> previousOverdueState, OverdueState<T> nextOverdueState, DateTime timeOfNextCheck) throws OverdueError {
+        if(previousOverdueState.getName().equals(nextOverdueState.getName())) {
+            return; // nothing to do
+        }
+        
+        storeNewState(overdueable, nextOverdueState);
+  
+        if(timeOfNextCheck != null && !nextOverdueState.isClearState()) {
+            createFutureNotification(overdueable, timeOfNextCheck);
+        }
+
+        if(nextOverdueState.isClearState()) {
+            clear(overdueable);
+        }
+        
+        //If new state is clear state reset next events and override table
+        throw new NotImplementedException();
+    }
+
+
+    protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) throws OverdueError {
+        try {
+            accessApi.setOverrideState(overdueable, nextOverdueState, Overdueable.Type.get(overdueable));
+        } catch (Exception e) {
+            throw new OverdueError(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, overdueable.getId(), overdueable.getClass().getName());
+        }
+    }
+
+    protected void createFutureNotification(T overdueable,
+            DateTime timeOfNextCheck) {
+        // TODO Auto-generated method stub
+        
+    }
+
+
+    
+    protected void clear(T overdueable) {
+        // Clear future notification checks
+        // Clear any overrides
+        
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
new file mode 100644
index 0000000..eedde9a
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculator.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.calculator;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.clock.Clock;
+
+public abstract class BillingStateCalculator<T extends Overdueable> {
+
+    private final InvoiceUserApi invoiceApi;
+    private final Clock clock;
+    
+    protected class InvoiceDateComparator implements Comparator<Invoice> {
+        @Override
+        public int compare(Invoice i1, Invoice i2) {
+            DateTime d1 = i1.getInvoiceDate();
+            DateTime d2 = i2.getInvoiceDate();
+            if(d1.compareTo(d2) == 0) {
+                return i1.hashCode() - i2.hashCode(); // consistent (arbitrary) resolution for tied dates
+            }
+            return d1.compareTo(d2);
+        }
+    }
+
+    @Inject 
+    public BillingStateCalculator(InvoiceUserApi invoiceApi, Clock clock) {
+        this.invoiceApi = invoiceApi;
+        this.clock = clock;
+    }
+    
+    public abstract BillingState<T> calculateBillingState(T overdueable);
+    
+    protected DateTime earliest(SortedSet<Invoice> unpaidInvoices) {
+        return unpaidInvoices.first().getInvoiceDate();
+    }
+
+    protected BigDecimal sumBalance(SortedSet<Invoice> unpaidInvoices) {
+        BigDecimal sum = BigDecimal.ZERO;
+        Iterator<Invoice> it = unpaidInvoices.iterator();
+        while(it.hasNext()) {
+            sum = sum.add(it.next().getBalance());
+        }
+        return sum;
+    }
+
+    protected SortedSet<Invoice> unpaidInvoicesForAccount(UUID accountId) {
+        Collection<Invoice> invoices = invoiceApi.getUnpaidInvoicesByAccountId(accountId, clock.getUTCNow());
+        SortedSet<Invoice> sortedInvoices = new TreeSet<Invoice>(new InvoiceDateComparator());
+        sortedInvoices.addAll(invoices);
+        return sortedInvoices;
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
new file mode 100644
index 0000000..544420f
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.calculator;
+
+import java.math.BigDecimal;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.google.inject.Inject;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.overdue.config.api.BillingStateBundle;
+import com.ning.billing.overdue.config.api.PaymentResponse;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.tag.Tag;
+
+public class BillingStateCalculatorBundle  extends BillingStateCalculator<SubscriptionBundle>{
+
+    private EntitlementUserApi entitlementApi;
+
+    @Inject 
+    public BillingStateCalculatorBundle(EntitlementUserApi entitlementApi, InvoiceUserApi invoiceApi, Clock clock) {
+        super(invoiceApi, clock);
+        this.entitlementApi = entitlementApi;
+    }
+    
+    @Override
+    public BillingStateBundle calculateBillingState(SubscriptionBundle bundle) {
+        
+        SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForBundle(bundle.getId(), bundle.getAccountId());
+ 
+        Subscription basePlan = entitlementApi.getBaseSubscription(bundle.getId());
+        
+        UUID id = bundle.getId();
+        int numberOfUnpaidInvoices = unpaidInvoices.size(); 
+        BigDecimal unpaidInvoiceBalance = sumBalance(unpaidInvoices);
+        DateTime dateOfEarliestUnpaidInvoice = earliest(unpaidInvoices);
+        PaymentResponse responseForLastFailedPayment = PaymentResponse.INSUFFICIENT_FUNDS; //TODO MDW
+        Tag[] tags = new Tag[]{}; //TODO MDW
+        Product basePlanProduct = basePlan.getCurrentPlan().getProduct();
+        BillingPeriod basePlanBillingPeriod = basePlan.getCurrentPlan().getBillingPeriod();
+        PriceList basePlanPriceList = basePlan.getCurrentPriceList();
+        PhaseType basePlanPhaseType = basePlan.getCurrentPhase().getPhaseType();
+        
+
+        return new BillingStateBundle( 
+            id, 
+            numberOfUnpaidInvoices, 
+            unpaidInvoiceBalance,
+            dateOfEarliestUnpaidInvoice,
+            responseForLastFailedPayment,
+            tags, 
+            basePlanProduct,
+            basePlanBillingPeriod, 
+            basePlanPriceList, 
+            basePlanPhaseType);
+        
+    }
+
+    public SortedSet<Invoice> unpaidInvoicesForBundle(UUID bundleId, UUID accountId) {
+        SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(accountId);
+        SortedSet<Invoice> result = new TreeSet<Invoice>(new InvoiceDateComparator());
+        result.addAll(unpaidInvoices);
+        for(Invoice invoice : unpaidInvoices) {
+            if(!invoiceHasAnItemFromBundle(invoice, bundleId)) {
+                result.remove(invoice);
+            }
+        }
+        return result;
+    }
+
+    private boolean invoiceHasAnItemFromBundle(Invoice invoice, UUID bundleId) {
+        for(InvoiceItem item : invoice.getInvoiceItems()) {
+            if(item.getBundleId().equals(bundleId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java b/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java
new file mode 100644
index 0000000..7f79215
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/Condition.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.Overdueable;
+
+
+public interface Condition<T extends Overdueable> {
+
+    public boolean evaluate(BillingState state, DateTime now);
+
+}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java
new file mode 100644
index 0000000..8b6efac
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultCondition.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import java.math.BigDecimal;
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.PaymentResponse;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationErrors;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class DefaultCondition<T extends Overdueable> extends ValidatingConfig<OverdueConfig> implements Condition<T> {
+	@XmlElement(required=false, name="numberOfUnpaidInvoicesEqualsOrExceeds")
+	private Integer numberOfUnpaidInvoicesEqualsOrExceeds;
+
+	@XmlElement(required=false, name="totalUnpaidInvoiceBalanceEqualsOrExceeds")
+	private BigDecimal totalUnpaidInvoiceBalanceEqualsOrExceeds;
+
+	@XmlElement(required=false, name="timeSinceEarliestUnpaidInvoiceEqualsOrExceeds")
+	private DefaultDuration timeSinceEarliestUnpaidInvoiceEqualsOrExceeds;
+
+	@XmlElementWrapper(required=false, name="responseForLastFailedPaymentIn")
+	@XmlElement(required=false, name="response")
+	private PaymentResponse[] responseForLastFailedPayment;
+
+	@XmlElement(required=false, name="controlTag")
+	private ControlTagType controlTag;
+	
+	/* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.Condition#evaluate(com.ning.billing.catalog.api.overdue.BillingState, org.joda.time.DateTime)
+     */
+	@Override
+    public boolean evaluate(BillingState state, DateTime now) {
+		return 
+				(numberOfUnpaidInvoicesEqualsOrExceeds == null || state.getNumberOfUnpaidInvoices() >= numberOfUnpaidInvoicesEqualsOrExceeds.intValue() ) &&
+				(totalUnpaidInvoiceBalanceEqualsOrExceeds == null || totalUnpaidInvoiceBalanceEqualsOrExceeds.compareTo(state.getBalanceOfUnpaidInvoices()) <= 0) &&
+				(timeSinceEarliestUnpaidInvoiceEqualsOrExceeds == null || !timeSinceEarliestUnpaidInvoiceEqualsOrExceeds.addToDateTime(state.getDateOfEarliestUnpaidInvoice()).isAfter(now)) &&
+				(responseForLastFailedPayment == null || responseIsIn(state.getResponseForLastFailedPayment(), responseForLastFailedPayment)) &&
+				(controlTag == null || isTagIn(controlTag, state.getTags()));
+	}
+	
+	private boolean responseIsIn(PaymentResponse actualResponse,
+			PaymentResponse[] responseForLastFailedPayment) {
+		for(PaymentResponse response: responseForLastFailedPayment) {
+			if(response.equals(actualResponse)) return true;
+		}
+		return false;
+	}
+
+	private boolean isTagIn(ControlTagType tag, Tag[] tags) {
+		for(Tag t : tags) {
+			if (t.getTagDefinitionName().equals(tag.toString())) return true;
+		}
+		return false;
+	}
+
+	@Override
+	public ValidationErrors validate(OverdueConfig root,
+			ValidationErrors errors) {
+		return errors;
+	}
+
+	@Override
+	public void initialize(OverdueConfig root, URI uri) {
+	}
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultDuration.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultDuration.java
new file mode 100644
index 0000000..c5eee5e
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultDuration.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.TimeUnit;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationErrors;
+import org.joda.time.DateTime;
+import org.joda.time.Period;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class DefaultDuration extends ValidatingConfig<OverdueConfig> implements Duration {
+	@XmlElement(required=true)
+    private TimeUnit unit;
+
+	@XmlElement(required=false)
+    private Integer number = -1;
+	
+    /* (non-Javadoc)
+	 * @see com.ning.billing.catalog.IDuration#getUnit()
+	 */
+    @Override
+	public TimeUnit getUnit() {
+        return unit;
+    }
+
+    /* (non-Javadoc)
+	 * @see com.ning.billing.catalog.IDuration#getLength()
+	 */
+    @Override
+	public int getNumber() {
+        return number;
+    }
+
+    @Override
+    public DateTime addToDateTime(DateTime dateTime) {
+        if ((number == null) && (unit != TimeUnit.UNLIMITED)) {return dateTime;}
+
+        switch (unit) {
+            case DAYS:
+                return dateTime.plusDays(number);
+            case MONTHS:
+                return dateTime.plusMonths(number);
+            case YEARS:
+                return dateTime.plusYears(number);
+            case UNLIMITED:
+                return dateTime.plusYears(100);
+            default:
+                return dateTime;
+        }
+    }
+
+    @Override
+    public Period toJodaPeriod() {
+        if ((number == null) && (unit != TimeUnit.UNLIMITED)) {return new Period();}
+
+        switch (unit) {
+            case DAYS:
+                return new Period().withDays(number);
+            case MONTHS:
+                return new Period().withMonths(number);
+            case YEARS:
+                return new Period().withYears(number);
+            case UNLIMITED:
+                return new Period().withYears(100);
+            default:
+                return new Period();
+        }
+    }
+
+    @Override
+	public ValidationErrors validate(OverdueConfig catalog, ValidationErrors errors) {
+		//TODO MDW - Validation TimeUnit UNLIMITED iff number == -1
+		return errors;
+	}
+
+	protected DefaultDuration setUnit(TimeUnit unit) {
+		this.unit = unit;
+		return this;
+	}
+
+	protected DefaultDuration setNumber(Integer number) {
+		this.number = number;
+		return this;
+	}
+	
+	
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
new file mode 100644
index 0000000..3da59b1
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueState.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+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.XmlID;
+
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationError;
+import com.ning.billing.util.config.ValidationErrors;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig<OverdueConfig>  implements OverdueState<T> {
+
+    private static final int MAX_NAME_LENGTH = 50;
+    
+    @XmlElement(required=false, name="condition")
+	private DefaultCondition<T> condition;
+
+	@XmlAttribute(required=true, name="name")
+    @XmlID
+    private String name; 
+
+	@XmlElement(required=false, name="externalMessage")
+	private String externalMessage = "";
+
+    @XmlElement(required=false, name="disableEntitlementAndChangesBlocked")
+    private Boolean disableEntitlement = false;
+    
+    @XmlElement(required=false, name="blockChanges")
+    private Boolean blockChanges = false;
+    
+    @XmlElement(required=false, name="daysBetweenPaymentRetries")
+    private Integer daysBetweenPaymentRetries = 8;
+    
+    @XmlElement(required=false, name="isClearState")
+    private Boolean isClearState = false;
+    
+	//Other actions could include
+	// - send email
+	// - trigger payment retry?
+	// - add tags to bundle/account
+	// - set payment failure email template
+	// - set payment retry interval
+	// - backup payment mechanism?
+
+	/* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.OverdueState#getStageName()
+     */
+	@Override
+    public String getName() {
+		return name;
+	}
+
+	/* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.OverdueState#getExternalMessage()
+     */
+	@Override
+    public String getExternalMessage() {
+		return externalMessage;
+	}
+	
+    @Override
+    public boolean blockChanges() {
+        return blockChanges || disableEntitlement;
+    }
+
+	/* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.OverdueState#applyCancel()
+     */
+	@Override
+    public boolean disableEntitlementAndChangesBlocked() {
+		return disableEntitlement;
+	}
+	
+	
+    protected DefaultCondition<T> getCondition() {
+		return condition;
+	}
+
+	protected DefaultOverdueState<T> setName(String name) {
+		this.name = name;
+		return this;
+	}
+
+	protected DefaultOverdueState<T> setExternalMessage(String externalMessage) {
+		this.externalMessage = externalMessage;
+		return this;
+	}
+
+    protected DefaultOverdueState<T> setDisableEntitlement(boolean cancel) {
+        this.disableEntitlement = cancel;
+        return this;
+    }
+
+    protected DefaultOverdueState<T> setBlockChanges(boolean cancel) {
+        this.blockChanges = cancel;
+        return this;
+    }
+
+	protected DefaultOverdueState<T> setCondition(DefaultCondition<T> condition) {
+		this.condition = condition;
+		return this;
+	}
+
+    @Override
+    public boolean isClearState() {
+        return isClearState;
+    }
+
+    @Override
+    public ValidationErrors validate(OverdueConfig root,
+            ValidationErrors errors) {
+        if(name.length() > MAX_NAME_LENGTH) {
+            errors.add(new ValidationError(String.format("Name of state '%s' exceeds the maximum length of %d",name,MAX_NAME_LENGTH),root.getURI(), DefaultOverdueState.class, name));
+        }
+        return errors;
+    }
+
+    @Override
+    public int getDaysBetweenPaymentRetries() {
+         return daysBetweenPaymentRetries;
+    }
+
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java
new file mode 100644
index 0000000..7e82aa4
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/DefaultOverdueStateSet.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.joda.time.DateTime;
+
+import com.ning.billing.ErrorCode;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationErrors;
+
+@XmlAccessorType(XmlAccessType.NONE)
+public abstract class DefaultOverdueStateSet<T extends Overdueable> extends ValidatingConfig<OverdueConfig> implements OverdueStateSet<T> {
+    private DefaultOverdueState<T> clearState;
+    
+    protected abstract DefaultOverdueState<T>[] getStates();
+    
+    private DefaultOverdueState<T> getClearState() throws CatalogApiException {
+        for(DefaultOverdueState<T> overdueState : getStates()) {
+            if(overdueState.isClearState()) {   
+                return overdueState;
+            }
+        }
+        throw new CatalogApiException(ErrorCode.CAT_MISSING_CLEAR_STATE);
+    }
+    
+    @Override
+    public OverdueState<T> findState(String stateName) throws CatalogApiException {
+        for(DefaultOverdueState<T> state: getStates()) {
+            if(state.getName().equals(stateName) ) { return state; }
+        }
+        throw new CatalogApiException(ErrorCode.CAT_NO_SUCH_OVEDUE_STATE, stateName);
+    }
+    
+    
+    /* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.OverdueBillingState#findClearState()
+     */
+    @Override
+    public DefaultOverdueState<T> findClearState() throws CatalogApiException {
+        if (clearState != null) {
+            clearState = getClearState();
+        }
+        return clearState;
+    }
+    
+    /* (non-Javadoc)
+     * @see com.ning.billing.catalog.overdue.OverdueBillingState#calculateOverdueState(com.ning.billing.catalog.api.overdue.BillingState, org.joda.time.DateTime)
+     */
+    @Override
+    public DefaultOverdueState<T> calculateOverdueState(BillingState<T> billingState, DateTime now) throws CatalogApiException {         
+            for(DefaultOverdueState<T> overdueState : getStates()) {
+                if(overdueState.getCondition().evaluate(billingState, now)) {   
+                    return overdueState;
+                }
+            }
+            return  findClearState();
+    }
+
+    @Override
+    public DateTime dateOfNextCheck(BillingState<T> billingState, DateTime now) {
+        throw new NotImplementedException();
+    }
+        
+
+    @Override
+    public ValidationErrors validate(OverdueConfig root,
+            ValidationErrors errors) {
+        for(DefaultOverdueState<T> state: getStates()) {
+            state.validate(root, errors);
+        }
+        try {
+            getClearState();
+        } catch (CatalogApiException e) {
+            if(e.getCode() == ErrorCode.CAT_MISSING_CLEAR_STATE.getCode()) {
+                errors.add("Overdue state set is missing a clear state.", 
+                        root.getURI(), this.getClass(), "");
+                }
+        }
+        
+        return errors;
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/OverdueConfig.java b/overdue/src/main/java/com/ning/billing/overdue/config/OverdueConfig.java
new file mode 100644
index 0000000..1217122
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/OverdueConfig.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.util.config.ValidatingConfig;
+import com.ning.billing.util.config.ValidationErrors;
+
+@XmlRootElement(name="overdueConfig")
+@XmlAccessorType(XmlAccessType.NONE)
+public class OverdueConfig  extends ValidatingConfig<OverdueConfig> {
+
+    @XmlElement(required=true, name="bundleOverdueStates")
+    private OverdueStatesBundle bundleOverdueStates;
+
+    public DefaultOverdueStateSet<SubscriptionBundle> getBundleStateSet() {
+        return bundleOverdueStates;
+    }
+
+
+    @Override
+    public ValidationErrors validate(OverdueConfig root,
+            ValidationErrors errors) {
+        return bundleOverdueStates.validate(root, errors);
+    }
+    
+    public OverdueConfig setOverdueStatesBundle(OverdueStatesBundle bundleODS) {
+        this.bundleOverdueStates = bundleODS;
+        return this;
+    }
+
+
+    public URI getURI() {
+        return null;
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/config/OverdueStatesBundle.java b/overdue/src/main/java/com/ning/billing/overdue/config/OverdueStatesBundle.java
new file mode 100644
index 0000000..50d000b
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/config/OverdueStatesBundle.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import javax.xml.bind.annotation.XmlElement;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public class OverdueStatesBundle extends DefaultOverdueStateSet<SubscriptionBundle>{
+
+    @XmlElement(required=true, name="state")
+    private DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates;
+
+    @Override
+    protected DefaultOverdueState<SubscriptionBundle>[] getStates() {
+        return bundleOverdueStates;
+    }
+
+    protected OverdueStatesBundle setBundleOverdueStates(DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates) {
+        this.bundleOverdueStates = bundleOverdueStates;
+        return this;
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java b/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java
new file mode 100644
index 0000000..3959408
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/exceptions/OverdueError.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.exceptions;
+
+public class OverdueError extends Error {
+
+    private static final long serialVersionUID = 131398536;
+
+    public OverdueError() {
+        super();
+    }
+
+    public OverdueError(String msg, Throwable arg1) {
+        super(msg, arg1);
+    }
+
+    public OverdueError(String msg) {
+        super(msg);
+    }
+
+    public OverdueError(Throwable msg) {
+        super(msg);
+    }
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java b/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java
new file mode 100644
index 0000000..08fd53d
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/glue/OverdueModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.glue;
+
+import com.google.inject.AbstractModule;
+
+public class OverdueModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        // TODO Auto-generated method stub
+        
+    }
+    
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
new file mode 100644
index 0000000..dd2bd86
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.service;
+
+import java.net.URI;
+
+import com.google.inject.Inject;
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+import com.ning.billing.ovedue.OverdueProperties;
+import com.ning.billing.overdue.OverdueService;
+import com.ning.billing.overdue.OverdueUserApi;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.util.config.XMLLoader;
+
+public class DefaultOverdueService implements ExtendedOverdueService {
+    public static final String OVERDUE_SERVICE_NAME = "overdue-service";
+    private OverdueUserApi userApi;
+    private OverdueConfig overdueConfig;
+    private OverdueProperties properties;
+
+    private boolean isInitialized;
+
+    @Inject
+    public DefaultOverdueService(OverdueUserApi userApi, OverdueProperties properties){
+        this.userApi = userApi;
+        this.properties = properties;
+    }
+    
+    @Override
+    public String getName() {
+        return OVERDUE_SERVICE_NAME;
+    }
+
+    @Override
+    public OverdueUserApi getUserApi() {
+        return userApi;
+    }
+
+    @Override
+   public OverdueConfig getOverdueConfig() {
+        return overdueConfig;
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.INIT_SERVICE)
+    public synchronized void loadConfig() throws ServiceException {
+        if (!isInitialized) {
+            try {
+                System.out.println("Overdue config URI" + properties.getConfigURI());
+                URI u = new URI(properties.getConfigURI());
+                overdueConfig = XMLLoader.getObjectFromUri(u, OverdueConfig.class);
+
+                isInitialized = true;
+            } catch (Exception e) {
+                throw new ServiceException(e);
+            }
+        }
+    }
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java
new file mode 100644
index 0000000..abcb38a
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/ExtendedOverdueService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.service;
+
+import com.ning.billing.overdue.OverdueService;
+import com.ning.billing.overdue.config.OverdueConfig;
+
+public interface ExtendedOverdueService extends OverdueService {
+
+    public OverdueConfig getOverdueConfig();
+
+}
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
new file mode 100644
index 0000000..e7b1a8e
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapper.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.wrapper;
+
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.applicator.OverdueStateApplicator;
+import com.ning.billing.overdue.calculator.BillingStateCalculator;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.OverdueState;
+import com.ning.billing.overdue.config.api.OverdueStateSet;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.util.clock.Clock;
+
+public class OverdueWrapper<T extends Overdueable> {
+    private final T overdueable;
+    private final OverdueAccessApi api;
+    private final Clock clock;
+    private final OverdueStateSet<T> overdueStateSet;
+    private final BillingStateCalculator<T> billingStateCalcuator;
+    private final OverdueStateApplicator<T> overdueStateApplicator;
+
+    public OverdueWrapper(T overdueable, OverdueAccessApi api,
+            OverdueStateSet<T> overdueStateSet,
+            Clock clock,
+            BillingStateCalculator<T> billingStateCalcuator,
+            OverdueStateApplicator<T> overdueStateApplicator) {
+        this.overdueable = overdueable;
+        this.overdueStateSet = overdueStateSet;
+        this.api = api;
+        this.clock = clock;
+        this.billingStateCalcuator = billingStateCalcuator;
+        this.overdueStateApplicator = overdueStateApplicator;
+    }
+
+    public OverdueState<T> refresh() throws OverdueError, CatalogApiException {
+        OverdueState<T> nextOverdueState;
+        BillingState<T> billingState = billingStateCalcuator.calculateBillingState(overdueable);
+        String previousOverdueStateName = api.getOverdueStateNameFor(overdueable);
+        nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getUTCNow());
+        if(!previousOverdueStateName.equals(nextOverdueState.getName())) {
+            overdueStateApplicator.apply(overdueable, nextOverdueState, nextOverdueState, overdueStateSet.dateOfNextCheck(billingState, clock.getUTCNow())); 
+        }
+
+        return nextOverdueState;
+    }
+}
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
new file mode 100644
index 0000000..8d1c5b8
--- /dev/null
+++ b/overdue/src/main/java/com/ning/billing/overdue/wrapper/OverdueWrapperFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.wrapper;
+
+import com.google.inject.Inject;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.overdue.OverdueAccessApi;
+import com.ning.billing.overdue.applicator.OverdueStateApplicator;
+import com.ning.billing.overdue.calculator.BillingStateCalculatorBundle;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.overdue.config.api.OverdueError;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.service.ExtendedOverdueService;
+import com.ning.billing.util.clock.Clock;
+
+public class OverdueWrapperFactory {
+
+    private final OverdueConfig overdueConfig;
+    private final BillingStateCalculatorBundle billingStateCalcuatorBundle;
+    private final OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle;
+    private final OverdueAccessApi api;
+    private final Clock clock;
+
+    @Inject
+    public OverdueWrapperFactory(OverdueAccessApi api, ExtendedOverdueService service, Clock clock, 
+            BillingStateCalculatorBundle billingStateCalcuatorBundle, OverdueStateApplicator<SubscriptionBundle> overdueStateApplicatorBundle) {
+        this.billingStateCalcuatorBundle = billingStateCalcuatorBundle;
+        this.overdueStateApplicatorBundle = overdueStateApplicatorBundle;
+        this.overdueConfig = service.getOverdueConfig();
+        this.api = api;
+        this.clock = clock;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Overdueable> OverdueWrapper<T> createOverdueWrapperFor(T overdueable) throws OverdueError {
+        if(overdueable instanceof SubscriptionBundle) {
+            return (OverdueWrapper<T>)new OverdueWrapper<SubscriptionBundle>((SubscriptionBundle)overdueable, api, overdueConfig.getBundleStateSet(), 
+                    clock, billingStateCalcuatorBundle, overdueStateApplicatorBundle );
+        } else {
+            throw new OverdueError(ErrorCode.OVERDUE_OVERDUEABLE_NOT_SUPPORTED, overdueable.getClass());
+        }
+    }
+
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java
new file mode 100644
index 0000000..db9ab74
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.calculator;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+
+public class TestBillingStateCalculator {
+    Clock clock = new ClockMock();
+    InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
+    private int hash = 0;
+    DateTime now;
+    
+    public BillingStateCalculator<SubscriptionBundle> createBSCalc() {
+        now = new DateTime();
+        Collection<Invoice> invoices = new ArrayList<Invoice>();
+        invoices.add(createInvoice(now, BigDecimal.ZERO, null));
+        invoices.add(createInvoice(now.plusDays(1), BigDecimal.TEN, null));
+        invoices.add(createInvoice(now.plusDays(2), new BigDecimal("100.0"), null));
+     
+        ((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
+            
+        return new BillingStateCalculator<SubscriptionBundle>(invoiceApi, clock) {
+            @Override
+            public BillingState<SubscriptionBundle> calculateBillingState(
+                    SubscriptionBundle overdueable) {
+               return null;
+            }};
+    }
+    
+    public Invoice createInvoice(DateTime date, BigDecimal balance, List<InvoiceItem> invoiceItems) {
+        Invoice invoice = BrainDeadProxyFactory.createBrainDeadProxyFor(Invoice.class);
+        ((ZombieControl)invoice).addResult("getBalance", balance);
+        ((ZombieControl)invoice).addResult("getInvoiceDate", date);
+        ((ZombieControl)invoice).addResult("hashCode", hash++);
+        ((ZombieControl)invoice).addResult("getInvoiceItems", invoiceItems);
+        
+        return invoice;
+    }
+    
+    @Test(groups={"fast"}, enabled=true)
+    public void testUnpaidInvoices() {
+        BillingStateCalculator<SubscriptionBundle> calc = createBSCalc();
+        SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L,0L));
+        
+        Assert.assertEquals(invoices.size(), 3);
+        Assert.assertEquals(BigDecimal.ZERO.compareTo(invoices.first().getBalance()), 0);
+        Assert.assertEquals(new BigDecimal("100.0").compareTo(invoices.last().getBalance()), 0);
+    }
+    
+    @Test(groups={"fast"}, enabled=true)
+    public void testSum() {
+        
+        BillingStateCalculator<SubscriptionBundle> calc = createBSCalc();
+        SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L,0L));
+        Assert.assertEquals(new BigDecimal("110.0").compareTo(calc.sumBalance(invoices)), 0);
+    }
+
+    @Test(groups={"fast"}, enabled=true)
+    public void testEarliest() {
+        
+        BillingStateCalculator<SubscriptionBundle> calc = createBSCalc();
+        SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L,0L));
+        Assert.assertEquals(calc.earliest(invoices), now);
+    }
+
+    
+    
+    
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
new file mode 100644
index 0000000..3d5b855
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.calculator;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.catalog.MockPlan;
+import com.ning.billing.catalog.MockPriceList;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.overdue.config.api.BillingStateBundle;
+import com.ning.billing.overdue.config.api.PaymentResponse;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+
+public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator {
+    
+    
+    private List<InvoiceItem> createInvoiceItems(UUID[] bundleIds) {
+        List<InvoiceItem> result = new ArrayList<InvoiceItem> ();
+        for (UUID id : bundleIds) {
+           InvoiceItem ii = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceItem.class);
+           ((ZombieControl)ii).addResult("getBundleId", id);
+           result.add(ii);
+        }
+        return result;
+    }
+    
+    @Test(groups = {"fast"}, enabled=true)
+    public void testUnpaidInvoiceForBundle() {
+       UUID thisBundleId = new UUID(0L,0L);
+       UUID thatBundleId = new UUID(0L,1L);
+       
+       now = new DateTime();
+       List<Invoice> invoices = new ArrayList<Invoice>(5);
+       invoices.add(createInvoice(now, BigDecimal.ZERO, createInvoiceItems(new UUID[]{thisBundleId,thatBundleId})));
+       invoices.add(createInvoice(now, BigDecimal.TEN, createInvoiceItems(new UUID[]{thatBundleId})));
+       invoices.add(createInvoice(now, new BigDecimal("100.00"), createInvoiceItems(new UUID[]{thatBundleId,thisBundleId,thatBundleId})));
+       invoices.add(createInvoice(now, new BigDecimal("1000.00"), createInvoiceItems(new UUID[]{thisBundleId})));
+       invoices.add(createInvoice(now, new BigDecimal("10000.00"), createInvoiceItems(new UUID[]{thatBundleId, thisBundleId})));
+       
+       
+       Clock clock = new ClockMock();
+       InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
+       EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+       ((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
+       
+       
+       BillingStateCalculatorBundle calc = new BillingStateCalculatorBundle(entitlementApi, invoiceApi, clock);
+       SortedSet<Invoice> resultinvoices = calc.unpaidInvoicesForBundle(thisBundleId, new UUID(0L,0L));
+       
+       Assert.assertEquals(resultinvoices.size(), 4);
+       Assert.assertEquals(BigDecimal.ZERO.compareTo(resultinvoices.first().getBalance()), 0);
+       Assert.assertEquals(new BigDecimal("10000.0").compareTo(resultinvoices.last().getBalance()), 0);
+       
+    }
+    
+    @Test(groups = {"fast"}, enabled=true)
+    public void testcalculateBillingStateForBundle() {
+       UUID thisBundleId = new UUID(0L,0L);
+       UUID thatBundleId = new UUID(0L,1L);
+       
+       now = new DateTime();
+       List<Invoice> invoices = new ArrayList<Invoice>(5);
+       invoices.add(createInvoice(now.minusDays(5), BigDecimal.ZERO, createInvoiceItems(new UUID[]{thisBundleId,thatBundleId})));
+       invoices.add(createInvoice(now.minusDays(4), BigDecimal.TEN, createInvoiceItems(new UUID[]{thatBundleId})));
+       invoices.add(createInvoice(now.minusDays(3), new BigDecimal("100.00"), createInvoiceItems(new UUID[]{thatBundleId,thisBundleId,thatBundleId})));
+       invoices.add(createInvoice(now.minusDays(2), new BigDecimal("1000.00"), createInvoiceItems(new UUID[]{thisBundleId})));
+       invoices.add(createInvoice(now.minusDays(1), new BigDecimal("10000.00"), createInvoiceItems(new UUID[]{thatBundleId, thisBundleId})));
+       
+       
+       Clock clock = new ClockMock();
+       InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
+       ((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
+       
+       SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+       ((ZombieControl)bundle).addResult("getId", thisBundleId);
+       ((ZombieControl)bundle).addResult("getAccountId", UUID.randomUUID());
+       
+       EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+       Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+       ((ZombieControl)entitlementApi).addResult("getBaseSubscription",subscription);
+       
+       Plan plan = MockPlan.createBicycleNoTrialEvergreen1USD();
+       PriceList pricelist = new MockPriceList();
+       ((ZombieControl)subscription).addResult("getCurrentPlan", plan);
+       ((ZombieControl)subscription).addResult("getCurrentPriceList", pricelist);
+       ((ZombieControl)subscription).addResult("getCurrentPhase", plan.getFinalPhase());
+      
+       BillingStateCalculatorBundle calc = new BillingStateCalculatorBundle(entitlementApi, invoiceApi, clock);
+            
+       BillingStateBundle state = calc.calculateBillingState(bundle); 
+       
+       Assert.assertEquals(state.getNumberOfUnpaidInvoices(),4);
+       Assert.assertEquals(state.getBalanceOfUnpaidInvoices().intValue(), 11100);
+       Assert.assertEquals(state.getDateOfEarliestUnpaidInvoice().compareTo(now.minusDays(5)), 0);
+       Assert.assertEquals(state.getResponseForLastFailedPayment(),PaymentResponse.INSUFFICIENT_FUNDS); //TODO needs more when implemented
+       Assert.assertEquals(state.getTags().length,0);//TODO needs more when implemented
+       Assert.assertEquals(state.getBasePlanBillingPeriod(), plan.getBillingPeriod());
+       Assert.assertEquals(state.getBasePlanPhaseType(), plan.getFinalPhase().getPhaseType());
+       Assert.assertEquals(state.getBasePlanPriceList(), pricelist);
+       Assert.assertEquals(state.getBasePlanProduct(), plan.getProduct());
+       
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java b/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java
new file mode 100644
index 0000000..bbd4b18
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/CreateOverdueConfigSchema.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+
+import com.ning.billing.util.config.XMLSchemaGenerator;
+
+public class CreateOverdueConfigSchema {
+
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) throws Exception {
+		if(args.length != 1) {
+			System.err.println("Usage: <filepath>");
+			System.exit(0);
+		}
+		
+		File f = new File(args[0]);
+		Writer w = new FileWriter(f);
+		w.write(XMLSchemaGenerator.xmlSchemaAsString(OverdueConfig.class));
+		w.close();
+
+	}
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java b/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java
new file mode 100644
index 0000000..76cd152
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/io/TestReadConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config.io;
+
+import org.testng.annotations.Test;
+
+import com.google.common.io.Resources;
+import com.ning.billing.overdue.config.OverdueConfig;
+import com.ning.billing.util.config.XMLLoader;
+
+public class TestReadConfig {
+    @Test(enabled=false) //TODO MDW whilst refactoring
+    public void testConfigLoad() throws Exception {
+        XMLLoader.getObjectFromString(Resources.getResource("OverdueConfig.xml").toExternalForm(), OverdueConfig.class);
+    }
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java
new file mode 100644
index 0000000..5ef0364
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueRules.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
+
+public class MockOverdueRules extends OverdueConfig {
+
+    @SuppressWarnings("unchecked")
+    public MockOverdueRules() {
+        OverdueStatesBundle bundleODS =  new OverdueStatesBundle();
+        bundleODS.setBundleOverdueStates(new DefaultOverdueState[] { new DefaultOverdueState<SubscriptionBundle>().setName(MockOverdueAccessModule.CLEAR_STATE) });
+        setOverdueStatesBundle(bundleODS);
+
+    }
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java
new file mode 100644
index 0000000..bf41f8e
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+import com.ning.billing.overdue.config.api.Overdueable;
+
+public class MockOverdueState<T extends Overdueable> extends DefaultOverdueState<T> {
+    
+    public MockOverdueState() {
+        setName(MockOverdueAccessModule.CLEAR_STATE);
+    }
+
+    public MockOverdueState(String name, boolean blockChanges, boolean disableEntitlementAndBlockChanges) {
+        setName(name);
+        setBlockChanges(blockChanges);
+        setDisableEntitlement(disableEntitlementAndBlockChanges);
+    }
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueStatesBundle.java b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueStatesBundle.java
new file mode 100644
index 0000000..f1020b2
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/MockOverdueStatesBundle.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+
+public class MockOverdueStatesBundle extends OverdueStatesBundle {
+
+    public MockOverdueStatesBundle() {
+        
+    }
+    
+   public MockOverdueStatesBundle(DefaultOverdueState<SubscriptionBundle>[] states) {
+       setBundleOverdueStates(states);
+    }
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
new file mode 100644
index 0000000..3cd02ea
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestCondition.java
@@ -0,0 +1,147 @@
+/*
+00 * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.joda.time.DateTime;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.overdue.config.api.BillingState;
+import com.ning.billing.overdue.config.api.Overdueable;
+import com.ning.billing.overdue.config.api.PaymentResponse;
+import com.ning.billing.util.config.XMLLoader;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.DefaultControlTag;
+import com.ning.billing.util.tag.DescriptiveTag;
+import com.ning.billing.util.tag.Tag;
+
+public class TestCondition {
+	
+	@XmlRootElement(name="condition")
+	private static class MockCondition extends DefaultCondition<Overdueable> {}
+
+	@Test(groups={"fast"}, enabled=true)
+	public void testNumberOfUnpaidInvoicesEqualsOrExceeds() throws Exception {
+		String xml = 
+				"<condition>" +
+				"	<numberOfUnpaidInvoicesEqualsOrExceeds>1</numberOfUnpaidInvoicesEqualsOrExceeds>" +
+				"</condition>";
+		InputStream is = new ByteArrayInputStream(xml.getBytes());
+		MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is,  MockCondition.class);
+		
+		BillingState<Overdueable> state0 = new BillingState<Overdueable>(new UUID(0L,1L), 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state1 = new BillingState<Overdueable>(new UUID(0L,1L), 1, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state2 = new BillingState<Overdueable>(new UUID(0L,1L), 2, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		
+		Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+		Assert.assertTrue(c.evaluate(state1, new DateTime()));
+		Assert.assertTrue(c.evaluate(state2, new DateTime()));
+	}
+	
+	@Test(groups={"fast"}, enabled=true)
+	public void testTotalUnpaidInvoiceBalanceEqualsOrExceeds() throws Exception {
+		String xml = 
+				"<condition>" +
+				"	<totalUnpaidInvoiceBalanceEqualsOrExceeds>100.00</totalUnpaidInvoiceBalanceEqualsOrExceeds>" +
+				"</condition>";
+		InputStream is = new ByteArrayInputStream(xml.getBytes());
+		MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is,  MockCondition.class);
+		
+		BillingState<Overdueable> state0 = new BillingState<Overdueable>(new UUID(0L,1L), 0, BigDecimal.ZERO, new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state1 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("100.00"), new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state2 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("200.00"), new DateTime(), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		
+		Assert.assertTrue(!c.evaluate(state0, new DateTime()));
+		Assert.assertTrue(c.evaluate(state1, new DateTime()));
+		Assert.assertTrue(c.evaluate(state2, new DateTime()));
+	}
+
+	
+	@Test(groups={"fast"}, enabled=true)
+	public void testTimeSinceEarliestUnpaidInvoiceEqualsOrExceeds() throws Exception {
+		String xml = 
+				"<condition>" +
+				"	<timeSinceEarliestUnpaidInvoiceEqualsOrExceeds><unit>DAYS</unit><number>10</number></timeSinceEarliestUnpaidInvoiceEqualsOrExceeds>" +
+				"</condition>";
+		InputStream is = new ByteArrayInputStream(xml.getBytes());
+		MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is,  MockCondition.class);
+		
+		DateTime now = new DateTime();
+		
+		BillingState<Overdueable> state0 = new BillingState<Overdueable>(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state1 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state2 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		
+		Assert.assertTrue(!c.evaluate(state0, now));
+		Assert.assertTrue(c.evaluate(state1, now));
+		Assert.assertTrue(c.evaluate(state2, now));
+	}
+
+	@Test(groups={"fast"}, enabled=true)
+	public void testResponseForLastFailedPaymentIn() throws Exception {
+		String xml = 
+				"<condition>" +
+				"	<responseForLastFailedPaymentIn><response>INSUFFICIENT_FUNDS</response><response>DO_NOT_HONOR</response></responseForLastFailedPaymentIn>" +
+				"</condition>";
+		InputStream is = new ByteArrayInputStream(xml.getBytes());
+		MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is,  MockCondition.class);
+		
+		DateTime now = new DateTime();
+		
+		BillingState<Overdueable> state0 = new BillingState<Overdueable>(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{});
+		BillingState<Overdueable> state1 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+		BillingState<Overdueable> state2 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), PaymentResponse.DO_NOT_HONOR , new Tag[]{});
+		
+		Assert.assertTrue(!c.evaluate(state0, now));
+		Assert.assertTrue(c.evaluate(state1, now));
+		Assert.assertTrue(c.evaluate(state2, now));
+	}
+
+	@Test(groups={"fast"}, enabled=true)
+	public void testHasControlTag() throws Exception {
+		String xml = 
+				"<condition>" +
+				"	<controlTag>OVERDUE_ENFORCEMENT_OFF</controlTag>" +
+				"</condition>";
+		InputStream is = new ByteArrayInputStream(xml.getBytes());
+		MockCondition c = XMLLoader.getObjectFromStreamNoValidation(is,  MockCondition.class);
+		
+		DateTime now = new DateTime();
+		
+		BillingState<Overdueable> state0 = new BillingState<Overdueable>(new UUID(0L,1L), 0, BigDecimal.ZERO, now, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF),new DescriptiveTag("Tag")});
+		BillingState<Overdueable> state1 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("100.00"), now.minusDays(10), PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF)});
+		BillingState<Overdueable> state2 = new BillingState<Overdueable>(new UUID(0L,1L), 1, new BigDecimal("200.00"), now.minusDays(20), 
+				PaymentResponse.DO_NOT_HONOR, 
+				new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF), 
+						  new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF),
+						  new DescriptiveTag("Tag")});
+		
+		Assert.assertTrue(!c.evaluate(state0, now));
+		Assert.assertTrue(c.evaluate(state1, now));
+		Assert.assertTrue(c.evaluate(state2, now));
+	}
+
+
+
+}
diff --git a/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdue.java b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdue.java
new file mode 100644
index 0000000..6d0a45d
--- /dev/null
+++ b/overdue/src/test/java/com/ning/billing/overdue/config/TestOverdue.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.overdue.config;
+
+public class TestOverdue {
+
+}
diff --git a/overdue/src/test/resources/log4j.xml b/overdue/src/test/resources/log4j.xml
new file mode 100644
index 0000000..ac530a1
--- /dev/null
+++ b/overdue/src/test/resources/log4j.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2010-2011 Ning, Inc.
+  ~
+  ~ Ning 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.
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
+        <param name="Target" value="System.out"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%p	%d{ISO8601}	%X{trace}	%t	%c	%m%n"/>
+        </layout>
+    </appender>
+
+
+    <logger name="com.ning.billing.entitlement">
+        <level value="info"/>
+    </logger>
+
+    <logger name="com.ning.billing.util.notificationq">
+        <level value="info"/>
+    </logger>
+
+    <root>
+        <priority value="info"/>
+        <appender-ref ref="stdout"/>
+    </root>
+</log4j:configuration>
diff --git a/overdue/src/test/resources/OverdueConfig.xml b/overdue/src/test/resources/OverdueConfig.xml
new file mode 100644
index 0000000..6318e8d
--- /dev/null
+++ b/overdue/src/test/resources/OverdueConfig.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- ~ Copyright 2010-2011 Ning, Inc. ~ ~ Ning 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. -->
+
+<overdueRules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
+	<bundleOverdueStates>
+		<state name="Clear">
+			<isClearState>true</isClearState>
+		</state>
+	</bundleOverdueStates>
+</overdueRules>
+
+    
\ No newline at end of file
diff --git a/overdue/src/test/resources/OverdueConfigSchema.xsd b/overdue/src/test/resources/OverdueConfigSchema.xsd
new file mode 100644
index 0000000..36379ef
--- /dev/null
+++ b/overdue/src/test/resources/OverdueConfigSchema.xsd
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
+<xs:element name="overdue" type="overdueRules"/>
+<xs:complexType name="overdueRules">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element name="bundleOverdueStates" type="overdueStatesBundle"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType abstract="true" name="validatingConfig">
+<xs:sequence/>
+</xs:complexType>
+<xs:complexType name="overdueStatesBundle">
+<xs:complexContent>
+<xs:extension base="defaultOverdueStateSet">
+<xs:sequence>
+<xs:element maxOccurs="unbounded" name="state" type="defaultOverdueState"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType abstract="true" name="defaultOverdueStateSet">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence/>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultOverdueState">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element minOccurs="0" name="condition" type="defaultCondition"/>
+<xs:element minOccurs="0" name="externalMessage" type="xs:string"/>
+<xs:element minOccurs="0" name="disableEntitlementAndChangesBlocked" type="xs:boolean"/>
+<xs:element minOccurs="0" name="blockChanges" type="xs:boolean"/>
+<xs:element minOccurs="0" name="daysBetweenPaymentRetries" type="xs:int"/>
+<xs:element minOccurs="0" name="isClearState" type="xs:boolean"/>
+</xs:sequence>
+<xs:attribute name="name" type="xs:ID" use="required"/>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultCondition">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element minOccurs="0" name="numberOfUnpaidInvoicesEqualsOrExceeds" type="xs:int"/>
+<xs:element minOccurs="0" name="totalUnpaidInvoiceBalanceEqualsOrExceeds" type="xs:decimal"/>
+<xs:element minOccurs="0" name="timeSinceEarliestUnpaidInvoiceEqualsOrExceeds" type="defaultDuration"/>
+<xs:element minOccurs="0" name="responseForLastFailedPaymentIn">
+<xs:complexType>
+<xs:sequence>
+<xs:element maxOccurs="unbounded" minOccurs="0" name="response" type="paymentResponse"/>
+</xs:sequence>
+</xs:complexType>
+</xs:element>
+<xs:element minOccurs="0" name="controlTag" type="controlTagType"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:complexType name="defaultDuration">
+<xs:complexContent>
+<xs:extension base="validatingConfig">
+<xs:sequence>
+<xs:element name="unit" type="timeUnit"/>
+<xs:element minOccurs="0" name="number" type="xs:int"/>
+</xs:sequence>
+</xs:extension>
+</xs:complexContent>
+</xs:complexType>
+<xs:simpleType name="timeUnit">
+<xs:restriction base="xs:string">
+<xs:enumeration value="DAYS"/>
+<xs:enumeration value="MONTHS"/>
+<xs:enumeration value="YEARS"/>
+<xs:enumeration value="UNLIMITED"/>
+</xs:restriction>
+</xs:simpleType>
+<xs:simpleType name="paymentResponse">
+<xs:restriction base="xs:string">
+<xs:enumeration value="INVALID_CARD"/>
+<xs:enumeration value="EXPIRED_CARD"/>
+<xs:enumeration value="LOST_OR_STOLEN_CARD"/>
+<xs:enumeration value="DO_NOT_HONOR"/>
+<xs:enumeration value="INSUFFICIENT_FUNDS"/>
+<xs:enumeration value="DECLINE"/>
+<xs:enumeration value="PROCESSING_ERROR"/>
+<xs:enumeration value="INVALID_AMOUNT"/>
+<xs:enumeration value="DUPLICATE_TRANSACTION"/>
+<xs:enumeration value="OTHER"/>
+</xs:restriction>
+</xs:simpleType>
+<xs:simpleType name="controlTagType">
+<xs:restriction base="xs:string">
+<xs:enumeration value="AUTO_PAY_OFF"/>
+<xs:enumeration value="AUTO_INVOICING_OFF"/>
+<xs:enumeration value="OVERDUE_ENFORCEMENT_OFF"/>
+<xs:enumeration value="WRITTEN_OFF"/>
+</xs:restriction>
+</xs:simpleType>
+</xs:schema>
diff --git a/overdue/src/test/resources/resource.properties b/overdue/src/test/resources/resource.properties
new file mode 100644
index 0000000..d63334b
--- /dev/null
+++ b/overdue/src/test/resources/resource.properties
@@ -0,0 +1,7 @@
+killbill.catalog.uri=file:src/test/resources/catalogSample.xml
+killbill.entitlement.dao.claim.time=60000
+killbill.entitlement.dao.ready.max=1
+killbill.entitlement.engine.notifications.sleep=500
+user.timezone=UTC
+
+
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index ac2b9f3..c5ca20c 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -27,11 +27,6 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.DefaultCallContext;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.clock.Clock;
 import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -49,6 +44,11 @@ import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.payment.TestHelper;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.entity.EntityPersistenceException;
 
 public abstract class TestPaymentApi {
@@ -83,9 +83,11 @@ public abstract class TestPaymentApi {
         final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);
         final BigDecimal amount = new BigDecimal("10.0011");
         final UUID subscriptionId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
 
         invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(), account.getId(),
                                                        subscriptionId,
+                                                       bundleId,
                                                        "test plan", "test phase",
                                                        now,
                                                        now.plusMonths(1),
diff --git a/payment/src/test/java/com/ning/billing/payment/TestHelper.java b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
index 6112fc2..39115db 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -93,6 +93,7 @@ public class TestHelper {
                 RecurringInvoiceItem recurringInvoiceItem = (RecurringInvoiceItem) item;
                 invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
                                                                account.getId(),
+                                                               recurringInvoiceItem.getBundleId(),
                                                                recurringInvoiceItem.getSubscriptionId(),
                                                                recurringInvoiceItem.getPlanName(),
                                                                recurringInvoiceItem.getPhaseName(),
@@ -110,10 +111,13 @@ public class TestHelper {
     public Invoice createTestInvoice(Account account) {
         final DateTime now = new DateTime(DateTimeZone.UTC);
         final UUID subscriptionId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
         final BigDecimal amount = new BigDecimal("10.00");
-        final InvoiceItem item = new RecurringInvoiceItem(null, account.getId(), subscriptionId, "test plan", "test phase", now, now.plusMonths(1),
+        
+        final InvoiceItem item = new RecurringInvoiceItem(null, account.getId(), bundleId, subscriptionId, "test plan", "test phase", now, now.plusMonths(1),
                 amount, new BigDecimal("1.0"), Currency.USD);
 
+
         return createTestInvoice(account, now, Currency.USD, item);
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index 1fe2cc4..26414aa 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -116,12 +116,14 @@ public class TestRetryService {
         final Invoice invoice = testHelper.createTestInvoice(account, clock.getUTCNow(), Currency.USD);
         final BigDecimal amount = new BigDecimal("10.00");
         final UUID subscriptionId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
 
         final DateTime startDate = clock.getUTCNow();
         final DateTime endDate = startDate.plusMonths(1);
         invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
                                                        account.getId(),
                                                        subscriptionId,
+                                                       bundleId,
                                                        "test plan", "test phase",
                                                        startDate,
                                                        endDate,
@@ -157,12 +159,14 @@ public class TestRetryService {
         final Invoice invoice = testHelper.createTestInvoice(account, clock.getUTCNow(), Currency.USD);
         final BigDecimal amount = new BigDecimal("10.00");
         final UUID subscriptionId = UUID.randomUUID();
+        final UUID bundleId = UUID.randomUUID();
 
         final DateTime now = clock.getUTCNow();
 
         invoice.addInvoiceItem(new RecurringInvoiceItem(invoice.getId(),
                                                        account.getId(),
                                                        subscriptionId,
+                                                       bundleId,
                                                        "test plan", "test phase",
                                                        now,
                                                        now.plusMonths(1),

pom.xml 17(+17 -0)

diff --git a/pom.xml b/pom.xml
index e0b602f..f7ab718 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,8 @@
         <module>catalog</module>
         <module>entitlement</module>
         <module>invoice</module>
+        <module>ne</module>
+        <module>overdue</module>
         <module>payment</module>
         <module>util</module>
         <module>jaxrs</module>
@@ -109,6 +111,18 @@
             </dependency>
             <dependency>
                 <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-ne</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
+                <artifactId>killbill-ne</artifactId>
+                <version>${project.version}</version>
+                <type>test-jar</type>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.ning.billing</groupId>
                 <artifactId>killbill-entitlement</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -407,6 +421,7 @@
                                 <exclude>**/.project</exclude>
                                 <exclude>.git/**</exclude>
                                 <exclude>.gitignore</exclude>
+                                <exclude>**/.classpath</exclude>
                                 <exclude>ignore/**</exclude>
                                 <exclude>API.txt</exclude>
                                 <exclude>RELEASE.sh</exclude>
@@ -428,6 +443,8 @@
                                 <exclude>**/*.dont-let-git-remove-this-directory</exclude>
                                 <exclude>**/test-output/**</exclude>
                                 <exclude>**/bin/**</exclude>
+                                <exclude>**/target/**</exclude>
+                                <exclude>**/.settings/**</exclude>
                                 <exclude>.travis.yml</exclude>
                                 <!--  until we merge from server branch we disable rat for those -->
                                 <exclude>jaxrs/**</exclude>
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index a33ac8a..2cdced0 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -16,6 +16,10 @@
 
 package com.ning.billing.server.modules;
 
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+
+import com.google.inject.AbstractModule;
 import com.ning.billing.account.glue.AccountModule;
 import com.ning.billing.analytics.setup.AnalyticsModule;
 import com.ning.billing.beatrix.glue.BeatrixModule;
@@ -38,10 +42,6 @@ import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.jetty.jdbi.guice.providers.DBIProvider;
 
-import com.google.inject.AbstractModule;
-import org.skife.jdbi.v2.DBI;
-import org.skife.jdbi.v2.IDBI;
-
 public class KillbillServerModule extends AbstractModule
 {
     @Override
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index 96e1ed6..fc7ef09 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -44,7 +44,6 @@ import org.testng.annotations.BeforeSuite;
 
 import com.google.inject.Injector;
 import com.google.inject.Module;
-import com.google.inject.util.Modules;
 import com.ning.billing.account.glue.AccountModule;
 import com.ning.billing.analytics.setup.AnalyticsModule;
 import com.ning.billing.beatrix.glue.BeatrixModule;
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
index 3bd2524..914de1a 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
@@ -20,6 +20,7 @@ import java.util.Map;
 import javax.ws.rs.core.Response.Status;
 
 import org.joda.time.DateTime;
+import org.joda.time.Period;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -86,6 +87,10 @@ public class TestSubscription extends TestJaxrsBase {
             public DateTime addToDateTime(DateTime dateTime) {
                 return null;
             }
+            @Override
+            public Period toJodaPeriod() {
+                throw new UnsupportedOperationException();
+            }
         }, 1000);
 
         crappyWaitForLackOfProperSynchonization();
diff --git a/util/src/main/java/com/ning/billing/util/config/XMLLoader.java b/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
index d0487b8..9d35352 100644
--- a/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
+++ b/util/src/main/java/com/ning/billing/util/config/XMLLoader.java
@@ -71,6 +71,18 @@ public class XMLLoader {
             return null;
         }
     } 
+	
+	public static <T> T getObjectFromStreamNoValidation(InputStream stream, Class<T> clazz) throws SAXException, InvalidConfigException, JAXBException, IOException, TransformerException {
+        Object o = unmarshaller(clazz).unmarshal(stream);
+        if (clazz.isInstance(o)) {
+        	@SuppressWarnings("unchecked")
+			T castObject = (T)o;
+        	return castObject;
+        } else {
+            return null;
+        }
+    } 
+
 
 	public static <T extends ValidatingConfig<T>> void validate(URI uri, T c) throws ValidationException {
             c.initialize(c, uri);
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
index 3d0a8b1..bb97dd7 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
@@ -58,6 +58,9 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
     public void clearNotification(@Bind("id") long id, @Bind("owner") String owner);
 
     @SqlUpdate
+    public void removeNotificationsByKey(@Bind("notification_key") String key);
+    
+    @SqlUpdate
     public void insertNotification(@Bind(binder = NotificationSqlDaoBinder.class) Notification evt);
 
     @SqlUpdate
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index e12b8a7..392a218 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -19,6 +19,7 @@ package com.ning.billing.util.notificationq;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
@@ -119,4 +120,10 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
             log.debug(String.format("Thread %d [queue = %s] %s", Thread.currentThread().getId(), getFullQName(), realDebug));
         }
     }
+
+    @Override
+    public void removeNotificationsByKey(UUID key) {
+        dao.removeNotificationsByKey(key.toString());
+        
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
index 3200424..32cba9d 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationLifecycle.java
@@ -24,7 +24,8 @@ public interface NotificationLifecycle {
     public enum NotificationLifecycleState {
         AVAILABLE,
         IN_PROCESSING,
-        PROCESSED
+        PROCESSED,
+        REMOVED
     }
 
     public String getOwner();
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
index fb88d4c..14b68e0 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueue.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.util.notificationq;
 
+import java.util.UUID;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
@@ -44,6 +46,13 @@ public interface NotificationQueue {
            final DateTime futureNotificationTime, final NotificationKey notificationKey);
 
    /**
+    * Remove all notifications associated with this key   
+    * 
+    * @param key
+    */
+   public void removeNotificationsByKey(UUID key);
+
+   /**
     * This is only valid when the queue has been configured with isNotificationProcessingOff is true
     * In which case, it will callback users for all the ready notifications.
     *
@@ -71,4 +80,6 @@ public interface NotificationQueue {
     */
    public String getFullQName();
 
+   
+
 }
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index cf993fa..e5e9488 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -119,3 +119,5 @@ CREATE TABLE audit_log (
     user_token char(36),
     PRIMARY KEY(id)
 ) ENGINE=innodb;
+
+
diff --git a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
index 7a7ecab..899e828 100644
--- a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
@@ -16,6 +16,7 @@ getReadyNotifications(now, max) ::= <<
       effective_dt \<= :now
       and queue_name = :queue_name
       and processing_state != 'PROCESSED'
+      and processing_state != 'REMOVED'
       and (processing_owner IS NULL OR processing_available_dt \<= :now)
     order by
       effective_dt asc
@@ -35,6 +36,7 @@ claimNotification(owner, next_available, id, now) ::= <<
     where
       id = :id
       and processing_state != 'PROCESSED'
+      and processing_state != 'REMOVED'
       and (processing_owner IS NULL OR processing_available_dt \<= :now)
     ;
 >>
@@ -48,6 +50,16 @@ clearNotification(id, owner) ::= <<
     ;
 >>
 
+removeNotificationsByKey(notification_key) ::= <<
+    update notifications
+    set
+      processing_state = 'REMOVED'
+    where
+      notification_key = :notification_key
+    ;
+>>
+
+
 insertNotification() ::= <<
     insert into notifications (
       notification_id
diff --git a/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java b/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
index 7404331..7a3d28f 100644
--- a/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
+++ b/util/src/test/java/com/ning/billing/mock/BrainDeadProxyFactory.java
@@ -19,12 +19,15 @@ package com.ning.billing.mock;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import bsh.This;
+
 public class BrainDeadProxyFactory {
     private static final Logger log = LoggerFactory.getLogger(BrainDeadProxyFactory.class);
     
@@ -39,9 +42,12 @@ public class BrainDeadProxyFactory {
     }
 
     @SuppressWarnings("unchecked")
-    public static <T> T createBrainDeadProxyFor(final Class<T> clazz) {
+    public static <T> T createBrainDeadProxyFor(final Class<T> clazz, final Class<?> ... others) {
+        Class<?>[] clazzes = Arrays.copyOf(others, others.length + 2);
+        clazzes[others.length] = ZombieControl.class;
+        clazzes[others.length + 1] = clazz;
         return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
-                new Class[] { clazz , ZombieControl.class},
+                clazzes,
                 new InvocationHandler() {
             private final Map<String,Object> results = new HashMap<String,Object>();
 
@@ -68,6 +74,8 @@ public class BrainDeadProxyFactory {
                     		throw ((Throwable) result);
                     	}
                         return result;
+                    } else if (method.getName().equals("equals")){
+                       return proxy == args[0];
                     } else {
                         log.error(String.format("No result for Method: '%s' on Class '%s'",method.getName(), method.getDeclaringClass().getName()));
                         throw new UnsupportedOperationException();
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
index ae66819..a9cd1db 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
@@ -21,6 +21,7 @@ import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.TreeSet;
+import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -110,4 +111,20 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
         }
         return result;
     }
+
+    @Override
+    public void removeNotificationsByKey(UUID key) {
+        List<Notification> toClearNotifications = new ArrayList<Notification>();
+        for (Notification notification : notifications) {
+            if (notification.getNotificationKey().equals(key.toString())) {
+                    toClearNotifications.add(notification);
+            }
+        }
+        synchronized(notifications) {
+            if (toClearNotifications.size() > 0) {
+                notifications.removeAll(toClearNotifications);
+            }
+        }
+        
+    }
 }
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index e2718a9..1a9654c 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -109,6 +109,7 @@ public class TestNotificationQueue {
         });
         // Reset time to real value
         ((ClockMock) clock).resetDeltaFromReality();
+        eventsReceived=0;
     }
 
 
@@ -407,6 +408,82 @@ public class TestNotificationQueue {
             }
         };
     }
+    
+    
+    @Test(groups="slow")
+    public void testRemoveNotifications() throws InterruptedException {
+        
+        final UUID key = UUID.randomUUID();
+        final NotificationKey notificationKey = new NotificationKey() {
+            @Override
+            public String toString() {
+                return key.toString();
+            }
+        };        
+        final UUID key2 = UUID.randomUUID();
+        final NotificationKey notificationKey2 = new NotificationKey() {
+            @Override
+            public String toString() {
+                return key2.toString();
+            }
+        };        
+
+        final DefaultNotificationQueue queue = new DefaultNotificationQueue(dbi, clock, "test-svc", "many",
+                new NotificationQueueHandler() {
+            @Override
+            public void handleReadyNotification(String key, DateTime eventDateTime) {
+                    if(key.equals(notificationKey) || key.equals(notificationKey2)) { //ig nore stray events from other tests
+                        log.info("Received notification with key: " + notificationKey);
+                        eventsReceived++;
+                    }
+            }
+        },
+        getNotificationConfig(false, 100, 10, 10000));
+
+
+        queue.startQueue();
+
+        final DateTime start = clock.getUTCNow().plusHours(1);
+        final int nextReadyTimeIncrementMs = 1000;
+ 
+        // add 3 events
+
+        dao.inTransaction(new Transaction<Void, DummySqlTest>() {
+            @Override
+            public Void inTransaction(DummySqlTest transactional,
+                    TransactionStatus status) throws Exception {
+
+                queue.recordFutureNotificationFromTransaction(transactional,
+                        start.plus(nextReadyTimeIncrementMs), notificationKey);
+                queue.recordFutureNotificationFromTransaction(transactional,
+                        start.plus(2 *nextReadyTimeIncrementMs), notificationKey);
+                queue.recordFutureNotificationFromTransaction(transactional,
+                        start.plus(3 * nextReadyTimeIncrementMs), notificationKey2);
+                return null;
+            }
+        });
+    
+    
+      queue.removeNotificationsByKey(key); // should remove 2 of the 3
+
+    // Move time in the future after the notification effectiveDate
+        ((ClockMock) clock).setDeltaFromReality(4000000 + nextReadyTimeIncrementMs * 3 );
+        
+        try {
+            await().atMost(10, TimeUnit.SECONDS).until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    return eventsReceived >= 2;
+                }
+            });
+            Assert.fail("There should only have been only one event left in the queue we got: " + eventsReceived);
+        } catch (Exception e) {
+            // expected behavior
+        }
+        log.info("Received " + eventsReceived + " events");
+        queue.stopQueue();
+    }
+
 
 
     public static class TestNotificationQueueModule extends AbstractModule {