killbill-memoizeit

catalog: Modify catalog api to take as an input a PlanSpecifier

7/20/2016 10:51:18 PM

Changes

pom.xml 2(+1 -1)

Details

diff --git a/api/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionBaseTimeline.java b/api/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionBaseTimeline.java
index 434b964..878b789 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionBaseTimeline.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/timeline/SubscriptionBaseTimeline.java
@@ -24,6 +24,7 @@ import java.util.UUID;
 import org.joda.time.DateTime;
 
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.util.entity.Entity;
 
@@ -60,6 +61,12 @@ public interface SubscriptionBaseTimeline extends Entity {
         public SubscriptionBaseTransitionType getSubscriptionTransitionType();
 
         /**
+         *
+         * @return the product category
+         */
+        public ProductCategory getProductCategory();
+
+        /**
          * @return the date at which this event was effective
          */
         public DateTime getEffectiveDate();
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
index 648d522..413d676 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestBundleTransfer.java
@@ -166,7 +166,7 @@ public class TestBundleTransfer extends TestIntegrationBase {
         //
         // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE, NextEvent.BLOCK NextEvent.INVOICE
         //
-        final PlanPhaseSpecifier bpPlanPhaseSpecifier = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null);
+        final PlanPhaseSpecifier bpPlanPhaseSpecifier = new PlanPhaseSpecifier(productName, term, planSetName, null);
 
         final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
         assertNotNull(bpEntitlement);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
index 6d98f81..919890e 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestCatalogRetireElements.java
@@ -79,7 +79,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
 
         // Catalog v2 should start now.
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         try {
             entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
             fail(); // force to fail is there is not an exception
@@ -135,7 +135,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
 
         // Catalog v3 should start now.
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         try {
             entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey2", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
             fail(); // force to fail is there is not an exception
@@ -170,7 +170,7 @@ public class TestCatalogRetireElements extends TestIntegrationBase {
 
         final String productName = "Pistol";
         final BillingPeriod term = BillingPeriod.MONTHLY;
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, "SpecialDiscount", null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, term, "SpecialDiscount", null);
 
         busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
         final Entitlement bpEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "externalKey", null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 50af600..59a72b9 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -606,7 +606,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
             @Override
             public Entitlement apply(@Nullable final Void dontcare) {
                 try {
-                    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+                    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
                     final Entitlement entitlement = entitlementApi.createBaseEntitlement(accountId, spec, bundleExternalKey, overrides, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
                     assertNotNull(entitlement);
                     return entitlement;
@@ -640,7 +640,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
             @Override
             public Entitlement apply(@Nullable final Void dontcare) {
                 try {
-                    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, productCategory, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+                    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, PriceListSet.DEFAULT_PRICELIST_NAME, null);
                     final Entitlement entitlement = entitlementApi.addEntitlement(bundleId, spec, null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
                     assertNotNull(entitlement);
                     return entitlement;
@@ -808,7 +808,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                                    final LocalDate effectiveDate,
                                    final BillingActionPolicy billingPolicy) {
             this.dryRunType = dryRunType;
-            this.spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceList, phaseType);
+            this.spec = new PlanPhaseSpecifier(productName, billingPeriod, priceList, phaseType);
             this.action = action;
             this.subscriptionId = subscriptionId;
             this.bundleId = bundleId;
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
index cdd69e5..3069314 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestMigrationSubscriptions.java
@@ -30,7 +30,6 @@ import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.PriceListSet;
-import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier;
 import org.killbill.billing.entitlement.api.Entitlement;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -72,7 +71,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
         final LocalDate billingMigrationDate = new LocalDate(2016, 1, 31);
 
         // Entitlement wil be created in PENDING state
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
         Assert.assertEquals(entitlement.getState(), EntitlementState.PENDING);
 
@@ -128,7 +127,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
 
         // Entitlement wil be created in ACTIVE state because entitlementMigrationDate was set in the past
         busHandler.pushExpectedEvents(NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -173,7 +172,7 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
 
         // Entitlement wil be created in ACTIVE state because entitlementMigrationDate was set in the past
         busHandler.pushExpectedEvents(NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleKey", null, entitlementMigrationDate, billingMigrationDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
         Assert.assertEquals(entitlement.getState(), EntitlementState.ACTIVE);
@@ -224,8 +223,8 @@ public class TestMigrationSubscriptions extends TestIntegrationBase {
         final LocalDate entitlementMigrationDate = new LocalDate(2015, 12, 20);
         final LocalDate billingMigrationDate = new LocalDate(2016, 2, 1);
 
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
-        final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
+        final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.EVERGREEN);
 
         final String externalKey = "baseExternalKey";
         EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index b174219..695e480 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -198,9 +198,9 @@ public class TestSubscription extends TestIntegrationBase {
 
         final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
 
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-        final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-        final PlanPhaseSpecifier addOnSpec2 = new PlanPhaseSpecifier("Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec2 = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final String externalKey = "baseExternalKey";
         EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
@@ -254,7 +254,7 @@ public class TestSubscription extends TestIntegrationBase {
 
         final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final LocalDate futureDate = new LocalDate(2015, 10, 1);
 
@@ -286,7 +286,7 @@ public class TestSubscription extends TestIntegrationBase {
 
         final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final LocalDate futureDate = new LocalDate(2015, 10, 1);
 
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
index 4ef9834..de723e3 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
@@ -133,7 +133,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", ProductCategory.BASE, BillingPeriod.MONTHLY, "notrial", null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
         Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -178,7 +178,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", ProductCategory.BASE, BillingPeriod.MONTHLY, "notrial", null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
         Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -230,7 +230,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
         }
 
         busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", ProductCategory.BASE, BillingPeriod.MONTHLY, "notrial", null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", BillingPeriod.MONTHLY, "notrial", null);
         // Pass a date of today, to trigger TimeAwareContext#toUTCDateTime
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), clock.getUTCToday(), clock.getUTCToday(), false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
index 629db2b..f348183 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCase.java
@@ -49,7 +49,6 @@ public abstract class DefaultCase<T> extends ValidatingConfig<StandaloneCatalog>
 
     protected boolean satisfiesCase(final PlanSpecifier planPhase, final StaticCatalog c) throws CatalogApiException {
         return (getProduct() == null || getProduct().equals(c.findCurrentProduct(planPhase.getProductName()))) &&
-                (getProductCategory() == null || getProductCategory().equals(planPhase.getProductCategory())) &&
                 (getBillingPeriod() == null || getBillingPeriod().equals(planPhase.getBillingPeriod())) &&
                 (getPriceList() == null || getPriceList().equals(c.findCurrentPricelist(planPhase.getPriceListName())));
     }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
index a9e25d9..9955ed8 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultCaseChange.java
@@ -80,10 +80,8 @@ public abstract class DefaultCaseChange<T> extends ValidatingConfig<StandaloneCa
         if (
                 (phaseType == null || from.getPhaseType() == phaseType) &&
                         (fromProduct == null || fromProduct.equals(catalog.findCurrentProduct(from.getProductName()))) &&
-                        (fromProductCategory == null || fromProductCategory.equals(from.getProductCategory())) &&
                         (fromBillingPeriod == null || fromBillingPeriod.equals(from.getBillingPeriod())) &&
                         (toProduct == null || toProduct.equals(catalog.findCurrentProduct(to.getProductName()))) &&
-                        (toProductCategory == null || toProductCategory.equals(to.getProductCategory())) &&
                         (toBillingPeriod == null || toBillingPeriod.equals(to.getBillingPeriod())) &&
                         (fromPriceList == null || fromPriceList.equals(catalog.findCurrentPricelist(from.getPriceListName()))) &&
                         (toPriceList == null || toPriceList.equals(catalog.findCurrentPricelist(to.getPriceListName())))
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
index b0e3222..34dd757 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/rules/DefaultPlanRules.java
@@ -74,7 +74,6 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
     @XmlElement(name = "priceListCase", required = false)
     private DefaultCasePriceList[] priceListCase;
 
-
     @Override
     public Iterable<CaseChangePlanPolicy> getCaseChangePlanPolicy() {
         return ImmutableList.<CaseChangePlanPolicy>copyOf(changeCase);
@@ -105,28 +104,26 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
         return ImmutableList.<CasePriceList>copyOf(priceListCase);
     }
 
-
-
     public PlanAlignmentCreate getPlanCreateAlignment(final PlanSpecifier specifier, final StaticCatalog catalog) throws CatalogApiException {
-        final PlanAlignmentCreate result =  DefaultCase.getResult(createAlignmentCase, specifier, catalog);
+        final PlanAlignmentCreate result = DefaultCase.getResult(createAlignmentCase, specifier, catalog);
         return (result != null) ? result : PlanAlignmentCreate.START_OF_BUNDLE;
     }
 
     public BillingActionPolicy getPlanCancelPolicy(final PlanPhaseSpecifier planPhase, final StaticCatalog catalog) throws CatalogApiException {
-        final BillingActionPolicy result =  DefaultCasePhase.getResult(cancelCase, planPhase, catalog);
+        final BillingActionPolicy result = DefaultCasePhase.getResult(cancelCase, planPhase, catalog);
         return (result != null) ? result : BillingActionPolicy.END_OF_TERM;
     }
 
     public BillingAlignment getBillingAlignment(final PlanPhaseSpecifier planPhase, final StaticCatalog catalog) throws CatalogApiException {
         final BillingAlignment result = DefaultCasePhase.getResult(billingAlignmentCase, planPhase, catalog);
-        return (result != null) ?  result : BillingAlignment.ACCOUNT;
+        return (result != null) ? result : BillingAlignment.ACCOUNT;
     }
 
     public PlanChangeResult planChange(final PlanPhaseSpecifier from, PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
         final DefaultPriceList toPriceList;
         if (to.getPriceListName() == null) { // Pricelist may be null because it is unspecified this is the principal use-case
-            toPriceList = findPriceList(from.toPlanSpecifier(), catalog);
-            to = new PlanSpecifier(to.getProductName(), to.getProductCategory(), to.getBillingPeriod(), toPriceList.getName());
+            toPriceList = findPriceList(from, catalog);
+            to = new PlanSpecifier(to.getProductName(), to.getBillingPeriod(), toPriceList.getName());
         } else {
             toPriceList = (DefaultPriceList) catalog.findCurrentPricelist(to.getPriceListName());
         }
@@ -143,7 +140,7 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
 
     public PlanAlignmentChange getPlanChangeAlignment(final PlanPhaseSpecifier from,
                                                       final PlanSpecifier to, final StaticCatalog catalog) throws CatalogApiException {
-        final PlanAlignmentChange result =  DefaultCaseChange.getResult(changeAlignmentCase, from, to, catalog);
+        final PlanAlignmentChange result = DefaultCaseChange.getResult(changeAlignmentCase, from, to, catalog);
         return (result != null) ? result : PlanAlignmentChange.START_OF_BUNDLE;
     }
 
@@ -156,7 +153,7 @@ public class DefaultPlanRules extends ValidatingConfig<StandaloneCatalog> implem
         }
         //Plan toPlan = catalog.findPlan()
 
-        final BillingActionPolicy result =  DefaultCaseChange.getResult(changeCase, from, to, catalog);
+        final BillingActionPolicy result = DefaultCaseChange.getResult(changeCase, from, to, catalog);
         return (result != null) ? result : BillingActionPolicy.END_OF_TERM;
     }
 
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
index ddb6492..9d2fb75 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalog.java
@@ -161,18 +161,18 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
       * @see org.killbill.billing.catalog.ICatalog#getPlan(java.lang.String, java.lang.String)
       */
     @Override
-    public DefaultPlan createOrFindCurrentPlan(final String productName, final BillingPeriod period, final String priceListName, final PlanPhasePriceOverridesWithCallContext unused) throws CatalogApiException {
-        if (productName == null) {
+    public DefaultPlan createOrFindCurrentPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext unused) throws CatalogApiException {
+        if (spec.getProductName() == null) {
             throw new CatalogApiException(ErrorCode.CAT_NULL_PRODUCT_NAME);
         }
         if (priceLists == null) {
-            throw new CatalogApiException(ErrorCode.CAT_PRICE_LIST_NOT_FOUND, priceListName);
+            throw new CatalogApiException(ErrorCode.CAT_PRICE_LIST_NOT_FOUND, spec.getPriceListName());
         }
-        final Product product = findCurrentProduct(productName);
-        final DefaultPlan result = priceLists.getPlanFrom(priceListName, product, period);
+        final Product product = findCurrentProduct(spec.getProductName());
+        final DefaultPlan result = priceLists.getPlanFrom(spec.getPriceListName(), product, spec.getBillingPeriod());
         if (result == null) {
-            final String periodString = (period == null) ? "NULL" : period.toString();
-            throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND, productName, periodString, priceListName);
+            final String periodString = (spec.getBillingPeriod() == null) ? "NULL" : spec.getBillingPeriod().toString();
+            throw new CatalogApiException(ErrorCode.CAT_PLAN_NOT_FOUND, spec.getProductName(), periodString, spec.getPriceListName());
         }
         return result;
     }
@@ -344,7 +344,7 @@ public class StandaloneCatalog extends ValidatingConfig<StandaloneCatalog> imple
     @Override
     public boolean canCreatePlan(final PlanSpecifier specifier) throws CatalogApiException {
         final Product product = findCurrentProduct(specifier.getProductName());
-        final Plan plan = createOrFindCurrentPlan(specifier.getProductName(), specifier.getBillingPeriod(), specifier.getPriceListName(), null);
+        final Plan plan = createOrFindCurrentPlan(specifier, null);
         final DefaultPriceList priceList = findCurrentPriceList(specifier.getPriceListName());
 
         return (product != null) &&
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
index 1e14391..76e2c2d 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/StandaloneCatalogWithPriceOverride.java
@@ -130,8 +130,8 @@ public class StandaloneCatalogWithPriceOverride extends ValidatingConfig<Standal
     }
 
     @Override
-    public Plan createOrFindCurrentPlan(final String productName, final BillingPeriod period, final String priceListName, final PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
-        final Plan defaultPlan = standaloneCatalog.createOrFindCurrentPlan(productName, period, priceListName, null);
+    public Plan createOrFindCurrentPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
+        final Plan defaultPlan = standaloneCatalog.createOrFindCurrentPlan(spec, null);
 
         if (overrides == null ||
             overrides.getOverrides() == null ||
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
index d70a831..cc00006 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/VersionedCatalog.java
@@ -120,29 +120,26 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
 
     private class PlanRequestWrapper {
 
-        String name;
-        String productName;
-        BillingPeriod bp;
-        String priceListName;
-        PlanPhasePriceOverridesWithCallContext overrides;
-
-        public PlanRequestWrapper(final String name) {
-            this.name = name;
+        private final PlanSpecifier spec;
+        private final PlanPhasePriceOverridesWithCallContext overrides;
+
+        public PlanRequestWrapper(final String planName) {
+            this.spec = new PlanSpecifier(planName);
+            this.overrides = null;
         }
 
-        public PlanRequestWrapper(final String productName, final BillingPeriod bp,
-                                  final String priceListName, final PlanPhasePriceOverridesWithCallContext overrides) {
-            this.productName = productName;
-            this.bp = bp;
-            this.priceListName = priceListName;
+        public PlanRequestWrapper(final PlanSpecifier spec,
+                                  final PlanPhasePriceOverridesWithCallContext overrides) {
+            this.spec = spec;
             this.overrides = overrides;
         }
 
+
         public Plan findPlan(final StandaloneCatalogWithPriceOverride catalog) throws CatalogApiException {
-            if (name != null) {
-                return catalog.findCurrentPlan(name);
+            if (spec.getPlanName() != null) {
+                return catalog.findCurrentPlan(spec.getPlanName());
             } else {
-                return catalog.createOrFindCurrentPlan(productName, bp, priceListName, overrides);
+                return catalog.createOrFindCurrentPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName()), overrides);
             }
         }
     }
@@ -288,13 +285,11 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
     }
 
     @Override
-    public Plan createOrFindPlan(final String productName,
-                                 final BillingPeriod term,
-                                 final String priceListName,
+    public Plan createOrFindPlan(final PlanSpecifier spec,
                                  final PlanPhasePriceOverridesWithCallContext overrides,
                                  final DateTime requestedDate)
             throws CatalogApiException {
-        return versionForDate(requestedDate).createOrFindCurrentPlan(productName, term, priceListName, overrides);
+        return versionForDate(requestedDate).createOrFindCurrentPlan(spec, overrides);
     }
 
     @Override
@@ -307,14 +302,12 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
     }
 
     @Override
-    public Plan createOrFindPlan(final String productName,
-                                 final BillingPeriod term,
-                                 final String priceListName,
+    public Plan createOrFindPlan(final PlanSpecifier spec,
                                  final PlanPhasePriceOverridesWithCallContext overrides,
                                  final DateTime requestedDate,
                                  final DateTime subscriptionStartDate)
             throws CatalogApiException {
-        final CatalogPlanEntry entry =  findCatalogPlanEntry(new PlanRequestWrapper(productName, term, priceListName, overrides), requestedDate, subscriptionStartDate);
+        final CatalogPlanEntry entry =  findCatalogPlanEntry(new PlanRequestWrapper(spec, overrides), requestedDate, subscriptionStartDate);
         return entry.getPlan();
     }
 
@@ -463,9 +456,8 @@ public class VersionedCatalog extends ValidatingConfig<StandaloneCatalogWithPric
     }
 
     @Override
-    public Plan createOrFindCurrentPlan(final String productName, final BillingPeriod term,
-                                        final String priceList, final PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
-        return versionForDate(clock.getUTCNow()).createOrFindCurrentPlan(productName, term, priceList, overrides);
+    public Plan createOrFindCurrentPlan(final PlanSpecifier spec, final PlanPhasePriceOverridesWithCallContext overrides) throws CatalogApiException {
+        return versionForDate(clock.getUTCNow()).createOrFindCurrentPlan(spec, overrides);
     }
 
     @Override
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/catalogTemplate.xml b/catalog/src/main/resources/org/killbill/billing/catalog/catalogTemplate.xml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/catalogTemplate.xml
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
index 5e6c579..ca6adad 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalog.java
@@ -120,9 +120,9 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public Plan createOrFindPlan(final String productName, final BillingPeriod term, final String priceListName, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate)
+    public Plan createOrFindPlan(final PlanSpecifier spec, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate)
             throws CatalogApiException {
-        return createOrFindCurrentPlan(productName, term, priceListName, overrides);
+        return createOrFindCurrentPlan(spec, overrides);
     }
 
     @Override
@@ -132,9 +132,9 @@ public class MockCatalog extends StandaloneCatalog implements Catalog {
     }
 
     @Override
-    public Plan createOrFindPlan(final String productName, final BillingPeriod term, final String priceListName, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate,
+    public Plan createOrFindPlan(final PlanSpecifier spec, PlanPhasePriceOverridesWithCallContext overrides, final DateTime requestedDate,
                          final DateTime subscriptionStartDate) throws CatalogApiException {
-        return createOrFindCurrentPlan(productName, term, priceListName, overrides);
+        return createOrFindCurrentPlan(spec, overrides);
     }
 
     @Override
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCase.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCase.java
index b3f16dd..93774c4 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCase.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCase.java
@@ -121,7 +121,6 @@ public class TestCase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", cat);
     }
@@ -143,7 +142,6 @@ public class TestCase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertion(Result.FOO, cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", cat);
     }
@@ -187,7 +185,6 @@ public class TestCase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", cat);
     }
@@ -209,7 +206,6 @@ public class TestCase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), cat);
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", cat);
     }
@@ -250,21 +246,21 @@ public class TestCase extends CatalogTestSuiteNoDB {
                 Result.LALA);
 
         final Result r1 = DefaultCase.getResult(new DefaultCaseResult[]{cr0, cr1, cr2, cr3},
-                                                new PlanSpecifier(product.getName(), product.getCategory(), BillingPeriod.MONTHLY, priceList.getName()), cat);
+                                                new PlanSpecifier(product.getName(), BillingPeriod.MONTHLY, priceList.getName()), cat);
         Assert.assertEquals(r1, Result.FOO);
 
         final Result r2 = DefaultCase.getResult(new DefaultCaseResult[]{cr0, cr1, cr2},
-                                                new PlanSpecifier(product.getName(), product.getCategory(), BillingPeriod.ANNUAL, priceList.getName()), cat);
+                                                new PlanSpecifier(product.getName(), BillingPeriod.ANNUAL, priceList.getName()), cat);
         Assert.assertEquals(r2, Result.DIPSY);
     }
 
     protected void assertionNull(final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final StandaloneCatalog cat) throws CatalogApiException {
-        Assert.assertNull(cr.getResult(new PlanSpecifier(productName, productCategory, bp, priceListName), cat));
+        Assert.assertNull(cr.getResult(new PlanSpecifier(productName, bp, priceListName), cat));
     }
 
     protected void assertionException(final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final StandaloneCatalog cat) {
         try {
-            cr.getResult(new PlanSpecifier(productName, productCategory, bp, priceListName), cat);
+            cr.getResult(new PlanSpecifier(productName, bp, priceListName), cat);
             Assert.fail("Expecting an exception");
         } catch (CatalogApiException e) {
             Assert.assertEquals(e.getCode(), ErrorCode.CAT_PRICE_LIST_NOT_FOUND.getCode());
@@ -272,6 +268,6 @@ public class TestCase extends CatalogTestSuiteNoDB {
     }
 
     protected void assertion(final Result result, final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final StandaloneCatalog cat) throws CatalogApiException {
-        Assert.assertEquals(result, cr.getResult(new PlanSpecifier(productName, productCategory, bp, priceListName), cat));
+        Assert.assertEquals(result, cr.getResult(new PlanSpecifier(productName, bp, priceListName), cat));
     }
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
index 6de6027..92464c1 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCaseChange.java
@@ -87,7 +87,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -108,20 +107,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionNull(cr,
                       product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
                       ProductCategory.BASE, ProductCategory.BASE,
                       BillingPeriod.ANNUAL, BillingPeriod.MONTHLY,
                       priceList1.getName(), priceList2.getName(),
@@ -136,14 +121,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -176,31 +159,16 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
 
         assertion(Result.FOO, cr,
                   cat.getCurrentProducts()[1].getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
@@ -218,14 +186,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -258,7 +224,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -270,23 +235,9 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertion(Result.FOO, cr,
                   product1.getName(), cat.getCurrentProducts()[1].getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -307,14 +258,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -347,7 +296,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -368,20 +316,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.ADD_ON, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
                       ProductCategory.BASE, ProductCategory.BASE,
                       BillingPeriod.ANNUAL, BillingPeriod.MONTHLY,
                       priceList1.getName(), priceList2.getName(),
@@ -396,14 +336,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -436,7 +374,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -455,16 +392,9 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.ADD_ON,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -485,14 +415,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -525,7 +453,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -538,20 +465,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
                       ProductCategory.BASE, ProductCategory.BASE,
                       BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
@@ -560,7 +473,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.ANNUAL, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -574,14 +486,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -614,7 +524,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -626,19 +535,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
@@ -656,21 +552,18 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.ANNUAL,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -703,7 +596,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -715,19 +607,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
@@ -752,14 +631,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
@@ -792,7 +669,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -804,19 +680,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
@@ -841,14 +704,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                   PhaseType.EVERGREEN, cat);
@@ -881,7 +742,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.EVERGREEN, cat);
@@ -893,19 +753,6 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                       priceList1.getName(), priceList2.getName(),
                       PhaseType.EVERGREEN, cat);
 
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.ADD_ON, ProductCategory.BASE,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
-
-        assertionNull(cr,
-                      product1.getName(), product2.getName(),
-                      ProductCategory.BASE, ProductCategory.ADD_ON,
-                      BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
-                      priceList1.getName(), priceList2.getName(),
-                      PhaseType.EVERGREEN, cat);
 
         assertionNull(cr,
                       product1.getName(), cat.getCurrentProducts()[1].getName(),
@@ -930,21 +777,18 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            cat.getCurrentProducts()[1].getName(), priceList2.getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertionException(cr,
                            product1.getName(), product2.getName(),
-                           ProductCategory.BASE, ProductCategory.BASE,
                            BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                            priceList1.getName(), cat.getCurrentProducts()[1].getName(),
                            PhaseType.EVERGREEN, cat);
 
         assertion(Result.FOO, cr,
                   product1.getName(), product2.getName(),
-                  ProductCategory.BASE, ProductCategory.BASE,
                   BillingPeriod.MONTHLY, BillingPeriod.MONTHLY,
                   priceList1.getName(), priceList2.getName(),
                   PhaseType.TRIAL, cat);
@@ -1001,14 +845,14 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                 Result.LALA);
 
         final Result r1 = DefaultCaseChange.getResult(new DefaultCaseChangeResult[]{cr0, cr1, cr2, cr3, cr4},
-                                                      new PlanPhaseSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN),
-                                                      new PlanSpecifier(product2.getName(), product2.getCategory(), BillingPeriod.MONTHLY, priceList2.getName()), cat);
+                                                      new PlanPhaseSpecifier(product1.getName(),  BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN),
+                                                      new PlanSpecifier(product2.getName(),  BillingPeriod.MONTHLY, priceList2.getName()), cat);
 
         Assert.assertEquals(r1, Result.FOO);
 
         final Result r2 = DefaultCaseChange.getResult(new DefaultCaseChangeResult[]{cr0, cr1, cr2, cr3, cr4},
-                                                      new PlanPhaseSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN),
-                                                      new PlanSpecifier(product2.getName(), product2.getCategory(), BillingPeriod.ANNUAL, priceList2.getName()), cat);
+                                                      new PlanPhaseSpecifier(product1.getName(),  BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN),
+                                                      new PlanSpecifier(product2.getName(),  BillingPeriod.ANNUAL, priceList2.getName()), cat);
 
         Assert.assertEquals(r2, Result.DIPSY);
     }
@@ -1020,8 +864,8 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
                                  final String fromPriceListName, final String toPriceListName,
                                  final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType),
-                                           new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName), cat));
+            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(fromProductName, fromBp, fromPriceListName, phaseType),
+                                           new PlanSpecifier(toProductName, toBp, toPriceListName), cat));
         } catch (CatalogApiException e) {
             Assert.fail("", e);
         }
@@ -1029,13 +873,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
     protected void assertionException(final DefaultCaseChangeResult cr,
                                       final String fromProductName, final String toProductName,
-                                      final ProductCategory fromProductCategory, final ProductCategory toProductCategory,
                                       final BillingPeriod fromBp, final BillingPeriod toBp,
                                       final String fromPriceListName, final String toPriceListName,
                                       final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType),
-                         new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName), cat);
+            cr.getResult(new PlanPhaseSpecifier(fromProductName, fromBp, fromPriceListName, phaseType),
+                         new PlanSpecifier(toProductName, toBp, toPriceListName), cat);
             Assert.fail("Expecting an exception");
         } catch (CatalogApiException e) {
             Assert.assertEquals(e.getCode(), ErrorCode.CAT_PRICE_LIST_NOT_FOUND.getCode());
@@ -1044,13 +887,12 @@ public class TestCaseChange extends CatalogTestSuiteNoDB {
 
     protected void assertion(final Result result, final DefaultCaseChangeResult cr,
                              final String fromProductName, final String toProductName,
-                             final ProductCategory fromProductCategory, final ProductCategory toProductCategory,
                              final BillingPeriod fromBp, final BillingPeriod toBp,
                              final String fromPriceListName, final String toPriceListName,
                              final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            Assert.assertEquals(result, cr.getResult(new PlanPhaseSpecifier(fromProductName, fromProductCategory, fromBp, fromPriceListName, phaseType),
-                                                     new PlanSpecifier(toProductName, toProductCategory, toBp, toPriceListName), cat));
+            Assert.assertEquals(result, cr.getResult(new PlanPhaseSpecifier(fromProductName, fromBp, fromPriceListName, phaseType),
+                                                     new PlanSpecifier(toProductName, toBp, toPriceListName), cat));
         } catch (CatalogApiException e) {
             Assert.fail("", e);
         }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCasePhase.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCasePhase.java
index 3fa6052..22ecc52 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCasePhase.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestCasePhase.java
@@ -74,7 +74,6 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
@@ -97,7 +96,6 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertion(Result.FOO, cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
@@ -143,7 +141,6 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
@@ -166,7 +163,6 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
@@ -189,7 +185,6 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, cat.getCurrentProducts()[1].getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
-        assertionNull(cr, product.getName(), ProductCategory.ADD_ON, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionNull(cr, product.getName(), ProductCategory.BASE, BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN, cat);
         assertionException(cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, "dipsy", PhaseType.EVERGREEN, cat);
         assertion(Result.FOO, cr, product.getName(), ProductCategory.BASE, BillingPeriod.MONTHLY, priceList.getName(), PhaseType.TRIAL, cat);
@@ -243,12 +238,12 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
                 Result.LALA);
 
         final Result r1 = DefaultCasePhase.getResult(new DefaultCaseResult[]{cr0, cr1, cr2, cr3, cr4},
-                                                     new PlanPhaseSpecifier(product.getName(), product.getCategory(), BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN), cat);
+                                                     new PlanPhaseSpecifier(product.getName(), BillingPeriod.MONTHLY, priceList.getName(), PhaseType.EVERGREEN), cat);
 
         Assert.assertEquals(Result.FOO, r1);
 
         final Result r2 = DefaultCasePhase.getResult(new DefaultCaseResult[]{cr0, cr1, cr2, cr3, cr4},
-                                                     new PlanPhaseSpecifier(product.getName(), product.getCategory(), BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN), cat);
+                                                     new PlanPhaseSpecifier(product.getName(), BillingPeriod.ANNUAL, priceList.getName(), PhaseType.EVERGREEN), cat);
 
         Assert.assertEquals(Result.DIPSY, r2);
 
@@ -256,7 +251,7 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
     protected void assertionNull(final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(productName, productCategory, bp, priceListName, phaseType), cat));
+            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(productName, bp, priceListName, phaseType), cat));
         } catch (CatalogApiException e) {
             Assert.fail("", e);
         }
@@ -264,7 +259,7 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
     protected void assertionException(final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(productName, productCategory, bp, priceListName, phaseType), cat));
+            Assert.assertNull(cr.getResult(new PlanPhaseSpecifier(productName, bp, priceListName, phaseType), cat));
             Assert.fail("Exception expected");
         } catch (CatalogApiException e) {
             Assert.assertEquals(e.getCode(), ErrorCode.CAT_PRICE_LIST_NOT_FOUND.getCode());
@@ -273,7 +268,7 @@ public class TestCasePhase extends CatalogTestSuiteNoDB {
 
     protected void assertion(final Result result, final DefaultCaseResult cr, final String productName, final ProductCategory productCategory, final BillingPeriod bp, final String priceListName, final PhaseType phaseType, final StandaloneCatalog cat) {
         try {
-            Assert.assertEquals(result, cr.getResult(new PlanPhaseSpecifier(productName, productCategory, bp, priceListName, phaseType), cat));
+            Assert.assertEquals(result, cr.getResult(new PlanPhaseSpecifier(productName, bp, priceListName, phaseType), cat));
         } catch (CatalogApiException e) {
             Assert.fail("", e);
         }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestLoadRules.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestLoadRules.java
index 47ca215..fc7b061 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestLoadRules.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestLoadRules.java
@@ -40,13 +40,13 @@ public class TestLoadRules extends CatalogTestSuiteNoDB {
         Assert.assertNotNull(catalog);
         final DefaultPlanRules rules = catalog.getPlanRules();
 
-        final PlanSpecifier specifier = new PlanSpecifier("Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY,
+        final PlanSpecifier specifier = new PlanSpecifier("Laser-Scope", BillingPeriod.MONTHLY,
                                                           "DEFAULT");
 
         final PlanAlignmentCreate alignment = rules.getPlanCreateAlignment(specifier, catalog);
         Assert.assertEquals(alignment, PlanAlignmentCreate.START_OF_SUBSCRIPTION);
 
-        final PlanSpecifier specifier2 = new PlanSpecifier("Extra-Ammo", ProductCategory.ADD_ON, BillingPeriod.MONTHLY,
+        final PlanSpecifier specifier2 = new PlanSpecifier("Extra-Ammo", BillingPeriod.MONTHLY,
                                                            "DEFAULT");
 
         final PlanAlignmentCreate alignment2 = rules.getPlanCreateAlignment(specifier2, catalog);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
index 152ad5f..d5acda6 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/rules/TestPlanRules.java
@@ -60,8 +60,8 @@ public class TestPlanRules extends CatalogTestSuiteNoDB {
         final DefaultProduct product1 = cat.getCurrentProducts()[0];
         final DefaultPriceList priceList1 = cat.findCurrentPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
-        final PlanSpecifier to = new PlanSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName());
+        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
+        final PlanSpecifier to = new PlanSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName());
 
         try {
             cat.getPlanRules().planChange(from, to, cat);
@@ -78,8 +78,8 @@ public class TestPlanRules extends CatalogTestSuiteNoDB {
         final DefaultProduct product1 = cat.getCurrentProducts()[0];
         final DefaultPriceList priceList1 = cat.findCurrentPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
 
-        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
-        final PlanSpecifier to = new PlanSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.ANNUAL, priceList1.getName());
+        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
+        final PlanSpecifier to = new PlanSpecifier(product1.getName(), BillingPeriod.ANNUAL, priceList1.getName());
 
         PlanChangeResult result = null;
         try {
@@ -102,8 +102,8 @@ public class TestPlanRules extends CatalogTestSuiteNoDB {
         final DefaultPriceList priceList1 = cat.findCurrentPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
         final DefaultPriceList priceList2 = cat.getPriceLists().getChildPriceLists()[0];
 
-        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), product1.getCategory(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
-        final PlanSpecifier to = new PlanSpecifier(product2.getName(), product2.getCategory(), BillingPeriod.MONTHLY, null);
+        final PlanPhaseSpecifier from = new PlanPhaseSpecifier(product1.getName(), BillingPeriod.MONTHLY, priceList1.getName(), PhaseType.EVERGREEN);
+        final PlanSpecifier to = new PlanSpecifier(product2.getName(), BillingPeriod.MONTHLY, null);
 
         PlanChangeResult result = null;
         try {
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index 26290f9..f26c167 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -191,17 +191,6 @@ public class DefaultEntitlementApi extends DefaultEntitlementApiBase implements 
         logCreateEntitlementWithAOs(log, externalKey, entitlementSpecifiers, entitlementEffectiveDate, billingEffectiveDate);
 
 
-        final EntitlementSpecifier baseSpecifier = Iterables.tryFind(entitlementSpecifiers, new Predicate<EntitlementSpecifier>() {
-            @Override
-            public boolean apply(final EntitlementSpecifier specifier) {
-                return specifier.getPlanPhaseSpecifier() != null && ProductCategory.BASE.equals(specifier.getPlanPhaseSpecifier().getProductCategory());
-            }
-        }).orNull();
-
-        if (baseSpecifier == null) {
-            throw new EntitlementApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
-        }
-
         final List<EntitlementSpecifier> entitlementSpecifierList = new ArrayList<EntitlementSpecifier>();
         Iterables.addAll(entitlementSpecifierList, entitlementSpecifiers);
 
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index ba5f169..bd6e009 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -378,7 +378,6 @@ public class EventsStreamBuilder {
             phaseType = subscription.getLastActivePhase().getPhaseType();
         }
         return new PlanPhaseSpecifier(lastActiveProductName,
-                                      productCategory,
                                       billingPeriod,
                                       priceListName,
                                       phaseType);
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
index 4b54799..20c886d 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/logging/EntitlementLoggingHelper.java
@@ -322,8 +322,6 @@ public abstract class EntitlementLoggingHelper {
             if (addParentheseQuote) {
                 logLine.append("'(");
             }
-            logLine.append(spec.getProductCategory() != null ? spec.getProductCategory() : "null");
-            logLine.append(":");
             logLine.append(spec.getProductName() != null ? spec.getProductName() : "null");
             logLine.append(":");
             logLine.append(spec.getBillingPeriod() != null ? spec.getBillingPeriod() : "null");
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
index 327046c..15cb7cb 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlement.java
@@ -51,7 +51,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -79,7 +79,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -112,7 +112,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -145,7 +145,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -170,7 +170,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -213,7 +213,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -253,7 +253,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -290,7 +290,7 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
 
         final Account account = accountApi.createAccount(getAccountData(7), callContext);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, startDate, startDate, false, ImmutableList.<PluginProperty>of(), callContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
index a963f6b..fe59e7d 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultEntitlementApi.java
@@ -58,7 +58,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Keep the same object for the whole test, to make sure we refresh its state before r/w calls
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -67,7 +67,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         // Add ADD_ON
         // Keep the same object for the whole test, to make sure we refresh its state before r/w calls
-        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement addOnEntitlement = entitlementApi.addEntitlement(entitlement.getBundleId(), addOnSpec, null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
@@ -121,7 +121,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Keep the same object for the whole test, to make sure we refresh its state before r/w calls
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -154,7 +154,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -246,7 +246,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -254,7 +254,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         assertListenerStatus();
 
         // Add ADD_ON
-        final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement telescopicEntitlement = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), spec1, null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
@@ -285,7 +285,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -294,7 +294,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         clock.addDays(1);
         final LocalDate effectiveDateSpec1 = new LocalDate(clock.getUTCNow(), account.getTimeZone());
-        final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec1 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement telescopicEntitlement = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), spec1, null, effectiveDateSpec1, effectiveDateSpec1, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
@@ -321,7 +321,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         // Try to add an ADD_ON, it should fail
         try {
-            final PlanPhaseSpecifier spec3 = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+            final PlanPhaseSpecifier spec3 = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
             final Entitlement telescopicEntitlement3 = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), spec1, null, effectiveDateSpec1, effectiveDateSpec1, false, ImmutableList.<PluginProperty>of(), callContext);
         } catch (EntitlementApiException e) {
             assertEquals(e.getCode(), ErrorCode.SUB_GET_NO_SUCH_BASE_SUBSCRIPTION.getCode());
@@ -360,7 +360,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         // Create entitlement
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -413,7 +413,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         // internal context will be configured for accountSrc
         final Account accountSrc = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement (with migrated flag so we can check later that transferred subscription is in right status)
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -461,7 +461,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Keep the same object for the whole test, to make sure we refresh its state before r/w calls
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.PHASE);
@@ -506,8 +506,8 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Cleaning", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Cleaning", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final String externalKey = "baseExternalKey";
         EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
@@ -544,8 +544,8 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Invalid", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Invalid",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final String externalKey = "baseExternalKey";
         EntitlementSpecifier baseEntitlementSpecifier = new DefaultEntitlementSpecifier(baseSpec, null);
@@ -574,8 +574,8 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Cleaning", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
-        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Bullets", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Cleaning",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Bullets",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final String externalKey = "addOnExternalKey";
         EntitlementSpecifier addOnEntitlementSpecifier1 = new DefaultEntitlementSpecifier(baseSpec, null);
@@ -607,7 +607,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = initialDate.plusDays(3);
         final LocalDate billingDate = initialDate.plusDays(5);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
@@ -635,7 +635,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = initialDate.plusDays(3);
         final LocalDate billingDate = null;
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.CREATE);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
@@ -662,7 +662,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = null;
         final LocalDate billingDate = initialDate.plusDays(5);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.BLOCK);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
@@ -686,7 +686,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = initialDate.minusDays(3);
         final LocalDate billingDate = initialDate.minusDays(5);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
@@ -706,7 +706,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = initialDate.minusDays(3);
         final LocalDate billingDate = null;
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
@@ -726,7 +726,7 @@ public class TestDefaultEntitlementApi extends EntitlementTestSuiteWithEmbeddedD
         final LocalDate entitlementDate = null;
         final LocalDate billingDate = initialDate.minusDays(5);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, entitlementDate, billingDate, false, ImmutableList.<PluginProperty>of(), callContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index 4d6c5f2..aef34c1 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -59,7 +59,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
         clock.setDay(initialDate);
 
         final Account account = createAccount(getAccountData(7));
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement entitlement1 = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         // Sleep 1 sec so created date are apart from each other and ordering in the bundle does not default on the UUID which is random.
@@ -110,7 +110,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -144,7 +144,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         clock.addDays(1);
         // Re-create a new bundle with same externalKey
-        final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec2 = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -218,7 +218,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         // Create entitlement
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -271,7 +271,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         //2013-08-07
         final LocalDate effectiveDate = initialDate.plusMonths(1);
@@ -304,7 +304,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         final LocalDate futureDate = new LocalDate(2013, 9, 1);
 
@@ -334,7 +334,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = accountApi.createAccount(getAccountData(7), callContext);
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
@@ -408,7 +408,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
@@ -482,7 +482,7 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
 
         final Account account = createAccount(getAccountData(7));
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         // Create entitlement and check each field
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
index ae7f4ba..ae12fdc 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestRegessionSubscriptionApi.java
@@ -63,7 +63,7 @@ public class TestRegessionSubscriptionApi extends EntitlementTestSuiteWithEmbedd
         final LocalDate entitlementEffectiveDate = initialDate.minusDays(1);
 
         final Account account = createAccount(getAccountData(7));
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun",  BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, UUID.randomUUID().toString(), null, entitlementEffectiveDate, null, false, ImmutableList.<PluginProperty>of(), callContext);
         // Because of the BlockingState event ENT_STARTED, the entitlement date should be correctly set
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
index e5f00d3..d96a38c 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/block/TestBlockingApi.java
@@ -135,7 +135,7 @@ public class TestBlockingApi extends EntitlementTestSuiteWithEmbeddedDB {
         subscriptionApi.addBlockingState(state1, null, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         Entitlement baseEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
index b22454a..c15abba 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/dao/TestDefaultBlockingStateDao.java
@@ -58,7 +58,7 @@ public class TestDefaultBlockingStateDao extends EntitlementTestSuiteWithEmbedde
         // This is a simple smoke test at the dao level only to make sure we do sane
         // things in case there are no future add-on cancellation events to add in the stream.
         // See TestEntitlementUtils for a more comprehensive test
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index 4ca0b7a..589189b 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -72,13 +72,13 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
 
         // Create base entitlement
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier baseSpec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         baseEntitlement = (DefaultEntitlement) entitlementApi.createBaseEntitlement(account.getId(), baseSpec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
         // Add ADD_ON
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOnSpec = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         addOnEntitlement = (DefaultEntitlement) entitlementApi.addEntitlement(baseEntitlement.getBundleId(), addOnSpec, null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -266,7 +266,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
     public void testChangePlanEOTWith2AddOns() throws Exception {
         // Add a second ADD_ON (Laser-Scope is available, not included)
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier secondAddOnSpec = new PlanPhaseSpecifier("Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier secondAddOnSpec = new PlanPhaseSpecifier("Laser-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final DefaultEntitlement secondAddOnEntitlement = (DefaultEntitlement) entitlementApi.addEntitlement(baseEntitlement.getBundleId(), secondAddOnSpec, null, clock.getUTCToday(), clock.getUTCToday(), false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
@@ -325,7 +325,7 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
     public void testCancelAddonsWhenBaseEntitlementIsCancelled() throws Exception {
         // Add a second ADD_ON
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.PHASE);
-        final PlanPhaseSpecifier addOn2Spec = new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier addOn2Spec = new PlanPhaseSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement addOn2Entitlement = entitlementApi.addEntitlement(baseEntitlement.getBundleId(), addOn2Spec, null, initialDate, initialDate, false, ImmutableList.<PluginProperty>of(), callContext);
         assertListenerStatus();
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index 6f8745a..2365957 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -127,7 +127,7 @@ public class PhasePriceOverrideJson {
                     return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
                 } else {
                     final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
-                    final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(spec.getProductName(), spec.getProductCategory(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
+                    final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
                     return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
                 }
             }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index e754aef..cb7a00d 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -1026,7 +1026,6 @@ public class InvoiceResource extends JaxRsResourceBase {
                                                                input.getProductCategory() != null &&
                                                                input.getBillingPeriod() != null) ?
                                                               new PlanPhaseSpecifier(input.getProductName(),
-                                                                                     ProductCategory.valueOf(input.getProductCategory()),
                                                                                      BillingPeriod.valueOf(input.getBillingPeriod()),
                                                                                      input.getPriceListName(),
                                                                                      input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null) :
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 f75cadf..d9df67f 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
@@ -195,13 +195,11 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 final Account account = getAccountFromSubscriptionJson(entitlement, callContext);
                 final PhaseType phaseType = entitlement.getPhaseType() != null ? PhaseType.valueOf(entitlement.getPhaseType()) : null;
                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(entitlement.getProductName(),
-                                                                       ProductCategory.valueOf(entitlement.getProductCategory()),
                                                                        BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), phaseType);
 
                 final LocalDate resolvedEntitlementDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(entitlementDate);
                 final LocalDate resolvedBillingDate = requestedDate != null ? toLocalDate(requestedDate) : toLocalDate(billingDate);
                 final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
-                                                                 ProductCategory.valueOf(entitlement.getProductCategory()),
                                                                  BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
 
                 final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
@@ -311,11 +309,9 @@ public class SubscriptionResource extends JaxRsResourceBase {
                 for (final SubscriptionJson entitlement : entitlements) {
 
                     final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(entitlement.getProductName(),
-                                                                                         ProductCategory.valueOf(entitlement.getProductCategory()),
                                                                                          BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList(), null);
 
                     final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
-                                                                     ProductCategory.valueOf(entitlement.getProductCategory()),
                                                                      BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
                     final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
 
@@ -419,7 +415,6 @@ public class SubscriptionResource extends JaxRsResourceBase {
 
                 final Account account = accountUserApi.getAccountById(current.getAccountId(), callContext);
                 final PlanSpecifier planSpec = new PlanSpecifier(entitlement.getProductName(),
-                                                                 ProductCategory.valueOf(entitlement.getProductCategory()),
                                                                  BillingPeriod.valueOf(entitlement.getBillingPeriod()), entitlement.getPriceList());
                 final List<PlanPhasePriceOverride> overrides = PhasePriceOverrideJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
 
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index e556f31..549adf1 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -58,7 +58,6 @@ import org.killbill.billing.util.UUIDs;
 import org.killbill.billing.util.bcd.BillCycleDayCalculator;
 import org.killbill.billing.util.tag.ControlTagType;
 import org.killbill.billing.util.tag.Tag;
-import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -248,10 +247,9 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
         final BillingPeriod billingPeriod = phase.getRecurring() != null ? phase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
 
         return new PlanPhaseSpecifier(product.getName(),
-                               product.getCategory(),
-                               billingPeriod,
-                               transition.getNextPriceList(),
-                               phase.getPhaseType());
+                                      billingPeriod,
+                                      transition.getNextPriceList(),
+                                      phase.getPhaseType());
     }
 
     private boolean is_AUTO_INVOICING_OFF(final List<Tag> tags) {
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
index c5cc8a9..f72fb2f 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultInternalBillingApi.java
@@ -57,7 +57,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
         final Account account = createAccount(getAccountData(7));
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
         assertListenerStatus();
@@ -193,7 +193,7 @@ public class TestDefaultInternalBillingApi extends JunctionTestSuiteWithEmbedded
         final Account account = createAccount(getAccountData(7));
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
-        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
         final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), callContext);
         final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
         assertListenerStatus();

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index f06fe33..5298d25 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.115</version>
+        <version>0.116-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.17.2-SNAPSHOT</version>
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
index 879f9f9..551ff4a 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
@@ -198,7 +198,6 @@ public class PlanAligner extends BaseAligner {
         final Catalog catalog = catalogService.getFullCatalog(context);
 
         final PlanSpecifier planSpecifier = new PlanSpecifier(plan.getProduct().getName(),
-                                                              plan.getProduct().getCategory(),
                                                               plan.getRecurringBillingPeriod(),
                                                               priceList);
 
@@ -254,13 +253,11 @@ public class PlanAligner extends BaseAligner {
         final Catalog catalog = catalogService.getFullCatalog(context);
         final ProductCategory currentCategory = currentPlan.getProduct().getCategory();
         final PlanPhaseSpecifier fromPlanPhaseSpecifier = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                                 currentCategory,
                                                                                  currentPlan.getRecurringBillingPeriod(),
                                                                                  currentPriceList,
                                                                                  currentPhase.getPhaseType());
 
         final PlanSpecifier toPlanSpecifier = new PlanSpecifier(nextPlan.getProduct().getName(),
-                                                                nextPlan.getProduct().getCategory(),
                                                                 nextPlan.getRecurringBillingPeriod(),
                                                                 priceList);
 
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 2e7a534..db2c5a9 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
@@ -47,6 +47,7 @@ import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -158,7 +159,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             final Catalog catalog = catalogService.getFullCatalog(context);
             final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
 
-            final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, effectiveDate);
+            final Plan plan = catalog.createOrFindPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), realPriceList), 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",
@@ -196,6 +197,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             final Catalog catalog = catalogService.getFullCatalog(context);
             final CallContext callContext = internalCallContextFactory.createCallContext(context);
 
+            final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, context);
+            if (bundle == null) {
+                throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleId);
+            }
+
+            boolean first = true;
             for (EntitlementSpecifier entitlement : entitlements) {
 
                 final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
@@ -203,16 +210,18 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                 final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
 
-                final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, effectiveDate);
+                final Plan plan = catalog.createOrFindPlan(new PlanSpecifier(spec.getProductName(), spec.getBillingPeriod(), realPriceList), 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(), realPriceList));
                 }
 
-                final SubscriptionBaseBundle bundle = dao.getSubscriptionBundleFromId(bundleId, context);
-                if (bundle == null) {
-                    throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_NO_BUNDLE, bundleId);
+                if (first) {
+                    first = false;
+                    if (plan.getProduct().getCategory() != ProductCategory.BASE) {
+                        throw new SubscriptionBaseApiException(new IllegalArgumentException(), ErrorCode.SUB_CREATE_NO_BP.getCode(), "Missing Base Subscription.");
+                    }
                 }
 
                 SubscriptionSpecifier subscription = new SubscriptionSpecifier();
@@ -535,7 +544,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
             final PlanPhasePriceOverridesWithCallContext overridesWithContext = null; // TODO not supported to dryRun with custom price
             final Plan plan = (inputSpec != null && inputSpec.getProductName() != null && inputSpec.getBillingPeriod() != null) ?
-                              catalog.createOrFindPlan(inputSpec.getProductName(), inputSpec.getBillingPeriod(), realPriceList, overridesWithContext, utcNow) : null;
+                              catalog.createOrFindPlan(new PlanSpecifier(inputSpec.getProductName(), inputSpec.getBillingPeriod(), realPriceList), overridesWithContext, utcNow) : null;
             final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
 
             if (dryRunArguments != null) {
@@ -585,7 +594,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                                 final Plan currentPlan = subscriptionForCancellation.getCurrentPlan();
                                 final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                                       currentPlan.getProduct().getCategory(),
                                                                                        subscriptionForCancellation.getCurrentPlan().getRecurringBillingPeriod(),
                                                                                        subscriptionForCancellation.getCurrentPriceList().getName(),
                                                                                        subscriptionForCancellation.getCurrentPhase().getPhaseType());
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
index f554eeb..552f878 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
@@ -124,7 +124,7 @@ public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline
             final String planNameWithClosure = planName;
             final String planPhaseNameWithClosure = planPhaseName;
             final Integer billCycleDayLocalWithClosure = billCycleDayLocal;
-            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceListName, phaseType);
+            final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, billingPeriod, priceListName, phaseType);
             result.add(new ExistingEvent() {
                 @Override
                 public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
@@ -132,6 +132,11 @@ public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline
                 }
 
                 @Override
+                public ProductCategory getProductCategory() {
+                    return category;
+                }
+
+                @Override
                 public PlanPhaseSpecifier getPlanPhaseSpecifier() {
                     return spec;
                 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
index e7ec71a..ad37b0f 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
@@ -215,7 +215,7 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
                     continue;
                 }
                 final List<ExistingEvent> existingEvents = cur.getExistingEvents();
-                final ProductCategory productCategory = existingEvents.get(0).getPlanPhaseSpecifier().getProductCategory();
+                final ProductCategory productCategory = existingEvents.get(0).getProductCategory();
 
                 // For future add-on cancellations, don't add a cancellation on disk right away (mirror the behavior
                 // on base plan cancellations, even though we don't support un-transfer today)
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 bab81c5..1560427 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
@@ -180,10 +180,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         final Plan currentPlan = subscription.getCurrentPlan();
         final PlanPhaseSpecifier planPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                    currentPlan.getProduct().getCategory(),
                                                                     subscription.getCurrentPlan().getRecurringBillingPeriod(),
-                                                                    subscription.getCurrentPriceList().getName(),
-                                                                    subscription.getCurrentPhase().getPhaseType());
+                                                                    subscription.getCurrentPriceList().getName(), null);
 
         try {
             final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
@@ -386,12 +384,10 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
             final Plan currentPlan = subscription.getCurrentPlan();
             final PriceList currentPriceList = subscription.getCurrentPriceList();
             final PlanPhaseSpecifier fromPlanPhase = new PlanPhaseSpecifier(currentPlan.getProduct().getName(),
-                                                                            currentPlan.getProduct().getCategory(),
                                                                             currentPlan.getRecurringBillingPeriod(),
                                                                             currentPriceList.getName(),
                                                                             subscription.getCurrentPhase().getPhaseType());
             final PlanSpecifier toPlanPhase = new PlanSpecifier(productName,
-                                                                destProduct.getCategory(),
                                                                 term,
                                                                 priceList);
 
@@ -412,7 +408,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                               final CallContext context) throws SubscriptionBaseApiException, CatalogApiException {
         final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
         final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, context);
-        final Plan newPlan = catalogService.getFullCatalog(internalCallContext).createOrFindPlan(newProductName, newBillingPeriod, newPriceList, overridesWithContext, effectiveDate, subscription.getStartDate());
+        final Plan newPlan = catalogService.getFullCatalog(internalCallContext).createOrFindPlan(new PlanSpecifier(newProductName, newBillingPeriod, newPriceList), overridesWithContext, effectiveDate, subscription.getStartDate());
 
         if (newPlan.getProduct().getCategory() != subscription.getCategory()) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_INVALID, subscription.getId());
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
index c6704e1..466b2e2 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/transfer/TestDefaultSubscriptionTransferApi.java
@@ -134,7 +134,7 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
             @Override
             public PlanPhaseSpecifier getPlanPhaseSpecifier() {
                 return SubscriptionBaseTransitionType.CANCEL.equals(subscriptionTransitionType) ? null :
-                       new PlanPhaseSpecifier("BicycleTrialEvergreen1USD", ProductCategory.BASE, BillingPeriod.NO_BILLING_PERIOD,
+                       new PlanPhaseSpecifier("BicycleTrialEvergreen1USD",  BillingPeriod.NO_BILLING_PERIOD,
                                               PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.FIXEDTERM);
             }
 
@@ -142,6 +142,11 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
             public SubscriptionBaseTransitionType getSubscriptionTransitionType() {
                 return subscriptionTransitionType;
             }
+
+            @Override
+            public ProductCategory getProductCategory() {
+                return ProductCategory.BASE;
+            }
         };
     }
 }
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestSubscriptionHelper.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestSubscriptionHelper.java
index d93ee18..52ba58e 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestSubscriptionHelper.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestSubscriptionHelper.java
@@ -91,7 +91,7 @@ public class TestSubscriptionHelper {
             throws SubscriptionBaseApiException {
         testListener.pushExpectedEvent(NextEvent.CREATE);
         final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) subscriptionApi.createSubscription(bundleId,
-                                                                                                                  new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSet, null), null,
+                                                                                                                  new PlanPhaseSpecifier(productName, term, planSet, null), null,
                                                                                                                   requestedDate == null ? clock.getUTCNow() : requestedDate, false, internalCallContext);
         assertNotNull(subscription);
 
@@ -162,7 +162,7 @@ public class TestSubscriptionHelper {
     public PlanPhaseSpecifier getProductSpecifier(final String productName, final String priceList,
                                                   final BillingPeriod term,
                                                   @Nullable final PhaseType phaseType) {
-        return new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, priceList, phaseType);
+        return new PlanPhaseSpecifier(productName, term, priceList, phaseType);
     }
 
     public void printEvents(final List<SubscriptionBaseEvent> events) {
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
index 8829276..424475e 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiAddOn.java
@@ -396,7 +396,6 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
 
         // This is just to double check our test catalog gives us what we want before we start the test
         final PlanSpecifier planSpecifier = new PlanSpecifier(aoProduct,
-                                                              ProductCategory.ADD_ON,
                                                               aoTerm,
                                                               aoPriceList);
         final PlanAlignmentCreate alignement = catalog.planCreateAlignment(planSpecifier, clock.getUTCNow());
@@ -413,7 +412,6 @@ public class TestUserApiAddOn extends SubscriptionTestSuiteWithEmbeddedDB {
 
         // This is just to double check our test catalog gives us what we want before we start the test
         final PlanSpecifier planSpecifier = new PlanSpecifier(aoProduct,
-                                                              ProductCategory.ADD_ON,
                                                               aoTerm,
                                                               aoPriceList);
         final PlanAlignmentCreate alignement = catalog.planCreateAlignment(planSpecifier, clock.getUTCNow());
diff --git a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
index 7fb088e..fcf5f05 100644
--- a/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
+++ b/tenant/src/main/java/org/killbill/billing/tenant/api/DefaultTenantInternalApi.java
@@ -79,13 +79,13 @@ public class DefaultTenantInternalApi implements TenantInternalApi {
 
     @Override
     public String getInvoiceTemplate(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.INVOICE_TEMPLATE.toString()), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(TenantKey.INVOICE_TEMPLATE.toString(), tenantContext);
         return getUniqueValue(values, "invoice template", tenantContext);
     }
 
     @Override
     public String getManualPayInvoiceTemplate(final Locale locale, final InternalTenantContext tenantContext) {
-        final List<String> values = tenantDao.getTenantValueForKey(LocaleUtils.localeString(locale, TenantKey.INVOICE_MP_TEMPLATE.toString()), tenantContext);
+        final List<String> values = tenantDao.getTenantValueForKey(TenantKey.INVOICE_MP_TEMPLATE.toString(), tenantContext);
         return getUniqueValue(values, "manual pay invoice template", tenantContext);
     }