killbill-aplcache

#219 - Changes and fixes suggested during code review to reuse

10/25/2016 12:53:42 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index 4e1a83f..db052e6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -386,18 +386,19 @@ public class SubscriptionResource extends JaxRsResourceBase {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
 
-        final SubscriptionJson baseEntitlement = Iterables.tryFind(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
-            @Override
-            public boolean apply(final SubscriptionJson subscription) {
-                return ProductCategory.BASE.toString().equalsIgnoreCase(subscription.getProductCategory());
-            }
-        }).orNull();
-        verifyNonNull(baseEntitlement.getAccountId(), "SubscriptionJson accountId needs to be set for BASE product.");
-
-        final Account account = getAccountFromSubscriptionJson(baseEntitlement, callContext);
+        final Account account = accountUserApi.getAccountById(UUID.fromString(entitlementsWithAddOns.get(0).getBaseEntitlementAndAddOns().get(0).getAccountId()), callContext);
 
         final List<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifierList = new ArrayList<BaseEntitlementWithAddOnsSpecifier>();
         for (BulkBaseSubscriptionAndAddOnsJson bulkBaseEntitlementWithAddOns : entitlementsWithAddOns) {
+
+            final SubscriptionJson baseEntitlement = Iterables.tryFind(bulkBaseEntitlementWithAddOns.getBaseEntitlementAndAddOns(), new Predicate<SubscriptionJson>() {
+                @Override
+                public boolean apply(final SubscriptionJson subscription) {
+                    return ProductCategory.BASE.toString().equalsIgnoreCase(subscription.getProductCategory());
+                }
+            }).orNull();
+            verifyNonNull(baseEntitlement.getAccountId(), "SubscriptionJson accountId needs to be set for BASE product.");
+
             final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
 
             // verify the number of BASE subscriptions
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
index 3067e37..c367ebd 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
@@ -51,7 +51,7 @@ public interface SubscriptionBaseApiService {
     public List<DefaultSubscriptionBase> createPlans(Iterable<SubscriptionSpecifier> subscriptions, CallContext context)
             throws SubscriptionBaseApiException;
 
-    public List<List<DefaultSubscriptionBase>> createPlansWithAddOns(UUID accountId, Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, CallContext context)
+    public List<DefaultSubscriptionBase> createPlansWithAddOns(UUID accountId, Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, CallContext context)
             throws SubscriptionBaseApiException;
 
     public boolean cancel(DefaultSubscriptionBase subscription, CallContext context)
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 48391d5..6be5c7c 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -204,7 +204,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
 
         try {
-            final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
             final Catalog catalog = catalogService.getFullCatalog(true, true, context);
             final CallContext callContext = internalCallContextFactory.createCallContext(context);
 
@@ -213,68 +212,81 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleId);
             }
 
-            boolean first = true;
-            final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundleId, null, context);
+            final List<SubscriptionSpecifier> subscriptions = verifyAndBuildSubscriptionSpecifiers(bundleId,
+                                                                                                   entitlements,
+                                                                                                   isMigrated,
+                                                                                                   context,
+                                                                                                   now,
+                                                                                                   effectiveDate,
+                                                                                                   catalog,
+                                                                                                   callContext);
 
-            for (EntitlementSpecifier entitlement : entitlements) {
+            final List<DefaultSubscriptionBase> result = apiService.createPlans(subscriptions, callContext);
+            return ImmutableList.copyOf(Iterables.transform(result, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
+                @Override
+                public SubscriptionBase apply(final DefaultSubscriptionBase input) {
+                    return (SubscriptionBase) input;
+                }
+            }));
+        } catch (final CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
+        }
+    }
 
-                final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
+    private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final UUID bundleId, final Iterable<EntitlementSpecifier> entitlements, final boolean isMigrated, final InternalCallContext context, final DateTime now, final DateTime effectiveDate, final Catalog catalog, final CallContext callContext) throws SubscriptionBaseApiException, CatalogApiException {
+        final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
+        boolean first = true;
+        final List<SubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundleId, null, context);
 
-                final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
+        for (EntitlementSpecifier entitlement : entitlements) {
 
-                final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
-                final PlanPhase phase = plan.getAllPhases()[0];
-                if (phase == null) {
-                    throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
-                                                                  spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
-                }
+            final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
 
-                if (first) {
-                    first = false;
-                    if (plan.getProduct().getCategory() != ProductCategory.BASE) {
-                        throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
-                    }
+            final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
+
+            final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
+            final PlanPhase phase = plan.getAllPhases()[0];
+            if (phase == null) {
+                throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
+                                                              spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
+            }
+
+            if (first) {
+                first = false;
+                if (plan.getProduct().getCategory() != ProductCategory.BASE) {
+                    throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
                 }
+            }
 
-                // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
-                if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
-                    if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
-                        int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
-                        int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
-                        if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
-                            // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
-                            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
-                        }
+            // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
+            if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
+                if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
+                    int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
+                    int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlements, catalog, plan.getName(), effectiveDate, callContext);
+                    if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
+                        // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
+                        throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
                     }
                 }
-
-                SubscriptionSpecifier subscription = new SubscriptionSpecifier();
-                subscription.setRealPriceList(plan.getPriceListName());
-                subscription.setEffectiveDate(effectiveDate);
-                subscription.setProcessedDate(now);
-                subscription.setPlan(plan);
-                subscription.setInitialPhase(spec.getPhaseType());
-                subscription.setBuilder(new SubscriptionBuilder()
-                                                .setId(UUIDs.randomUUID())
-                                                .setBundleId(bundleId)
-                                                .setCategory(plan.getProduct().getCategory())
-                                                .setBundleStartDate(effectiveDate)
-                                                .setAlignStartDate(effectiveDate)
-                                                .setMigrated(isMigrated));
-
-                subscriptions.add(subscription);
             }
 
-            final List<DefaultSubscriptionBase> result = apiService.createPlans(subscriptions, callContext);
-            return ImmutableList.copyOf(Iterables.transform(result, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
-                @Override
-                public SubscriptionBase apply(final DefaultSubscriptionBase input) {
-                    return (SubscriptionBase) input;
-                }
-            }));
-        } catch (final CatalogApiException e) {
-            throw new SubscriptionBaseApiException(e);
+            SubscriptionSpecifier subscription = new SubscriptionSpecifier();
+            subscription.setRealPriceList(plan.getPriceListName());
+            subscription.setEffectiveDate(effectiveDate);
+            subscription.setProcessedDate(now);
+            subscription.setPlan(plan);
+            subscription.setInitialPhase(spec.getPhaseType());
+            subscription.setBuilder(new SubscriptionBuilder()
+                                            .setId(UUIDs.randomUUID())
+                                            .setBundleId(bundleId)
+                                            .setCategory(plan.getProduct().getCategory())
+                                            .setBundleStartDate(effectiveDate)
+                                            .setAlignStartDate(effectiveDate)
+                                            .setMigrated(isMigrated));
+
+            subscriptions.add(subscription);
         }
+        return subscriptions;
     }
 
     @Override
@@ -285,89 +297,37 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
             final List<SubscriptionAndAddOnsSpecifier> subscriptionAndAddOns = new ArrayList<SubscriptionAndAddOnsSpecifier>();
             for (BaseEntitlementWithAddOnsSpecifier entitlementWithAddOnsSpecifier : baseEntitlementWithAddOnsSpecifier) {
-                final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
                 final DateTime now = clock.getUTCNow();
                 final DateTime effectiveDate = (entitlementWithAddOnsSpecifier.getEntitlementEffectiveDate() != null) ?
                                                DefaultClock.truncateMs(entitlementWithAddOnsSpecifier.getEntitlementEffectiveDate().toDateTimeAtCurrentTime()) : now;
 
                 final SubscriptionBaseBundle bundle = createBundleForAccount(accountId, entitlementWithAddOnsSpecifier.getExternalKey(), context);
-                final List<SubscriptionBase> subscriptionWithAddOns = createBaseSubscriptionWithAddOns(bundle.getId(), entitlementWithAddOnsSpecifier.getEntitlementSpecifier(),
-                                                                                                       entitlementWithAddOnsSpecifier.getEntitlementEffectiveDate().toDateTimeAtCurrentTime(),
-                                                                                                       entitlementWithAddOnsSpecifier.isMigrated(), context);
-                boolean first = true;
-                for (EntitlementSpecifier entitlement : entitlementWithAddOnsSpecifier.getEntitlementSpecifier()) {
-                    final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
-
-                    final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
-
-                    final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, entitlementWithAddOnsSpecifier.getEntitlementEffectiveDate().toDateTimeAtCurrentTime());
-                    final PlanPhase phase = plan.getAllPhases()[0];
-                    if (phase == null) {
-                        throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
-                                                                      spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceListName()));
-                    }
-
-                    if (first) {
-                        first = false;
-                        if (plan.getProduct().getCategory() != ProductCategory.BASE) {
-                            throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
-                        }
-                    }
 
-                    // verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
-                    if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
-                        if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
-                            int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionWithAddOns, plan.getName());
-                            int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlementWithAddOnsSpecifier.getEntitlementSpecifier(), catalog, plan.getName(), effectiveDate, callContext);
-                            if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
-                                // a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
-                                throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
-                            }
-                        }
-                    }
+                final List<SubscriptionSpecifier> subscriptions = verifyAndBuildSubscriptionSpecifiers(bundle.getId(),
+                                                                                                       entitlementWithAddOnsSpecifier.getEntitlementSpecifier(),
+                                                                                                       entitlementWithAddOnsSpecifier.isMigrated(),
+                                                                                                       context,
+                                                                                                       now,
+                                                                                                       effectiveDate,
+                                                                                                       catalog,
+                                                                                                       callContext);
 
-                    SubscriptionSpecifier subscription = new SubscriptionSpecifier();
-                    subscription.setRealPriceList(plan.getPriceListName());
-                    subscription.setEffectiveDate(effectiveDate);
-                    subscription.setProcessedDate(now);
-                    subscription.setPlan(plan);
-                    subscription.setInitialPhase(spec.getPhaseType());
-                    subscription.setBuilder(new SubscriptionBuilder()
-                                                    .setId(UUIDs.randomUUID())
-                                                    .setBundleId(bundle.getId())
-                                                    .setCategory(plan.getProduct().getCategory())
-                                                    .setBundleStartDate(effectiveDate)
-                                                    .setAlignStartDate(effectiveDate)
-                                                    .setMigrated(entitlementWithAddOnsSpecifier.isMigrated()));
-
-                    subscriptions.add(subscription);
-                }
                 SubscriptionAndAddOnsSpecifier subscriptionAndAddOnsSpecifier = new SubscriptionAndAddOnsSpecifier();
                 subscriptionAndAddOnsSpecifier.setSubscriptionSpecifiers(subscriptions);
                 subscriptionAndAddOns.add(subscriptionAndAddOnsSpecifier);
             }
 
-            final List<List<DefaultSubscriptionBase>> result = apiService.createPlansWithAddOns(accountId, subscriptionAndAddOns, callContext);
-            return buildSubscriptionBaseList(result);
-
-        } catch (CatalogApiException e) {
-            throw new SubscriptionBaseApiException(e);
-        }
-    }
-
-    private List<SubscriptionBase> buildSubscriptionBaseList(final List<List<DefaultSubscriptionBase>> defaultSubscriptionBaseList) {
-        List<SubscriptionBase> result = new ArrayList<SubscriptionBase>();
-
-        for (List<DefaultSubscriptionBase> defaultSubscriptionBase : defaultSubscriptionBaseList) {
-            final ImmutableList<SubscriptionBase> subscriptionBases = ImmutableList.copyOf(Iterables.transform(defaultSubscriptionBase, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
+            final List<DefaultSubscriptionBase> result = apiService.createPlansWithAddOns(accountId, subscriptionAndAddOns, callContext);
+            return ImmutableList.copyOf(Iterables.transform(result, new Function<DefaultSubscriptionBase, SubscriptionBase>() {
                 @Override
                 public SubscriptionBase apply(final DefaultSubscriptionBase input) {
-                    return input;
+                    return (SubscriptionBase) input;
                 }
             }));
-            result.addAll(subscriptionBases);
+
+        } catch (CatalogApiException e) {
+            throw new SubscriptionBaseApiException(e);
         }
-        return result;
     }
 
     private int countCurrentAddOnsWithSamePlanName(final Iterable<EntitlementSpecifier> entitlements,
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 4137398..b4115db 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -34,7 +34,6 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
-import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
@@ -118,63 +117,44 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     @Override
-    public List<List<DefaultSubscriptionBase>> createPlansWithAddOns(final UUID accountId, final Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, final CallContext context) throws SubscriptionBaseApiException {
+    public List<DefaultSubscriptionBase> createPlans(final Iterable<SubscriptionSpecifier> subscriptions, final CallContext context) throws SubscriptionBaseApiException {
+        Map<UUID, List<SubscriptionBaseEvent>> eventsMap = new HashMap<UUID, List<SubscriptionBaseEvent>>();
+        List<DefaultSubscriptionBase> subscriptionBaseList = new ArrayList<DefaultSubscriptionBase>();
+        createEvents(subscriptions, context, eventsMap, subscriptionBaseList);
+
+        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBaseList.get(0).getBundleId(), context);
+        dao.createSubscriptionsWithAddOns(subscriptionBaseList, eventsMap, internalCallContext);
 
+        final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptionBaseList);
+        rebuildTransitions(internalCallContext, subscriptionBaseList, baseSubscription);
+        return subscriptionBaseList;
+    }
+
+    @Override
+    public List<DefaultSubscriptionBase> createPlansWithAddOns(final UUID accountId, final Iterable<SubscriptionAndAddOnsSpecifier> subscriptionsAndAddOns, final CallContext context) throws SubscriptionBaseApiException {
         Map<UUID, List<SubscriptionBaseEvent>> eventsMap = new HashMap<UUID, List<SubscriptionBaseEvent>>();
         List<List<DefaultSubscriptionBase>> subscriptionBaseAndAddOnsList = new ArrayList<List<DefaultSubscriptionBase>>();
+        List<DefaultSubscriptionBase> allSubscriptions = new ArrayList<DefaultSubscriptionBase>();
 
         for (SubscriptionAndAddOnsSpecifier subscriptionAndAddOns : subscriptionsAndAddOns) {
             List<DefaultSubscriptionBase> subscriptionBaseList = new ArrayList<DefaultSubscriptionBase>();
-            for (SubscriptionSpecifier subscription : subscriptionAndAddOns.getSubscriptionSpecifiers()) {
-
-                try {
-                    final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(subscription.getBuilder(), this, clock);
-                    final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBase.getBundleId(), context);
-                    final List<SubscriptionBaseEvent> events = getEventsOnCreation(subscriptionBase.getBundleId(), subscriptionBase.getId(), subscriptionBase.getAlignStartDate(),
-                                                                                   subscriptionBase.getBundleStartDate(), subscription.getPlan(),
-                                                                                   subscription.getInitialPhase(), subscription.getRealPriceList(),
-                                                                                   subscription.getEffectiveDate(), subscription.getProcessedDate(), internalCallContext);
-                    eventsMap.put(subscriptionBase.getId(), events);
-                    subscriptionBaseList.add(subscriptionBase);
-
-                } catch (final CatalogApiException e) {
-                    throw new SubscriptionBaseApiException(e);
-                }
-            }
+            createEvents(subscriptionAndAddOns.getSubscriptionSpecifiers(), context, eventsMap, subscriptionBaseList);
             subscriptionBaseAndAddOnsList.add(subscriptionBaseList);
+            allSubscriptions.addAll(subscriptionBaseList);
         }
 
         final InternalCallContext internalCallContext = createCallContextFromAccountId(accountId, context);
-        dao.createSubscriptionsWithAddOns(subscriptionBaseAndAddOnsList, eventsMap, internalCallContext);
-
-        for (List<DefaultSubscriptionBase> subscriptionBase : subscriptionBaseAndAddOnsList) {
-            final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptionBase);
-            try {
-                baseSubscription.rebuildTransitions(dao.getEventsForSubscription(baseSubscription.getId(), internalCallContext),
-                                                    catalogService.getFullCatalog(true, true, internalCallContext));
-
-                for (final DefaultSubscriptionBase input : subscriptionBase) {
-                    if (input.getId().equals(baseSubscription.getId())) {
-                        continue;
-                    }
+        dao.createSubscriptionsWithAddOns(allSubscriptions, eventsMap, internalCallContext);
 
-                    input.rebuildTransitions(dao.getEventsForSubscription(input.getId(), internalCallContext),
-                                             catalogService.getFullCatalog(true, true, internalCallContext));
-                }
-            } catch (CatalogApiException e) {
-                throw new SubscriptionBaseApiException(e);
-            }
+        for (List<DefaultSubscriptionBase> subscriptions : subscriptionBaseAndAddOnsList) {
+            final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptions);
+            rebuildTransitions(internalCallContext, subscriptions, baseSubscription);
         }
-        return subscriptionBaseAndAddOnsList;
+        return allSubscriptions;
     }
 
-    @Override
-    public List<DefaultSubscriptionBase> createPlans(final Iterable<SubscriptionSpecifier> subscriptions, final CallContext context) throws SubscriptionBaseApiException {
-
-        Map<UUID, List<SubscriptionBaseEvent>> eventsMap = new HashMap<UUID, List<SubscriptionBaseEvent>>();
-        List<DefaultSubscriptionBase> subscriptionBaseList = new ArrayList<DefaultSubscriptionBase>();
+    private void createEvents(final Iterable<SubscriptionSpecifier> subscriptions, final CallContext context, final Map<UUID, List<SubscriptionBaseEvent>> eventsMap, final List<DefaultSubscriptionBase> subscriptionBaseList) throws SubscriptionBaseApiException {
         for (SubscriptionSpecifier subscription : subscriptions) {
-
             try {
                 final DefaultSubscriptionBase subscriptionBase = new DefaultSubscriptionBase(subscription.getBuilder(), this, clock);
                 final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBase.getBundleId(), context);
@@ -189,16 +169,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                 throw new SubscriptionBaseApiException(e);
             }
         }
+    }
 
-        final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBaseList.get(0).getBundleId(), context);
-        dao.createSubscriptionWithAddOns(subscriptionBaseList, eventsMap, internalCallContext);
-
-        final DefaultSubscriptionBase baseSubscription = findBaseSubscription(subscriptionBaseList);
+    private void rebuildTransitions(final InternalCallContext internalCallContext, final List<DefaultSubscriptionBase> subscriptions, final DefaultSubscriptionBase baseSubscription) throws SubscriptionBaseApiException {
         try {
             baseSubscription.rebuildTransitions(dao.getEventsForSubscription(baseSubscription.getId(), internalCallContext),
                                                 catalogService.getFullCatalog(true, true, internalCallContext));
 
-            for (final DefaultSubscriptionBase input : subscriptionBaseList) {
+            for (final DefaultSubscriptionBase input : subscriptions) {
                 if (input.getId().equals(baseSubscription.getId())) {
                     continue;
                 }
@@ -209,7 +187,6 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         } catch (CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
-        return subscriptionBaseList;
     }
 
     private DefaultSubscriptionBase findBaseSubscription(final List<DefaultSubscriptionBase> subscriptionBaseList) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index cd3a84a..9939d8d 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -513,57 +513,34 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     }
 
     @Override
-    public void createSubscriptionsWithAddOns(final List<List<DefaultSubscriptionBase>> subscriptionsWithAddOns,
-                                              final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
-                                              final InternalCallContext context) {
+    public void createSubscriptionsWithAddOns(final List<DefaultSubscriptionBase> subscriptions, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
-
                 final SubscriptionSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
                 final SubscriptionEventSqlDao eventsDaoFromSameTransaction = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
 
-                for (List<DefaultSubscriptionBase> subscriptionWithAddOns : subscriptionsWithAddOns) {
-                    createSubscription(entitySqlDaoWrapperFactory, transactional, eventsDaoFromSameTransaction, subscriptionWithAddOns, context, initialEventsMap);
-                }
-                return null;
-            }
-        });
-    }
+                for (DefaultSubscriptionBase subscription : subscriptions) {
+                    transactional.create(new SubscriptionModelDao(subscription), context);
 
-    @Override
-    public void createSubscriptionWithAddOns(final List<DefaultSubscriptionBase> subscriptions, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
-            @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
-                final SubscriptionSqlDao transactional = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
-                final SubscriptionEventSqlDao eventsDaoFromSameTransaction = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class);
+                    final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
+                    for (final SubscriptionBaseEvent cur : initialEvents) {
+                        eventsDaoFromSameTransaction.create(new SubscriptionEventModelDao(cur), context);
 
-                createSubscription(entitySqlDaoWrapperFactory, transactional, eventsDaoFromSameTransaction, subscriptions, context, initialEventsMap);
+                        final boolean isBusEvent = cur.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 && (cur.getType() == EventType.API_USER);
+                        recordBusOrFutureNotificationFromTransaction(subscription, cur, entitySqlDaoWrapperFactory, isBusEvent, 0, context);
+
+                    }
+                    // Notify the Bus of the latest requested change, if needed
+                    if (initialEvents.size() > 0) {
+                        notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscription, initialEvents.get(initialEvents.size() - 1), SubscriptionBaseTransitionType.CREATE, context);
+                    }
+                }
                 return null;
             }
         });
     }
 
-    private void createSubscription(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final SubscriptionSqlDao transactional, final SubscriptionEventSqlDao eventsDaoFromSameTransaction, final List<DefaultSubscriptionBase> subscriptions, final InternalCallContext context, final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap) throws EntityPersistenceException {
-        for (DefaultSubscriptionBase subscription : subscriptions) {
-            transactional.create(new SubscriptionModelDao(subscription), context);
-
-            final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
-            for (final SubscriptionBaseEvent cur : initialEvents) {
-                eventsDaoFromSameTransaction.create(new SubscriptionEventModelDao(cur), context);
-
-                final boolean isBusEvent = cur.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 && (cur.getType() == EventType.API_USER);
-                recordBusOrFutureNotificationFromTransaction(subscription, cur, entitySqlDaoWrapperFactory, isBusEvent, 0, context);
-
-            }
-            // Notify the Bus of the latest requested change, if needed
-            if (initialEvents.size() > 0) {
-                notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subscription, initialEvents.get(initialEvents.size() - 1), SubscriptionBaseTransitionType.CREATE, context);
-            }
-        }
-    }
-
     @Override
     public void cancelSubscriptionsOnBasePlanEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent event, final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionBaseEvent> cancelEvents, final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
index d08cd40..b908c73 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/SubscriptionDao.java
@@ -81,9 +81,7 @@ public interface SubscriptionDao extends EntityDao<SubscriptionBundleModelDao, S
     // SubscriptionBase creation, cancellation, changePlanWithRequestedDate apis
     public void createSubscription(DefaultSubscriptionBase subscription, List<SubscriptionBaseEvent> initialEvents, InternalCallContext context);
 
-    public void createSubscriptionWithAddOns(List<DefaultSubscriptionBase> subscriptions, Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, InternalCallContext context);
-
-    public void createSubscriptionsWithAddOns(List<List<DefaultSubscriptionBase>> subscriptionsWithAddOns, Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, InternalCallContext context);
+    public void createSubscriptionsWithAddOns(List<DefaultSubscriptionBase> subscriptions, Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap, InternalCallContext context);
 
     public void cancelSubscriptionsOnBasePlanEvent(DefaultSubscriptionBase subscription, SubscriptionBaseEvent event, List<DefaultSubscriptionBase> subscriptions, List<SubscriptionBaseEvent> cancelEvents, InternalCallContext context);
 
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
index 6291b97..d6af5ce 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/engine/dao/MockSubscriptionDaoMemory.java
@@ -220,10 +220,9 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
         mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
     }
 
-    @Override
-    public void createSubscriptionWithAddOns(final List<DefaultSubscriptionBase> subscriptions,
-                                             final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
-                                             final InternalCallContext context) {
+    public void createSubscriptionsWithAddOns(final List<DefaultSubscriptionBase> subscriptions,
+                                              final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
+                                              final InternalCallContext context) {
         synchronized (events) {
             for (DefaultSubscriptionBase subscription : subscriptions) {
                 final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
@@ -239,26 +238,6 @@ public class MockSubscriptionDaoMemory extends MockEntityDaoBase<SubscriptionBun
     }
 
     @Override
-    public void createSubscriptionsWithAddOns(final List<List<DefaultSubscriptionBase>> subscriptionsWithAddOns,
-                                              final Map<UUID, List<SubscriptionBaseEvent>> initialEventsMap,
-                                              final InternalCallContext context) {
-        synchronized (events) {
-            for (List<DefaultSubscriptionBase> subscriptionAndAddOns : subscriptionsWithAddOns) {
-                for (DefaultSubscriptionBase subscription : subscriptionAndAddOns) {
-                    final List<SubscriptionBaseEvent> initialEvents = initialEventsMap.get(subscription.getId());
-                    events.addAll(initialEvents);
-                    for (final SubscriptionBaseEvent cur : initialEvents) {
-                        recordFutureNotificationFromTransaction(null, cur.getEffectiveDate(), new SubscriptionNotificationKey(cur.getId()), context);
-                    }
-                    final SubscriptionBase updatedSubscription = buildSubscription(subscription, context);
-                    this.subscriptions.add(updatedSubscription);
-                    mockNonEntityDao.addTenantRecordIdMapping(updatedSubscription.getId(), context);
-                }
-            }
-        }
-    }
-
-    @Override
     public List<SubscriptionBase> getSubscriptions(final UUID bundleId, final List<SubscriptionBaseEvent> dryRunEvents, final InternalTenantContext context) {
         final List<SubscriptionBase> results = new ArrayList<SubscriptionBase>();
         for (final SubscriptionBase cur : subscriptions) {