killbill-memoizeit

entitlement: fix NPE in transfer code We ignore cancel events

11/28/2012 2:02:53 AM

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 8ddc345..535353c 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
@@ -90,7 +90,11 @@ public class DefaultEntitlementTransferApi implements EntitlementTransferApi {
         final PlanPhaseSpecifier spec = existingEvent.getPlanPhaseSpecifier();
         final PlanPhase currentPhase = existingEvent.getPlanPhaseName() != null ? catalog.findPhase(existingEvent.getPlanPhaseName(), effectiveDate, subscription.getAlignStartDate()) : null;
 
-        final ApiEventBuilder apiBuilder = currentPhase != null ? new ApiEventBuilder()
+        if (spec == null || currentPhase == null) {
+            // Ignore cancellations - we assume that transferred subscriptions should always be active
+            return null;
+        }
+        final ApiEventBuilder apiBuilder = new ApiEventBuilder()
                 .setSubscriptionId(subscription.getId())
                 .setEventPlan(currentPhase.getPlan().getName())
                 .setEventPlanPhase(currentPhase.getName())
@@ -100,7 +104,7 @@ public class DefaultEntitlementTransferApi implements EntitlementTransferApi {
                 .setEffectiveDate(effectiveDate)
                 .setRequestedDate(effectiveDate)
                 .setUserToken(context.getUserToken())
-                .setFromDisk(true) : null;
+                .setFromDisk(true);
 
         switch (existingEvent.getSubscriptionTransitionType()) {
             case TRANSFER:
@@ -121,15 +125,17 @@ public class DefaultEntitlementTransferApi implements EntitlementTransferApi {
                 break;
 
             // Ignore these events except if it's the first event for the new subscription
-            case CANCEL:
-            case UNCANCEL:
             case MIGRATE_BILLING:
                 if (firstEvent) {
                     newEvent = new ApiEventTransfer(apiBuilder);
                 }
                 break;
+            case CANCEL:
+            case UNCANCEL:
+                break;
+
             default:
-                throw new EntitlementError(String.format("Unepxected transitionType %s", existingEvent.getSubscriptionTransitionType()));
+                throw new EntitlementError(String.format("Unexpected transitionType %s", existingEvent.getSubscriptionTransitionType()));
         }
         return newEvent;
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
index ced19b9..2f21fe2 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestDefaultEntitlementTransferApi.java
@@ -70,6 +70,39 @@ public class TestDefaultEntitlementTransferApi extends EntitlementTestSuite {
     }
 
     @Test(groups = "fast")
+    public void testEventsForCancelledSubscriptionBeforeTransfer() throws Exception {
+        final DateTime subscriptionStartTime = clock.getUTCNow();
+        final DateTime subscriptionCancelTime = subscriptionStartTime.plusDays(1);
+        final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionTransitionType.CREATE),
+                                                                                            createEvent(subscriptionCancelTime, SubscriptionTransitionType.CANCEL));
+        final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
+        final SubscriptionData subscription = new SubscriptionData(subscriptionBuilder);
+
+        final DateTime transferDate = subscriptionStartTime.plusDays(10);
+        final List<EntitlementEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
+
+        Assert.assertEquals(events.size(), 0);
+    }
+
+    @Test(groups = "fast")
+    public void testEventsForCancelledSubscriptionAfterTransfer() throws Exception {
+        final DateTime subscriptionStartTime = clock.getUTCNow();
+        final DateTime subscriptionCancelTime = subscriptionStartTime.plusDays(1);
+        final ImmutableList<ExistingEvent> existingEvents = ImmutableList.<ExistingEvent>of(createEvent(subscriptionStartTime, SubscriptionTransitionType.CREATE),
+                                                                                            createEvent(subscriptionCancelTime, SubscriptionTransitionType.CANCEL));
+        final SubscriptionBuilder subscriptionBuilder = new SubscriptionBuilder();
+        final SubscriptionData subscription = new SubscriptionData(subscriptionBuilder);
+
+        final DateTime transferDate = subscriptionStartTime.plusHours(1);
+        final List<EntitlementEvent> events = transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
+
+        Assert.assertEquals(events.size(), 1);
+        Assert.assertEquals(events.get(0).getType(), EventType.API_USER);
+        Assert.assertEquals(events.get(0).getEffectiveDate(), transferDate);
+        Assert.assertEquals(((ApiEventTransfer) events.get(0)).getEventType(), ApiEventType.TRANSFER);
+    }
+
+    @Test(groups = "fast")
     public void testEventsAfterTransferForMigratedBundle1() throws Exception {
         // MIGRATE_ENTITLEMENT then MIGRATE_BILLING (both in the past)
         final DateTime transferDate = clock.getUTCNow();
@@ -134,6 +167,42 @@ public class TestDefaultEntitlementTransferApi extends EntitlementTestSuite {
         return transferApi.toEvents(existingEvents, subscription, transferDate, callContext);
     }
 
+    private ExistingEvent createEvent(final DateTime eventEffectiveDate, final SubscriptionTransitionType subscriptionTransitionType) {
+        return new ExistingEvent() {
+            @Override
+            public DateTime getEffectiveDate() {
+                return eventEffectiveDate;
+            }
+
+            @Override
+            public String getPlanPhaseName() {
+                return SubscriptionTransitionType.CANCEL.equals(subscriptionTransitionType) ? null : "BicycleTrialEvergreen1USD-trial";
+            }
+
+            @Override
+            public UUID getEventId() {
+                return UUID.randomUUID();
+            }
+
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                return SubscriptionTransitionType.CANCEL.equals(subscriptionTransitionType) ? null :
+                       new PlanPhaseSpecifier("BicycleTrialEvergreen1USD", ProductCategory.BASE, BillingPeriod.NO_BILLING_PERIOD,
+                                              PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.FIXEDTERM);
+            }
+
+            @Override
+            public DateTime getRequestedDate() {
+                return getEffectiveDate();
+            }
+
+            @Override
+            public SubscriptionTransitionType getSubscriptionTransitionType() {
+                return subscriptionTransitionType;
+            }
+        };
+    }
+
     private ImmutableList<ExistingEvent> createMigrateEvents(final DateTime migrateEntitlementEventEffectiveDate, final DateTime migrateBillingEventEffectiveDate) {
         final ExistingEvent migrateEntitlementEvent = new ExistingEvent() {
             @Override