killbill-aplcache

Overdue integration into entitlement with tests. Removed

4/13/2012 10:49:30 PM

Changes

bin/db-helper 157(+157 -0)

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

entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestEntitlementOverdueApi.java 58(+0 -58)

overdue/pom.xml 7(+6 -1)

Details

diff --git a/analytics/pom.xml b/analytics/pom.xml
index b6f27c9..e7e0e94 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -75,6 +75,12 @@
         </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-invoice</artifactId>
             <scope>test</scope>
         </dependency>
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..4d26ac0 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,24 @@
 
 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.api.overdue.MockOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 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,10 +48,17 @@ 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 EntitlementModule() {
+
+            @Override
+            protected void installOverdueChecker() {
+                bind(OverdueChecker.class).to(MockOverdueChecker.class).asEagerSingleton();
+            }
+            
+        });
         install(new InvoiceModule());
+        install(new MockOverdueAccessModule());
         install(new PaymentModule());
         install(new TagStoreModule());
         install(new NotificationQueueModule());
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 59ad218..a3040fd 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
@@ -51,6 +51,7 @@ 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;
@@ -89,7 +90,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";
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
index 6f80e03..533367f 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockIEntitlementUserApi.java
@@ -124,4 +124,9 @@ public class MockIEntitlementUserApi implements EntitlementUserApi
 	public DateTime getNextBillingDate(UUID account) {
 		throw new UnsupportedOperationException();
 	}
+
+    @Override
+    public Subscription getBaseSubscription(UUID bundleId) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
index 9910c7e..d11c353 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/Overdueable.java
@@ -18,11 +18,31 @@ package com.ning.billing.catalog.api.overdue;
 
 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 {
-        ACCOUNT,
-        SUBSCRIPTION_BUNDLE
+        //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/catalog/api/overdue/OverdueState.java b/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
index d9596e4..856d048 100644
--- a/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
+++ b/api/src/main/java/com/ning/billing/catalog/api/overdue/OverdueState.java
@@ -25,9 +25,9 @@ public interface OverdueState<T extends Overdueable> {
     
     public int getDaysBetweenPaymentRetries();
 
-    public boolean entitlementDisabledAndChangesBlocked();
+    public boolean disableEntitlementAndChangesBlocked();
 
-    public boolean changesBlocked();
+    public boolean blockChanges();
     
     public boolean isClearState();
 }
\ No newline at end of file
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 bb7f632..2f8646c 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
@@ -81,6 +81,5 @@ public interface StaticCatalog {
     public abstract boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException;
 
     public abstract OverdueStateSet<SubscriptionBundle> currentBundleOverdueStateSet()  throws CatalogApiException;
-    public abstract OverdueStateSet<Account>            currentAccountOverdueStateSet() throws CatalogApiException;
 
 }
\ No newline at end of file
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 6340560..a0d8e93 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.SubscriptionTransition.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/user/EntitlementUserApi.java b/api/src/main/java/com/ning/billing/entitlement/api/user/EntitlementUserApi.java
index 1867cfe..162b92e 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
@@ -35,6 +35,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)
         throws EntitlementUserApiException;
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 0a8bfd5..db73376 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -115,6 +115,7 @@ public enum ErrorCode {
      */
     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
@@ -165,7 +166,7 @@ public enum ErrorCode {
      * 
      */
     OVERDUE_OVERDUEABLE_NOT_SUPPORTED(5001, "The Overdueable type '%s' is not supported"), 
-    OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered when attempting to refresh the state of Overdueable: id='%s', type='%s'") 
+    OVERDUE_CAT_ERROR_ENCOUNTERED(5002,"Catalog error encountered on Overdueable: id='%s', type='%s'"),  
     
     
     ;
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 304cb0b..0e8063d 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
@@ -45,6 +45,7 @@ import com.ning.billing.entitlement.glue.EntitlementModule;
 import com.ning.billing.invoice.api.InvoiceService;
 import com.ning.billing.invoice.glue.InvoiceModule;
 import com.ning.billing.lifecycle.KillbillService;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.payment.api.PaymentService;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
 import com.ning.billing.payment.setup.PaymentConfig;
@@ -93,6 +94,7 @@ public class MockModule extends AbstractModule {
         install(new EntitlementModule());
         install(new InvoiceModule());
         install(new PaymentMockModule());
+        install(new MockOverdueAccessModule());
     }
 
     private static final class PaymentMockModule extends PaymentModule {
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index 5b7aeaf..fabda9d 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -184,7 +184,15 @@ Use Cases to do:
 			</priceListCase>
 		</priceList>
 	</rules>
-
+	
+   <overdueRules> 
+      <bundleOverdueStates>
+           <state name="Clear">
+               <isClearState>true</isClearState>
+           </state> 
+       </bundleOverdueStates>
+    </overdueRules>
+    
 	<plans>
 		<plan name="pistol-monthly-no-trial">
 			<product>Pistol</product>

bin/db-helper 157(+157 -0)

diff --git a/bin/db-helper b/bin/db-helper
new file mode 100755
index 0000000..cd99dc8
--- /dev/null
+++ b/bin/db-helper
@@ -0,0 +1,157 @@
+#! /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.                                                         #
+#                                                                                 #
+###################################################################################
+
+#set -x 
+
+HERE=`cd \`dirname $0\`; pwd`
+TOP=$HERE/..
+
+POM="$TOP/pom.xml"
+
+ACTION=
+DATABASE="killbill"
+USER="root"
+PWD="root"
+TEST_ALSO=
+
+DDL_FILE=
+CLEAN_FILE=
+
+function usage() {
+   echo -n "./db_helper "
+   echo -n " -a <create|clean|dump>"
+   echo -n " -d database_name (default = killbill)"    
+   echo -n " -u user_name (default = root)"
+   echo -n " -p password (default = root)"
+   echo -n " -t (also include test ddl)"
+   echo -n "-h this message"
+   echo
+   exit 1
+}
+
+function get_modules() {
+   local modules=`grep module $POM  | grep -v modules | cut -d '>' -f 2 | cut -d '<' -f 1`
+   echo $modules
+}
+
+function find_test_ddl() {
+
+   local modules=`get_modules`
+   local ddl_test=
+
+   local cur_ddl=
+   for m in $modules; do
+       cur_ddl=`find $m/src/test/resources/ -name ddl_test.sql 2>/dev/null`
+       ddl_test="$ddl_test $cur_ddl"
+   done
+   echo "$ddl_test"
+
+}
+function find_src_ddl() {
+
+   local modules=`get_modules`
+   local ddl_src=
+
+   local cur_ddl=
+   for m in $modules; do
+       cur_ddl=`find $m/src/main/resources/ -name ddl.sql 2>/dev/null`
+       ddl_src="$ddl_src $cur_ddl"
+   done
+   echo "$ddl_src"
+}
+
+
+function create_clean_file() {
+   local ddl_file=$1
+   local tables=`cat $ddl_file | grep -i "create table" | awk ' { print $3 } '` 
+
+   local tmp="/tmp/clean-$DATABASE.$$" 
+   echo "use $DATABASE;" >> $tmp
+   echo "" >> $tmp
+   for t in $tables; do
+       echo "truncate $t;" >> $tmp
+   done
+   echo $tmp
+}
+
+function create_ddl_file() {
+   local ddls=`find_src_ddl`
+   local test_ddls=
+   if [ ! -z $TEST_ALSO ]; then
+       test_ddls=`find_test_ddl`
+       ddls="$ddls $test_ddls"
+   fi
+
+   local tmp="/tmp/ddl-$DATABASE.$$"
+   touch $tmp
+   echo "use $DATABASE;" >> $tmp
+   echo "" >> $tmp
+   for d in $ddls; do
+       cat $d >> $tmp
+       echo "" >> $tmp
+   done
+   echo $tmp
+}
+
+function cleanup() {
+   rm -f "/tmp/*.$$"
+}
+
+
+while getopts ":a:d:u:pt" options; do
+ case $options in
+   a ) ACTION=$OPTARG;;
+	d ) DATABASE=$OPTARG;;
+	u ) USER=$OPTARG;;
+	p ) PWD=$OPTARG;;
+	t ) TEST_ALSO=1;;
+   h ) usage;;
+   * ) usage;;
+ esac
+done
+
+
+
+if [ -z $ACTION ]; then
+   echo "Need to specify an action <CREATE|CLEAN>"
+   usage
+fi
+
+
+if [ $ACTION == "dump" ]; then
+   DDL_FILE=`create_ddl_file`
+   cat $DDL_FILE
+fi
+
+if [ $ACTION == "create" ]; then
+   DDL_FILE=`create_ddl_file`
+   echo "Applying new schema $tmp to database $DATABASE"    
+   mysql -u $USER --password=$PWD < $DDL_FILE
+fi
+
+if [ $ACTION == "clean" ]; then
+   DDL_FILE=`create_ddl_file` 
+   CLEAN_FILE=`create_clean_file $DDL_FILE`   
+   echo "Cleaning db tables on database $DATABASE"
+   mysql -u $USER --password=$PWD < $DDL_FILE
+fi
+
+cleanup

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

diff --git a/catalog/pom.xml b/catalog/pom.xml
index dee138d..60984c5 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/overdue/DefaultOverdueState.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
index 579b759..081edd6 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueState.java
@@ -44,15 +44,18 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
 	@XmlElement(required=false, name="externalMessage")
 	private String externalMessage = "";
 
-    @XmlElement(required=false, name="overrideEntitlementAndChangesBlocked")
-    private Boolean overrideEntitlement = false;
+    @XmlElement(required=false, name="disableEntitlementAndChangesBlocked")
+    private Boolean disableEntitlement = false;
     
-    @XmlElement(required=false, name="changesBlocked")
-    private Boolean changesBlocked = 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?
@@ -78,21 +81,19 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
 	}
 	
     @Override
-    public boolean changesBlocked() {
-        return changesBlocked && overrideEntitlement;
+    public boolean blockChanges() {
+        return blockChanges || disableEntitlement;
     }
 
 	/* (non-Javadoc)
      * @see com.ning.billing.catalog.overdue.OverdueState#applyCancel()
      */
 	@Override
-    public boolean entitlementDisabledAndChangesBlocked() {
-		return overrideEntitlement;
+    public boolean disableEntitlementAndChangesBlocked() {
+		return disableEntitlement;
 	}
 	
 	
-
-
     protected DefaultCondition<T> getCondition() {
 		return condition;
 	}
@@ -107,10 +108,15 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
 		return this;
 	}
 
-	protected DefaultOverdueState<T> setCancel(boolean cancel) {
-		this.overrideEntitlement = cancel;
-		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;
@@ -119,7 +125,7 @@ public class DefaultOverdueState<T extends Overdueable> extends ValidatingConfig
 
     @Override
     public boolean isClearState() {
-        return false;
+        return isClearState;
     }
 
     @Override
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
index 9ebc851..4bdcb99 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/DefaultOverdueStateSet.java
@@ -16,6 +16,9 @@
 
 package com.ning.billing.catalog.overdue;
 
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
 import org.apache.commons.lang.NotImplementedException;
 import org.joda.time.DateTime;
 
@@ -26,10 +29,10 @@ import com.ning.billing.catalog.api.overdue.BillingState;
 import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.catalog.api.overdue.OverdueStateSet;
 import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 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<StandaloneCatalog> implements OverdueStateSet<T> {
     private DefaultOverdueState<T> clearState;
     
@@ -100,5 +103,4 @@ public abstract class DefaultOverdueStateSet<T extends Overdueable> extends Vali
         
         return errors;
     }
-      
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
index 74351cc..8e8b174 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueRules.java
@@ -22,7 +22,6 @@ import javax.xml.bind.annotation.XmlElement;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.util.config.ValidatingConfig;
 import com.ning.billing.util.config.ValidationErrors;
@@ -30,12 +29,8 @@ import com.ning.billing.util.config.ValidationErrors;
 @XmlAccessorType(XmlAccessType.NONE)
 public class OverdueRules  extends ValidatingConfig<StandaloneCatalog> {
 
-    @XmlElement(required=false, name="bundleOverdueStates")
+    @XmlElement(required=true, name="bundleOverdueStates")
     private OverdueStatesBundle bundleOverdueStates;
-    
-    @XmlElement(required=false, name="accountOverdueStates")
-    private OverdueStatesAccount accountOverdueStates;
-
 
     public DefaultOverdueStateSet<SubscriptionBundle> getBundleStateSet() {
         return bundleOverdueStates;
@@ -47,9 +42,10 @@ public class OverdueRules  extends ValidatingConfig<StandaloneCatalog> {
             ValidationErrors errors) {
         return bundleOverdueStates.validate(root, errors);
     }
-
-
-    public DefaultOverdueStateSet<Account> getAccountStateSet() {
-        return accountOverdueStates;
+    
+    public OverdueRules setOverdueStatesBundle(OverdueStatesBundle bundleODS) {
+        this.bundleOverdueStates = bundleODS;
+        return this;
     }
+
 }
diff --git a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
index d7736ac..e12050d 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/overdue/OverdueStatesBundle.java
@@ -18,15 +18,11 @@ package com.ning.billing.catalog.overdue;
 
 import javax.xml.bind.annotation.XmlElement;
 
-import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.StandaloneCatalog;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import com.ning.billing.util.config.ValidationErrors;
 
 public class OverdueStatesBundle extends DefaultOverdueStateSet<SubscriptionBundle>{
-    @XmlElement(required=false, name="bundleOverdueStages")
+
+    @XmlElement(required=true, name="state")
     private DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates;
 
     @Override
@@ -34,4 +30,8 @@ public class OverdueStatesBundle extends DefaultOverdueStateSet<SubscriptionBund
         return bundleOverdueStates;
     }
 
+    protected OverdueStatesBundle setBundleOverdueStates(DefaultOverdueState<SubscriptionBundle>[] bundleOverdueStates) {
+        this.bundleOverdueStates = bundleOverdueStates;
+        return this;
+    }
 }
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 7208884..fee8c37 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/StandaloneCatalog.java
@@ -27,7 +27,6 @@ import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.api.ActionPolicy;
 import com.ning.billing.catalog.api.BillingAlignment;
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -73,11 +72,11 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
 	@XmlElement(name="rules", required=true)
 	private PlanRules planRules;
 
-    @XmlElement(name="overdueRules", required=false)
+    @XmlElement(name="overdueRules", required=true)
     private OverdueRules overdueRules;
 
 	@XmlElementWrapper(name="plans", required=true)
-	@XmlElement(name="plan", required=true)
+	@XmlElement(name="plan", required=true) 
 	private DefaultPlan[] plans;
 
     @XmlElement(name="priceLists", required=true)
@@ -306,10 +305,15 @@ 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;
+    }
+
+    protected StandaloneCatalog setOverdueRules(OverdueRules overdueRules) {
+        this.overdueRules = overdueRules;
+        return this;
+    }
 
 	@Override
 	public boolean canCreatePlan(PlanSpecifier specifier) throws CatalogApiException {
@@ -328,12 +332,5 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
          return overdueRules.getBundleStateSet();
     }
 
-    @Override
-    public OverdueStateSet<Account> currentAccountOverdueStateSet()
-            throws CatalogApiException {
-         return overdueRules.getAccountStateSet();
-    }
-
-
 
 }
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 c468755..567da32 100644
--- a/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/com/ning/billing/catalog/VersionedCatalog.java
@@ -454,12 +454,6 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalog> implem
         return versionForDate(clock.getUTCNow()).currentBundleOverdueStateSet();
     }
 
-    @Override
-    public OverdueStateSet<Account> currentAccountOverdueStateSet()
-            throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).currentAccountOverdueStateSet();
-    }
-
 
  
 }
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..09fd0e5 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockCatalog.java
@@ -18,6 +18,8 @@ package com.ning.billing.catalog;
 
 import java.util.Date;
 
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.OverdueRules;
 import com.ning.billing.catalog.rules.CaseCancelPolicy;
 import com.ning.billing.catalog.rules.CaseChangePlanAlignment;
 import com.ning.billing.catalog.rules.CaseChangePlanPolicy;
@@ -33,9 +35,15 @@ public class MockCatalog extends StandaloneCatalog {
 		setPlans((DefaultPlan[])MockPlan.createAll());
 		populateRules();
 		populatePriceLists();
+		setOverdueRules();
 	}
 	
-	public void populateRules(){
+	public void setOverdueRules() {
+	    OverdueRules overdueRules = new MockOverdueRules();
+        setOverdueRules(overdueRules);  
+    }
+
+    public void populateRules(){
 		setPlanRules(new PlanRules());
 	}
 
@@ -47,6 +55,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/overdue/MockOverdueState.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueState.java
new file mode 100644
index 0000000..f3d5a24
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/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.catalog.overdue;
+
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
+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/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueStatesBundle.java b/catalog/src/test/java/com/ning/billing/catalog/overdue/MockOverdueStatesBundle.java
new file mode 100644
index 0000000..c7532f1
--- /dev/null
+++ b/catalog/src/test/java/com/ning/billing/catalog/overdue/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.catalog.overdue;
+
+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/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
index c21aac1..5612fb6 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-1.xml
@@ -67,6 +67,14 @@
             </createAlignmentCase>
         </createAlignment>
 	</rules>
+	
+    <overdueRules>
+       <bundleOverdueStates>
+           <state name="ClearBundle">
+               <isClearState>true</isClearState>
+           </state>
+       </bundleOverdueStates>
+    </overdueRules>
 
 
 	<plans>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
index 0e650f1..77ea3bf 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-2.xml
@@ -68,6 +68,14 @@
         </createAlignment>
 	</rules>
 
+    <overdueRules>
+        <bundleOverdueStates>
+           <state name="ClearBundle">
+               <isClearState>true</isClearState>
+           </state>
+       </bundleOverdueStates>
+    </overdueRules>
+
 	<plans>
 		<plan name="pistol-monthly">
 			<effectiveDateForExistingSubscriptons>2011-02-14T00:00:00+00:00</effectiveDateForExistingSubscriptons>
diff --git a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
index f7ae066..9c98563 100644
--- a/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
+++ b/catalog/src/test/resources/versionedCatalog/WeaponsHireSmall-3.xml
@@ -68,6 +68,14 @@
         </createAlignment>
 	</rules>
 
+    <overdueRules>
+        <bundleOverdueStates>
+           <state name="ClearBundle">
+               <isClearState>true</isClearState>
+           </state>
+       </bundleOverdueStates>
+    </overdueRules>
+
 
 	<plans>
 		<plan name="pistol-monthly">
diff --git a/catalog/src/test/resources/WeaponsHire.xml b/catalog/src/test/resources/WeaponsHire.xml
index 3d36b9d..8fbb1f5 100644
--- a/catalog/src/test/resources/WeaponsHire.xml
+++ b/catalog/src/test/resources/WeaponsHire.xml
@@ -169,7 +169,15 @@ Use Cases to do:
 				<toPriceList>DEFAULT</toPriceList>
 			</priceListCase>
 		</priceList>
-	</rules>
+	</rules> 
+	
+	<overdueRules> 
+       <bundleOverdueStates>
+	       <state name="ClearBundles">
+               <isClearState>true</isClearState>
+           </state> 
+	   </bundleOverdueStates>
+	</overdueRules>
 
 	<plans>
 		<plan name="pistol-monthly">
diff --git a/catalog/src/test/resources/WeaponsHireSmall.xml b/catalog/src/test/resources/WeaponsHireSmall.xml
index 21a9f08..2c363c0 100644
--- a/catalog/src/test/resources/WeaponsHireSmall.xml
+++ b/catalog/src/test/resources/WeaponsHireSmall.xml
@@ -70,6 +70,15 @@
             </createAlignmentCase>
         </createAlignment>
 	</rules>
+	
+	 <overdueRules>
+        <bundleOverdueStates>
+           <state name="ClearBundle">
+               <isClearState>true</isClearState>
+           </state>
+       </bundleOverdueStates>
+    </overdueRules>
+	
 
 	<plans>
 		<plan name="pistol-monthly">
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
index 6cbc05f..92b6654 100644
--- 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
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.api.billing;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,6 +32,7 @@ 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.SubscriptionTransition;
@@ -42,11 +42,13 @@ 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) {
+	public BillCycleDayCalculator(final CatalogService catalogService, final EntitlementUserApi entitlementApi) {
 		super();
 		this.catalogService = catalogService;
+		this.entitlementApi = entitlementApi;
 	}
 
 	protected int calculateBcd(SubscriptionBundle bundle, Subscription subscription, final SubscriptionTransition transition, final Account account) throws CatalogApiException, AccountApiException {
@@ -69,16 +71,16 @@ public class BillCycleDayCalculator {
 						switch (alignment) {
 						case ACCOUNT :
 							result = account.getBillCycleDay();
-
 							if(result == 0) {
 								result = calculateBcdFromSubscription(subscription, plan, account);
 							}
 							break;
 						case BUNDLE :
-							result = bundle.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
+						    Subscription baseSub = entitlementApi.getBaseSubscription(bundle.getId());
+							result = calculateBcdFromSubscription(baseSub, plan, account);
 							break;
 						case SUBSCRIPTION :
-							result = subscription.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
+							result = calculateBcdFromSubscription(subscription, plan, account);
 							break;
 						}
 						if(result == -1) {
@@ -89,26 +91,8 @@ public class BillCycleDayCalculator {
 	}
 
 	private int calculateBcdFromSubscription(Subscription subscription, Plan plan, Account account) 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);
-		}
-		return result;
-	}
-
-	private int billCycleDay(DateTime requestedDate, DateTimeZone timeZone, 
-			Plan plan) throws CatalogApiException {
-
-		DateTime date = plan.dateOfFirstRecurringNonZeroCharge(requestedDate);
-		return date.toDateTime(timeZone).getDayOfMonth();
-
+		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 2a4d8ec..b3ada17 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.SubscriptionTransition;
 import com.ning.billing.entitlement.api.user.SubscriptionTransition.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(SubscriptionTransition transition, Subscription subscription, int billCycleDay, Currency currency) throws CatalogApiException {
+    public DefaultBillingEvent(Account account, SubscriptionTransition 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 32d01b9..1fd595c 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
@@ -71,7 +71,6 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
         for (final SubscriptionBundle bundle: bundles) {
         	List<Subscription> subscriptions = entitlementDao.getSubscriptions(bundle.getId());
-
         	for (final Subscription subscription: subscriptions) {
         		for (final SubscriptionTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
         			try {
@@ -82,10 +81,8 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         			        modifiedData.setBillCycleDay(bcd);
                             accountApi.updateAccount(account.getExternalKey(), modifiedData, context);
         			    }
-        			    
-
 
-        				BillingEvent event = new DefaultBillingEvent(transition, subscription, bcd, account.getCurrency());
+        				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: " +
@@ -96,6 +93,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         		}
         	}
         }
+              
         return result;
     }
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java
new file mode 100644
index 0000000..f68e2c9
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/OverdueEventCalculator.java
@@ -0,0 +1,283 @@
+/*
+ * 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 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.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.overdue.OverdueState;
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.entitlement.exceptions.EntitlementError;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
+
+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 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 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) {
+        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/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
new file mode 100644
index 0000000..440173f
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/overdue/DefaultOverdueChecker.java
@@ -0,0 +1,59 @@
+/*
+ * 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.catalog.api.overdue.OverdueState;
+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.entitlement.engine.dao.EntitlementDao;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+
+public class DefaultOverdueChecker implements OverdueChecker {
+
+    private final EntitlementDao dao;
+    private final CatalogService catalogService;
+    private final OverdueAccessApi overdueApi;
+
+    @Inject
+    public DefaultOverdueChecker(EntitlementDao dao, CatalogService catalogService, OverdueAccessApi overdueApi) {
+        this.catalogService = catalogService;
+        this.dao = dao;
+        this.overdueApi = overdueApi;
+    }
+
+    @Override
+    public void checkBlocked(Subscription subscription) throws EntitlementUserApiException {
+        if(subscription.getBundleId() != null) {
+            SubscriptionBundle bundle = dao.getSubscriptionBundleFromId(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/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 20bad8d..a664327 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
@@ -31,7 +31,7 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
-import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
@@ -45,17 +45,19 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     private final EntitlementDao dao;
     private final CatalogService catalogService;
     private final SubscriptionApiService apiService;
+    private final OverdueChecker overdueChecker;
     private final AddonUtils addonUtils;
 
     @Inject
     public DefaultEntitlementUserApi(Clock clock, EntitlementDao dao, CatalogService catalogService,
-            SubscriptionApiService apiService, AddonUtils addonUtils) {
+            SubscriptionApiService apiService, AddonUtils addonUtils, OverdueChecker overdueChecker) {
         super();
         this.clock = clock;
         this.apiService = apiService;
         this.dao = dao;
         this.catalogService = catalogService;
         this.addonUtils = addonUtils;
+        this.overdueChecker = overdueChecker;
     }
 
     @Override
@@ -89,16 +91,15 @@ public class DefaultEntitlementUserApi implements EntitlementUserApi {
     }
 
     @Override
+    public Subscription getBaseSubscription(UUID bundleId) {
+        return dao.getBaseSubscription(bundleId);
+    }
+    
+    @Override
     public SubscriptionBundle createBundleForAccount(UUID accountId, String bundleName)
             throws EntitlementUserApiException {
-        OverdueState<SubscriptionBundle> clearState;
-        try {
-            clearState = catalogService.getCurrentCatalog().currentBundleOverdueStateSet().findClearState();
-            SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId);
-            return dao.createSubscriptionBundle(bundle);
-        } catch (CatalogApiException e) {
-            throw new EntitlementUserApiException(e);
-        }
+        SubscriptionBundleData bundle = new SubscriptionBundleData(bundleName, accountId);
+        return dao.createSubscriptionBundle(bundle);
     }
 
     @Override
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 096914c..4a3dcfb 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,26 +16,46 @@
 
 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.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionFactory.SubscriptionBuilder;
 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 {
 
@@ -43,26 +63,34 @@ public class SubscriptionApiService {
     private final EntitlementDao dao;
     private final CatalogService catalogService;
     private final PlanAligner planAligner;
+    private final OverdueChecker overdueChecker;
 
     @Inject
-    public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner) {
+    public SubscriptionApiService(Clock clock, EntitlementDao dao, CatalogService catalogService, PlanAligner planAligner, OverdueChecker overdueChecker) {
         this.clock = clock;
         this.catalogService = catalogService;
         this.planAligner = planAligner;
         this.dao = dao;
+        this.overdueChecker = overdueChecker;
     }
 
     public SubscriptionData createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
             String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate)
         throws EntitlementUserApiException {
-
+        
         SubscriptionData subscription = new SubscriptionData(builder, this, clock);
+
+        overdueChecker.checkBlocked(subscription);
+
+        
         createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false);
         return subscription;
     }
 
     public void recreatePlan(SubscriptionData subscription, PlanPhaseSpecifier spec, DateTime requestedDate)
         throws EntitlementUserApiException {
+        
+        overdueChecker.checkBlocked(subscription);
 
         SubscriptionState currentState = subscription.getState();
         if (currentState != SubscriptionState.CANCELLED) {
@@ -95,6 +123,8 @@ public class SubscriptionApiService {
             String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate, boolean reCreate)
         throws EntitlementUserApiException {
 
+        overdueChecker.checkBlocked(subscription);
+
         try {
             TimedPhase [] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate);
 
@@ -207,6 +237,8 @@ public class SubscriptionApiService {
     public void changePlan(SubscriptionData subscription, String productName, BillingPeriod term,
             String priceList, DateTime requestedDate)
         throws EntitlementUserApiException {
+        
+        overdueChecker.checkBlocked(subscription);
 
         try {
 
@@ -279,6 +311,7 @@ public class SubscriptionApiService {
         }
     }
 
+
     public void commitCustomFields(SubscriptionData subscription, CallContext context) {
         dao.saveCustomFields(subscription, context);
     }
@@ -296,4 +329,6 @@ public class SubscriptionApiService {
                     requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
         }
     }
+    
+
 }
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 8fc1eef..01c33f7 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
@@ -27,8 +27,8 @@ import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.migration.DefaultEntitlementMigrationApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
-import com.ning.billing.entitlement.api.overdue.DefaultEntitlementOverdueApi;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+import com.ning.billing.entitlement.api.overdue.DefaultOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.SubscriptionApiService;
@@ -46,6 +46,10 @@ public class EntitlementModule extends AbstractModule {
     protected void installEntitlementDao() {
         bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
     }
+    
+    protected void installOverdueChecker() {
+        bind(OverdueChecker.class).to(DefaultOverdueChecker.class).asEagerSingleton();       
+    }
 
     protected void installEntitlementCore() {
         bind(SubscriptionApiService.class).asEagerSingleton();
@@ -57,7 +61,6 @@ public class EntitlementModule extends AbstractModule {
         bind(EntitlementUserApi.class).to(DefaultEntitlementUserApi.class).asEagerSingleton();
         bind(EntitlementBillingApi.class).to(DefaultEntitlementBillingApi.class).asEagerSingleton();
         bind(EntitlementMigrationApi.class).to(DefaultEntitlementMigrationApi.class).asEagerSingleton();
-        bind(EntitlementOverdueApi.class).to(DefaultEntitlementOverdueApi.class).asEagerSingleton();
     }
 
     @Override
@@ -65,5 +68,6 @@ public class EntitlementModule extends AbstractModule {
         installConfig();
         installEntitlementDao();
         installEntitlementCore();
+        installOverdueChecker();
     }
 }
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 7209239..9a5af34 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 c754b2c..c514164 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
@@ -47,6 +47,7 @@ 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;
@@ -80,7 +81,6 @@ public class TestDefaultEntitlementBillingApi {
 
 	private Clock clock;
 	private SubscriptionData subscription;
-    private CallContextFactory factory;
 	private DateTime subscriptionStartDate;
 
 	@BeforeSuite(alwaysRun=true)
@@ -90,7 +90,6 @@ public class TestDefaultEntitlementBillingApi {
 
         catalogService = g.getInstance(CatalogService.class);
         clock = g.getInstance(Clock.class);
-        factory = g.getInstance(CallContextFactory.class);
 
         ((DefaultCatalogService)catalogService).loadCatalog();
 	}
@@ -135,10 +134,12 @@ 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);
 
-        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
 		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
 		SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -163,7 +164,9 @@ public class TestDefaultEntitlementBillingApi {
         ((ZombieControl)account).addResult("getCurrency", Currency.USD);
         ((ZombieControl)accountApi).addResult("getAccountById", account);
 		       
-        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
         DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
         SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -189,7 +192,10 @@ public class TestDefaultEntitlementBillingApi {
 
 		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
 		((ZombieControl)accountApi).addResult("getAccountById", account);
-        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+
+		EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
         DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
         SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -214,7 +220,9 @@ public class TestDefaultEntitlementBillingApi {
         ((ZombieControl)account).addResult("getCurrency", Currency.USD);
         ((ZombieControl)accountApi).addResult("getAccountById", account);
 
-        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+        EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
         CallContextFactory factory = new DefaultCallContextFactory(clock);
         DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(factory, dao, accountApi, bcdCalculator);
         SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
@@ -237,14 +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);
-        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService);
+        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, dao, accountApi, bcdCalculator);
         SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
 
-		checkFirstEvent(events, nextPlan, bundles.get(0).getStartDate().getDayOfMonth(), oneId, now, nextPhase, ApiEventType.CREATE.toString());
+		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..06d2ae1
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestOverdueEventCalculator.java
@@ -0,0 +1,771 @@
+/*
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+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 org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.MockPlan;
+import com.ning.billing.catalog.MockPlanPhase;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.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.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
+import com.ning.billing.catalog.overdue.DefaultOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.MockOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueStatesBundle;
+import com.ning.billing.catalog.overdue.OverdueRules;
+import com.ning.billing.catalog.overdue.OverdueStatesBundle;
+import com.ning.billing.entitlement.api.billing.OverdueEventCalculator.DisabledDuration;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+public class TestOverdueEventCalculator {
+
+    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/TestMigrationMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
index 6ea53bc..c7e155d 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationMemory.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 @Test(groups = "fast")
 public class TestMigrationMemory extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
index 587ca46..67b0371 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 @Test(groups = "slow")
 public class TestMigrationSql extends TestMigration {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
new file mode 100644
index 0000000..e9fbc85
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/overdue/TestOverdueChecker.java
@@ -0,0 +1,197 @@
+/*
+ * 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 java.util.UUID;
+
+import junit.framework.Assert;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.catalog.overdue.DefaultOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueRules;
+import com.ning.billing.catalog.overdue.MockOverdueState;
+import com.ning.billing.catalog.overdue.MockOverdueStatesBundle;
+import com.ning.billing.catalog.overdue.OverdueRules;
+import com.ning.billing.catalog.overdue.OverdueStatesBundle;
+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.entitlement.engine.dao.EntitlementDao;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+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/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestApiBase.java
index 59121c9..a770b4d 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
@@ -72,6 +72,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;
 
@@ -184,7 +185,7 @@ public abstract class TestApiBase {
     }
 
     @BeforeMethod(alwaysRun = true)
-    public void setupTest() {
+    public void setupTest() throws Exception {
 
         log.warn("RESET TEST FRAMEWORK\n\n");
 
@@ -192,13 +193,10 @@ public abstract class TestApiBase {
 
         clock.resetDeltaFromReality();
         ((MockEntitlementDao) dao).reset();
-        try {
-            busService.getBus().register(testListener);
-            UUID accountId = UUID.randomUUID();
-            bundle = entitlementApi.createBundleForAccount(accountId, "myDefaultBundle");
-        } catch (Exception e) {
-            Assert.fail(e.getMessage());
-        }
+
+        busService.getBus().register(testListener);
+        UUID accountId = UUID.randomUUID();
+        bundle = entitlementApi.createBundleForAccount(accountId, "myDefaultBundle");
         assertNotNull(bundle);
 
         ((Engine)entitlementService).start();
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 7db938e..4043254 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
@@ -43,6 +43,7 @@ import com.ning.billing.entitlement.api.ApiTestListener.NextEvent;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionTransition.SubscriptionTransitionType;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
 
 public class TestUserApiAddOn 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 fec3550..b21b16d 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
@@ -21,6 +21,8 @@ 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 com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 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..bdf02e7 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
@@ -21,6 +21,8 @@ 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 com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 import org.testng.annotations.Test;
 
 public class TestUserApiCancelSql extends TestUserApiCancel {
@@ -34,7 +36,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/TestUserApiChangePlanMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlanMemory.java
index ab76734..0359d8c 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
@@ -21,6 +21,8 @@ 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 com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 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..0396f35 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
@@ -21,6 +21,8 @@ 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 com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 import org.testng.annotations.Test;
 
 public class TestUserApiChangePlanSql extends TestUserApiChangePlan {
@@ -33,7 +35,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/TestUserApiCreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCreateMemory.java
index 047ca67..b88ed86 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
@@ -20,6 +20,8 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 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..e5dcc11 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
@@ -20,6 +20,8 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
+
 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 472e7c0..ab60304 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
@@ -190,7 +190,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 7442298..e18b8cd 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
@@ -27,6 +27,7 @@ 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.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 import org.testng.Assert;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
index b6f97c1..fc7de36 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateMemory.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 public class TestUserApiRecreateMemory extends TestUserApiRecreate {
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
index 2c1db68..0202753 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiRecreateSql.java
@@ -22,6 +22,7 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.entitlement.glue.MockEngineModuleSql;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 
 public class TestUserApiRecreateSql extends TestUserApiRecreate {
 
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 f69b36a..81125db 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
@@ -28,6 +28,7 @@ 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.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 import org.testng.Assert;
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 f6881fd..c7ef8ad 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
@@ -21,6 +21,7 @@ import java.util.List;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
@@ -51,7 +52,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/glue/MockEngineModule.java b/entitlement/src/test/java/com/ning/billing/entitlement/glue/MockEngineModule.java
index acb1a2a..9b5a593 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
@@ -18,13 +18,21 @@ package com.ning.billing.entitlement.glue;
 
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.catalog.glue.CatalogModule;
+import com.ning.billing.entitlement.api.overdue.MockOverdueChecker;
+import com.ning.billing.entitlement.api.overdue.OverdueChecker;
 import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 import com.ning.billing.util.clock.MockClockModule;
 import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.glue.CallContextModule;
 
 public class MockEngineModule extends EntitlementModule {
 
+    
+    protected void installOverdueChecker() {
+        bind(OverdueChecker.class).to(MockOverdueChecker.class).asEagerSingleton();       
+    }
+
     @Override
     protected void configure() {
         super.configure();
@@ -33,5 +41,6 @@ public class MockEngineModule extends EntitlementModule {
         bind(AccountUserApi.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class));
         install(new MockClockModule());
         install(new CallContextModule());
+        install(new MockOverdueAccessModule());
     }
 }
diff --git a/entitlement/src/test/resources/testInput.xml b/entitlement/src/test/resources/testInput.xml
index 8a97d57..6d761e0 100644
--- a/entitlement/src/test/resources/testInput.xml
+++ b/entitlement/src/test/resources/testInput.xml
@@ -171,6 +171,14 @@ Use Cases to do:
 		</priceList>
 	</rules>
 
+    <overdueRules> 
+      <bundleOverdueStates>
+           <state name="Clear">
+               <isClearState>true</isClearState>
+           </state> 
+       </bundleOverdueStates>
+    </overdueRules>
+
 	<plans>
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
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 60c36de..71be8c5 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
@@ -179,7 +179,7 @@ public class TestDefaultInvoiceMigrationApi {
 		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));
 
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 33a1c6a..2caa37f 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
@@ -410,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);
 
@@ -428,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);
@@ -461,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();
@@ -494,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();
@@ -510,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);
@@ -554,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);
@@ -562,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);
@@ -601,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);
@@ -613,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);
@@ -639,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);
@@ -670,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/MockModule.java b/invoice/src/test/java/com/ning/billing/invoice/MockModule.java
index 99f12b4..f3d5aaf 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,8 @@
 
 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 java.util.UUID;
+
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.jdbi.v2.IDBI;
 
@@ -29,14 +27,22 @@ 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.entitlement.api.overdue.OverdueChecker;
+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.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 +80,27 @@ public class MockModule extends AbstractModule {
     }
     
     protected void installEntitlementModule() {
-    	install(new EntitlementModule());
+        install(new EntitlementModule() {
+
+            @Override
+            protected void installOverdueChecker() {
+                bind(OverdueChecker.class).toInstance(new OverdueChecker() {
+
+                    @Override
+                    public void checkBlocked(Subscription subscription)
+                            throws EntitlementUserApiException {
+                    }
+
+                    @Override
+                    public void checkBlocked(SubscriptionBundle bundle)
+                            throws EntitlementUserApiException {
+                     }
+
+                            
+                });
+            }
+            
+        });
     }
 
     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 adc78b7..c75395f 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;
@@ -52,30 +35,51 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-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.overdue.OverdueChecker;
+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.mock.overdue.MockOverdueAccessModule;
 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;
@@ -115,9 +119,10 @@ public class TestNextBillingDateNotifier {
 	@BeforeClass(groups={"slow"})
 	public void setup() throws ServiceException, IOException, ClassNotFoundException, SQLException {
 		//TestApiBase.loadSystemPropertiesFromClasspath("/entitlement.properties");
-        final Injector g = Guice.createInjector(Stage.PRODUCTION,  new AbstractModule() {
-			@Override
+        final Injector g = Guice.createInjector(Stage.PRODUCTION,  new MockOverdueAccessModule() {
+			
             protected void configure() {
+                super.configure();
                 bind(Clock.class).to(ClockMock.class).asEagerSingleton();
                 bind(CallContextFactory.class).to(DefaultCallContextFactory.class).asEagerSingleton();
                 bind(Bus.class).to(InMemoryBus.class).asEagerSingleton();
@@ -140,6 +145,16 @@ 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(OverdueChecker.class).toInstance(new OverdueChecker() {
+
+                    @Override
+                    public void checkBlocked(Subscription subscription){}
+
+                    @Override
+                    public void checkBlocked(SubscriptionBundle bundle){}
+                                           
+                });
 			}
         });
 
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 4f5f991..2e57eea 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,25 +51,27 @@ import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionTransition.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;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.mock.overdue.MockOverdueAccessModule;
 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")
-@Guice(modules = {MockModule.class})
+@Guice(modules = {MockModule.class, MockOverdueAccessModule.class})
 public class TestInvoiceDispatcher {
 	private Logger log = LoggerFactory.getLogger(TestInvoiceDispatcher.class);
 
 	@Inject
-	private InvoiceUserApi invoiceUserApi;
-
-	@Inject
 	private InvoiceGenerator generator;
 
 	@Inject
@@ -149,7 +146,7 @@ public class TestInvoiceDispatcher {
 		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));
 
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 6e6b9b3..f09a520 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(),

overdue/pom.xml 7(+6 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 0f5a57d..44f3149 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -44,7 +44,6 @@
          <dependency>
             <groupId>org.jdbi</groupId>
             <artifactId>jdbi</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.testng</groupId>
@@ -88,6 +87,12 @@
             <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>
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
index 1323e55..e9d3f77 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/applicator/OverdueStateApplicator.java
@@ -20,6 +20,8 @@ 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.catalog.api.overdue.OverdueError;
 import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.overdue.dao.OverdueDao;
@@ -38,7 +40,7 @@ public class OverdueStateApplicator<T extends Overdueable>{
         this.clock = clock;
     }
 
-    public void apply(T overdueable, OverdueState<T> previousOverdueState, OverdueState<T> nextOverdueState, DateTime timeOfNextCheck) {
+    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
         }
@@ -57,11 +59,15 @@ public class OverdueStateApplicator<T extends Overdueable>{
         throw new NotImplementedException();
     }
 
- 
-    protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) {
-       overdueDao.setOverdueState(overdueable, nextOverdueState, clock);
+
+    protected void storeNewState(T overdueable, OverdueState<T> nextOverdueState) throws OverdueError {
+        try {
+            overdueDao.setOverdueState(overdueable, nextOverdueState, Overdueable.Type.get(overdueable), clock);
+        } 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
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
index cbd9219..6705c30 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/calculator/BillingStateCalculatorBundle.java
@@ -30,7 +30,7 @@ import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.overdue.BillingStateBundle;
 import com.ning.billing.catalog.api.overdue.PaymentResponse;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+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;
@@ -41,10 +41,10 @@ import com.ning.billing.util.tag.Tag;
 
 public class BillingStateCalculatorBundle  extends BillingStateCalculator<SubscriptionBundle>{
 
-    private EntitlementOverdueApi entitlementApi;
+    private EntitlementUserApi entitlementApi;
 
     @Inject 
-    public BillingStateCalculatorBundle(EntitlementOverdueApi entitlementApi, InvoiceUserApi invoiceApi, Clock clock) {
+    public BillingStateCalculatorBundle(EntitlementUserApi entitlementApi, InvoiceUserApi invoiceApi, Clock clock) {
         super(invoiceApi, clock);
         this.entitlementApi = entitlementApi;
     }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
index fe69e34..278fe59 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueDao.java
@@ -22,6 +22,6 @@ import com.ning.billing.util.clock.Clock;
 
 public interface OverdueDao {
 
-    <T extends Overdueable> void  setOverdueState(T overdueable, OverdueState<T> newOverdueState, Clock clock);
+    <T extends Overdueable> void  setOverdueState(T overdueable, OverdueState<T> newOverdueState, Overdueable.Type type, Clock clock);
 
 }
\ No newline at end of file
diff --git a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
index bd77283..18a2814 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/dao/OverdueSqlDao.java
@@ -20,21 +20,25 @@ import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.Binder;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 
 import com.ning.billing.catalog.api.overdue.OverdueState;
 import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.entity.BinderBase;
 
 @ExternalizedSqlViaStringTemplate3()
-public interface OverdueSqlDao extends OverdueDao {
+public interface OverdueSqlDao extends OverdueDao, 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) ;
 
     public static class OverdueableBinder extends BinderBase implements Binder<Bind, Overdueable> {
@@ -43,6 +47,7 @@ public interface OverdueSqlDao extends OverdueDao {
             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) {
@@ -50,10 +55,19 @@ public interface OverdueSqlDao extends OverdueDao {
         }
     }
     
+    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());
+            stmt.bind("created_date", clock.getUTCNow().toDate());
         }
         
     }
diff --git a/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg b/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
index 229a6a7..a081e92 100644
--- a/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
+++ b/overdue/src/main/resources/com/ning/billing/overdue/dao/OverdueSqlDao.sql.stg
@@ -1,13 +1,15 @@
 group OverdueSqlDao;
 
-setOverdueStateForBundle() ::= <<
+setOverdueState() ::= <<
     insert into overdue_states (
         id
       , state
+      , type
       , created_date
     ) values (
         :id
       , :state
-      , NOW() 
+      , :type
+      , :created_date 
     );
 >>
\ No newline at end of file
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
index f04575c..6374ce1 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/calculator/TestBillingStateCalculatorBundle.java
@@ -32,7 +32,7 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.overdue.BillingStateBundle;
 import com.ning.billing.catalog.api.overdue.PaymentResponse;
-import com.ning.billing.entitlement.api.overdue.EntitlementOverdueApi;
+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;
@@ -72,7 +72,7 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
        
        Clock clock = new ClockMock();
        InvoiceUserApi invoiceApi = BrainDeadProxyFactory.createBrainDeadProxyFor(InvoiceUserApi.class);
-       EntitlementOverdueApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementOverdueApi.class);
+       EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
        ((ZombieControl)invoiceApi).addResult("getUnpaidInvoicesByAccountId", invoices);
        
        
@@ -107,7 +107,7 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
        ((ZombieControl)bundle).addResult("getId", thisBundleId);
        ((ZombieControl)bundle).addResult("getAccountId", UUID.randomUUID());
        
-       EntitlementOverdueApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementOverdueApi.class);
+       EntitlementUserApi entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
        Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
        ((ZombieControl)entitlementApi).addResult("getBaseSubscription",subscription);
        
@@ -131,9 +131,6 @@ public class TestBillingStateCalculatorBundle extends TestBillingStateCalculator
        Assert.assertEquals(state.getBasePlanPriceList(), pricelist);
        Assert.assertEquals(state.getBasePlanProduct(), plan.getProduct());
        
-       
-       
-       
     }
     
     
diff --git a/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java b/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
index c0efba2..41a8ab0 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/dao/TestOverdueDao.java
@@ -17,10 +17,10 @@
 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.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -29,9 +29,9 @@ import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
-import com.ning.billing.catalog.api.Duration;
-import com.ning.billing.catalog.api.TimeUnit;
+import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.overdue.OverdueState;
+import com.ning.billing.catalog.api.overdue.Overdueable;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.mock.BrainDeadProxyFactory;
@@ -39,6 +39,7 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.overdue.glue.OverdueModule;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.glue.OverdueAccessModule;
+import com.ning.billing.util.overdue.OverdueEvent;
 import com.ning.billing.util.overdue.dao.OverdueAccessDao;
 
 @Guice(modules = {MockModule.class, OverdueModule.class, OverdueAccessModule.class})
@@ -78,15 +79,48 @@ public class TestOverdueDao {
         OverdueState<SubscriptionBundle> state = BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueState.class);
         ((ZombieControl)state).addResult("getName", overdueStateName);
         
-        dao.setOverdueState(bundle, state, clock);
+        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, clock);
+        dao.setOverdueState(bundle, state, Overdueable.Type.SUBSCRIPTION_BUNDLE, clock);
         
-        Assert.assertEquals(accessDao.getOverdueStateNameFor(bundle), overdueStateName2);
+        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/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
index 6327dc5..ac61a4d 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessDao.java
@@ -16,10 +16,22 @@
 
 package com.ning.billing.util.overdue.dao;
 
+import java.util.SortedSet;
+import java.util.UUID;
+
 import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
+import com.ning.billing.util.overdue.OverdueEvent;
 
 
 public interface OverdueAccessDao {
 
-    public String getOverdueStateNameFor(Overdueable overdueable);
+    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);
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
index b6e0426..8dfd32b 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.java
@@ -18,7 +18,10 @@ package com.ning.billing.util.overdue.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;
@@ -31,10 +34,13 @@ 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.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
 import com.ning.billing.util.entity.BinderBase;
 import com.ning.billing.util.entity.MapperBase;
 import com.ning.billing.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.OverdueEvent;
 
 @ExternalizedSqlViaStringTemplate3()
 public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>, CloseMe, Transmogrifier, OverdueAccessDao {
@@ -42,7 +48,45 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
     @Override
     @SqlQuery
     @Mapper(OverdueStateSqlMapper.class)
-    public abstract String getOverdueStateNameFor(@Bind(binder = OverdueableBinder.class)Overdueable overdueable) ;
+    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> {
 
@@ -53,6 +97,15 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
         }
     }
     
+    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) {
@@ -60,4 +113,14 @@ public interface OverdueAccessSqlDao extends Transactional<OverdueAccessSqlDao>,
         }
     }
    
+    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());
+        }
+
+    }
+
+
 }
diff --git a/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java b/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
index 67d6948..d104a44 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/DefaultOverdueAcessApi.java
@@ -16,15 +16,12 @@
 
 package com.ning.billing.util.overdue;
 
+import java.util.SortedSet;
+import java.util.UUID;
+
 import com.google.inject.Inject;
-import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
-import com.ning.billing.catalog.api.overdue.OverdueStateSet;
 import com.ning.billing.catalog.api.overdue.Overdueable;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.catalog.api.overdue.Overdueable.Type;
 import com.ning.billing.util.overdue.dao.OverdueAccessDao;
 
 public class DefaultOverdueAcessApi implements OverdueAccessApi {
@@ -37,7 +34,23 @@ public class DefaultOverdueAcessApi implements OverdueAccessApi {
     
     @Override
     public String getOverdueStateNameFor(Overdueable overdueable) {
-        return dao.getOverdueStateNameFor(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);
     }
 
 }
diff --git a/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java b/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
index 5fd9c0d..3978c7e 100644
--- a/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
+++ b/util/src/main/java/com/ning/billing/util/overdue/OverdueAccessApi.java
@@ -16,9 +16,9 @@
 
 package com.ning.billing.util.overdue;
 
-import com.ning.billing.catalog.api.StaticCatalog;
-import com.ning.billing.catalog.api.overdue.OverdueError;
-import com.ning.billing.catalog.api.overdue.OverdueState;
+import java.util.SortedSet;
+import java.util.UUID;
+
 import com.ning.billing.catalog.api.overdue.Overdueable;
 
 public interface OverdueAccessApi {
@@ -26,5 +26,10 @@ public interface OverdueAccessApi {
 
     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);
 
 }
diff --git a/util/src/main/java/com/ning/billing/util/overdue/OverdueEvent.java b/util/src/main/java/com/ning/billing/util/overdue/OverdueEvent.java
new file mode 100644
index 0000000..645fad0
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/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.util.overdue;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+
+import com.ning.billing.catalog.api.overdue.Overdueable;
+import com.ning.billing.catalog.api.overdue.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/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index 2bce344..b40e5a4 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -122,6 +122,7 @@ 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);
diff --git a/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
index 606a4d0..81a38aa 100644
--- a/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/overdue/dao/OverdueAccessSqlDao.sql.stg
@@ -1,13 +1,54 @@
 group OverdueAccessSqlDao;
 
-getOverdueStateNameFor() ::= <<
+getOverdueStateFor() ::= <<
     select
         id
       , state
+      , type
       , created_date   
     from overdue_states
-    where id = :id
+    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
+    ;
 >>
\ No newline at end of file
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 9cfbe9f..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,7 +74,9 @@ public class BrainDeadProxyFactory {
                     		throw ((Throwable) result);
                     	}
                         return result;
-                    }  else {
+                    } 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/mock/overdue/MockOverdueAccessModule.java b/util/src/test/java/com/ning/billing/mock/overdue/MockOverdueAccessModule.java
new file mode 100644
index 0000000..a5add78
--- /dev/null
+++ b/util/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.util.overdue.OverdueAccessApi;
+import com.ning.billing.util.overdue.dao.OverdueAccessDao;
+
+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(OverdueAccessDao.class).toInstance(BrainDeadProxyFactory.createBrainDeadProxyFor(OverdueAccessDao.class));
+        bind(OverdueAccessApi.class).toInstance(overdueAccessApi);
+    }
+}