killbill-aplcache

Ingoing entitlement repair work

4/19/2012 10:26:51 PM

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index 8a833ec..6ab0eea 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -70,6 +70,9 @@ public enum ErrorCode {
     ENT_REPAIR_UNKNOWN_SUBSCRIPTION(1098, "Unknown subscription %s"),     
     ENT_REPAIR_NO_ACTIVE_SUBSCRIPTIONS(1099, "No active subscriptions on bundle %s"),         
     ENT_REPAIR_VIEW_CHANGED(1100, "View for bundle %s has changed from %s to %s"),             
+    ENT_REPAIR_SUB_RECREATE_NOT_EMPTY(1101, "Subscription %s with recreation for bundle %s should specify all existing events to be deleted"),    
+    ENT_REPAIR_BP_RECREATE_MISSING_AO(1102, "BP recreation for bundle %s implies repair all subscriptions"),    
+    ENT_REPAIR_BP_RECREATE_MISSING_AO_CREATE(1103, "BP recreation for bundle %s implies that all AO should be start also with a CREATE"),        
     
     /*
     *
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index a3a22cf..c03d798 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -194,7 +194,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
             .setChargedThroughDate(ctd)
             .setPaidThroughDate(subscription.getPaidThroughDate());
 
-        entitlementDao.updateSubscription(new SubscriptionData(builder), context);
+        entitlementDao.updateChargedThroughDate(new SubscriptionData(builder), context);
     }
 
     @Override
@@ -206,12 +206,9 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         if (subscription == null) {
             log.warn("Subscription not found when setting CTD.");
         } else {
-            Date paidThroughDate = (subscription.getPaidThroughDate() == null) ? null : subscription.getPaidThroughDate().toDate();
-
             DateTime chargedThroughDate = subscription.getChargedThroughDate();
             if (chargedThroughDate == null || chargedThroughDate.isBefore(ctd)) {
-                subscriptionSqlDao.updateSubscription(subscriptionId.toString(), subscription.getActiveVersion(),
-                                                      ctd.toDate(), paidThroughDate, context);
+                subscriptionSqlDao.updateActiveVersion(subscriptionId.toString(), subscription.getActiveVersion(), context);
                 AuditSqlDao auditSqlDao = transactionalDao.become(AuditSqlDao.class);
                 auditSqlDao.insertAuditFromTransaction(SUBSCRIPTION_TABLE_NAME, subscriptionId.toString(), ChangeType.UPDATE, context);
             }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
index 5dbb3a2..4db5523 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
@@ -33,6 +33,7 @@ import com.google.inject.name.Named;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.repair.SubscriptionRepair.ExistingEvent;
 import com.ning.billing.entitlement.api.repair.SubscriptionRepair.NewEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
@@ -61,7 +62,7 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
         this.repairDao = repairDao;
         this.factory = factory;
     }
-    
+
 
     @Override
     public BundleRepair getBundleRepair(final UUID bundleId) 
@@ -79,34 +80,36 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
         final List<SubscriptionRepair> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionRepair>emptyList()); 
         return createGetBundleRepair(bundleId, viewId, repairs);
     }
-
-
+    
 
     @Override
     public BundleRepair repairBundle(final BundleRepair input, final boolean dryRun, final CallContext context)
     throws EntitlementRepairException {
 
         try {
-            
+
             SubscriptionBundle bundle = dao.getSubscriptionBundleFromId(input.getBundleId());
             if (bundle == null) {
                 throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_BUNDLE, input.getBundleId());
             }
-            
+
             // Subscriptions are ordered with BASE subscription first-- if exists
             final List<Subscription> subscriptions = dao.getSubscriptions(factory, input.getBundleId());
             if (subscriptions.size() == 0) {
-                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_BUNDLE,input.getBundleId());
+                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_NO_ACTIVE_SUBSCRIPTIONS, input.getBundleId());
             }
-            
+
             final String viewId = getViewId(((SubscriptionBundleData) bundle).getLastSysUpdateTime(), subscriptions);
             if (!viewId.equals(input.getViewId())) {
                 throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_VIEW_CHANGED,input.getBundleId(), input.getViewId(), viewId);
             }
-            
+
             DateTime firstDeletedBPEventTime = null;
             DateTime lastRemainingBPEventTime = null;
 
+            boolean isBasePlanRecreate = false;
+            DateTime newBundleStartDate = null;
+
             SubscriptionDataRepair baseSubscriptionRepair = null;
             List<SubscriptionDataRepair> addOnSubscriptionInRepair = new LinkedList<SubscriptionDataRepair>();
             List<SubscriptionDataRepair> inRepair =  new LinkedList<SubscriptionDataRepair>();
@@ -117,23 +120,35 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
                     SubscriptionDataRepair curData = ((SubscriptionDataRepair) cur);
                     List<EntitlementEvent> remaining = getRemainingEventsAndValidateDeletedEvents(curData, firstDeletedBPEventTime, curRepair.getDeletedEvents());
 
+                    
+                    
+                    boolean isPlanRecreate = (curRepair.getNewEvents().size() > 0 
+                            && (curRepair.getNewEvents().get(0).getSubscriptionTransitionType() == SubscriptionTransitionType.CREATE 
+                                    || curRepair.getNewEvents().get(0).getSubscriptionTransitionType() == SubscriptionTransitionType.RE_CREATE));
+                    
+                    DateTime newSubscriptionStartDate = isPlanRecreate ? curRepair.getNewEvents().get(0).getRequestedDate() : null;
+                    
+                    if (isPlanRecreate && remaining.size() != 0) {
+                        throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_SUB_RECREATE_NOT_EMPTY, cur.getId(), cur.getBundleId());
+                    }
+                    
                     if (cur.getCategory() == ProductCategory.BASE) {
+
                         int bpTransitionSize =((SubscriptionData) cur).getAllTransitions().size();
                         lastRemainingBPEventTime = (remaining.size() > 0) ? curData.getAllTransitions().get(remaining.size() - 1).getEffectiveTransitionTime() : null;
                         firstDeletedBPEventTime =  (remaining.size() < bpTransitionSize) ? curData.getAllTransitions().get(remaining.size()).getEffectiveTransitionTime() : null;
+
+                        isBasePlanRecreate = isPlanRecreate;
+                        newBundleStartDate = newSubscriptionStartDate;
                     }
 
-                    if (curRepair.getNewEvents() != null && curRepair.getNewEvents().size() > 0) {
-                        Collections.sort(curRepair.getNewEvents(), new Comparator<NewEvent>() {
-                            @Override
-                            public int compare(NewEvent o1, NewEvent o2) {
-                                return o1.getRequestedDate().compareTo(o2.getRequestedDate());
-                            }
-                        });
+                    if (curRepair.getNewEvents().size() > 0) {
                         DateTime lastRemainingEventTime = (remaining.size() == 0) ? null : curData.getAllTransitions().get(remaining.size() - 1).getEffectiveTransitionTime();
                         validateFirstNewEvent(curData, curRepair.getNewEvents().get(0), lastRemainingBPEventTime, lastRemainingEventTime);
                     }
-                    SubscriptionDataRepair sRepair = createSubscriptionDataRepair(curData, remaining);
+
+
+                    SubscriptionDataRepair sRepair = createSubscriptionDataRepair(curData, newBundleStartDate, newSubscriptionStartDate, remaining);
                     repairDao.initializeRepair(curData.getId(), remaining);
                     inRepair.add(sRepair);
                     if (sRepair.getCategory() == ProductCategory.ADD_ON) {
@@ -144,20 +159,8 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
                 }
             }
 
-            if (input.getSubscriptions().size() != inRepair.size()) {
-                for (SubscriptionRepair cur : input.getSubscriptions()) {
-                    boolean found = false;
-                    for (Subscription s : subscriptions) {
-                        if (s.getId().equals(cur.getId())) {
-                            found = true;
-                            break;
-                        }
-                    }
-                    if (!found) {
-                        throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_SUBSCRIPTION, cur.getId());
-                    }
-                }
-            }
+            validateBasePlanRecreate(isBasePlanRecreate, subscriptions, input.getSubscriptions());
+            validateInputSubscriptionsKnown(subscriptions, input.getSubscriptions());
 
             TreeSet<NewEvent> newEventSet = new TreeSet<SubscriptionRepair.NewEvent>(new Comparator<NewEvent>() {
                 @Override
@@ -185,84 +188,52 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
                 final List<SubscriptionRepair> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair)); 
                 return createGetBundleRepair(input.getBundleId(), input.getViewId(), repairs);
             } else {
-                // STEPH no implemented yet
-                return null;
+                dao.repair(input.getBundleId(), inRepair, context);
+                bundle = dao.getSubscriptionBundleFromId(input.getBundleId());
+                String newViewId = getViewId(((SubscriptionBundleData) bundle).getLastSysUpdateTime(), subscriptions);
+                final List<SubscriptionRepair> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionRepair>emptyList()); 
+                return createGetBundleRepair(input.getBundleId(), viewId, repairs);
             }
         } finally {
             repairDao.cleanup();
         }
     }
-    
-    private String getViewId(DateTime lastUpdateBundleDate, List<Subscription> subscriptions) {
-        StringBuilder tmp = new StringBuilder();
-        long lastOrderedId = -1;
-        for (Subscription cur : subscriptions) {
-            lastOrderedId = lastOrderedId < ((SubscriptionData) cur).getLastEventOrderedId() ? ((SubscriptionData) cur).getLastEventOrderedId() : lastOrderedId;
-        }
-        tmp.append(lastOrderedId);
-        tmp.append("-");
-        tmp.append(lastUpdateBundleDate.toDate().getTime());
-        return tmp.toString();
-    }
 
-    private BundleRepair createGetBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionRepair> repairList) {
-        return new BundleRepair() {
-            @Override
-            public String getViewId() {
-                return viewId;
-            }
-            @Override
-            public List<SubscriptionRepair> getSubscriptions() {
-                return repairList;
-            }
-            @Override
-            public UUID getBundleId() {
-                return bundleId;
-            }
-        };
-
-    }
     
-    private List<SubscriptionRepair> createGetSubscriptionRepairList(final List<Subscription> subscriptions, final List<SubscriptionRepair> inRepair) {
-
-        final List<SubscriptionRepair> result = new LinkedList<SubscriptionRepair>();
-        Set<UUID> repairIds = new TreeSet<UUID>();
-        for (final SubscriptionRepair cur : inRepair) {
-            repairIds.add(cur.getId());
-            result.add(cur);
+    private void validateBasePlanRecreate(boolean isBasePlanRecreate, List<Subscription> subscriptions, List<SubscriptionRepair> input) 
+        throws EntitlementRepairException  {
+        
+        if (!isBasePlanRecreate) {
+            return;
         }
-        for (final Subscription cur : subscriptions) {
-            if ( !repairIds.contains(cur.getId())) { 
-                result.add(new DefaultSubscriptionRepair((SubscriptionData) cur));
-            }
+        if (subscriptions.size() != input.size()) {
+            throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_BP_RECREATE_MISSING_AO, subscriptions.get(0).getBundleId());
         }
-        return result;
-    }
-
-
-    private List<SubscriptionRepair> convertDataRepair(List<SubscriptionDataRepair> input) {
-        List<SubscriptionRepair> result = new LinkedList<SubscriptionRepair>();
-        for (SubscriptionDataRepair cur : input) {
-            result.add(new DefaultSubscriptionRepair(cur));
+        for (SubscriptionRepair cur : input) {
+            if (cur.getNewEvents().size() != 0 
+                    && (cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionTransitionType.CREATE
+                            && cur.getNewEvents().get(0).getSubscriptionTransitionType() != SubscriptionTransitionType.RE_CREATE)) {
+                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_BP_RECREATE_MISSING_AO_CREATE, subscriptions.get(0).getBundleId());
+            }
         }
-        return result;
     }
+    
+    
+    private void validateInputSubscriptionsKnown(List<Subscription> subscriptions, List<SubscriptionRepair> input)
+        throws EntitlementRepairException {
 
-    private SubscriptionDataRepair findSubscriptionDataRepair(final UUID targetId, final List<SubscriptionDataRepair> input) {
-        for (SubscriptionDataRepair cur : input) {
-            if (cur.getId().equals(targetId)) {
-                return cur;
+        for (SubscriptionRepair cur : input) {
+            boolean found = false;
+            for (Subscription s : subscriptions) {
+                if (s.getId().equals(cur.getId())) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_SUBSCRIPTION, cur.getId());
             }
         }
-        return null;
-    }
-
-
-    private SubscriptionDataRepair createSubscriptionDataRepair(final SubscriptionData curData, final List<EntitlementEvent> initialEvents) {
-        SubscriptionBuilder builder = new SubscriptionBuilder(curData);
-        builder.setActiveVersion(curData.getActiveVersion() + 1);
-        SubscriptionDataRepair result = (SubscriptionDataRepair) factory.createSubscription(builder, initialEvents);
-        return result;
     }
 
     private void validateFirstNewEvent(final SubscriptionData data, final NewEvent firstNewEvent, final DateTime lastBPRemainingTime, final DateTime lastRemainingTime) 
@@ -329,6 +300,91 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
         return result;
     }
 
+    
+    private String getViewId(DateTime lastUpdateBundleDate, List<Subscription> subscriptions) {
+        StringBuilder tmp = new StringBuilder();
+        long lastOrderedId = -1;
+        for (Subscription cur : subscriptions) {
+            lastOrderedId = lastOrderedId < ((SubscriptionData) cur).getLastEventOrderedId() ? ((SubscriptionData) cur).getLastEventOrderedId() : lastOrderedId;
+        }
+        tmp.append(lastOrderedId);
+        tmp.append("-");
+        tmp.append(lastUpdateBundleDate.toDate().getTime());
+        return tmp.toString();
+    }
+
+    private BundleRepair createGetBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionRepair> repairList) {
+        return new BundleRepair() {
+            @Override
+            public String getViewId() {
+                return viewId;
+            }
+            @Override
+            public List<SubscriptionRepair> getSubscriptions() {
+                return repairList;
+            }
+            @Override
+            public UUID getBundleId() {
+                return bundleId;
+            }
+        };
+
+    }
+
+    private List<SubscriptionRepair> createGetSubscriptionRepairList(final List<Subscription> subscriptions, final List<SubscriptionRepair> inRepair) {
+
+        final List<SubscriptionRepair> result = new LinkedList<SubscriptionRepair>();
+        Set<UUID> repairIds = new TreeSet<UUID>();
+        for (final SubscriptionRepair cur : inRepair) {
+            repairIds.add(cur.getId());
+            result.add(cur);
+        }
+        for (final Subscription cur : subscriptions) {
+            if ( !repairIds.contains(cur.getId())) { 
+                result.add(new DefaultSubscriptionRepair((SubscriptionData) cur));
+            }
+        }
+        return result;
+    }
+
+
+    private List<SubscriptionRepair> convertDataRepair(List<SubscriptionDataRepair> input) {
+        List<SubscriptionRepair> result = new LinkedList<SubscriptionRepair>();
+        for (SubscriptionDataRepair cur : input) {
+            result.add(new DefaultSubscriptionRepair(cur));
+        }
+        return result;
+    }
+
+    private SubscriptionDataRepair findSubscriptionDataRepair(final UUID targetId, final List<SubscriptionDataRepair> input) {
+        for (SubscriptionDataRepair cur : input) {
+            if (cur.getId().equals(targetId)) {
+                return cur;
+            }
+        }
+        return null;
+    }
+
+
+    private SubscriptionDataRepair createSubscriptionDataRepair(final SubscriptionData curData, final DateTime newBundleStartDate, final DateTime newSubscriptionStartDate, final List<EntitlementEvent> initialEvents) {
+        SubscriptionBuilder builder = new SubscriptionBuilder(curData);
+        builder.setActiveVersion(curData.getActiveVersion() + 1);
+        if (newBundleStartDate != null) {
+            builder.setBundleStartDate(newBundleStartDate);
+        }
+        if (newSubscriptionStartDate != null) {
+            builder.setStartDate(newSubscriptionStartDate);
+        }
+        if (initialEvents.size() > 0) {
+            for (EntitlementEvent cur : initialEvents) {
+                cur.setActiveVersion(builder.getActiveVersion());
+            }
+        }
+        SubscriptionDataRepair result = (SubscriptionDataRepair) factory.createSubscription(builder, initialEvents);
+        return result;
+    }
+
+
     private SubscriptionRepair findAndCreateSubscriptionRepair(final UUID target, final List<SubscriptionRepair> input) {
         for (SubscriptionRepair cur : input) {
             if (target.equals(cur.getId())) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/RepairSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/RepairSubscriptionFactory.java
index eb32bb0..a76599e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/RepairSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/RepairSubscriptionFactory.java
@@ -44,13 +44,8 @@ public class RepairSubscriptionFactory extends DefaultSubscriptionFactory implem
     @Override
     public SubscriptionData createSubscription(SubscriptionBuilder builder,
             List<EntitlementEvent> events) {
-        SubscriptionData subscription = new SubscriptionDataRepair(builder, apiService, clock, addonUtils);
-        if (events.size() > 0) {
-            for (EntitlementEvent cur : events) {
-                cur.setActiveVersion(builder.getActiveVersion());
-            }
-            subscription.rebuildTransitions(events, catalogService.getFullCatalog());
-        }
+        SubscriptionData subscription = new SubscriptionDataRepair(builder, events, apiService, clock, addonUtils);
+        subscription.rebuildTransitions(events, catalogService.getFullCatalog());
         return subscription;
     }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/SubscriptionDataRepair.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/SubscriptionDataRepair.java
index 4885ca1..1df8ee2 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/SubscriptionDataRepair.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/SubscriptionDataRepair.java
@@ -15,12 +15,15 @@
  */
 package com.ning.billing.entitlement.api.repair;
 
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.joda.time.DateTime;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogApiException;
@@ -43,18 +46,18 @@ public class SubscriptionDataRepair extends SubscriptionData {
     private final AddonUtils addonUtils;
     private final Clock clock;
 
-    private final List<EntitlementEvent> newEvents;
+    private final List<EntitlementEvent> initialEvents;
 
     // Low level events are ONLY used for Repair APIs
     protected List<EntitlementEvent> events;
 
 
-    public SubscriptionDataRepair(SubscriptionBuilder builder, SubscriptionApiService apiService,
+    public SubscriptionDataRepair(SubscriptionBuilder builder, List<EntitlementEvent> initialEvents, SubscriptionApiService apiService,
             Clock clock, AddonUtils addonUtils) {
         super(builder, apiService, clock);
         this.addonUtils = addonUtils;
         this.clock = clock;
-        this.newEvents = new LinkedList<EntitlementEvent>();
+        this.initialEvents = initialEvents;
     }
 
     public void addNewRepairEvent(final DefaultNewEvent input, final SubscriptionDataRepair baseSubscription, final List<SubscriptionDataRepair> addonSubscriptions, final CallContext context)
@@ -131,7 +134,22 @@ public class SubscriptionDataRepair extends SubscriptionData {
         super.rebuildTransitions(inputEvents, catalog);
     }
 
-    public List<EntitlementEvent>  getEvents() {
+    public List<EntitlementEvent> getEvents() {
         return events;
     }
+
+    public List<EntitlementEvent> getInitialEvents() {
+        return initialEvents;
+    }
+
+    
+    public Collection<EntitlementEvent> getNewEvents() {
+        Collection<EntitlementEvent> newEvents  = Collections2.filter(events, new Predicate<EntitlementEvent>() {
+            @Override
+            public boolean apply(EntitlementEvent input) {
+                return ! initialEvents.contains(input);
+            }
+        });
+        return newEvents;
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index ccec474..7e1e91f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -67,7 +67,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
     throws EntitlementUserApiException {
 
         SubscriptionState currentState = subscription.getState();
-        if (currentState != SubscriptionState.CANCELLED) {
+        if (currentState != null && currentState != SubscriptionState.CANCELLED) {
             throw new EntitlementUserApiException(ErrorCode.ENT_RECREATE_BAD_STATE, subscription.getId(), currentState);
         }
         DateTime now = clock.getUTCNow();
@@ -296,7 +296,7 @@ public class DefaultSubscriptionApiService implements SubscriptionApiService {
         }
 
         SubscriptionEventTransition previousTransition = subscription.getPreviousTransition();
-        if (previousTransition.getEffectiveTransitionTime().isAfter(requestedDate)) {
+        if (previousTransition != null && previousTransition.getEffectiveTransitionTime().isAfter(requestedDate)) {
             throw new EntitlementUserApiException(ErrorCode.ENT_INVALID_REQUESTED_DATE,
                     requestedDate.toString(), previousTransition.getEffectiveTransitionTime());
         }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 2373588..5136a72 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -24,6 +24,7 @@ import com.ning.billing.util.callcontext.CallContext;
 
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
+import com.ning.billing.entitlement.api.repair.SubscriptionDataRepair;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -53,7 +54,7 @@ public interface EntitlementDao {
     public List<Subscription> getSubscriptionsForKey(final SubscriptionFactory factory, final String bundleKey);
 
     // Update
-    public void updateSubscription(final SubscriptionData subscription, final CallContext context);
+    public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context);
 
     // Event apis
     public void createNextPhaseEvent(final UUID subscriptionId, final EntitlementEvent nextPhase, final CallContext context);
@@ -79,6 +80,9 @@ public interface EntitlementDao {
 
     public void migrate(final UUID accountId, final AccountMigrationData data, final CallContext context);
 
+    // Repair
+    public void repair(final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context);
+    
     // Custom Fields
     public void saveCustomFields(final SubscriptionData subscription, final CallContext context);
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index fbb2cba..d066389 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -49,6 +49,7 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.BundleMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.SubscriptionMigrationData;
+import com.ning.billing.entitlement.api.repair.SubscriptionDataRepair;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -189,16 +190,15 @@ public class EntitlementSqlDao implements EntitlementDao {
     }
 
     @Override
-    public void updateSubscription(final SubscriptionData subscription, final CallContext context) {
+    public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context) {
 
         final Date ctd = (subscription.getChargedThroughDate() != null)  ? subscription.getChargedThroughDate().toDate() : null;
-        final Date ptd = (subscription.getPaidThroughDate() != null)  ? subscription.getPaidThroughDate().toDate() : null;
 
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
             @Override
             public Void inTransaction(SubscriptionSqlDao transactionalDao,
                     TransactionStatus status) throws Exception {
-                transactionalDao.updateSubscription(subscription.getId().toString(), subscription.getActiveVersion(), ctd, ptd, context);
+                transactionalDao.updateChargedThroughDate(subscription.getId().toString(), ctd, context);
 
                 BundleSqlDao tmpDao = transactionalDao.become(BundleSqlDao.class);
                 tmpDao.updateBundleLastSysTime(subscription.getBundleId().toString(), clock.getUTCNow().toDate());
@@ -600,6 +600,28 @@ public class EntitlementSqlDao implements EntitlementDao {
         });
     }
 
+    public void repair(final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context) {
+        subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
+
+            @Override
+            public Void inTransaction(SubscriptionSqlDao transactional,
+                    TransactionStatus status) throws Exception {
+
+                EventSqlDao transEventDao = transactional.become(EventSqlDao.class);
+                for (SubscriptionDataRepair cur : inRepair) {
+                    transactional.updateActiveVersion(cur.getId().toString(), cur.getActiveVersion(), context);
+                    for (EntitlementEvent event : cur.getInitialEvents()) {
+                        transEventDao.updateVersion(event.getId().toString(), cur.getActiveVersion(), context);
+                    }
+                    for (EntitlementEvent event : cur.getNewEvents()) {
+                        transEventDao.insertEvent(event, context);
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
 
     private Subscription getBaseSubscription(final SubscriptionFactory factory, final UUID bundleId, boolean rebuildSubscription) {
         List<Subscription> subscriptions = subscriptionsDao.getSubscriptionsFromBundleId(bundleId.toString());
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
index 89baed8..5889c95 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EventSqlDao.java
@@ -66,6 +66,11 @@ public interface EventSqlDao extends Transactional<EventSqlDao>, CloseMe, Transm
     public void reactiveEvent(@Bind("event_id")String eventId,
                               @CallContextBinder final CallContext context);
 
+    @SqlUpdate
+    public void updateVersion(@Bind("event_id")String eventId,
+                              @Bind("current_version") Long currentVersion, 
+                              @CallContextBinder final CallContext context);
+    
     @SqlQuery
     @Mapper(EventSqlMapper.class)
     public List<EntitlementEvent> getFutureActiveEventForSubscription(@Bind("subscription_id") String subscriptionId, @Bind("now") Date now);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
index 85247ec..dfb81d2 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
@@ -27,6 +27,7 @@ import java.util.UUID;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
 import com.ning.billing.entitlement.api.repair.RepairEntitlementLifecycleDao;
+import com.ning.billing.entitlement.api.repair.SubscriptionDataRepair;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -187,7 +188,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
     }
 
     @Override
-    public void updateSubscription(SubscriptionData subscription,
+    public void updateChargedThroughDate(SubscriptionData subscription,
             CallContext context) {
         throw new EntitlementError("Not implemented");
     }
@@ -227,4 +228,10 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
             CallContext context) {
         throw new EntitlementError("Not implemented");
     }
+
+    @Override
+    public void repair(UUID bundleId, List<SubscriptionDataRepair> inRepair,
+            CallContext context) {
+        throw new EntitlementError("Not implemented");
+    }
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
index d50572e..b61b287 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
@@ -59,10 +59,13 @@ public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, C
     public List<Subscription> getSubscriptionsFromBundleId(@Bind("bundle_id") String bundleId);
 
     @SqlUpdate
-    public void updateSubscription(@Bind("id") String id, @Bind("active_version") long activeVersion,
-                                   @Bind("ctd_dt") Date ctd, @Bind("ptd_dt") Date ptd,
+    public void updateChargedThroughDate(@Bind("id") String id, @Bind("ctd_dt") Date ctd,
                                    @CallContextBinder final CallContext context);
-   
+
+    @SqlUpdate
+    public void updateActiveVersion(@Bind("id") String id, @Bind("active_version") long activeVersion,
+                                   @CallContextBinder final CallContext context);
+
     public static class SubscriptionBinder extends BinderBase implements Binder<Bind, SubscriptionData> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, SubscriptionData sub) {
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
index cd5afbf..817afcc 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/EventSqlDao.sql.stg
@@ -50,6 +50,15 @@ insertEvent() ::= <<
     );   
 >>
 
+updateVersion() ::= <<
+    update entitlement_events
+    set
+      current_version = :current_version
+    where
+      event_id = :event_id
+    ;
+>>
+
 unactiveEvent() ::= <<
     update entitlement_events
     set
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
index 780c06a..671be3f 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
@@ -60,12 +60,20 @@ getSubscriptionsFromBundleId(bundle_id) ::= <<
     ;
 >>
 
-updateSubscription(id, active_version, ctd_dt, ptd_dt) ::= <<
+updateChargedThroughDate() ::= <<
+    update subscriptions
+    set
+      ctd_dt = :ctd_dt
+      , updated_by = :userName
+      , updated_date = :updatedDate
+    where id = :id
+    ;
+>>
+
+updateActiveVersion() ::= <<
     update subscriptions
     set
       active_version = :active_version
-      , ctd_dt = :ctd_dt
-      , ptd_dt = :ptd_dt
       , updated_by = :userName
       , updated_date = :updatedDate
     where id = :id
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/repair/TestRepair.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/repair/TestRepair.java
index 61e0e19..5d31076 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/repair/TestRepair.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/repair/TestRepair.java
@@ -125,18 +125,139 @@ public class TestRepair extends TestApiBase {
             Assert.fail(e.getMessage());
         }
     }
-
+    
     @Test(groups={"slow"})
+    public void testSimpleBPRepairReplaceCreateBeforeTrial() throws Exception {
+        String baseProduct = "Shotgun";
+        String newBaseProduct = "Assault-Rifle";
+        
+        DateTime startDate = clock.getUTCNow();
+        int clockShift = -10;
+        DateTime restartDate =  startDate.plusDays(clockShift).minusDays(1);
+        LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionRepair.ExistingEvent>();
+        
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.PHASE, newBaseProduct, PhaseType.EVERGREEN,
+                    ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, restartDate.plusDays(30)));
+
+        testSimpleBPRepairCreate(true, startDate, clockShift, baseProduct, newBaseProduct, expected);
+    }
+
+    @Test(groups={"slow"}, enabled=true)
     public void testSimpleBPRepairReplaceCreateInTrial() throws Exception {
+        String baseProduct = "Shotgun";
+        String newBaseProduct = "Assault-Rifle";
+        
+        DateTime startDate = clock.getUTCNow();
+        int clockShift = 10;
+        DateTime restartDate =  startDate.plusDays(clockShift).minusDays(1);
+        LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionRepair.ExistingEvent>();
         
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.PHASE, newBaseProduct, PhaseType.EVERGREEN,
+                    ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, restartDate.plusDays(30)));
+
+        testSimpleBPRepairCreate(true, startDate, clockShift, baseProduct, newBaseProduct, expected);
     }
 
     
     @Test(groups={"slow"})
     public void testSimpleBPRepairReplaceCreateAfterTrial() throws Exception {
+        String baseProduct = "Shotgun";
+        String newBaseProduct = "Assault-Rifle";
+        
+        DateTime startDate = clock.getUTCNow();
+        int clockShift = 40;
+        DateTime restartDate =  startDate.plusDays(clockShift).minusDays(1);
+        LinkedList<ExistingEvent> expected = new LinkedList<SubscriptionRepair.ExistingEvent>();
+        
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, newBaseProduct, PhaseType.TRIAL,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, restartDate));
+        expected.add(createExistingEventForAssertion(SubscriptionTransitionType.PHASE, newBaseProduct, PhaseType.EVERGREEN,
+                    ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, restartDate.plusDays(30)));
+
+        testSimpleBPRepairCreate(false, startDate, clockShift, baseProduct, newBaseProduct, expected);
         
     }
     
+    
+    private void testSimpleBPRepairCreate(boolean inTrial, DateTime startDate, int clockShift, 
+            String baseProduct, String newBaseProduct, List<ExistingEvent> expectedEvents) throws Exception {
+
+        // CREATE BP
+        Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
+
+        // MOVE CLOCK
+        if (clockShift > 0) {
+            if (!inTrial) {
+                testListener.pushExpectedEvent(NextEvent.PHASE);
+            }               
+            Duration durationShift = getDurationDay(clockShift);
+            clock.setDeltaFromReality(durationShift, 0);
+            if (!inTrial) {
+                assertTrue(testListener.isCompleted(5000));
+            }
+        }
+
+        BundleRepair bundleRepair = repairApi.getBundleRepair(bundle.getId());
+        sortEventsOnBundle(bundleRepair);
+        
+        DateTime newCreateTime = baseSubscription.getStartDate().plusDays(clockShift - 1);
+
+        PlanPhaseSpecifier spec = new PlanPhaseSpecifier(newBaseProduct, ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
+
+        NewEvent ne = createNewEvent(SubscriptionTransitionType.CREATE, newCreateTime, spec);
+        List<DeletedEvent> des = new LinkedList<SubscriptionRepair.DeletedEvent>();
+        des.add(createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(0).getEventId()));
+        des.add(createDeletedEvent(bundleRepair.getSubscriptions().get(0).getExistingEvents().get(1).getEventId()));
+
+        SubscriptionRepair sRepair = createSubscriptionReapir(baseSubscription.getId(), des, Collections.singletonList(ne));
+        
+        // FIRST ISSUE DRY RUN
+        BundleRepair bRepair =  createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(sRepair));
+        
+        boolean dryRun = true;
+        BundleRepair dryRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+        List<SubscriptionRepair> subscriptionRepair = dryRunBundleRepair.getSubscriptions();
+        assertEquals(subscriptionRepair.size(), 1);
+        SubscriptionRepair cur = subscriptionRepair.get(0);
+        assertEquals(cur.getId(), baseSubscription.getId());
+
+        List<ExistingEvent> events = cur.getExistingEvents();
+        assertEquals(expectedEvents.size(), events.size());
+        int index = 0;
+        for (ExistingEvent e : expectedEvents) {
+           validateExistingEventForAssertion(e, events.get(index++));           
+        }
+        SubscriptionData dryRunBaseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
+        
+        assertEquals(dryRunBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION);
+        assertEquals(dryRunBaseSubscription.getBundleId(), bundle.getId());
+        assertEquals(dryRunBaseSubscription.getStartDate(), baseSubscription.getStartDate());
+
+        Plan currentPlan = dryRunBaseSubscription.getCurrentPlan();
+        assertNotNull(currentPlan);
+        assertEquals(currentPlan.getProduct().getName(), baseProduct);
+        assertEquals(currentPlan.getProduct().getCategory(), ProductCategory.BASE);
+        assertEquals(currentPlan.getBillingPeriod(), BillingPeriod.MONTHLY);
+
+        PlanPhase currentPhase = dryRunBaseSubscription.getCurrentPhase();
+        assertNotNull(currentPhase);
+        if (inTrial) {
+            assertEquals(currentPhase.getPhaseType(), PhaseType.TRIAL);
+        } else {
+            assertEquals(currentPhase.getPhaseType(), PhaseType.EVERGREEN);
+        }
+        
+        
+       // SECOND RE-ISSUE CALL-- NON DRY RUN
+        dryRun = false;
+        BundleRepair realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
+
+        
+    }
 
     @Test(groups={"slow"})
     public void testSimpleBPRepairAddChangeInTrial() throws Exception {
@@ -182,17 +303,15 @@ public class TestRepair extends TestApiBase {
     private void testSimpleBPRepairAddChange(boolean inTrial, DateTime startDate, int clockShift, 
             String baseProduct, String newBaseProduct, List<ExistingEvent> expectedEvents) throws Exception {
 
-
-
         // CREATE BP
-        Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME);
+        Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
 
         // MOVE CLOCK
         if (!inTrial) {
             testListener.pushExpectedEvent(NextEvent.PHASE);
         }               
-        int durationDays = (inTrial) ? 10 : 40;
-        Duration durationShift = getDurationDay(durationDays);
+
+        Duration durationShift = getDurationDay(clockShift);
         clock.setDeltaFromReality(durationShift, 0);
         if (!inTrial) {
             assertTrue(testListener.isCompleted(5000));
@@ -201,7 +320,7 @@ public class TestRepair extends TestApiBase {
         BundleRepair bundleRepair = repairApi.getBundleRepair(bundle.getId());
         sortEventsOnBundle(bundleRepair);
         
-        DateTime changeTime = baseSubscription.getStartDate().plusDays(durationDays - 1);
+        DateTime changeTime = baseSubscription.getStartDate().plusDays(clockShift - 1);
 
         PlanPhaseSpecifier spec = new PlanPhaseSpecifier(newBaseProduct, ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
 
@@ -250,6 +369,8 @@ public class TestRepair extends TestApiBase {
         
         
        // SECOND RE-ISSUE CALL-- NON DRY RUN
+        dryRun = false;
+        BundleRepair realRunBundleRepair = repairApi.repairBundle(bRepair, dryRun, context);
         
     }
 
@@ -322,13 +443,13 @@ public class TestRepair extends TestApiBase {
         return ev;
     }
     
-    // STEPH missing dates
     private void validateExistingEventForAssertion(final ExistingEvent expected, final ExistingEvent input) {
         assertEquals(expected.getPlanPhaseSpecifier().getProductName(), input.getPlanPhaseSpecifier().getProductName());
         assertEquals(expected.getPlanPhaseSpecifier().getPhaseType(), input.getPlanPhaseSpecifier().getPhaseType());
         assertEquals(expected.getPlanPhaseSpecifier().getProductCategory(), input.getPlanPhaseSpecifier().getProductCategory());                    
         assertEquals(expected.getPlanPhaseSpecifier().getPriceListName(), input.getPlanPhaseSpecifier().getPriceListName());                    
         assertEquals(expected.getPlanPhaseSpecifier().getBillingPeriod(), input.getPlanPhaseSpecifier().getBillingPeriod());
+        assertEquals(expected.getEffectiveDate(), input.getEffectiveDate());        
     }
     
     private DeletedEvent createDeletedEvent(final UUID eventId) {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index 18c3ee3..57b59b9 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -41,6 +41,7 @@ import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.BundleMigrationData;
 import com.ning.billing.entitlement.api.migration.AccountMigrationData.SubscriptionMigrationData;
+import com.ning.billing.entitlement.api.repair.SubscriptionDataRepair;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
@@ -264,7 +265,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
     }
 
     @Override
-    public void updateSubscription(final SubscriptionData subscription, final CallContext context) {
+    public void updateChargedThroughDate(final SubscriptionData subscription, final CallContext context) {
 
         boolean found = false;
         Iterator<Subscription> it = subscriptions.iterator();
@@ -454,4 +455,8 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
         return null;
     }
 
+    @Override
+    public void repair(UUID bundleId, List<SubscriptionDataRepair> inRepair,
+            CallContext context) {
+    }
 }