killbill-memoizeit

Merge branch 'entitlement-bug-fixes'

10/30/2013 6:19:28 PM

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 2(+1 -1)

junction/pom.xml 2(+1 -1)

osgi/pom.xml 2(+1 -1)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

server/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

diff --git a/.idea/dictionaries/pierre.xml b/.idea/dictionaries/pierre.xml
index 044303d..987b7a2 100644
--- a/.idea/dictionaries/pierre.xml
+++ b/.idea/dictionaries/pierre.xml
@@ -2,6 +2,7 @@
   <dictionary name="pierre">
     <words>
       <w>aoped</w>
+      <w>blockable</w>
       <w>daos</w>
       <w>guice</w>
       <w>infos</w>

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 956cacc..4280b1b 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
index 328f846..10d4edc 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
@@ -87,25 +87,19 @@ getAccountByKey() ::= <<
 >>
 
 searchAccounts(searchKey, offset, rowCount) ::= <<
-select SQL_CALC_FOUND_ROWS <allTableFields()>
-from (
-  select <allTableFields()>
-  from accounts
-  where name like ('%<searchKey>%') <AND_CHECK_TENANT()>
-  union
-  select <allTableFields()>
-  from accounts
-  where email like ('%<searchKey>%') <AND_CHECK_TENANT()>
-  union
-  select <allTableFields()>
-  from accounts
-  where external_key like ('%<searchKey>%') <AND_CHECK_TENANT()>
-  union
-  select <allTableFields()>
-  from accounts
-  where company_name like ('%<searchKey>%') <AND_CHECK_TENANT()>
-) results
-order by results.record_id
+select SQL_CALC_FOUND_ROWS
+<allTableFields("t.")>
+from <tableName()> t
+where 1 = 1
+and (
+     <idField("t.")> = '<searchKey>'
+  or t.name like '%<searchKey>%'
+  or t.email like '%<searchKey>%'
+  or t.external_key like '%<searchKey>%'
+  or t.company_name like '%<searchKey>%'
+)
+<AND_CHECK_TENANT("t.")>
+order by <recordIdField("t.")> ASC
 limit :offset, :rowCount
 ;
 >>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index 4663821..6c128e9 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>
diff --git a/api/src/main/java/com/ning/billing/junction/BlockingInternalApi.java b/api/src/main/java/com/ning/billing/junction/BlockingInternalApi.java
index 7019e6a..bce4909 100644
--- a/api/src/main/java/com/ning/billing/junction/BlockingInternalApi.java
+++ b/api/src/main/java/com/ning/billing/junction/BlockingInternalApi.java
@@ -19,10 +19,10 @@ package com.ning.billing.junction;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.entitlement.api.Blockable;
-import com.ning.billing.entitlement.api.BlockingState;
 import com.ning.billing.callcontext.InternalCallContext;
 import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.entitlement.api.Blockable;
+import com.ning.billing.entitlement.api.BlockingState;
 
 public interface BlockingInternalApi {
 
@@ -34,10 +34,6 @@ public interface BlockingInternalApi {
 
     public List<BlockingState> getBlockingHistoryForService(UUID blockableId, String serviceName, InternalTenantContext context);
 
-    public List<BlockingState> getBlockingHistory(Blockable blockable, InternalTenantContext context);
-
-    public List<BlockingState> getBlockingHistory(UUID blockableId, InternalTenantContext context);
-
     public List<BlockingState> getBlockingAll(Blockable blockable, InternalTenantContext context);
 
     public List<BlockingState> getBlockingAll(UUID blockableId, InternalTenantContext context);

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 4f35f9e..6320eb8 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index fbeedf0..06840ca 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index cff903a..5653995 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
@@ -93,12 +93,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.ning.billing</groupId>
-            <artifactId>killbill-util</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>com.ning.billing.commons</groupId>
             <artifactId>killbill-clock</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 7eb1882..29b0d6a 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
@@ -234,20 +234,33 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
             throw new EntitlementApiException(ErrorCode.SUB_CANCEL_BAD_STATE, getId(), EntitlementState.CANCELLED);
         }
         final InternalCallContext contextWithValidAccountRecordId = internalCallContextFactory.createInternalCallContext(accountId, callContext);
-        final List<BlockingState> blockingStates = blockingStateDao.getBlockingHistoryForService(getId(), EntitlementService.ENTITLEMENT_SERVICE_NAME, contextWithValidAccountRecordId);
-        final Collection<BlockingState> filtered = Collections2.filter(blockingStates, new Predicate<BlockingState>() {
+        final List<BlockingState> blockingStatesForAccount = blockingStateDao.getBlockingAllForAccountRecordId(contextWithValidAccountRecordId);
+        final Collection<BlockingState> futureEntitlementCancellationEvents = Collections2.filter(blockingStatesForAccount, new Predicate<BlockingState>() {
             @Override
             public boolean apply(final BlockingState input) {
-                return EntitlementService.ENTITLEMENT_SERVICE_NAME.equals(input.getService()) && input.getEffectiveDate().isAfter(clock.getUTCNow());
+                // Delete all future cancellation events...
+                return EntitlementService.ENTITLEMENT_SERVICE_NAME.equals(input.getService()) &&
+                       DefaultEntitlementApi.ENT_STATE_CANCELLED.equals(input.getStateName()) &&
+                       input.getEffectiveDate().isAfter(clock.getUTCNow()) &&
+                       (
+                               // ... for that subscription
+                               BlockingStateType.SUBSCRIPTION.equals(input.getType()) && input.getBlockedId().equals(getId()) ||
+                               // ... for the associated base subscription (to make sure an add-on isn't associated with a cancelled base entitlement)
+                               BlockingStateType.SUBSCRIPTION.equals(input.getType()) && input.getBlockedId().equals(getBaseEntitlementId()) ||
+                               // ... for that bundle (to make sure the subscription isn't associated with a cancelled bundle - not yet implemented)
+                               BlockingStateType.SUBSCRIPTION_BUNDLE.equals(input.getType()) && input.getBlockedId().equals(getBundleId()) ||
+                               // ... for that bundle (to make sure the subscription isn't associated with a cancelled account - not yet implemented)
+                               BlockingStateType.ACCOUNT.equals(input.getType()) && input.getBlockedId().equals(getAccountId())
+                       );
             }
         });
-        final BlockingState futureCancellation = filtered.iterator().hasNext() ? filtered.iterator().next() : null;
-        if (futureCancellation == null) {
-            return;
-        }
 
         // Reactivate entitlement
-        blockingStateDao.unactiveBlockingState(futureCancellation.getId(), contextWithValidAccountRecordId);
+        // We should only have one future event in theory - but cleanup the data if it's not the case
+        // See https://github.com/killbill/killbill/issues/111
+        for (final BlockingState futureCancellation : futureEntitlementCancellationEvents) {
+            blockingStateDao.unactiveBlockingState(futureCancellation.getId(), contextWithValidAccountRecordId);
+        }
 
         // If billing was previously cancelled, reactivate
         if (subscriptionBase.getFutureEndDate() != null) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
index 4248ef9..4792c0e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/DefaultSubscriptionBundleTimeline.java
@@ -17,6 +17,7 @@
 package com.ning.billing.entitlement.api;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -226,24 +227,16 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
         return result;
     }
 
-
     private LinkedList<SubscriptionEvent> computeSubscriptionBaseEvents(final List<Entitlement> entitlements, final DateTimeZone accountTimeZone) {
-
         final LinkedList<SubscriptionEvent> result = new LinkedList<SubscriptionEvent>();
-        for (Entitlement cur : entitlements) {
+        for (final Entitlement cur : entitlements) {
             final SubscriptionBase base = ((DefaultEntitlement) cur).getSubscriptionBase();
             final List<SubscriptionBaseTransition> baseTransitions = base.getAllTransitions();
-            for (SubscriptionBaseTransition tr : baseTransitions) {
-                final SubscriptionEventType eventType = toEventType(tr.getTransitionType());
-                if (eventType == null) {
-                    continue;
-                }
-                final SubscriptionEvent event = toSubscriptionEvent(tr, eventType, accountTimeZone);
-                insertSubscriptionEvent(event, result);
-                if (tr.getTransitionType() == SubscriptionBaseTransitionType.CREATE ||
-                    tr.getTransitionType() == SubscriptionBaseTransitionType.TRANSFER) {
-                    final SubscriptionEvent billingEvent = toSubscriptionEvent(tr, SubscriptionEventType.START_BILLING, accountTimeZone);
-                    insertSubscriptionEvent(billingEvent, result);
+            for (final SubscriptionBaseTransition tr : baseTransitions) {
+                final List<SubscriptionEventType> eventTypes = toEventTypes(tr.getTransitionType());
+                for (final SubscriptionEventType eventType : eventTypes) {
+                    final SubscriptionEvent event = toSubscriptionEvent(tr, eventType, accountTimeZone);
+                    insertSubscriptionEvent(event, result);
                 }
             }
         }
@@ -251,14 +244,12 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
         return result;
     }
 
-
     //
-    // Old version of code would use CANCEL/ RE_CREATE to simulate PAUSE_BILLING/RESUME_BILLING
+    // Old version of code would use CANCEL/RE_CREATE to simulate PAUSE_BILLING/RESUME_BILLING
     //
     private void sanitizeForBaseRecreateEvents(final LinkedList<SubscriptionEvent> input) {
-
-        final Set<UUID> guiltyEntitlementIds = new TreeSet<UUID>();
-        ListIterator<SubscriptionEvent> it = input.listIterator(input.size());
+        final Collection<UUID> guiltyEntitlementIds = new TreeSet<UUID>();
+        final ListIterator<SubscriptionEvent> it = input.listIterator(input.size());
         while (it.hasPrevious()) {
             final SubscriptionEvent cur = it.previous();
             if (cur.getSubscriptionEventType() == SubscriptionEventType.RESUME_BILLING) {
@@ -268,13 +259,16 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
             if (cur.getSubscriptionEventType() == SubscriptionEventType.STOP_BILLING &&
                 guiltyEntitlementIds.contains(cur.getEntitlementId())) {
                 guiltyEntitlementIds.remove(cur.getEntitlementId());
-                final SubscriptionEvent correctedEvent = new DefaultSubscriptionEvent((DefaultSubscriptionEvent) cur, SubscriptionEventType.PAUSE_BILLING);
-                it.set(correctedEvent);
+                final SubscriptionEvent correctedBillingEvent = new DefaultSubscriptionEvent((DefaultSubscriptionEvent) cur, SubscriptionEventType.PAUSE_BILLING);
+                it.set(correctedBillingEvent);
+
+                // Old versions of the code won't have an associated event in blocking_states - we need to add one on the fly
+                final SubscriptionEvent correctedEntitlementEvent = new DefaultSubscriptionEvent((DefaultSubscriptionEvent) cur, SubscriptionEventType.PAUSE_ENTITLEMENT);
+                it.add(correctedEntitlementEvent);
             }
         }
     }
 
-
     private void insertSubscriptionEvent(final SubscriptionEvent event, final LinkedList<SubscriptionEvent> result) {
         int index = 0;
         for (SubscriptionEvent cur : result) {
@@ -374,25 +368,25 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
         }
     }
 
-    private SubscriptionEventType toEventType(final SubscriptionBaseTransitionType in) {
+    private List<SubscriptionEventType> toEventTypes(final SubscriptionBaseTransitionType in) {
         switch (in) {
             case CREATE:
-                return SubscriptionEventType.START_ENTITLEMENT;
-            case MIGRATE_ENTITLEMENT:
-                return SubscriptionEventType.START_ENTITLEMENT;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.START_ENTITLEMENT, SubscriptionEventType.START_BILLING);
             case TRANSFER:
-                return SubscriptionEventType.START_ENTITLEMENT;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.START_ENTITLEMENT, SubscriptionEventType.START_BILLING);
+            case MIGRATE_ENTITLEMENT:
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.START_ENTITLEMENT);
             case MIGRATE_BILLING:
-                return SubscriptionEventType.START_BILLING;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.START_BILLING);
             case CHANGE:
-                return SubscriptionEventType.CHANGE;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.CHANGE);
             case CANCEL:
-                return SubscriptionEventType.STOP_BILLING;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.STOP_BILLING);
             case PHASE:
-                return SubscriptionEventType.PHASE;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.PHASE);
             // STEPH This is the old way of pausing billing; not used any longer, but kept for compatibility reason
             case RE_CREATE:
-                return SubscriptionEventType.RESUME_BILLING;
+                return ImmutableList.<SubscriptionEventType>of(SubscriptionEventType.RESUME_ENTITLEMENT, SubscriptionEventType.RESUME_BILLING);
             /*
              * Those can be ignored:
              */
@@ -402,11 +396,10 @@ public class DefaultSubscriptionBundleTimeline implements SubscriptionBundleTime
             case START_BILLING_DISABLED:
             case END_BILLING_DISABLED:
             default:
-                return null;
+                return ImmutableList.<SubscriptionEventType>of();
         }
     }
 
-
     @Override
     public UUID getAccountId() {
         return accountId;
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 1e5d183..6cc1cd7 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
@@ -19,8 +19,6 @@ package com.ning.billing.entitlement.api.svcs;
 import java.util.List;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,16 +85,6 @@ public class DefaultInternalBlockingApi implements BlockingInternalApi {
     }
 
     @Override
-    public List<BlockingState> getBlockingHistory(final Blockable overdueable, final InternalTenantContext context) {
-        return dao.getBlockingHistory(overdueable.getId(), context);
-    }
-
-    @Override
-    public List<BlockingState> getBlockingHistory(final UUID overdueableId, final InternalTenantContext context) {
-        return dao.getBlockingHistory(overdueableId, context);
-    }
-
-    @Override
     public List<BlockingState> getBlockingAll(final Blockable overdueable, final InternalTenantContext context) {
         return dao.getBlockingAll(overdueable.getId(), context);
     }
@@ -129,7 +117,7 @@ public class DefaultInternalBlockingApi implements BlockingInternalApi {
     }
 
     private void postBlockingTransitionEvent(final UUID blockableId, final BlockingStateType type,
-            final BlockingAggregator previousState, final BlockingAggregator currentState, final InternalCallContext context) {
+                                             final BlockingAggregator previousState, final BlockingAggregator currentState, final InternalCallContext context) {
 
         try {
             final boolean isTransitionToBlockedBilling = !previousState.isBlockBilling() && currentState.isBlockBilling();
@@ -139,10 +127,10 @@ public class DefaultInternalBlockingApi implements BlockingInternalApi {
             final boolean isTransitionToUnblockedEntitlement = previousState.isBlockEntitlement() && !currentState.isBlockEntitlement();
 
             final BlockingTransitionInternalEvent event = new DefaultBlockingTransitionInternalEvent(blockableId, type,
-                                                                                               isTransitionToBlockedBilling, isTransitionToUnblockedBilling,
-                                                                                               isTransitionToBlockedEntitlement, isTransitionToUnblockedEntitlement,
+                                                                                                     isTransitionToBlockedBilling, isTransitionToUnblockedBilling,
+                                                                                                     isTransitionToBlockedEntitlement, isTransitionToUnblockedEntitlement,
 
-                                                                                               context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+                                                                                                     context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
 
             // TODO
             // STEPH Ideally we would like to post from transaction when we inserted the new blocking state, but new state would have to be recalculated from transaction which is
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 3a54f68..473d600 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
@@ -19,10 +19,10 @@ package com.ning.billing.entitlement.dao;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.entitlement.api.BlockingState;
 import com.ning.billing.callcontext.InternalCallContext;
 import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.api.BlockingState;
 
 public interface BlockingStateDao {
 
@@ -56,15 +56,6 @@ public interface BlockingStateDao {
     public List<BlockingState> getBlockingHistoryForService(UUID blockableId, String serviceName, InternalTenantContext context);
 
     /**
-     * Returns the state history across all the services
-     *
-     * @param blockableId
-     * @param context
-     * @return
-     */
-    public List<BlockingState> getBlockingHistory(UUID blockableId, InternalTenantContext context);
-
-    /**
      * Return all the events (past and future) across all services
      *
      * @param blockableId
@@ -76,6 +67,7 @@ public interface BlockingStateDao {
 
     /**
      * Return all events (past and future) across all services) for a given callcontext (account_record_id)
+     *
      * @param context
      * @return
      */
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 fbb82e2..e95ebe9 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
@@ -31,16 +31,16 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
+import com.ning.billing.callcontext.InternalCallContext;
+import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.entitlement.api.BlockingState;
 import com.ning.billing.entitlement.api.BlockingStateType;
+import com.ning.billing.junction.DefaultBlockingState;
 import com.ning.billing.util.audit.ChangeType;
-import com.ning.billing.callcontext.InternalCallContext;
-import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.util.dao.MapperBase;
 import com.ning.billing.util.entity.dao.Audited;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
-import com.ning.billing.junction.DefaultBlockingState;
 
 @EntitySqlDaoStringTemplate
 @RegisterMapper(BlockingStateSqlDao.BlockingHistorySqlMapper.class)
@@ -61,18 +61,11 @@ public interface BlockingStateSqlDao extends EntitySqlDao<BlockingStateModelDao,
     @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);
+                                                               @BindBean final InternalTenantContext context);
 
 
     @SqlUpdate
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 602ba75..c81784b 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
@@ -17,6 +17,9 @@
 package com.ning.billing.entitlement.dao;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.UUID;
 
@@ -25,11 +28,11 @@ import javax.inject.Inject;
 
 import org.skife.jdbi.v2.IDBI;
 
-import com.ning.billing.entitlement.api.BlockingState;
-import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.callcontext.InternalCallContext;
 import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
@@ -38,6 +41,7 @@ import com.ning.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Ordering;
 
 public class DefaultBlockingStateDao implements BlockingStateDao {
 
@@ -52,7 +56,7 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
 
     @Override
     public BlockingState getBlockingStateForService(final UUID blockableId, final String serviceName, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(  new EntitySqlDaoTransactionWrapper<BlockingState>() {
+        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, clock.getUTCNow().toDate(), context);
@@ -64,26 +68,10 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
 
     @Override
     public List<BlockingState> getBlockingState(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).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) {
-                        return BlockingStateModelDao.toBlockingState(src);
-                    }
-                }));
-            }
-        });
-    }
-
-    @Override
-    public List<BlockingState> getBlockingHistoryForService(final UUID blockableId, final String serviceName, 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).getBlockingHistoryForService(blockableId, serviceName, clock.getUTCNow().toDate(), 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) {
@@ -95,11 +83,11 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
     }
 
     @Override
-    public List<BlockingState> getBlockingHistory(final UUID blockableId, final InternalTenantContext context) {
+    public List<BlockingState> getBlockingHistoryForService(final UUID blockableId, final String serviceName, 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).getBlockingHistory(blockableId, clock.getUTCNow().toDate(), context);
+                final List<BlockingStateModelDao> models = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class).getBlockingHistoryForService(blockableId, serviceName, context);
                 return new ArrayList<BlockingState>(Collections2.transform(models, new Function<BlockingStateModelDao, BlockingState>() {
                     @Override
                     public BlockingState apply(@Nullable final BlockingStateModelDao src) {
@@ -147,8 +135,58 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+                final BlockingStateModelDao newBlockingStateModelDao = new BlockingStateModelDao(state, context);
+
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
-                sqlDao.create(new BlockingStateModelDao(state, context), context);
+                // Get all blocking states for that blocked id and service
+                final List<BlockingStateModelDao> allForBlockedItAndService = sqlDao.getBlockingHistoryForService(state.getBlockedId(), state.getService(), context);
+
+                // Add the new one (we rely below on the fact that the ID for newBlockingStateModelDao is now set)
+                allForBlockedItAndService.add(newBlockingStateModelDao);
+
+                // Re-order what should be the final list (allForBlockedItAndService is ordered by record_id in the SQL and we just added a new state)
+                final List<BlockingStateModelDao> allForBlockedItAndServiceOrdered = Ordering.<BlockingStateModelDao>from(new Comparator<BlockingStateModelDao>() {
+                    @Override
+                    public int compare(final BlockingStateModelDao o1, final BlockingStateModelDao o2) {
+                        // effective_date column NOT NULL
+                        final int comparison = o1.getEffectiveDate().compareTo(o2.getEffectiveDate());
+                        if (comparison == 0) {
+                            // Keep a stable ordering for ties
+                            return o1.getCreatedDate().compareTo(o2.getCreatedDate());
+                        } else {
+                            return comparison;
+                        }
+                    }
+                }).immutableSortedCopy(allForBlockedItAndService);
+
+                // Go through the (ordered) stream of blocking states for that blocked id and service and check
+                // if there is one or more blocking states for the same state following each others.
+                // If there are, delete them, as they are not needed anymore. A picture being worth a thousand words,
+                // if the current stream is: t0 S1 t1 S2 t3 S3 and we want to insert S2 at t0 < t1' < t1,
+                // the final stream should be: t0 S1 t1' S2 t3 S3 (and not t0 S1 t1' S2 t1 S2 t3 S3)
+                // Note that we also take care of the use case t0 S1 t1 S2 t2 S2 t3 S3 to cleanup legacy systems, although
+                // it shouldn't happen anymore
+                final Collection<UUID> blockingStatesToRemove = new HashSet<UUID>();
+                BlockingStateModelDao prevBlockingStateModelDao = null;
+                for (final BlockingStateModelDao blockingStateModelDao : allForBlockedItAndServiceOrdered) {
+                    if (prevBlockingStateModelDao != null && prevBlockingStateModelDao.getState().equals(blockingStateModelDao.getState())) {
+                        blockingStatesToRemove.add(blockingStateModelDao.getId());
+                    }
+                    prevBlockingStateModelDao = blockingStateModelDao;
+                }
+
+                // Delete unnecessary states (except newBlockingStateModelDao, which doesn't exist in the database)
+                for (final UUID blockedId : blockingStatesToRemove) {
+                    if (!newBlockingStateModelDao.getId().equals(blockedId)) {
+                        sqlDao.unactiveEvent(blockedId.toString(), context);
+                    }
+                }
+
+                // Create the state, if needed
+                if (!blockingStatesToRemove.contains(newBlockingStateModelDao.getId())) {
+                    sqlDao.create(new BlockingStateModelDao(state, context), context);
+                }
+
                 return null;
             }
         });
@@ -160,7 +198,7 @@ public class DefaultBlockingStateDao implements BlockingStateDao {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
                 final BlockingStateSqlDao sqlDao = entitySqlDaoWrapperFactory.become(BlockingStateSqlDao.class);
-                sqlDao.unactiveEvent(id.toString() , context);
+                sqlDao.unactiveEvent(id.toString(), context);
                 return null;
             }
         });
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 8cc83d5..d470eb9 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
@@ -82,18 +82,6 @@ order by record_id asc
 ;
 >>
 
-getBlockingHistory() ::= <<
-select
-<allTableFields()>
-from
-<tableName()>
-where blockable_id = :blockableId
-and is_active
-<AND_CHECK_TENANT()>
-order by record_id asc
-;
->>
-
 getBlockingAll() ::= <<
 select
 <allTableFields()>
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
index e367272..05d9adc 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
@@ -36,12 +36,12 @@ import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.Product;
 import com.ning.billing.entitlement.DefaultEntitlementService;
 import com.ning.billing.entitlement.EntitlementTestSuiteNoDB;
+import com.ning.billing.junction.DefaultBlockingState;
 import com.ning.billing.subscription.api.SubscriptionBase;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransition;
 import com.ning.billing.subscription.api.user.SubscriptionBaseTransitionData;
 import com.ning.billing.subscription.events.SubscriptionBaseEvent.EventType;
 import com.ning.billing.subscription.events.user.ApiEventType;
-import com.ning.billing.junction.DefaultBlockingState;
 
 import static org.testng.Assert.assertEquals;
 
@@ -116,11 +116,8 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
         assertEquals(events.get(3).getNextPhase(), null);
     }
 
-
-
     @Test(groups = "fast")
     public void testOneEntitlementWithRecreate() throws CatalogApiException {
-
         clock.setDay(new LocalDate(2013, 1, 1));
 
         final DateTimeZone accountTimeZone = DateTimeZone.UTC;
@@ -128,7 +125,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
         final UUID bundleId = UUID.randomUUID();
         final String externalKey = "foo";
 
-
         final UUID entitlementId = UUID.randomUUID();
 
         final List<SubscriptionBaseTransition> allTransitions = new ArrayList<SubscriptionBaseTransition>();
@@ -143,7 +139,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
         final SubscriptionBaseTransition tr2 = createTransition(entitlementId, EventType.PHASE, null, requestedDate, effectiveDate, clock.getUTCNow(), "trial", "phase");
         allTransitions.add(tr2);
 
-
         effectiveDate = effectiveDate.plusDays(15);
         clock.addDays(15);
         final SubscriptionBaseTransition tr3 = createTransition(entitlementId, EventType.API_USER, ApiEventType.CANCEL, requestedDate, effectiveDate, clock.getUTCNow(), "phase", null);
@@ -154,41 +149,44 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
         final SubscriptionBaseTransition tr4 = createTransition(entitlementId, EventType.API_USER, ApiEventType.RE_CREATE, requestedDate, effectiveDate, clock.getUTCNow(), null, "phase");
         allTransitions.add(tr4);
 
-
         final List<Entitlement> entitlements = new ArrayList<Entitlement>();
         final Entitlement entitlement = createEntitlement(entitlementId, allTransitions);
         entitlements.add(entitlement);
 
-        final DefaultSubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements, Collections.<BlockingState>emptyList());
+        final SubscriptionBundleTimeline timeline = new DefaultSubscriptionBundleTimeline(accountTimeZone, accountId, bundleId, externalKey, entitlements, Collections.<BlockingState>emptyList());
 
         assertEquals(timeline.getAccountId(), accountId);
         assertEquals(timeline.getBundleId(), bundleId);
         assertEquals(timeline.getExternalKey(), externalKey);
 
-        List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
-        assertEquals(events.size(), 5);
+        final List<SubscriptionEvent> events = timeline.getSubscriptionEvents();
+        assertEquals(events.size(), 7);
 
         assertEquals(events.get(0).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
         assertEquals(events.get(1).getEffectiveDate().compareTo(new LocalDate(tr1.getEffectiveTransitionTime(), accountTimeZone)), 0);
         assertEquals(events.get(2).getEffectiveDate().compareTo(new LocalDate(tr2.getEffectiveTransitionTime(), accountTimeZone)), 0);
         assertEquals(events.get(3).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
-        assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(tr4.getEffectiveTransitionTime(), accountTimeZone)), 0);
+        assertEquals(events.get(4).getEffectiveDate().compareTo(new LocalDate(tr3.getEffectiveTransitionTime(), accountTimeZone)), 0);
+        assertEquals(events.get(5).getEffectiveDate().compareTo(new LocalDate(tr4.getEffectiveTransitionTime(), accountTimeZone)), 0);
+        assertEquals(events.get(6).getEffectiveDate().compareTo(new LocalDate(tr4.getEffectiveTransitionTime(), accountTimeZone)), 0);
 
         assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
         assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
         assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
-        assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
-        assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
+        assertEquals(events.get(3).getSubscriptionEventType(), SubscriptionEventType.PAUSE_ENTITLEMENT);
+        assertEquals(events.get(4).getSubscriptionEventType(), SubscriptionEventType.PAUSE_BILLING);
+        assertEquals(events.get(5).getSubscriptionEventType(), SubscriptionEventType.RESUME_ENTITLEMENT);
+        assertEquals(events.get(6).getSubscriptionEventType(), SubscriptionEventType.RESUME_BILLING);
 
         assertEquals(events.get(0).getNextPhase().getName(), "trial");
         assertEquals(events.get(1).getNextPhase().getName(), "trial");
         assertEquals(events.get(2).getNextPhase().getName(), "phase");
         assertEquals(events.get(3).getNextPhase(), null);
-        assertEquals(events.get(4).getNextPhase().getName(), "phase");
+        assertEquals(events.get(4).getNextPhase(), null);
+        assertEquals(events.get(5).getNextPhase().getName(), "phase");
+        assertEquals(events.get(6).getNextPhase().getName(), "phase");
     }
 
-
-
     @Test(groups = "fast")
     public void testOneEntitlementWithInitialBlockingState() throws CatalogApiException {
 
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 43895ee..5dae30d 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
@@ -41,7 +41,7 @@ public class MockBlockingStateDao implements BlockingStateDao {
 
     @Override
     public BlockingState getBlockingStateForService(final UUID blockableId, final String serviceName, final InternalTenantContext context) {
-        final List<BlockingState> states = getBlockingHistory(blockableId, context);
+        final List<BlockingState> states = getBlockingAll(blockableId, context);
         if (states == null) {
             return null;
         }
@@ -89,13 +89,6 @@ public class MockBlockingStateDao implements BlockingStateDao {
     }
 
     @Override
-    public List<BlockingState> getBlockingHistory(final UUID overdueableId, final InternalTenantContext context) {
-        final List<BlockingState> states = blockingStates.get(overdueableId);
-        // Note! The returned list cannot be immutable!
-        return states == null ? new ArrayList<BlockingState>() : states;
-    }
-
-    @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!
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestBlockingDao.java b/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestBlockingDao.java
index 4092a0a..c9d3e53 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestBlockingDao.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestBlockingDao.java
@@ -91,7 +91,7 @@ public class TestBlockingDao extends EntitlementTestSuiteWithEmbeddedDB {
         final SubscriptionBaseBundle bundle = Mockito.mock(SubscriptionBaseBundle.class);
         Mockito.when(bundle.getId()).thenReturn(uuid);
 
-        final List<BlockingState> history2 = blockingStateDao.getBlockingHistory(bundle.getId(), internalCallContext);
+        final List<BlockingState> history2 = blockingStateDao.getBlockingAll(bundle.getId(), internalCallContext);
         Assert.assertEquals(history2.size(), 2);
         Assert.assertEquals(history2.get(0).getStateName(), overdueStateName);
         Assert.assertEquals(history2.get(1).getStateName(), overdueStateName2);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestDefaultBlockingStateDao.java b/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestDefaultBlockingStateDao.java
new file mode 100644
index 0000000..31a87a2
--- /dev/null
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/dao/TestDefaultBlockingStateDao.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.entitlement.dao;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
+import com.ning.billing.entitlement.api.BlockingState;
+import com.ning.billing.entitlement.api.BlockingStateType;
+import com.ning.billing.junction.DefaultBlockingState;
+
+public class TestDefaultBlockingStateDao extends EntitlementTestSuiteWithEmbeddedDB {
+
+    // See https://github.com/killbill/killbill/issues/111
+    @Test(groups = "slow", description = "Verify we don't insert duplicate blocking states")
+    public void testSetBlockingState() throws Exception {
+        final UUID blockableId = UUID.randomUUID();
+        final BlockingStateType type = BlockingStateType.ACCOUNT;
+        final String state = "state";
+        final String state2 = "state-2";
+        final String serviceA = "service-A";
+        final String serviceB = "service-B";
+
+        // Verify initial state
+        Assert.assertEquals(blockingStateDao.getBlockingAll(blockableId, internalCallContext).size(), 0);
+
+        // Note: the checkers below rely on record_id ordering, not effective date
+
+        // Set a state for service A
+        final DateTime stateDateTime = new DateTime(2013, 5, 6, 10, 11, 12, DateTimeZone.UTC);
+        final BlockingState blockingState1 = new DefaultBlockingState(blockableId, type, state, serviceA, false, false, false, stateDateTime);
+        blockingStateDao.setBlockingState(blockingState1, clock, internalCallContext);
+        final List<BlockingState> blockingStates1 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates1.size(), 1);
+        Assert.assertEquals(blockingStates1.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates1.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates1.get(0).getService(), serviceA);
+        Assert.assertEquals(blockingStates1.get(0).getEffectiveDate(), stateDateTime);
+
+        // Set the same state again - no change
+        blockingStateDao.setBlockingState(blockingState1, clock, internalCallContext);
+        final List<BlockingState> blockingStates2 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates2.size(), 1);
+        Assert.assertEquals(blockingStates2.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates2.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates2.get(0).getService(), serviceA);
+        Assert.assertEquals(blockingStates2.get(0).getEffectiveDate(), stateDateTime);
+
+        // Set the state for service B
+        final BlockingState blockingState2 = new DefaultBlockingState(blockableId, type, state, serviceB, false, false, false, stateDateTime);
+        blockingStateDao.setBlockingState(blockingState2, clock, internalCallContext);
+        final List<BlockingState> blockingStates3 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates3.size(), 2);
+        Assert.assertEquals(blockingStates3.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates3.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates3.get(0).getService(), serviceA);
+        Assert.assertEquals(blockingStates3.get(0).getEffectiveDate(), stateDateTime);
+        Assert.assertEquals(blockingStates3.get(1).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates3.get(1).getStateName(), state);
+        Assert.assertEquals(blockingStates3.get(1).getService(), serviceB);
+        Assert.assertEquals(blockingStates3.get(1).getEffectiveDate(), stateDateTime);
+
+        // Set the state for service A in the future - there should be no change (already effective)
+        final DateTime stateDateTime2 = new DateTime(2013, 6, 6, 10, 11, 12, DateTimeZone.UTC);
+        final BlockingState blockingState3 = new DefaultBlockingState(blockableId, type, state, serviceA, false, false, false, stateDateTime2);
+        blockingStateDao.setBlockingState(blockingState3, clock, internalCallContext);
+        final List<BlockingState> blockingStates4 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates4.size(), 2);
+        Assert.assertEquals(blockingStates4.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates4.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates4.get(0).getService(), serviceA);
+        Assert.assertEquals(blockingStates4.get(0).getEffectiveDate(), stateDateTime);
+        Assert.assertEquals(blockingStates4.get(1).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates4.get(1).getStateName(), state);
+        Assert.assertEquals(blockingStates4.get(1).getService(), serviceB);
+        Assert.assertEquals(blockingStates4.get(1).getEffectiveDate(), stateDateTime);
+
+        // Set the state for service A in the past - the new effective date should be respected
+        final DateTime stateDateTime3 = new DateTime(2013, 2, 6, 10, 11, 12, DateTimeZone.UTC);
+        final BlockingState blockingState4 = new DefaultBlockingState(blockableId, type, state, serviceA, false, false, false, stateDateTime3);
+        blockingStateDao.setBlockingState(blockingState4, clock, internalCallContext);
+        final List<BlockingState> blockingStates5 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates5.size(), 2);
+        Assert.assertEquals(blockingStates5.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates5.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates5.get(0).getService(), serviceB);
+        Assert.assertEquals(blockingStates5.get(0).getEffectiveDate(), stateDateTime);
+        Assert.assertEquals(blockingStates5.get(1).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates5.get(1).getStateName(), state);
+        Assert.assertEquals(blockingStates5.get(1).getService(), serviceA);
+        Assert.assertEquals(blockingStates5.get(1).getEffectiveDate(), stateDateTime3);
+
+        // Set a new state for service A
+        final DateTime state2DateTime = new DateTime(2013, 12, 6, 10, 11, 12, DateTimeZone.UTC);
+        final BlockingState blockingState5 = new DefaultBlockingState(blockableId, type, state2, serviceA, false, false, false, state2DateTime);
+        blockingStateDao.setBlockingState(blockingState5, clock, internalCallContext);
+        final List<BlockingState> blockingStates6 = blockingStateDao.getBlockingAll(blockableId, internalCallContext);
+        Assert.assertEquals(blockingStates6.size(), 3);
+        Assert.assertEquals(blockingStates6.get(0).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates6.get(0).getStateName(), state);
+        Assert.assertEquals(blockingStates6.get(0).getService(), serviceB);
+        Assert.assertEquals(blockingStates6.get(0).getEffectiveDate(), stateDateTime);
+        Assert.assertEquals(blockingStates6.get(1).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates6.get(1).getStateName(), state);
+        Assert.assertEquals(blockingStates6.get(1).getService(), serviceA);
+        Assert.assertEquals(blockingStates6.get(1).getEffectiveDate(), stateDateTime3);
+        Assert.assertEquals(blockingStates6.get(2).getBlockedId(), blockableId);
+        Assert.assertEquals(blockingStates6.get(2).getStateName(), state2);
+        Assert.assertEquals(blockingStates6.get(2).getService(), serviceA);
+        Assert.assertEquals(blockingStates6.get(2).getEffectiveDate(), state2DateTime);
+    }
+}

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 7e72c1f..294bcd0 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>

jaxrs/pom.xml 2(+1 -1)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index c11eef0..79ce43a 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>

junction/pom.xml 2(+1 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index aa679bc..013d4db 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>

osgi/pom.xml 2(+1 -1)

diff --git a/osgi/pom.xml b/osgi/pom.xml
index 27b57f7..2ac1d46 100644
--- a/osgi/pom.xml
+++ b/osgi/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi</artifactId>
diff --git a/osgi-bundles/bundles/jruby/pom.xml b/osgi-bundles/bundles/jruby/pom.xml
index 42b79ff..0d60e2c 100644
--- a/osgi-bundles/bundles/jruby/pom.xml
+++ b/osgi-bundles/bundles/jruby/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill-osgi-bundles</artifactId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-jruby</artifactId>
diff --git a/osgi-bundles/bundles/logger/pom.xml b/osgi-bundles/bundles/logger/pom.xml
index 642ccfe..68d763d 100644
--- a/osgi-bundles/bundles/logger/pom.xml
+++ b/osgi-bundles/bundles/logger/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-logger</artifactId>
diff --git a/osgi-bundles/bundles/pom.xml b/osgi-bundles/bundles/pom.xml
index d812c6e..d4d0c49 100644
--- a/osgi-bundles/bundles/pom.xml
+++ b/osgi-bundles/bundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles</artifactId>
diff --git a/osgi-bundles/bundles/webconsolebranding/pom.xml b/osgi-bundles/bundles/webconsolebranding/pom.xml
index 0ef7e0f..ff72053 100644
--- a/osgi-bundles/bundles/webconsolebranding/pom.xml
+++ b/osgi-bundles/bundles/webconsolebranding/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-webconsolebranding</artifactId>
diff --git a/osgi-bundles/defaultbundles/pom.xml b/osgi-bundles/defaultbundles/pom.xml
index 90a21eb..d763512 100644
--- a/osgi-bundles/defaultbundles/pom.xml
+++ b/osgi-bundles/defaultbundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-defaultbundles</artifactId>
diff --git a/osgi-bundles/libs/killbill/pom.xml b/osgi-bundles/libs/killbill/pom.xml
index 0b116ad..bae5871 100644
--- a/osgi-bundles/libs/killbill/pom.xml
+++ b/osgi-bundles/libs/killbill/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-killbill</artifactId>
diff --git a/osgi-bundles/libs/pom.xml b/osgi-bundles/libs/pom.xml
index cd6c994..e3b1305 100644
--- a/osgi-bundles/libs/pom.xml
+++ b/osgi-bundles/libs/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-lib-bundles</artifactId>
diff --git a/osgi-bundles/libs/slf4j-osgi/pom.xml b/osgi-bundles/libs/slf4j-osgi/pom.xml
index c6bbd8b..213b4ca 100644
--- a/osgi-bundles/libs/slf4j-osgi/pom.xml
+++ b/osgi-bundles/libs/slf4j-osgi/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-lib-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-lib-slf4j-osgi</artifactId>
diff --git a/osgi-bundles/pom.xml b/osgi-bundles/pom.xml
index 4209588..f053e0b 100644
--- a/osgi-bundles/pom.xml
+++ b/osgi-bundles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-all-bundles</artifactId>
diff --git a/osgi-bundles/tests/beatrix/pom.xml b/osgi-bundles/tests/beatrix/pom.xml
index 8bfdc34..74b6fb2 100644
--- a/osgi-bundles/tests/beatrix/pom.xml
+++ b/osgi-bundles/tests/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-test-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-beatrix</artifactId>
diff --git a/osgi-bundles/tests/payment/pom.xml b/osgi-bundles/tests/payment/pom.xml
index d19819c..49050ea 100644
--- a/osgi-bundles/tests/payment/pom.xml
+++ b/osgi-bundles/tests/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-test-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-bundles-test-payment</artifactId>
diff --git a/osgi-bundles/tests/pom.xml b/osgi-bundles/tests/pom.xml
index 3fa0468..191b749 100644
--- a/osgi-bundles/tests/pom.xml
+++ b/osgi-bundles/tests/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill-osgi-all-bundles</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-osgi-test-bundles</artifactId>

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index bdf715e..6f233f3 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>
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 4dbaa2c..d239661 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
@@ -133,16 +133,6 @@ public class ApplicatorMockJunctionModule extends AbstractModule {
         }
 
         @Override
-        public List<BlockingState> getBlockingHistory(final Blockable blockable, final InternalTenantContext context) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public List<BlockingState> getBlockingHistory(final UUID blockableId, final InternalTenantContext context) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
         public List<BlockingState> getBlockingAll(final Blockable blockable, final InternalTenantContext context) {
             throw new UnsupportedOperationException();
         }

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index a54921f..d8d7f43 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 33db792..832de7c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
         <version>0.5.4</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.7.2-SNAPSHOT</version>
+    <version>0.7.3-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>

server/pom.xml 2(+1 -1)

diff --git a/server/pom.xml b/server/pom.xml
index 3d3696d..cfc825d 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-server</artifactId>
diff --git a/server/src/main/resources/update-checker/killbill-server-update-list.properties b/server/src/main/resources/update-checker/killbill-server-update-list.properties
index 9a6a681..311c8be 100644
--- a/server/src/main/resources/update-checker/killbill-server-update-list.properties
+++ b/server/src/main/resources/update-checker/killbill-server-update-list.properties
@@ -1,17 +1,27 @@
 ## Top level keys
 # general.notice = This notice should rarely, if ever, be used as everyone will see it
 
-## 0.7.0 -- latest release
-0.7.0.updates           =
-0.7.0.notices           = This is the latest GA release.
+## 0.7.2 -- latest release
+0.7.2.updates           =
+0.7.2.notices           = This is the latest GA release.
+0.7.2.release-notes     = http://kill-bill.org
+
+## 0.7.1
+0.7.1.updates           = 0.7.2
+0.7.1.notices           = We recommend upgrading to 0.7.2, our latest GA release.
+0.7.1.release-notes     = http://kill-bill.org
+
+## 0.7.0
+0.7.0.updates           = 0.7.2
+0.7.0.notices           = We recommend upgrading to 0.7.2, our latest GA release.
 0.7.0.release-notes     = http://kill-bill.org
 
 ## 0.6.17
 0.6.17.updates           =
-0.6.17.notices           = We recommend upgrading to 0.7.0, our latest GA release.
+0.6.17.notices           = We recommend upgrading to 0.7.2, our latest GA release.
 0.6.17.release-notes     = http://kill-bill.org
 
 ## 0.6.16
 0.6.16.updates           = 0.6.17
-0.6.16.notices           = We recommend upgrading to 0.7.0, our latest GA release.
+0.6.16.notices           = We recommend upgrading to 0.7.2, our latest GA release.
 0.6.16.release-notes     = http://kill-bill.org
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index e559557..5c0542e 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -319,6 +319,11 @@ public class TestAccount extends TestJaxrsBase {
     }
 
     private void searchAccount(final AccountJson input, @Nullable final AccountJson output) throws Exception {
+        // Search by id
+        if (output != null) {
+            doSearchAccount(input.getAccountId(), output);
+        }
+
         // Search by name
         doSearchAccount(input.getName(), output);
 
diff --git a/subscription/pom.xml b/subscription/pom.xml
index 56391e0..ff5f13a 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index ca1848d..11cd356 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index cc56b31..77d45fc 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index f2aa377..99220d4 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -12,7 +12,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>com.ning.billing</groupId>
-        <version>0.7.2-SNAPSHOT</version>
+        <version>0.7.3-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>