killbill-aplcache

Changes

Details

diff --git a/entitlement/killbill-entitlement.iml b/entitlement/killbill-entitlement.iml
index b72ca26..f6d9154 100644
--- a/entitlement/killbill-entitlement.iml
+++ b/entitlement/killbill-entitlement.iml
@@ -19,6 +19,11 @@
     <orderEntry type="library" scope="PROVIDED" name="Maven: javax.inject:javax.inject:1" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: aopalliance:aopalliance:1.0" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.h2database:h2:1.3.158" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: com.jayway.awaitility:awaitility:1.3.3" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: cglib:cglib-nodep:2.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:1.2" level="project" />
     <orderEntry type="module" module-name="killbill-account" />
     <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.1.0" level="project" />
     <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.1.0" level="project" />
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index fd23f09..0bc0275 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -50,6 +50,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>com.jayway.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>com.ning.billing</groupId>
             <artifactId>killbill-account</artifactId>
         </dependency>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
index f17d56b..4e270a0 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlement.java
@@ -22,8 +22,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.BillingActionPolicy;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Plan;
@@ -32,44 +31,48 @@ import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.EntitlementService;
 import com.ning.billing.entitlement.block.BlockingChecker;
+import com.ning.billing.entitlement.dao.BlockingStateDao;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.entity.EntityBase;
-import com.ning.billing.util.svcapi.account.AccountInternalApi;
-import com.ning.billing.util.timezone.DateAndTimeZoneContext;
+import com.ning.billing.util.svcapi.junction.DefaultBlockingState;
 
 public class DefaultEntitlement extends EntityBase implements Entitlement {
 
-    private final AccountInternalApi accountApi;
+    private final EntitlementDateHelper dateHelper;
     private final SubscriptionBase subscriptionBase;
     private final InternalCallContextFactory internalCallContextFactory;
     private final Clock clock;
-    private final boolean isBlocked;
+    private final EntitlementState state;
     private final BlockingState entitlementBlockingState;
     private final BlockingChecker checker;
     private final UUID accountId;
     private final String externalKey;
     private final DateTimeZone accountTimeZone;
+    private final BlockingStateDao blockingStateDao;
 
-    public DefaultEntitlement(final AccountInternalApi accountApi, final SubscriptionBase subscriptionBase, final UUID accountId,
-                              final String externalKey, final boolean isBlocked, final BlockingState entitlementBlockingState, final DateTimeZone accountTimeZone,
+    public DefaultEntitlement(final EntitlementDateHelper dateHelper, final SubscriptionBase subscriptionBase, final UUID accountId,
+                              final String externalKey, final EntitlementState state, final BlockingState entitlementBlockingState, final DateTimeZone accountTimeZone,
                               final InternalCallContextFactory internalCallContextFactory,
+                              final BlockingStateDao blockingStateDao,
                               final Clock clock, final BlockingChecker checker) {
         super(subscriptionBase.getId(), subscriptionBase.getCreatedDate(), subscriptionBase.getUpdatedDate());
-        this.accountApi = accountApi;
+        this.dateHelper = dateHelper;
         this.subscriptionBase = subscriptionBase;
         this.accountId = accountId;
         this.externalKey = externalKey;
-        this.isBlocked = isBlocked;
+        this.state = state;
         this.entitlementBlockingState = entitlementBlockingState;
         this.accountTimeZone = accountTimeZone;
         this.internalCallContextFactory = internalCallContextFactory;
         this.clock = clock;
         this.checker = checker;
+        this.blockingStateDao = blockingStateDao;
     }
 
     // STEPH_ENT should be remove but beatrix tests need to be changed
@@ -99,7 +102,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public EntitlementState getState() {
-        return isBlocked ? EntitlementState.BLOCKED : subscriptionBase.getState();
+        return state;
     }
 
     @Override
@@ -115,9 +118,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
     @Override
     public LocalDate getEffectiveEndDate() {
         if (entitlementBlockingState != null && entitlementBlockingState.getStateName().equals(DefaultEntitlementApi.ENT_STATE_CANCELLED)) {
-            return new LocalDate(entitlementBlockingState.getCreatedDate(), accountTimeZone);
+            return new LocalDate(entitlementBlockingState.getEffectiveDate(), accountTimeZone);
         }
-        return subscriptionBase.getEndDate() != null ? new LocalDate(subscriptionBase.getEndDate(), accountTimeZone) : null;
+        return null;
+        //return subscriptionBase.getEndDate() != null ? new LocalDate(subscriptionBase.getEndDate(), accountTimeZone) : null;
     }
 
     @Override
@@ -173,12 +177,23 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
 
     @Override
-    public boolean cancelEntitlementWithDate(final LocalDate localDate, final CallContext callContext) throws EntitlementApiException {
+    public boolean cancelEntitlementWithPolicy(final EntitlementActionPolicy entitlementPolicy, final CallContext callContext) throws EntitlementApiException {
+        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy);
+        return cancelEntitlementWithDate(cancellationDate, callContext);
+    }
 
-        final InternalCallContext context = internalCallContextFactory.createInternalCallContext(accountId, callContext);
-        final DateTime requestedDate = fromLocalDateAndReferenceTime(localDate, subscriptionBase.getStartDate(), clock, context);
+    @Override
+    public boolean cancelEntitlementWithDate(final LocalDate localCancelDate, final CallContext callContext) throws EntitlementApiException {
+
+        if (state == EntitlementState.CANCELLED) {
+            throw new EntitlementApiException(ErrorCode.SUB_CANCEL_BAD_STATE, getId(), EntitlementState.CANCELLED);
+        }
+        final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
+        final DateTime effectiveCancelDate = dateHelper.fromLocalDateAndReferenceTime(localCancelDate, subscriptionBase.getStartDate(), contextWithValidAccountRecordId);
         try {
-            return subscriptionBase.cancel(requestedDate, callContext);
+            subscriptionBase.cancel(null, callContext);
+            blockingStateDao.setBlockingState(new DefaultBlockingState(getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_CANCELLED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, false, effectiveCancelDate), clock, contextWithValidAccountRecordId);
+            return localCancelDate.compareTo(new LocalDate(clock.getUTCNow())) <= 0;
         } catch (SubscriptionBaseApiException e) {
             throw new EntitlementApiException(e);
         }
@@ -186,20 +201,45 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
 
     @Override
-    public boolean cancelEntitlementWithPolicy(final EntitlementActionPolicy entitlementPolicy, final CallContext callContext) throws EntitlementApiException {
-        return false;
+    public boolean cancelEntitlementWithPolicyOverrideBillingPolicy(final EntitlementActionPolicy entitlementPolicy, final BillingActionPolicy billingPolicy, final CallContext callContext) throws EntitlementApiException {
+        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy);
+        return cancelEntitlementWithDateOverrideBillingPolicy(cancellationDate, billingPolicy, callContext);
     }
 
     @Override
-    public boolean cancelEntitlementWithDateOverrideBillingPolicy(final LocalDate effectiveDate, final BillingActionPolicy billingPolicy, final CallContext context) throws EntitlementApiException {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+    public boolean cancelEntitlementWithDateOverrideBillingPolicy(final LocalDate localCancelDate, final BillingActionPolicy billingPolicy, final CallContext callContext) throws EntitlementApiException {
+
+        if (state == EntitlementState.CANCELLED) {
+            throw new EntitlementApiException(ErrorCode.SUB_CANCEL_BAD_STATE, getId(), EntitlementState.CANCELLED);
+        }
+        final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
+        final LocalDate effectiveLocalDate = new LocalDate(localCancelDate, accountTimeZone);
+        final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(effectiveLocalDate, subscriptionBase.getStartDate(), contextWithValidAccountRecordId);
+        try {
+            subscriptionBase.cancelWithPolicy(null, billingPolicy, callContext);
+            blockingStateDao.setBlockingState(new DefaultBlockingState(getId(), BlockingStateType.SUBSCRIPTION, DefaultEntitlementApi.ENT_STATE_CANCELLED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, false, effectiveDate), clock, contextWithValidAccountRecordId);
+            return effectiveLocalDate.compareTo(new LocalDate(clock.getUTCNow())) <= 0;
+        } catch (SubscriptionBaseApiException e) {
+            throw new EntitlementApiException(e);
+        }
     }
 
-    @Override
-    public boolean cancelEntitlementWithPolicyOverrideBillingPolicy(final EntitlementActionPolicy entitlementPolicy, final BillingActionPolicy billingPolicy, final CallContext context) throws EntitlementApiException {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+    private LocalDate getLocalDateFromEntitlementPolicy(final EntitlementActionPolicy entitlementPolicy) {
+        final LocalDate cancellationDate;
+        switch (entitlementPolicy) {
+            case IMM:
+                cancellationDate = new LocalDate(clock.getUTCNow(), accountTimeZone);
+                break;
+            case EOT:
+                cancellationDate = subscriptionBase.getChargedThroughDate() != null ? new LocalDate(subscriptionBase.getChargedThroughDate(), accountTimeZone) : new LocalDate(clock.getUTCNow(), accountTimeZone);
+                break;
+            default:
+                throw new RuntimeException("Unsupported policy " + entitlementPolicy);
+        }
+        return cancellationDate;
     }
 
+
     @Override
     public void uncancel(final CallContext context) throws EntitlementApiException {
         //To change body of implemented methods use File | Settings | File Templates.
@@ -209,8 +249,12 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
     @Override
     public boolean changePlan(final String productName, final BillingPeriod billingPeriod, final String priceList, final LocalDate localDate, final CallContext callContext) throws EntitlementApiException {
 
+        if (state != EntitlementState.ACTIVE) {
+            throw new EntitlementApiException(ErrorCode.SUB_CHANGE_NON_ACTIVE, getId(), state);
+        }
+
         final InternalCallContext context = internalCallContextFactory.createInternalCallContext(accountId, callContext);
-        final DateTime requestedDate = fromLocalDateAndReferenceTime(localDate, subscriptionBase.getStartDate(), clock, context);
+        final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(localDate, subscriptionBase.getStartDate(), context);
         try {
             checker.checkBlockedChange(subscriptionBase, context);
             return subscriptionBase.changePlan(productName, billingPeriod, priceList, requestedDate, callContext);
@@ -223,8 +267,13 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public boolean changePlanOverrideBillingPolicy(final String productName, final BillingPeriod billingPeriod, final String priceList, final LocalDate localDate, final BillingActionPolicy actionPolicy, final CallContext callContext) throws EntitlementApiException {
+
+        if (state != EntitlementState.ACTIVE) {
+            throw new EntitlementApiException(ErrorCode.SUB_CHANGE_NON_ACTIVE, getId(), state);
+        }
+
         final InternalCallContext context = internalCallContextFactory.createInternalCallContext(accountId, callContext);
-        final DateTime requestedDate = fromLocalDateAndReferenceTime(localDate, subscriptionBase.getStartDate(), clock, context);
+        final DateTime requestedDate = dateHelper.fromLocalDateAndReferenceTime(localDate, subscriptionBase.getStartDate(), context);
         try {
             checker.checkBlockedChange(subscriptionBase, context);
             return subscriptionBase.changePlanWithPolicy(productName, billingPeriod, priceList, requestedDate, actionPolicy, callContext);
@@ -237,9 +286,6 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public boolean block(final String serviceName, final LocalDate effectiveDate, final CallContext context) throws EntitlementApiException {
-
-
-
         return false;  //To change body of implemented methods use File | Settings | File Templates.
     }
 
@@ -248,31 +294,4 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         return false;  //To change body of implemented methods use File | Settings | File Templates.
     }
 
-
-
-    /**
-     * Returns a DateTime that is equals or beforeNow and whose LocalDate using the account timeZone is the one provided
-     * <p/>
-     * Relies on the subscriptionStartDate for the reference time
-     *
-     * @param requestedDate
-     * @param subscriptionStartDate
-     * @param clock
-     * @param callContext
-     * @return
-     * @throws EntitlementApiException
-     */
-    private DateTime fromLocalDateAndReferenceTime(final LocalDate requestedDate, final DateTime subscriptionStartDate, final Clock clock, final InternalCallContext callContext) throws EntitlementApiException {
-        try {
-            final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
-            final DateAndTimeZoneContext timeZoneContext = new DateAndTimeZoneContext(subscriptionStartDate, account.getTimeZone(), clock);
-            final DateTime computedTime = timeZoneContext.computeUTCDateTimeFromLocalDate(requestedDate);
-
-            return computedTime.isAfter(clock.getUTCNow()) ? clock.getUTCNow() : computedTime;
-        } catch (AccountApiException e) {
-            throw new EntitlementApiException(e);
-        }
-    }
-
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
index f838d8d..407f104 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultEntitlementApi.java
@@ -74,7 +74,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
     private final InternalCallContextFactory internalCallContextFactory;
     private final BlockingChecker checker;
     private final BlockingStateDao blockingStateDao;
-
+    private final EntitlementDateHelper dateHelper;
 
     @Inject
     public DefaultEntitlementApi(final InternalCallContextFactory internalCallContextFactory, final SubscriptionBaseInternalApi subscriptionInternalApi, final AccountInternalApi accountApi, final BlockingStateDao blockingStateDao, final Clock clock, final BlockingChecker checker) {
@@ -84,6 +84,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
         this.clock = clock;
         this.checker = checker;
         this.blockingStateDao = blockingStateDao;
+        this.dateHelper = new EntitlementDateHelper(accountApi, clock);
     }
 
 
@@ -94,7 +95,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
             final Account account = accountApi.getAccountById(accountId, contextWithValidAccountRecordId);
             final SubscriptionBaseBundle bundle = subscriptionInternalApi.createBundleForAccount(accountId, externalKey, contextWithValidAccountRecordId);
             final SubscriptionBase subscription = subscriptionInternalApi.createSubscription(bundle.getId(), planPhaseSpecifier, clock.getUTCNow(), contextWithValidAccountRecordId);
-            return new DefaultEntitlement(accountApi, subscription, accountId, bundle.getExternalKey(), false, null, account.getTimeZone(), internalCallContextFactory, clock, checker);
+            return new DefaultEntitlement(dateHelper, subscription, accountId, bundle.getExternalKey(), EntitlementState.ACTIVE, null, account.getTimeZone(),
+                                          internalCallContextFactory, blockingStateDao, clock, checker);
         } catch (SubscriptionBaseApiException e) {
             throw new EntitlementApiException(e);
         } catch (AccountApiException e) {
@@ -108,27 +110,30 @@ public class DefaultEntitlementApi implements EntitlementApi {
         try {
             final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(bundleId, context);
             final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, context);
+
+
+            final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundle.getAccountId(), callContext);
+            final BlockingState currentBaseState =  blockingStateDao.getBlockingStateForService(baseSubscription.getId(), EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
+
+            // Check if there is a BP and if it is active
+            final EntitlementState baseEntitlementState = getStateForEntitlement(baseSubscription, currentBaseState, contextWithValidAccountRecordId);
             if (baseSubscription.getCategory() != ProductCategory.BASE ||
-                baseSubscription.getState() != EntitlementState.ACTIVE) {
+                baseEntitlementState != EntitlementState.ACTIVE) {
                 throw new EntitlementApiException(ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION, baseSubscription.getBundleId());
             }
 
-            final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundle.getAccountId(), callContext);
+            // Check if BP is blockedChange
             final BlockingAggregator blocking = checker.getBlockedStatus(baseSubscription, contextWithValidAccountRecordId);
             if (blocking.isBlockChange()) {
                 throw new EntitlementApiException(new BlockingApiException(ErrorCode.BLOCK_BLOCKED_ACTION, BlockingChecker.ACTION_CHANGE, BlockingChecker.TYPE_SUBSCRIPTION, baseSubscription.getId().toString()));
             }
 
-            final BlockingState currentState =  blockingStateDao.getBlockingStateForService(baseSubscription.getId(), EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
-            if (currentState != null && currentState.getStateName().equals(ENT_STATE_CANCELLED)) {
-                throw new EntitlementApiException(new BlockingApiException(ErrorCode.BLOCK_BLOCKED_ACTION, BlockingChecker.ACTION_CHANGE, BlockingChecker.TYPE_SUBSCRIPTION, baseSubscription.getId().toString()));
-            }
-
             final Account account = accountApi.getAccountById(bundle.getAccountId(), context);
 
-            final DateTime requestedDate = fromNowAndReferenceTime(baseSubscription.getStartDate(), contextWithValidAccountRecordId);
+            final DateTime requestedDate = dateHelper.fromNowAndReferenceTime(baseSubscription.getStartDate(), contextWithValidAccountRecordId);
             final SubscriptionBase subscription = subscriptionInternalApi.createSubscription(baseSubscription.getBundleId(), planPhaseSpecifier, requestedDate, context);
-            return new DefaultEntitlement(accountApi, subscription, bundle.getAccountId(), bundle.getExternalKey(), blocking.isBlockEntitlement(), null, account.getTimeZone(), internalCallContextFactory, clock, checker);
+            return new DefaultEntitlement(dateHelper, subscription, bundle.getAccountId(), bundle.getExternalKey(), getStateForEntitlement(subscription, currentBaseState, context), null, account.getTimeZone(),
+                                          internalCallContextFactory, blockingStateDao, clock, checker);
         } catch (SubscriptionBaseApiException e) {
             throw new EntitlementApiException(e);
         } catch (BlockingApiException e) {
@@ -144,16 +149,14 @@ public class DefaultEntitlementApi implements EntitlementApi {
         try {
             final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(uuid, context);
             final SubscriptionBaseBundle bundle = subscriptionInternalApi.getBundleFromId(subscription.getBundleId(), context);
-            final BlockingAggregator blocking = checker.getBlockedStatus(subscription, context);
 
             final Account account = accountApi.getAccountById(bundle.getAccountId(), context);
             final BlockingState currentState =  blockingStateDao.getBlockingStateForService(subscription.getId(), EntitlementService.ENTITLEMENT_SERVICE_NAME, context);
 
-            return new DefaultEntitlement(accountApi, subscription, bundle.getAccountId(), bundle.getExternalKey(), blocking.isBlockEntitlement(), currentState, account.getTimeZone(), internalCallContextFactory, clock, checker);
+            return new DefaultEntitlement(dateHelper, subscription, bundle.getAccountId(), bundle.getExternalKey(), getStateForEntitlement(subscription, currentState, context), currentState, account.getTimeZone(),
+                                          internalCallContextFactory, blockingStateDao, clock, checker);
         } catch (SubscriptionBaseApiException e) {
             throw new EntitlementApiException(e);
-        } catch (BlockingApiException e) {
-            throw new EntitlementApiException(e);
         } catch (AccountApiException e) {
             throw new EntitlementApiException(e);
         }
@@ -203,19 +206,14 @@ public class DefaultEntitlementApi implements EntitlementApi {
                 @Nullable
                 @Override
                 public Entitlement apply(@Nullable final SubscriptionBase input) {
-                    BlockingAggregator blocking = null;
-                    try {
-                        blocking = checker.getBlockedStatus(input, context);
-                    } catch (BlockingApiException e) {
-                        log.warn("Failed to extract blocking state for subscription " + input.getId().toString());
-                    }
+
                     final BlockingState currentState =  blockingStateDao.getBlockingStateForService(input.getId(), EntitlementService.ENTITLEMENT_SERVICE_NAME, context);
 
-                    return new DefaultEntitlement(accountApi, input, accountId, externalKey,
-                                                  (blocking != null ? blocking.isBlockEntitlement() : false),
+                    return new DefaultEntitlement(dateHelper, input, accountId, externalKey,
+                                                  getStateForEntitlement(input, currentState, context),
                                                   currentState,
                                                   account.getTimeZone(),
-                                                  internalCallContextFactory, clock, checker);
+                                                  internalCallContextFactory, blockingStateDao, clock, checker);
                 }
             }));
         } catch (AccountApiException e) {
@@ -223,27 +221,70 @@ public class DefaultEntitlementApi implements EntitlementApi {
         }
     }
 
+    private EntitlementState getStateForEntitlement(final SubscriptionBase subscriptionBase, final BlockingState currentState, final InternalTenantContext context) {
+
+        // Current state for the ENTITLEMENT_SERVICE_NAME is set to cancelled
+        if (currentState != null && currentState.getStateName().equals(ENT_STATE_CANCELLED)) {
+            return EntitlementState.CANCELLED;
+        }
+
+        try {
+            // Gather states across all services and check if one of them is set to 'blockEntitlement'
+            BlockingAggregator blocking = checker.getBlockedStatus(subscriptionBase, context);
+            return blocking != null && blocking.isBlockEntitlement() ? EntitlementState.BLOCKED : EntitlementState.ACTIVE;
+        } catch (BlockingApiException e) {
+            log.warn("Failed to extract blocking state for subscription " + subscriptionBase.getId().toString());
+           return null;
+        }
+    }
+
+
     @Override
-    public void block(final UUID bundleId, final LocalDate effectiveDate, final CallContext context) throws EntitlementApiException {
+    public void pause(final UUID bundleId, final LocalDate localEffectiveDate, final CallContext context) throws EntitlementApiException {
+        try {
+            final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+            final BlockingState currentState =  blockingStateDao.getBlockingStateForService(bundleId, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
+            if (currentState != null && currentState.getStateName().equals(ENT_STATE_BLOCKED)) {
+                throw new EntitlementApiException(ErrorCode.ENT_ALREADY_BLOCKED, bundleId);
+            }
+            final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
+            final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(localEffectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
 
-        final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
-        final BlockingState currentState =  blockingStateDao.getBlockingStateForService(bundleId, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
-        if (currentState != null && currentState.getStateName().equals(ENT_STATE_BLOCKED)) {
-            throw new EntitlementApiException(ErrorCode.ENT_ALREADY_BLOCKED, bundleId);
+            blockingStateDao.setBlockingState(new DefaultBlockingState(bundleId, BlockingStateType.BUNDLE, ENT_STATE_BLOCKED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, true, effectiveDate), clock, contextWithValidAccountRecordId);
+
+        } catch (SubscriptionBaseApiException e) {
+            throw new EntitlementApiException(e);
         }
-        blockingStateDao.setBlockingState(new DefaultBlockingState(bundleId, BlockingStateType.BUNDLE, ENT_STATE_BLOCKED, EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, true, clock.getUTCNow()), clock, contextWithValidAccountRecordId);
     }
 
     @Override
-    public void unblock(final UUID bundleId, final LocalDate effectiveDate, final CallContext context) throws EntitlementApiException {
+    public void resume(final UUID bundleId, final LocalDate localEffectiveDate, final CallContext context) throws EntitlementApiException {
+        try {
+            final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+            final BlockingState currentState =  blockingStateDao.getBlockingStateForService(bundleId, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
+            if (currentState == null || currentState.getStateName().equals(ENT_STATE_CLEAR)) {
+                // Nothing to do.
+                return;
+            }
+            final SubscriptionBase baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, contextWithValidAccountRecordId);
 
-        final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
-        final BlockingState currentState =  blockingStateDao.getBlockingStateForService(bundleId, EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
-        if (currentState == null || currentState.getStateName().equals(ENT_STATE_CLEAR)) {
-            // Nothing to do.
-            return;
+            final DateTime effectiveDate = dateHelper.fromLocalDateAndReferenceTime(localEffectiveDate, baseSubscription.getStartDate(), contextWithValidAccountRecordId);
+
+            blockingStateDao.setBlockingState(new DefaultBlockingState(bundleId, BlockingStateType.BUNDLE, ENT_STATE_CLEAR, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, effectiveDate), clock, contextWithValidAccountRecordId);
+
+        } catch (SubscriptionBaseApiException e) {
+            throw new EntitlementApiException(e);
         }
-        blockingStateDao.setBlockingState(new DefaultBlockingState(bundleId, BlockingStateType.BUNDLE, ENT_STATE_CLEAR, EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, clock.getUTCNow()), clock, contextWithValidAccountRecordId);
+    }
+
+    @Override
+    public void block(final UUID bundleId, final String serviceName, final LocalDate effectiveDate, final boolean blockBilling, final boolean blockEntitlement, final boolean blockChange, final CallContext context) throws EntitlementApiException {
+        final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(bundleId, ObjectType.BUNDLE, context);
+
+    }
+
+    @Override
+    public void unblock(final UUID bundleId, final String serviceName, final LocalDate effectiveDate, final CallContext context) throws EntitlementApiException {
     }
 
 
@@ -258,14 +299,5 @@ public class DefaultEntitlementApi implements EntitlementApi {
     }
 
 
-    private DateTime fromNowAndReferenceTime(final DateTime subscriptionStartDate, final InternalCallContext callContext) throws EntitlementApiException {
-        try {
-            final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
-            final DateAndTimeZoneContext timeZoneContext = new DateAndTimeZoneContext(subscriptionStartDate, account.getTimeZone(), clock);
-            return timeZoneContext.computeUTCDateTimeFromNow();
-        } catch (AccountApiException e) {
-            throw new EntitlementApiException(e);
-        }
-    }
 
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java
new file mode 100644
index 0000000..5c80493
--- /dev/null
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java
@@ -0,0 +1,56 @@
+package com.ning.billing.entitlement.api;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.svcapi.account.AccountInternalApi;
+import com.ning.billing.util.timezone.DateAndTimeZoneContext;
+
+public class EntitlementDateHelper {
+
+    private final AccountInternalApi accountApi;
+    private final Clock clock;
+
+    public EntitlementDateHelper(final AccountInternalApi accountApi, final Clock clock) {
+        this.accountApi = accountApi;
+        this.clock = clock;
+    }
+
+    /**
+     * Returns a DateTime that is equals or beforeNow and whose LocalDate using the account timeZone is the one provided
+     * <p/>
+     * Relies on the subscriptionStartDate for the reference time
+     *
+     * @param requestedDate
+     * @param subscriptionStartDate
+     * @param callContext
+     * @return
+     * @throws EntitlementApiException
+     */
+    public DateTime fromLocalDateAndReferenceTime(final LocalDate requestedDate, final DateTime subscriptionStartDate, final InternalCallContext callContext) throws EntitlementApiException {
+        try {
+            final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
+            final DateAndTimeZoneContext timeZoneContext = new DateAndTimeZoneContext(subscriptionStartDate, account.getTimeZone(), clock);
+            final DateTime computedTime = timeZoneContext.computeUTCDateTimeFromLocalDate(requestedDate);
+
+            //return computedTime.isAfter(clock.getUTCNow()) ? clock.getUTCNow() : computedTime;
+            return computedTime;
+        } catch (AccountApiException e) {
+            throw new EntitlementApiException(e);
+        }
+    }
+
+    public DateTime fromNowAndReferenceTime(final DateTime subscriptionStartDate, final InternalCallContext callContext) throws EntitlementApiException {
+        try {
+            final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
+            final DateAndTimeZoneContext timeZoneContext = new DateAndTimeZoneContext(subscriptionStartDate, account.getTimeZone(), clock);
+            return timeZoneContext.computeUTCDateTimeFromNow();
+        } catch (AccountApiException e) {
+            throw new EntitlementApiException(e);
+        }
+    }
+}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultInternalBlockingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultInternalBlockingApi.java
index e2ae80c..7b17850 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultInternalBlockingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultInternalBlockingApi.java
@@ -78,6 +78,16 @@ public class DefaultInternalBlockingApi implements BlockingInternalApi {
     }
 
     @Override
+    public List<BlockingState> getBlockingAll(final Blockable overdueable, final InternalTenantContext context) {
+        return dao.getBlockingAll(overdueable.getId(), context);
+    }
+
+    @Override
+    public List<BlockingState> getBlockingAll(final UUID overdueableId, final InternalTenantContext context) {
+        return dao.getBlockingAll(overdueableId, context);
+    }
+
+    @Override
     public void setBlockingState(final BlockingState state, final InternalCallContext context) {
         dao.setBlockingState(state, clock, context);
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateDao.java
index 453c915..58bee54 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateDao.java
@@ -66,6 +66,15 @@ public interface BlockingStateDao {
     public List<BlockingState> getBlockingHistory(UUID blockableId, InternalTenantContext context);
 
     /**
+     * Return all the events (past and future) across all services
+     *
+     * @param blockableId
+     * @param context
+     * @return
+     */
+    public List<BlockingState> getBlockingAll(UUID blockableId, InternalTenantContext context);
+
+    /**
      * Sets a new state for a specific service
      *
      * @param state
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateModelDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateModelDao.java
index 8db83b7..0be4794 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateModelDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateModelDao.java
@@ -37,11 +37,13 @@ public class BlockingStateModelDao extends EntityBase implements EntityModelDao<
     private final Boolean blockChange;
     private final Boolean blockEntitlement;
     private final Boolean blockBilling;
+    private final DateTime effectiveDate;
 
     public BlockingStateModelDao(final UUID id, final UUID blockableId, final BlockingStateType blockingStateType, final String state, final String service, final Boolean blockChange, final Boolean blockEntitlement,
-                                 final Boolean blockBilling, final DateTime createDate, final DateTime updateDate) {
+                                 final Boolean blockBilling, final DateTime effectiveDate, final DateTime createDate, final DateTime updateDate) {
         super(id, createDate, updateDate);
         this.blockableId = blockableId;
+        this.effectiveDate = effectiveDate;
         this.type = blockingStateType;
         this.state = state;
         this.service = service;
@@ -52,7 +54,7 @@ public class BlockingStateModelDao extends EntityBase implements EntityModelDao<
 
     public BlockingStateModelDao(final BlockingState src, InternalCallContext context) {
         this(src.getId(), src.getBlockedId(), src.getType(), src.getStateName(), src.getService(), src.isBlockChange(),
-             src.isBlockEntitlement(), src.isBlockBilling(), context.getCreatedDate(), context.getUpdatedDate());
+             src.isBlockEntitlement(), src.isBlockBilling(), src.getEffectiveDate(), context.getCreatedDate(), context.getUpdatedDate());
     }
 
     public UUID getBlockableId() {
@@ -83,12 +85,16 @@ public class BlockingStateModelDao extends EntityBase implements EntityModelDao<
         return type;
     }
 
+    public DateTime getEffectiveDate() {
+        return effectiveDate;
+    }
+
     public static BlockingState toBlockingState(BlockingStateModelDao src) {
         if (src == null) {
             return null;
         }
         return new DefaultBlockingState(src.getId(), src.getBlockableId(), src.getType(), src.getState(), src.getService(), src.getBlockChange(), src.getBlockEntitlement(), src.getBlockBilling(),
-                                 src.getCreatedDate(), src.getUpdatedDate());
+                                 src.getEffectiveDate(), src.getCreatedDate(), src.getUpdatedDate());
     }
 
     @Override
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateSqlDao.java
index a7f6a83..6df54b4 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/BlockingStateSqlDao.java
@@ -18,6 +18,7 @@ package com.ning.billing.entitlement.dao;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
@@ -44,23 +45,32 @@ public interface BlockingStateSqlDao extends EntitySqlDao<BlockingStateModelDao,
     @SqlQuery
     public abstract BlockingStateModelDao getBlockingStateForService(@Bind("blockableId") UUID blockableId,
                                                                      @Bind("service") String serviceName,
+                                                                     @Bind("effectiveDate") Date effectiveDate,
                                                                      @BindBean final InternalTenantContext context);
 
     @SqlQuery
     public abstract List<BlockingStateModelDao> getBlockingState(@Bind("blockableId") UUID blockableId,
+                                                                 @Bind("effectiveDate") Date effectiveDate,
                                                                  @BindBean final InternalTenantContext context);
 
 
     @SqlQuery
     public abstract List<BlockingStateModelDao> getBlockingHistoryForService(@Bind("blockableId") UUID blockableId,
                                                                              @Bind("service") String serviceName,
+                                                                             @Bind("effectiveDate") Date effectiveDate,
                                                                              @BindBean final InternalTenantContext context);
 
 
     @SqlQuery
     public abstract List<BlockingStateModelDao> getBlockingHistory(@Bind("blockableId") UUID blockableId,
+                                                                   @Bind("effectiveDate") Date effectiveDate,
                                                                    @BindBean final InternalTenantContext context);
 
+    @SqlQuery
+    public abstract List<BlockingStateModelDao> getBlockingAll(@Bind("blockableId") UUID blockableId,
+                                                                   @BindBean final InternalTenantContext context);
+
+
     public class BlockingHistorySqlMapper extends MapperBase implements ResultSetMapper<BlockingStateModelDao> {
 
         @Override
@@ -74,6 +84,7 @@ public interface BlockingStateSqlDao extends EntitySqlDao<BlockingStateModelDao,
             final boolean blockChange;
             final boolean blockEntitlement;
             final boolean blockBilling;
+            final DateTime effectiveDate;
             final DateTime createdDate;
             final BlockingStateType type;
 
@@ -85,8 +96,9 @@ public interface BlockingStateSqlDao extends EntitySqlDao<BlockingStateModelDao,
             blockChange = r.getBoolean("block_change");
             blockEntitlement = r.getBoolean("block_entitlement");
             blockBilling = r.getBoolean("block_billing");
+            effectiveDate = getDateTime(r, "effective_date");
             createdDate = getDateTime(r, "created_date");
-            return new BlockingStateModelDao(id, blockableId, type, stateName, service, blockChange, blockEntitlement, blockBilling, createdDate, createdDate);
+            return new BlockingStateModelDao(id, blockableId, type, stateName, service, blockChange, blockEntitlement, blockBilling, effectiveDate, createdDate, createdDate);
         }
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/dao/DefaultBlockingStateDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/dao/DefaultBlockingStateDao.java
index 8c2ef5e..ac1b851 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/dao/DefaultBlockingStateDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/dao/DefaultBlockingStateDao.java
@@ -43,10 +43,12 @@ import com.google.common.collect.Collections2;
 public class DefaultBlockingStateDao implements BlockingStateDao {
 
     private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
+    private final Clock clock;
 
     @Inject
     public DefaultBlockingStateDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher, final NonEntityDao nonEntityDao) {
         this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
+        this.clock = clock;
     }
 
     @Override
@@ -54,7 +56,7 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
         return transactionalSqlDao.execute(  new EntitySqlDaoTransactionWrapper<BlockingState>() {
             @Override
             public BlockingState inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final BlockingStateModelDao model = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingStateForService(blockableId, serviceName, context);
+                final BlockingStateModelDao model = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingStateForService(blockableId, serviceName, clock.getUTCNow().toDate(), context);
                 return BlockingStateModelDao.toBlockingState(model);
 
             }
@@ -66,7 +68,7 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
         return transactionalSqlDao.execute(  new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
             @Override
             public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final  List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingState(blockableId, context);
+                final  List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingState(blockableId, clock.getUTCNow().toDate(), context);
                 return new ArrayList<BlockingState>(Collections2.transform(models, new Function<BlockingStateModelDao, BlockingState>() {
                     @Override
                     public BlockingState apply(@Nullable final BlockingStateModelDao src) {
@@ -82,7 +84,7 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
             @Override
             public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingHistoryForService(blockableId, serviceName, context);
+                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingHistoryForService(blockableId, serviceName, clock.getUTCNow().toDate(), context);
                 return new ArrayList<BlockingState>(Collections2.transform(models, new Function<BlockingStateModelDao, BlockingState>() {
                     @Override
                     public BlockingState apply(@Nullable final BlockingStateModelDao src) {
@@ -98,7 +100,23 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
             @Override
             public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingHistory(blockableId, context);
+                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingHistory(blockableId, clock.getUTCNow().toDate(), context);
+                return new ArrayList<BlockingState>(Collections2.transform(models, new Function<BlockingStateModelDao, BlockingState>() {
+                    @Override
+                    public BlockingState apply(@Nullable final BlockingStateModelDao src) {
+                        return BlockingStateModelDao.toBlockingState(src);
+                    }
+                }));
+            }
+        });
+    }
+
+    @Override
+    public List<BlockingState> getBlockingAll(final UUID blockableId, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<BlockingState>>() {
+            @Override
+            public List<BlockingState> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingAll(blockableId, context);
                 return new ArrayList<BlockingState>(Collections2.transform(models, new Function<BlockingStateModelDao, BlockingState>() {
                     @Override
                     public BlockingState apply(@Nullable final BlockingStateModelDao src) {
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/dao/BlockingStateSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
index 0a12fb5..ad7ed24 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/dao/BlockingStateSqlDao.sql.stg
@@ -11,6 +11,7 @@ tableFields(prefix) ::= <<
 , <prefix>block_change
 , <prefix>block_entitlement
 , <prefix>block_billing
+, <prefix>effective_date
 , <prefix>created_date
 >>
 
@@ -23,6 +24,7 @@ tableValues() ::= <<
 , :blockChange
 , :blockEntitlement
 , :blockBilling
+, :effectiveDate
 , :createdDate
 >>
 
@@ -34,6 +36,7 @@ from
 <tableName()>
 where blockable_id = :blockableId
 and service = :service
+and effective_date \<= :effectiveDate
 <AND_CHECK_TENANT()>
 -- We want the current state, hence the order desc and limit 1
 order by record_id desc
@@ -51,6 +54,7 @@ getBlockingState() ::= <<
          , service
          from blocking_states
          where blockable_id = :blockableId
+         and effective_date \<= :effectiveDate
          <AND_CHECK_TENANT()>
          group by service
  ) tmp
@@ -66,6 +70,7 @@ from
 <tableName()>
 where blockable_id = :blockableId
 and service = :service
+and effective_date \<= :effectiveDate
 <AND_CHECK_TENANT()>
 order by record_id asc
 ;
@@ -77,7 +82,19 @@ select
 from
 <tableName()>
 where blockable_id = :blockableId
+and effective_date \<= :effectiveDate
 <AND_CHECK_TENANT()>
 order by record_id asc
 ;
 >>
+
+getBlockingAll) ::= <<
+select
+<allTableFields()>
+from
+<tableName()>
+where blockable_id = :blockableId
+<AND_CHECK_TENANT()>
+order by record_id asc
+;
+>>
\ No newline at end of file
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
index 2747e2d..cfa82ed 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
@@ -11,6 +11,7 @@ CREATE TABLE blocking_states (
     block_change bool NOT NULL,
     block_entitlement bool NOT NULL,
     block_billing bool NOT NULL,
+    effective_date datetime NOT NULL,
     created_date datetime NOT NULL,
     account_record_id int(11) unsigned default null,
     tenant_record_id int(11) unsigned default null,
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java
new file mode 100644
index 0000000..1f8bcbe
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java
@@ -0,0 +1,165 @@
+package com.ning.billing.entitlement.api;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.api.TestApiListener.NextEvent;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
+import com.ning.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
+import com.ning.billing.entitlement.api.Entitlement.EntitlementState;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
+
+
+    @Test(groups = "slow")
+    public void testCancelWithEntitlementDate() {
+
+        try {
+            final LocalDate initialDate = new LocalDate(2013, 8, 7);
+            clock.setDay(initialDate);
+
+            final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+            // Create entitlement and check each field
+            final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), callContext);
+            assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
+
+            clock.addDays(5);
+            final LocalDate cancelDate = new LocalDate(clock.getUTCNow());
+            entitlement.cancelEntitlementWithDate(cancelDate, callContext);
+            final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement2.getState(), EntitlementState.CANCELLED);
+            assertEquals(entitlement2.getEffectiveEndDate(), cancelDate);
+
+        } catch (EntitlementApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        } catch (AccountApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        }
+    }
+
+
+    @Test(groups = "slow")
+    public void testCancelWithEntitlementDateInFuture() {
+
+        try {
+            final LocalDate initialDate = new LocalDate(2013, 8, 7);
+            clock.setDay(initialDate);
+
+            final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+            // Create entitlement and check each field
+            final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), callContext);
+            assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
+
+            clock.addDays(5);
+            final LocalDate cancelDate = new LocalDate(clock.getUTCToday().plusDays(1));
+            entitlement.cancelEntitlementWithDate(cancelDate, callContext);
+            final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement2.getState(), EntitlementState.ACTIVE);
+            assertNull(entitlement2.getEffectiveEndDate());
+
+            clock.addDays(1);
+            final Entitlement entitlement3 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement3.getState(), EntitlementState.CANCELLED);
+            assertEquals(entitlement3.getEffectiveEndDate(), cancelDate);
+
+
+        } catch (EntitlementApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        } catch (AccountApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        }
+    }
+
+    @Test(groups = "slow")
+    public void testCancelWithEntitlementPolicyEOTAndNOCTD() {
+
+        try {
+
+            final LocalDate initialDate = new LocalDate(2013, 8, 7);
+            clock.setDay(initialDate);
+
+            final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+            // Create entitlement and check each field
+            final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), callContext);
+
+            final boolean isCancelled = entitlement.cancelEntitlementWithPolicy(EntitlementActionPolicy.EOT, callContext);
+            assertTrue(isCancelled);
+
+            final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement2.getState(), EntitlementState.CANCELLED);
+            assertEquals(entitlement2.getEffectiveEndDate(), initialDate);
+
+        } catch (EntitlementApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        } catch (AccountApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        }
+    }
+
+
+    @Test(groups = "slow")
+    public void testCancelWithEntitlementPolicyEOTAndCTD() {
+
+        try {
+
+            final LocalDate initialDate = new LocalDate(2013, 8, 7);
+            clock.setDay(initialDate);
+
+            final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+            // Create entitlement and check each field
+            final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), callContext);
+
+            final DateTime ctd = clock.getUTCNow().plusDays(30).plusMonths(1);
+            testListener.pushExpectedEvent(NextEvent.PHASE);
+            clock.addDays(32);
+            // Set manually since no invoice
+            subscriptionInternalApi.setChargedThroughDate(entitlement.getId(), ctd, internalCallContext);
+            assertTrue(testListener.isCompleted(5000));
+
+            final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            final boolean isCancelled = entitlement2.cancelEntitlementWithPolicy(EntitlementActionPolicy.EOT, callContext);
+            assertFalse(isCancelled);
+
+            final Entitlement entitlement3 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement3.getState(), EntitlementState.ACTIVE);
+            assertNull(entitlement3.getEffectiveEndDate());
+
+            clock.addMonths(1);
+
+            final Entitlement entitlement4 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+            assertEquals(entitlement4.getState(), EntitlementState.CANCELLED);
+            assertEquals(entitlement4.getEffectiveEndDate(), new LocalDate(ctd));
+
+        } catch (EntitlementApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        } catch (AccountApiException e) {
+            Assert.fail("Test failed " + e.getMessage());
+        }
+    }
+
+}
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
index 4bff189..4a7b482 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -173,7 +173,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
 
     @Test(groups = "slow")
-    public void testBlockUnblock() {
+    public void testPauseUnpause() {
 
         try {
 
@@ -194,7 +194,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
             // Block all entitlement in the bundle
             clock.addDays(5);
-            entitlementApi.block(baseEntitlement.getBundleId(), new LocalDate(clock.getUTCNow()), callContext);
+            entitlementApi.pause(baseEntitlement.getBundleId(), new LocalDate(clock.getUTCNow()), callContext);
 
             // Verify blocking state
             final Entitlement baseEntitlement2 = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext);
@@ -205,7 +205,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
             // Check we can't block in a blocked state
             try {
-                entitlementApi.block(baseEntitlement.getBundleId(), new LocalDate(clock.getUTCNow()), callContext);
+                entitlementApi.pause(baseEntitlement.getBundleId(), new LocalDate(clock.getUTCNow()), callContext);
                 Assert.fail("Should not have succeeded to block in a blocked state");
             } catch (EntitlementApiException e) {
                 assertEquals(e.getCode(), ErrorCode.ENT_ALREADY_BLOCKED.getCode());
@@ -223,14 +223,14 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
                 final PlanPhaseSpecifier spec3 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
                 final Entitlement telescopicEntitlement3 = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), spec1, callContext);
             } catch (EntitlementApiException e) {
-                assertEquals(e.getCode(), ErrorCode.BLOCK_BLOCKED_ACTION.getCode());
+                assertEquals(e.getCode(), ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION.getCode());
             }
 
             clock.addDays(3);
-            entitlementApi.unblock(baseEntitlement.getBundleId(), new LocalDate(), callContext);
+            entitlementApi.resume(baseEntitlement.getBundleId(), new LocalDate(), callContext);
 
             // Verify call is idempotent
-            entitlementApi.unblock(baseEntitlement.getBundleId(), new LocalDate(), callContext);
+            entitlementApi.resume(baseEntitlement.getBundleId(), new LocalDate(), callContext);
 
             // Verify blocking state
             final Entitlement baseEntitlement3 = entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/block/TestDefaultBlockingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/block/TestDefaultBlockingApi.java
index be2bc15..b1b52e9 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/block/TestDefaultBlockingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/block/TestDefaultBlockingApi.java
@@ -52,7 +52,7 @@ public class TestDefaultBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
             }
         });
 
-        final BlockingState blockingState = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.ACCOUNT, "BLOCKED", "myService", true, true, true, internalCallContext.getCreatedDate(), null);
+        final BlockingState blockingState = new DefaultBlockingState(UUID.randomUUID(), bundleId, BlockingStateType.ACCOUNT, "BLOCKED", "myService", true, true, true, clock.getUTCNow(), internalCallContext.getCreatedDate(), null);
         blockingInternalApi.setBlockingState(blockingState, internalCallContext);
 
         // Verify the blocking state was applied
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/dao/MockBlockingStateDao.java b/entitlement/src/test/java/com/ning/billing/entitlement/dao/MockBlockingStateDao.java
index b284612..0d8377c 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/dao/MockBlockingStateDao.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/dao/MockBlockingStateDao.java
@@ -38,6 +38,8 @@ public class MockBlockingStateDao implements BlockingStateDao {
 
     private final Map<UUID, List<BlockingState>> blockingStates = new HashMap<UUID, List<BlockingState>>();
 
+    // TODO This mock class should also check that events are past or present except for getBlockingAll
+
     @Override
     public BlockingState getBlockingStateForService(final UUID blockableId, final String serviceName, final InternalTenantContext context) {
         final List<BlockingState> states = getBlockingHistory(blockableId, context);
@@ -63,7 +65,7 @@ public class MockBlockingStateDao implements BlockingStateDao {
         final Map<String, BlockingState> tmp  = new HashMap<String, BlockingState>();
         for (BlockingState cur : blockingStatesForId) {
             final BlockingState curStateForService = tmp.get(cur.getService());
-            if (curStateForService == null || curStateForService.getCreatedDate().compareTo(cur.getCreatedDate()) < 0) {
+            if (curStateForService == null || curStateForService.getEffectiveDate().compareTo(cur.getEffectiveDate()) < 0) {
                 tmp.put(cur.getService(), cur);
             }
         }
@@ -95,6 +97,13 @@ public class MockBlockingStateDao implements BlockingStateDao {
     }
 
     @Override
+    public List<BlockingState> getBlockingAll(final UUID blockableId, final InternalTenantContext context) {
+        final List<BlockingState> states = blockingStates.get(blockableId);
+        // Note! The returned list cannot be immutable!
+        return states == null ? new ArrayList<BlockingState>() : states;
+    }
+
+    @Override
     public synchronized void setBlockingState(final BlockingState state, final Clock clock, final InternalCallContext context) {
         if (blockingStates.get(state.getBlockedId()) == null) {
             blockingStates.put(state.getBlockedId(), new ArrayList<BlockingState>());
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
index 342f0fc..e881401 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -93,8 +93,8 @@ public class BlockingCalculator {
         final SortedSet<BillingEvent> billingEventsToRemove = new TreeSet<BillingEvent>();
 
         for (final UUID bundleId : bundleMap.keySet()) {
-            final List<BlockingState> blockingEvents = blockingApi.getBlockingHistory(bundleId, context);
-            blockingEvents.addAll(blockingApi.getBlockingHistory(account.getId(),context));
+            final List<BlockingState> blockingEvents = blockingApi.getBlockingAll(bundleId, context);
+            blockingEvents.addAll(blockingApi.getBlockingAll(account.getId(),context));
             final List<DisabledDuration> blockingDurations = createBlockingDurations(blockingEvents);
 
             for (final SubscriptionBase subscription : bundleMap.get(bundleId)) {
@@ -265,13 +265,13 @@ public class BlockingCalculator {
                 first = e;
             } else if (first != null && !e.isBlockBilling()) {
                 // End of the interval
-                result.add(new DisabledDuration(first.getTimestamp(), e.getTimestamp()));
+                result.add(new DisabledDuration(first.getEffectiveDate(), e.getEffectiveDate()));
                 first = null;
             }
         }
 
         if (first != null) { // found a transition to disabled with no terminating event
-            result.add(new DisabledDuration(first.getTimestamp(), null));
+            result.add(new DisabledDuration(first.getEffectiveDate(), null));
         }
 
         return result;
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
index 3f6c3af..91baf83 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
@@ -183,8 +183,8 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
         final Account account = createAccount(32);
 
         final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
-        blockingStates.add(new DefaultBlockingState(UUID.randomUUID(), bunId, BlockingStateType.BUNDLE,  DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
-        blockingStates.add(new DefaultBlockingState(UUID.randomUUID(), bunId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2), null));
+        blockingStates.add(new DefaultBlockingState(bunId, BlockingStateType.BUNDLE,  DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingStates.add(new DefaultBlockingState(bunId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2)));
 
         ((MockBlockingStateDao) blockingStateDao).setBlockingStates(bunId, blockingStates);
         final SortedSet<BillingEvent> events = billingInternalApi.getBillingEventsForAccountAndUpdateAccountBCD(account.getId(), internalCallContext);
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 837e66f..b256673 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -113,8 +113,8 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         billingEvents.add(D);
 
         final List<BlockingState> blockingStates = new ArrayList<BlockingState>();
-        blockingStates.add(new DefaultBlockingState(UUID.randomUUID(), bundleId1, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now, null));
-        blockingStates.add(new DefaultBlockingState(UUID.randomUUID(), bundleId1, BlockingStateType.BUNDLE, CLEAR_BUNDLE,  "test", false, false, false, now.plusDays(2), null));
+        blockingStates.add(new DefaultBlockingState(bundleId1, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now));
+        blockingStates.add(new DefaultBlockingState(bundleId1, BlockingStateType.BUNDLE, CLEAR_BUNDLE,  "test", false, false, false, now.plusDays(2)));
 
         setBlockingStates(bundleId1, blockingStates);
 
@@ -646,8 +646,8 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
         //simple events open clear -> disabled
         blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now, null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
 
         List<DisabledDuration> pairs = blockingCalculator.createBlockingDurations(blockingEvents);
         assertEquals(pairs.size(), 1);
@@ -657,9 +657,9 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
         //simple events closed clear -> disabled
         blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now, null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2)));
 
         pairs = blockingCalculator.createBlockingDurations(blockingEvents);
         assertEquals(pairs.size(), 1);
@@ -670,9 +670,9 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
         //simple BUNDLE events closed clear -> disabled
         blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now, null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(2)));
 
         pairs = blockingCalculator.createBlockingDurations(blockingEvents);
         assertEquals(pairs.size(), 1);
@@ -683,10 +683,10 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
         //two or more disableds in a row
         blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now, null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(2), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(3), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(2)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(3)));
 
         pairs = blockingCalculator.createBlockingDurations(blockingEvents);
         assertEquals(pairs.size(), 1);
@@ -696,11 +696,11 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         assertEquals(pairs.get(0).getEnd(), now.plusDays(3));
 
         blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now, null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(2), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(3), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(4), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(2)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, now.plusDays(3)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, now.plusDays(4)));
 
         pairs = blockingCalculator.createBlockingDurations(blockingEvents);
         assertEquals(pairs.size(), 1);
@@ -723,10 +723,10 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
         billingEvents.add(upgrade);
 
         final List<BlockingState> blockingEvents = new ArrayList<BlockingState>();
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, false, false, new LocalDate(2012, 7, 5).toDateTimeAtStartOfDay(DateTimeZone.UTC), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC), null));
-        blockingEvents.add(new DefaultBlockingState(UUID.randomUUID(), ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC), null));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, false, false, new LocalDate(2012, 7, 5).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, DISABLED_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+        blockingEvents.add(new DefaultBlockingState(ovdId, BlockingStateType.BUNDLE, CLEAR_BUNDLE, "test", false, false, false, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
 
         setBlockingStates(bundleId1, blockingEvents);
 
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 a013e59..c11a3d2 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
@@ -33,16 +33,13 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.bus.api.PersistentBus;
 import com.ning.billing.catalog.api.BillingActionPolicy;
-import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.api.Blockable;
+import com.ning.billing.entitlement.api.BlockingApiException;
 import com.ning.billing.entitlement.api.BlockingStateType;
 import com.ning.billing.entitlement.api.Entitlement;
 import com.ning.billing.entitlement.api.EntitlementApi;
 import com.ning.billing.entitlement.api.EntitlementApiException;
-import com.ning.billing.subscription.api.user.SubscriptionBaseApiException;
-import com.ning.billing.subscription.api.SubscriptionBase;
-import com.ning.billing.subscription.api.user.SubscriptionBaseBundle;
-import com.ning.billing.entitlement.api.Blockable;
-import com.ning.billing.entitlement.api.BlockingApiException;
 import com.ning.billing.ovedue.notification.OverdueCheckPoster;
 import com.ning.billing.overdue.OverdueApiException;
 import com.ning.billing.overdue.OverdueCancellationPolicicy;
@@ -52,14 +49,12 @@ import com.ning.billing.overdue.config.api.BillingState;
 import com.ning.billing.overdue.config.api.OverdueException;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.clock.Clock;
 import com.ning.billing.util.email.DefaultEmailSender;
 import com.ning.billing.util.email.EmailApiException;
 import com.ning.billing.util.email.EmailConfig;
 import com.ning.billing.util.email.EmailSender;
 import com.ning.billing.util.events.OverdueChangeInternalEvent;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
-import com.ning.billing.util.svcapi.subscription.SubscriptionBaseInternalApi;
 import com.ning.billing.util.svcapi.junction.BlockingInternalApi;
 import com.ning.billing.util.svcapi.junction.DefaultBlockingState;
 import com.ning.billing.util.svcapi.tag.TagInternalApi;
@@ -166,7 +161,7 @@ public class OverdueStateApplicator<T extends Blockable> {
     }
 
     private OverdueChangeInternalEvent createOverdueEvent(final Account overdueable, final String previousOverdueStateName, final String nextOverdueStateName, final InternalCallContext context) throws BlockingApiException {
-        return new DefaultOverdueChangeEvent(overdueable.getId(),  previousOverdueStateName, nextOverdueStateName,
+        return new DefaultOverdueChangeEvent(overdueable.getId(), previousOverdueStateName, nextOverdueStateName,
                                              context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
     }
 
diff --git a/overdue/src/test/java/com/ning/billing/overdue/glue/ApplicatorMockJunctionModule.java b/overdue/src/test/java/com/ning/billing/overdue/glue/ApplicatorMockJunctionModule.java
index dfed584..f37d8b9 100644
--- a/overdue/src/test/java/com/ning/billing/overdue/glue/ApplicatorMockJunctionModule.java
+++ b/overdue/src/test/java/com/ning/billing/overdue/glue/ApplicatorMockJunctionModule.java
@@ -66,7 +66,7 @@ public class ApplicatorMockJunctionModule extends AbstractModule {
                 }
 
                 @Override
-                public DateTime getTimestamp() {
+                public DateTime getEffectiveDate() {
                     return null;
                 }
 
@@ -142,6 +142,16 @@ public class ApplicatorMockJunctionModule extends AbstractModule {
             throw new UnsupportedOperationException();
         }
 
+        @Override
+        public List<BlockingState> getBlockingAll(final Blockable overdueable, final InternalTenantContext context) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public List<BlockingState> getBlockingAll(final UUID overdueableId, final InternalTenantContext context) {
+            throw new UnsupportedOperationException();
+        }
+
 
         @Override
         public void setBlockingState(final BlockingState state, final InternalCallContext context) {
diff --git a/util/src/main/java/com/ning/billing/util/svcapi/junction/BlockingInternalApi.java b/util/src/main/java/com/ning/billing/util/svcapi/junction/BlockingInternalApi.java
index 6b5cf5c..1833a36 100644
--- a/util/src/main/java/com/ning/billing/util/svcapi/junction/BlockingInternalApi.java
+++ b/util/src/main/java/com/ning/billing/util/svcapi/junction/BlockingInternalApi.java
@@ -38,6 +38,10 @@ public interface BlockingInternalApi {
 
     public List<BlockingState> getBlockingHistory(UUID overdueableId, InternalTenantContext context);
 
+    public List<BlockingState> getBlockingAll(Blockable overdueable, InternalTenantContext context);
+
+    public List<BlockingState> getBlockingAll(UUID overdueableId, InternalTenantContext context);
+
     public void setBlockingState(BlockingState state, InternalCallContext context);
 
 }
diff --git a/util/src/main/java/com/ning/billing/util/svcapi/junction/DefaultBlockingState.java b/util/src/main/java/com/ning/billing/util/svcapi/junction/DefaultBlockingState.java
index c2b532d..54e7a02 100644
--- a/util/src/main/java/com/ning/billing/util/svcapi/junction/DefaultBlockingState.java
+++ b/util/src/main/java/com/ning/billing/util/svcapi/junction/DefaultBlockingState.java
@@ -38,13 +38,13 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
     private final boolean blockChange;
     private final boolean blockEntitlement;
     private final boolean blockBilling;
-    private final DateTime timestamp;
+    private final DateTime effectiveDate;
     private final BlockingStateType type;
 
     public static BlockingState getClearState(final BlockingStateType type, final Clock clock) {
         if (clearState == null) {
             // STEPH_ENT should we not always have a service name?
-            clearState = new DefaultBlockingState(null, null, type, CLEAR_STATE_NAME, null, false, false, false, clock.getUTCNow(), clock.getUTCNow());
+            clearState = new DefaultBlockingState(null, type, CLEAR_STATE_NAME, null, false, false, false, clock.getUTCNow());
         }
         return clearState;
     }
@@ -58,6 +58,7 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
                                 final boolean blockChange,
                                 final boolean blockEntitlement,
                                 final boolean blockBilling,
+                                final DateTime effectiveDate,
                                 final DateTime createDate,
                                 final DateTime updatedDate) {
         super(id, createDate, updatedDate);
@@ -68,8 +69,10 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
         this.blockChange = blockChange;
         this.blockEntitlement = blockEntitlement;
         this.blockBilling = blockBilling;
-        this.timestamp = createDate;
+        this.effectiveDate = effectiveDate;
     }
+
+
     public DefaultBlockingState(final UUID blockingId,
                                 final BlockingStateType type,
                                  final String stateName,
@@ -77,7 +80,7 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
                                  final boolean blockChange,
                                  final boolean blockEntitlement,
                                  final boolean blockBilling,
-                                 final DateTime createDate) {
+                                 final DateTime effectiveDate) {
         this(UUID.randomUUID(),
              blockingId,
              type,
@@ -86,8 +89,9 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
              blockChange,
              blockEntitlement,
              blockBilling,
-             createDate,
-             createDate);
+             effectiveDate,
+             null,
+             null);
     }
 
     @Override
@@ -112,8 +116,8 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
     * @see com.ning.billing.junction.api.blocking.BlockingState#getTimestamp()
     */
     @Override
-    public DateTime getTimestamp() {
-        return timestamp;
+    public DateTime getEffectiveDate() {
+        return effectiveDate;
     }
 
     @Override
@@ -150,8 +154,8 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
      */
     @Override
     public int compareTo(final BlockingState arg0) {
-        if (timestamp.compareTo(arg0.getTimestamp()) != 0) {
-            return timestamp.compareTo(arg0.getTimestamp());
+        if (effectiveDate.compareTo(arg0.getEffectiveDate()) != 0) {
+            return effectiveDate.compareTo(arg0.getEffectiveDate());
         } else {
             return hashCode() - arg0.hashCode();
         }
@@ -167,7 +171,7 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
         result = prime * result + ((blockingId == null) ? 0 : blockingId.hashCode());
         result = prime * result + ((service == null) ? 0 : service.hashCode());
         result = prime * result + ((stateName == null) ? 0 : stateName.hashCode());
-        result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
+        result = prime * result + ((effectiveDate == null) ? 0 : effectiveDate.hashCode());
         return result;
     }
 
@@ -213,11 +217,11 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
         } else if (!stateName.equals(other.stateName)) {
             return false;
         }
-        if (timestamp == null) {
-            if (other.timestamp != null) {
+        if (effectiveDate == null) {
+            if (other.effectiveDate != null) {
                 return false;
             }
-        } else if (timestamp.compareTo(other.timestamp) != 0) {
+        } else if (effectiveDate.compareTo(other.effectiveDate) != 0) {
             return false;
         }
         return true;
@@ -247,6 +251,6 @@ public class DefaultBlockingState extends EntityBase implements BlockingState {
     public String toString() {
         return "BlockingState [blockingId=" + blockingId + ", stateName=" + stateName + ", service="
                 + service + ", blockChange=" + blockChange + ", blockEntitlement=" + blockEntitlement
-                + ", blockBilling=" + blockBilling + ", timestamp=" + timestamp + "]";
+                + ", blockBilling=" + blockBilling + ", effectiveDate=" + effectiveDate + "]";
     }
 }