killbill-aplcache

Add addon migration logics

2/29/2012 12:05:06 AM

Details

diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
index 7a1f9a9..26248e7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
@@ -18,20 +18,15 @@ package com.ning.billing.entitlement.api.migration;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
-import com.ning.billing.catalog.api.CatalogApiException;
-import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.Duration;
-import com.ning.billing.catalog.api.PhaseType;
-import com.ning.billing.catalog.api.Plan;
-import com.ning.billing.catalog.api.PlanPhase;
-import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.alignment.MigrationPlanAligner;
 import com.ning.billing.entitlement.alignment.TimedMigration;
@@ -52,7 +47,6 @@ import com.ning.billing.entitlement.events.user.ApiEventChange;
 import com.ning.billing.entitlement.events.user.ApiEventMigrate;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
 
 public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
 
@@ -60,19 +54,16 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
     private final EntitlementDao dao;
     private final MigrationPlanAligner migrationAligner;
     private final SubscriptionFactory factory;
-    private final CatalogService catalogService;
     private final Clock clock;
 
     @Inject
     public DefaultEntitlementMigrationApi(MigrationPlanAligner migrationAligner,
             SubscriptionFactory factory,
-            CatalogService catalogService,
             EntitlementDao dao,
             Clock clock) {
         this.dao = dao;
         this.migrationAligner = migrationAligner;
         this.factory = factory;
-        this.catalogService = catalogService;
         this.clock = clock;
     }
 
@@ -101,20 +92,39 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             SubscriptionBundleData bundleData = new SubscriptionBundleData(curBundle.getBundleKey(), accountId);
             List<SubscriptionMigrationData> bundleSubscriptionData = new LinkedList<AccountMigrationData.SubscriptionMigrationData>();
 
-            for (EntitlementSubscriptionMigration curSub : curBundle.getSubscriptions()) {
+
+            List<EntitlementSubscriptionMigration> sortedSubscriptions = Lists.newArrayList(curBundle.getSubscriptions());
+            // Make sure we have first mpp or legacy, then addon and for each category order by CED
+            Collections.sort(sortedSubscriptions, new Comparator<EntitlementSubscriptionMigration>() {
+                @Override
+                public int compare(EntitlementSubscriptionMigration o1,
+                        EntitlementSubscriptionMigration o2) {
+                    if (o1.getCategory().equals(o2.getCategory())) {
+                        return o1.getSubscriptionCases()[0].getEffectiveDate().compareTo(o2.getSubscriptionCases()[0].getEffectiveDate());
+                    } else {
+                        if (o1.getCategory().equals("mpp")) {
+                            return -1;
+                        } else if (o2.getCategory().equals("mpp")) {
+                            return 1;
+                        } else if (o1.getCategory().equals("legacy")) {
+                            return -1;
+                        } else if (o2.getCategory().equals("legacy")) {
+                            return 1;
+                        } else {
+                            return 0;
+                        }
+                    }
+                }
+            });
+
+            DateTime bundleStartDate = null;
+            for (EntitlementSubscriptionMigration curSub : sortedSubscriptions) {
                 SubscriptionMigrationData data = null;
-                switch (curSub.getCategory()) {
-                case BASE:
-                    data = createBaseSubscriptionMigrationData(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now);
-                    break;
-                case ADD_ON:
-                    // Not implemented yet
-                    break;
-                case STANDALONE:
-                    data = createStandaloneSubscriptionMigrationData(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now);
-                    break;
-                default:
-                    throw new EntitlementMigrationApiException(String.format("Unkown product type ", curSub.getCategory()));
+                if (bundleStartDate == null) {
+                    data = createInitialSubscription(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now);
+                    bundleStartDate = data.getInitialEvents().get(0).getEffectiveDate();
+                } else {
+                    data = createSubscriptionMigrationDataWithBundleDate(bundleData.getId(), curSub.getCategory(), curSub.getSubscriptionCases(), now, bundleStartDate);
                 }
                 if (data != null) {
                     bundleSubscriptionData.add(data);
@@ -127,7 +137,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
         return accountMigrationData;
     }
 
-    private SubscriptionMigrationData createBaseSubscriptionMigrationData(UUID bundleId, ProductCategory productCategory,
+    private SubscriptionMigrationData createInitialSubscription(UUID bundleId, ProductCategory productCategory,
             EntitlementSubscriptionMigrationCase [] input, DateTime now)
         throws EntitlementMigrationApiException {
 
@@ -144,8 +154,8 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
         return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, events));
     }
 
-    private SubscriptionMigrationData createStandaloneSubscriptionMigrationData(UUID bundleId, ProductCategory productCategory,
-            EntitlementSubscriptionMigrationCase [] input, DateTime now)
+    private SubscriptionMigrationData createSubscriptionMigrationDataWithBundleDate(UUID bundleId, ProductCategory productCategory,
+            EntitlementSubscriptionMigrationCase [] input, DateTime now, DateTime bundleStartDate)
     throws EntitlementMigrationApiException {
         TimedMigration [] events = migrationAligner.getEventsMigration(input, now);
         DateTime migrationStartDate= events[0].getEventTime();
@@ -154,7 +164,7 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
             .setId(UUID.randomUUID())
             .setBundleId(bundleId)
             .setCategory(productCategory)
-            .setBundleStartDate(migrationStartDate)
+            .setBundleStartDate(bundleStartDate)
             .setStartDate(migrationStartDate),
             emptyEvents);
         return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, events));
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index 7ef459d..acd64ea 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -29,6 +29,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 import org.testng.Assert;
 
+import com.google.common.collect.Lists;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
@@ -78,6 +79,48 @@ public abstract class TestMigration extends TestApiBase {
     }
 
 
+    public void testPlanWithAddOn() {
+        try {
+            DateTime beforeMigration = clock.getUTCNow();
+            final DateTime initalAddonStart = clock.getUTCNow().minusMonths(1).plusDays(7);
+            EntitlementAccountMigration toBeMigrated = createAccountWithRegularBasePlanAndAddons(initalAddonStart);
+            DateTime afterMigration = clock.getUTCNow();
+
+            testListener.pushExpectedEvent(NextEvent.MIGRATE_ENTITLEMENT);
+            migrationApi.migrate(toBeMigrated);
+            assertTrue(testListener.isCompleted(5000));
+
+            List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(toBeMigrated.getAccountKey());
+            assertEquals(bundles.size(), 1);
+            SubscriptionBundle bundle = bundles.get(0);
+
+            List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(bundle.getId());
+            assertEquals(subscriptions.size(), 2);
+
+            Subscription baseSubscription = (subscriptions.get(0).getCurrentPlan().getProduct().getCategory() == ProductCategory.BASE) ?
+                    subscriptions.get(0) : subscriptions.get(1);
+            assertDateWithin(baseSubscription.getStartDate(), beforeMigration, afterMigration);
+            assertEquals(baseSubscription.getEndDate(), null);
+            assertEquals(baseSubscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(baseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
+            assertEquals(baseSubscription.getState(), SubscriptionState.ACTIVE);
+            assertEquals(baseSubscription.getCurrentPlan().getName(), "assault-rifle-annual");
+
+            Subscription aoSubscription = (subscriptions.get(0).getCurrentPlan().getProduct().getCategory() == ProductCategory.ADD_ON) ?
+                    subscriptions.get(0) : subscriptions.get(1);
+            assertEquals(aoSubscription.getStartDate(), initalAddonStart);
+            assertEquals(aoSubscription.getEndDate(), null);
+            assertEquals(aoSubscription.getCurrentPriceList(), PriceListSet.DEFAULT_PRICELIST_NAME);
+            assertEquals(aoSubscription.getCurrentPhase().getPhaseType(), PhaseType.DISCOUNT);
+            assertEquals(aoSubscription.getState(), SubscriptionState.ACTIVE);
+            assertEquals(aoSubscription.getCurrentPlan().getName(), "telescopic-scope-monthly");
+
+        } catch (EntitlementMigrationApiException e) {
+            Assert.fail("", e);
+        }
+    }
+
+
     public void testSingleBasePlanFutureCancelled() {
 
         try {
@@ -212,7 +255,7 @@ public abstract class TestMigration extends TestApiBase {
     }
 
 
-    private EntitlementAccountMigration createAccountWithSingleBasePlan(final List<EntitlementSubscriptionMigrationCase> cases) {
+    private EntitlementAccountMigration createAccountWithSingleBasePlan(final List<List<EntitlementSubscriptionMigrationCase>> cases) {
 
         return new EntitlementAccountMigration() {
 
@@ -225,18 +268,24 @@ public abstract class TestMigration extends TestApiBase {
 
                     @Override
                     public EntitlementSubscriptionMigration[] getSubscriptions() {
-                        EntitlementSubscriptionMigration subscription = new EntitlementSubscriptionMigration() {
-                            @Override
-                            public EntitlementSubscriptionMigrationCase[] getSubscriptionCases() {
-                                return cases.toArray(new EntitlementSubscriptionMigrationCase[cases.size()]);
-                            }
-                            @Override
-                            public ProductCategory getCategory() {
-                                return ProductCategory.BASE;
-                            }
-                        };
-                        EntitlementSubscriptionMigration[] result = new EntitlementSubscriptionMigration[1];
-                        result[0] = subscription;
+
+                        EntitlementSubscriptionMigration[] result = new EntitlementSubscriptionMigration[cases.size()];
+
+                        for (int i = 0; i < cases.size(); i++) {
+
+                            final List<EntitlementSubscriptionMigrationCase> curCases = cases.get(i);
+                            EntitlementSubscriptionMigration subscription = new EntitlementSubscriptionMigration() {
+                                @Override
+                                public EntitlementSubscriptionMigrationCase[] getSubscriptionCases() {
+                                    return curCases.toArray(new EntitlementSubscriptionMigrationCase[curCases.size()]);
+                                }
+                                @Override
+                                public ProductCategory getCategory() {
+                                    return ProductCategory.BASE;
+                                }
+                            };
+                            result[i] = subscription;
+                        }
                         return result;
                     }
                     @Override
@@ -255,6 +304,61 @@ public abstract class TestMigration extends TestApiBase {
         };
     }
 
+    private EntitlementAccountMigration createAccountWithRegularBasePlanAndAddons(final DateTime initalAddonStart) {
+
+        List<EntitlementSubscriptionMigrationCase> cases = new LinkedList<EntitlementSubscriptionMigrationCase>();
+        cases.add(new EntitlementSubscriptionMigrationCase() {
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifer() {
+                return new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return clock.getUTCNow().minusMonths(3);
+            }
+            @Override
+            public DateTime getCancelledDate() {
+                return null;
+            }
+        });
+
+        List<EntitlementSubscriptionMigrationCase> firstAddOnCases = new LinkedList<EntitlementSubscriptionMigrationCase>();
+
+        firstAddOnCases.add(new EntitlementSubscriptionMigrationCase() {
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifer() {
+                return new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.DISCOUNT);
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return initalAddonStart;
+            }
+            @Override
+            public DateTime getCancelledDate() {
+                return initalAddonStart.plusMonths(1);
+            }
+        });
+        firstAddOnCases.add(new EntitlementSubscriptionMigrationCase() {
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifer() {
+                return new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return initalAddonStart.plusMonths(1);
+            }
+            @Override
+            public DateTime getCancelledDate() {
+                return null;
+            }
+        });
+
+        List<List<EntitlementSubscriptionMigrationCase>> input = new ArrayList<List<EntitlementSubscriptionMigrationCase>>();
+        input.add(cases);
+        input.add(firstAddOnCases);
+        return createAccountWithSingleBasePlan(input);
+    }
+
     private EntitlementAccountMigration createAccountWithRegularBasePlan() {
         List<EntitlementSubscriptionMigrationCase> cases = new LinkedList<EntitlementSubscriptionMigrationCase>();
         cases.add(new EntitlementSubscriptionMigrationCase() {
@@ -271,7 +375,9 @@ public abstract class TestMigration extends TestApiBase {
                 return null;
             }
         });
-        return createAccountWithSingleBasePlan(cases);
+        List<List<EntitlementSubscriptionMigrationCase>> input = new ArrayList<List<EntitlementSubscriptionMigrationCase>>();
+        input.add(cases);
+        return createAccountWithSingleBasePlan(input);
     }
 
     private EntitlementAccountMigration createAccountWithRegularBasePlanFutreCancelled() {
@@ -291,7 +397,9 @@ public abstract class TestMigration extends TestApiBase {
                 return effectiveDate.plusYears(1);
             }
         });
-        return createAccountWithSingleBasePlan(cases);
+        List<List<EntitlementSubscriptionMigrationCase>> input = new ArrayList<List<EntitlementSubscriptionMigrationCase>>();
+        input.add(cases);
+        return createAccountWithSingleBasePlan(input);
     }
 
 
@@ -325,7 +433,9 @@ public abstract class TestMigration extends TestApiBase {
                 return null;
             }
         });
-        return createAccountWithSingleBasePlan(cases);
+        List<List<EntitlementSubscriptionMigrationCase>> input = new ArrayList<List<EntitlementSubscriptionMigrationCase>>();
+        input.add(cases);
+        return createAccountWithSingleBasePlan(input);
     }
 
     private EntitlementAccountMigration createAccountFuturePendingChange() {
@@ -359,7 +469,9 @@ public abstract class TestMigration extends TestApiBase {
                 return null;
             }
         });
-        return createAccountWithSingleBasePlan(cases);
+        List<List<EntitlementSubscriptionMigrationCase>> input = new ArrayList<List<EntitlementSubscriptionMigrationCase>>();
+        input.add(cases);
+        return createAccountWithSingleBasePlan(input);
     }
 
 }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
index b3eb168..b7e83bc 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigrationSql.java
@@ -38,6 +38,12 @@ public class TestMigrationSql extends TestMigration {
 
     @Override
     @Test(enabled=true, groups="sql")
+    public void testPlanWithAddOn() {
+        super.testPlanWithAddOn();
+    }
+
+    @Override
+    @Test(enabled=true, groups="sql")
     public void testSingleBasePlanFutureCancelled() {
         super.testSingleBasePlanFutureCancelled();
     }