killbill-memoizeit

Remove UNCANCEL event from being part of a SubscriptionData

5/3/2013 6:29:38 PM

Details

diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/transfer/DefaultEntitlementTransferApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/transfer/DefaultEntitlementTransferApi.java
index f8d1f69..5c9a0d1 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/transfer/DefaultEntitlementTransferApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/transfer/DefaultEntitlementTransferApi.java
@@ -21,6 +21,8 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.Catalog;
@@ -128,7 +130,6 @@ public class DefaultEntitlementTransferApi extends EntitlementApiBase implements
                 }
                 break;
             case CANCEL:
-            case UNCANCEL:
                 break;
 
             default:
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 5841a98..f29646e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -383,11 +383,23 @@ public class SubscriptionData extends EntityBase implements Subscription {
         if (transitions == null || event == null) {
             return null;
         }
+        SubscriptionTransitionData prev = null;
         for (final SubscriptionTransition cur : transitions) {
-            if (((SubscriptionTransitionData) cur).getId().equals(event.getId())) {
-                final SubscriptionTransitionData withSeq = new SubscriptionTransitionData((SubscriptionTransitionData)cur, seqId);
+            final SubscriptionTransitionData curData = (SubscriptionTransitionData) cur;
+            if (curData.getId().equals(event.getId())) {
+
+                final SubscriptionTransitionData withSeq = new SubscriptionTransitionData(curData, seqId);
                 return withSeq;
             }
+            if (curData.getTotalOrdering() < event.getTotalOrdering()) {
+                prev = curData;
+            }
+        }
+        // Since UNCANCEL are not part of the transitions, we compute a new 'UNCANCEL' transition based on the event right before that UNCANCEL
+        // This is used to be able to send a bus event for uncancellation
+        if (prev != null && event.getType() == EventType.API_USER && ((ApiEvent) event).getEventType() == ApiEventType.UNCANCEL) {
+             final SubscriptionTransitionData withSeq = new SubscriptionTransitionData((SubscriptionTransitionData)prev, EventType.API_USER, ApiEventType.UNCANCEL, seqId);
+            return withSeq;
         }
         return null;
     }
@@ -587,7 +599,6 @@ public class SubscriptionData extends EntityBase implements Subscription {
                     nextPhaseName = null;
                     break;
                 case UNCANCEL:
-                    break;
                 default:
                     throw new EntitlementError(String.format(
                             "Unexpected UserEvent type = %s", userEV
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
index 2cadced..d4d44aa 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionData.java
@@ -102,12 +102,17 @@ public class SubscriptionTransitionData implements SubscriptionTransition {
     }
 
     public SubscriptionTransitionData(final SubscriptionTransitionData input, int remainingEventsForUserOperation) {
+       this(input, input.getEventType(), input.getApiEventType(), remainingEventsForUserOperation);
+    }
+
+    public SubscriptionTransitionData(final SubscriptionTransitionData input, final EventType eventType,
+                                      final ApiEventType apiEventType, int remainingEventsForUserOperation) {
         super();
         this.eventId = input.getId();
         this.subscriptionId = input.getSubscriptionId();
         this.bundleId = input.getBundleId();
-        this.eventType = input.getEventType();
-        this.apiEventType = input.getApiEventType();
+        this.eventType = eventType;
+        this.apiEventType = apiEventType;
         this.requestedTransitionTime = input.getRequestedTransitionTime();
         this.effectiveTransitionTime = input.getEffectiveTransitionTime();
         this.previousEventId = input.getPreviousEventId();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
index 9da28ea..e2e4154 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionTransitionDataIterator.java
@@ -98,10 +98,8 @@ public class SubscriptionTransitionDataIterator implements Iterator<Subscription
     }
 
     private boolean shouldSkipForBillingEvents(final SubscriptionTransitionData input) {
-        // Junction system knows about all events except for MIGRATE_ENTITLEMENT and UNCANCEL-- which is a NO event as it undo
-        // something that should have happened in the future.
-        return (input.getTransitionType() == SubscriptionTransitionType.MIGRATE_ENTITLEMENT ||
-                input.getTransitionType() == SubscriptionTransitionType.UNCANCEL);
+        // Junction system knows about all events except for MIGRATE_ENTITLEMENT
+        return input.getTransitionType() == SubscriptionTransitionType.MIGRATE_ENTITLEMENT;
     }
 
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
index f10b36b..8128583 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/DefaultEntitlementDao.java
@@ -324,8 +324,14 @@ public class DefaultEntitlementDao implements EntitlementDao {
             @Override
             public List<EntitlementEvent> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
                 final List<EntitlementEventModelDao> models = entitySqlDaoWrapperFactory.become(EntitlementEventSqlDao.class).getEventsForSubscription(subscriptionId.toString(), context);
-
-                return new ArrayList<EntitlementEvent>(Collections2.transform(models, new Function<EntitlementEventModelDao, EntitlementEvent>() {
+                // Remove UNCANCEL events early on as they are not representative of a state transition but are just markers
+                final Collection<EntitlementEventModelDao> filteredModels = Collections2.filter(models, new Predicate<EntitlementEventModelDao>() {
+                    @Override
+                    public boolean apply(@Nullable final EntitlementEventModelDao input) {
+                        return input.getUserType() != ApiEventType.UNCANCEL;
+                    }
+                });
+                return new ArrayList<EntitlementEvent>(Collections2.transform(filteredModels, new Function<EntitlementEventModelDao, EntitlementEvent>() {
                     @Override
                     public EntitlementEvent apply(@Nullable final EntitlementEventModelDao input) {
                         return EntitlementEventModelDao.toEntitlementEvent(input);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
index acc2167..6cc764c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/model/EntitlementEventModelDao.java
@@ -56,7 +56,9 @@ public class EntitlementEventModelDao extends EntityBase implements EntityModelD
     private long currentVersion;
     private boolean isActive;
 
-    public EntitlementEventModelDao() { /* For the DAO mapper */ }
+    public EntitlementEventModelDao() {
+    /* For the DAO mapper */
+    }
 
     public EntitlementEventModelDao(final UUID id, final long totalOrdering, final EventType eventType, final ApiEventType userType,
                                     final DateTime requestedDate, final DateTime effectiveDate, final UUID subscriptionId,
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
index 21f7b6b..04e6b3b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
@@ -473,4 +473,47 @@ public class TestTransfer extends EntitlementTestSuiteWithEmbeddedDB {
         final List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(newBundle.getId(), callContext);
         assertEquals(subscriptions.size(), 1);
     }
+
+    @Test(groups = "slow")
+    public void testTransferWithUncancel() throws Exception {
+
+        final UUID newAccountId = UUID.randomUUID();
+
+        final String baseProduct = "Shotgun";
+        final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
+        final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+        // CREATE BP
+        Subscription baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
+
+        testListener.pushExpectedEvent(NextEvent.PHASE);
+        clock.addDays(30);
+        assertTrue(testListener.isCompleted(3000));
+
+        // SET CTD TO TRIGGER CANCELLATION EOT
+        final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
+        entitlementInternalApi.setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
+
+
+        // CANCEL BP
+        baseSubscription = entitlementApi.getSubscriptionFromId(baseSubscription.getId(), callContext);
+        baseSubscription.cancel(clock.getUTCNow(), callContext);
+
+        // MOVE CLOCK one day AHEAD AND UNCANCEL BP
+        clock.addDays(1);
+        testListener.pushExpectedEvent(NextEvent.UNCANCEL);
+        baseSubscription.uncancel(callContext);
+        assertTrue(testListener.isCompleted(3000));
+
+        // MOVE CLOCK one day AHEAD AND UNCANCEL BP
+        clock.addDays(1);
+        final DateTime transferRequestedDate = clock.getUTCNow();
+        testListener.pushExpectedEvent(NextEvent.TRANSFER);
+        transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, true, false, callContext);
+        assertTrue(testListener.isCompleted(3000));
+
+        final SubscriptionBundle newBundle = entitlementApi.getBundleForAccountAndKey(newAccountId, bundle.getExternalKey(), callContext);
+        final List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(newBundle.getId(), callContext);
+        assertEquals(subscriptions.size(), 1);
+    }
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index d0cd6b0..ff67ff3 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -146,11 +146,10 @@ public class TestUserApiAddOn extends EntitlementTestSuiteWithEmbeddedDB {
 
             aoSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(aoSubscription.getId(), callContext);
             aoTransitions =  aoSubscription.getAllTransitions();
-            assertEquals(aoTransitions.size(), 4);
+            assertEquals(aoTransitions.size(), 3);
             assertEquals(aoTransitions.get(0).getTransitionType(), SubscriptionTransitionType.CREATE);
             assertEquals(aoTransitions.get(1).getTransitionType(), SubscriptionTransitionType.PHASE);
-            assertEquals(aoTransitions.get(2).getTransitionType(), SubscriptionTransitionType.UNCANCEL);
-            assertEquals(aoTransitions.get(3).getTransitionType(), SubscriptionTransitionType.CANCEL);
+            assertEquals(aoTransitions.get(2).getTransitionType(), SubscriptionTransitionType.CANCEL);
             assertTrue(aoSubscription.getFutureEndDate().compareTo(newBPChargedThroughDate) == 0);
 
             assertListenerStatus();