killbill-memoizeit

Merge branch 'work-for-release-0.19.x' of github.com:killbill/killbill

6/27/2018 2:42:47 PM

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

currency/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 6(+1 -5)

junction/pom.xml 3(+2 -1)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 4(+2 -2)

profiles/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index f06c200..aba871d 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index 20e15d3..feb6425 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>
diff --git a/api/src/main/java/org/killbill/billing/catalog/api/CatalogInternalApi.java b/api/src/main/java/org/killbill/billing/catalog/api/CatalogInternalApi.java
index c50693d..54d5d75 100644
--- a/api/src/main/java/org/killbill/billing/catalog/api/CatalogInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/catalog/api/CatalogInternalApi.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -23,7 +23,4 @@ public interface CatalogInternalApi {
 
     public Catalog getFullCatalog(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
 
-
-    public StaticCatalog getCurrentCatalog(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
-
 }

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 2348b27..7cd2739 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithCatalogPlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithCatalogPlugin.java
index 8978a13..ad84112 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithCatalogPlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithCatalogPlugin.java
@@ -31,9 +31,9 @@ import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogUserApi;
@@ -41,6 +41,7 @@ import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.billing.catalog.override.PriceOverride;
 import org.killbill.billing.catalog.plugin.TestModelStandalonePluginCatalog;
 import org.killbill.billing.catalog.plugin.TestModelVersionedPluginCatalog;
@@ -149,38 +150,38 @@ public class TestWithCatalogPlugin extends TestIntegrationBase {
 
         testCatalogPluginApi.addCatalogVersion("versionedCatalog/WeaponsHireSmall-1.xml");
 
-        final VersionedCatalog catalog1 = (VersionedCatalog) catalogUserApi.getCatalog("whatever", callContext);
+        final VersionedCatalog catalog1 = catalogUserApi.getCatalog("whatever", null, callContext);
         Assert.assertEquals(testCatalogPluginApi.getNbLatestCatalogVersionApiCalls(), 1);
         Assert.assertEquals(testCatalogPluginApi.getNbVersionedPluginCatalogApiCalls(), 1);
         Assert.assertEquals(catalog1.getEffectiveDate().compareTo(testCatalogPluginApi.getLatestCatalogUpdate().toDate()), 0);
 
         // Retrieve 3 more times
-        catalogUserApi.getCatalog("whatever", callContext);
-        catalogUserApi.getCatalog("whatever", callContext);
-        catalogUserApi.getCatalog("whatever", callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
         Assert.assertEquals(testCatalogPluginApi.getNbLatestCatalogVersionApiCalls(), 4);
         Assert.assertEquals(testCatalogPluginApi.getNbVersionedPluginCatalogApiCalls(), 1);
 
         testCatalogPluginApi.addCatalogVersion("versionedCatalog/WeaponsHireSmall-2.xml");
 
-        final VersionedCatalog catalog2 = (VersionedCatalog) catalogUserApi.getCatalog("whatever", callContext);
+        final VersionedCatalog catalog2 = catalogUserApi.getCatalog("whatever", null, callContext);
         Assert.assertEquals(testCatalogPluginApi.getNbLatestCatalogVersionApiCalls(), 5);
         Assert.assertEquals(testCatalogPluginApi.getNbVersionedPluginCatalogApiCalls(), 2);
         Assert.assertEquals(catalog2.getEffectiveDate().compareTo(testCatalogPluginApi.getLatestCatalogUpdate().toDate()), 0);
 
         testCatalogPluginApi.addCatalogVersion("versionedCatalog/WeaponsHireSmall-3.xml");
 
-        final VersionedCatalog catalog3 = (VersionedCatalog) catalogUserApi.getCatalog("whatever", callContext);
+        final VersionedCatalog catalog3 = catalogUserApi.getCatalog("whatever", null, callContext);
         Assert.assertEquals(testCatalogPluginApi.getNbLatestCatalogVersionApiCalls(), 6);
         Assert.assertEquals(testCatalogPluginApi.getNbVersionedPluginCatalogApiCalls(), 3);
         Assert.assertEquals(catalog3.getEffectiveDate().compareTo(testCatalogPluginApi.getLatestCatalogUpdate().toDate()), 0);
 
 
         // Retrieve 4 more times
-        catalogUserApi.getCatalog("whatever", callContext);
-        catalogUserApi.getCatalog("whatever", callContext);
-        catalogUserApi.getCatalog("whatever", callContext);
-        catalogUserApi.getCatalog("whatever", callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
+        catalogUserApi.getCatalog("whatever", null, callContext);
         Assert.assertEquals(testCatalogPluginApi.getNbLatestCatalogVersionApiCalls(), 10);
         Assert.assertEquals(testCatalogPluginApi.getNbVersionedPluginCatalogApiCalls(), 3);
 
@@ -193,7 +194,7 @@ public class TestWithCatalogPlugin extends TestIntegrationBase {
         final InternalTenantContext internalTenantContext;
         final InternalCallContextFactory internalCallContextFactory;
 
-        private VersionedCatalog versionedCatalog;
+        private DefaultVersionedCatalog versionedCatalog;
         private DateTime latestCatalogUpdate;
         private int nbLatestCatalogVersionApiCalls;
         private int nbVersionedPluginCatalogApiCalls;
@@ -225,7 +226,7 @@ public class TestWithCatalogPlugin extends TestIntegrationBase {
 
             this.latestCatalogUpdate = new DateTime(inputCatalogVersion.getEffectiveDate());
             if (versionedCatalog == null) {
-                versionedCatalog = new VersionedCatalog(getClock());
+                versionedCatalog = new DefaultVersionedCatalog(getClock());
             }
             versionedCatalog.add(inputCatalogVersionWithOverride);
         }

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index cc0632f..1077965 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/api/CatalogService.java b/catalog/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
index 4be34da..094fece 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/api/CatalogService.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -18,6 +18,7 @@
 package org.killbill.billing.catalog.api;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.platform.api.KillbillService;
 
 /**
@@ -25,11 +26,7 @@ import org.killbill.billing.platform.api.KillbillService;
  */
 public interface CatalogService extends KillbillService {
 
-    public Catalog getFullCatalog(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
+    public DefaultVersionedCatalog getFullCatalog(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
 
-    public Catalog getFullCatalogForInternalUse(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
-
-    public StaticCatalog getCurrentCatalog(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
-
-    public StaticCatalog getCurrentCatalogForInternalUse(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
+    public DefaultVersionedCatalog getFullCatalogForInternalUse(boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) throws CatalogApiException;
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/api/DefaultCatalogInternalApi.java b/catalog/src/main/java/org/killbill/billing/catalog/api/DefaultCatalogInternalApi.java
index afba853..4ad7536 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/api/DefaultCatalogInternalApi.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/api/DefaultCatalogInternalApi.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -20,19 +20,13 @@ package org.killbill.billing.catalog.api;
 import javax.inject.Inject;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class DefaultCatalogInternalApi implements CatalogInternalApi {
 
-    private final Logger logger = LoggerFactory.getLogger(DefaultCatalogInternalApi.class);
-
     private final CatalogService catalogService;
 
     @Inject
-    public DefaultCatalogInternalApi(final CatalogService catalogService,
-                                     final InternalCallContextFactory internalCallContextFactory) {
+    public DefaultCatalogInternalApi(final CatalogService catalogService) {
         this.catalogService = catalogService;
     }
 
@@ -40,9 +34,4 @@ public class DefaultCatalogInternalApi implements CatalogInternalApi {
     public Catalog getFullCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
         return catalogService.getFullCatalogForInternalUse(useDefaultCatalog, filterTemplateCatalog, context);
     }
-
-    @Override
-    public StaticCatalog getCurrentCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
-        return catalogService.getCurrentCatalogForInternalUse(useDefaultCatalog, filterTemplateCatalog, context);
-    }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
index 2fee429..a058104 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/api/user/DefaultCatalogUserApi.java
@@ -31,15 +31,15 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.CatalogUpdater;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.VersionedCatalog;
-import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
 import org.killbill.billing.catalog.api.CatalogUserApi;
 import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.catalog.api.SimplePlanDescriptor;
 import org.killbill.billing.catalog.api.StaticCatalog;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.billing.catalog.caching.CatalogCache;
 import org.killbill.billing.tenant.api.TenantApiException;
 import org.killbill.billing.tenant.api.TenantKV.TenantKey;
@@ -80,14 +80,26 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
     }
 
     @Override
-    public Catalog getCatalog(final String catalogName, final TenantContext tenantContext) throws CatalogApiException {
+    public VersionedCatalog<? extends StaticCatalog> getCatalog(final String catalogName, @Nullable final DateTime catalogDateVersion, final TenantContext tenantContext) throws CatalogApiException {
         final InternalTenantContext internalTenantContext;
         if (tenantContext.getAccountId() != null) {
             internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantContext.getAccountId(), tenantContext);
         } else {
             internalTenantContext = createInternalTenantContext(tenantContext);
         }
-        return catalogService.getFullCatalog(true, true, internalTenantContext);
+        final DefaultVersionedCatalog fullCatalog = catalogService.getFullCatalog(true, true, internalTenantContext);
+        if (catalogDateVersion == null) {
+            return fullCatalog;
+        } else {
+            final DefaultVersionedCatalog filteredCatalog = new DefaultVersionedCatalog(clock);
+            for (final StandaloneCatalog v : fullCatalog.getVersions()) {
+                if (v.getEffectiveDate().compareTo(catalogDateVersion.toDate()) >= 0) {
+                    filteredCatalog.add(v);
+                    break;
+                }
+            }
+            return filteredCatalog;
+        }
     }
 
     @Override
@@ -98,7 +110,7 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
         } else {
             internalTenantContext = createInternalTenantContext(tenantContext);
         }
-        return catalogService.getCurrentCatalog(true, true, internalTenantContext);
+        return catalogService.getFullCatalog(true, true, internalTenantContext);
     }
 
     @Override
@@ -108,7 +120,7 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
         final InternalTenantContext internalTenantContext = createInternalTenantContext(callContext);
         try {
 
-            final VersionedCatalog versionedCatalog = (VersionedCatalog) catalogService.getFullCatalog(false, true, internalTenantContext);
+            final DefaultVersionedCatalog versionedCatalog = catalogService.getFullCatalog(false, true, internalTenantContext);
 
             // Validation purpose:  Will throw if bad XML or catalog validation fails
             final InputStream stream = new ByteArrayInputStream(catalogXML.getBytes());
@@ -220,7 +232,7 @@ public class DefaultCatalogUserApi implements CatalogUserApi {
     }
 
     private StandaloneCatalog getCurrentStandaloneCatalogForTenant(final InternalTenantContext internalTenantContext) throws CatalogApiException {
-        final VersionedCatalog versionedCatalog = (VersionedCatalog) catalogService.getCurrentCatalog(false, false, internalTenantContext);
+        final DefaultVersionedCatalog versionedCatalog = catalogService.getFullCatalog(false, false, internalTenantContext);
         if (versionedCatalog != null && !versionedCatalog.getVersions().isEmpty()) {
             final StandaloneCatalog standaloneCatalogWithPriceOverride = versionedCatalog.getVersions().get(versionedCatalog.getVersions().size() - 1);
             return standaloneCatalogWithPriceOverride;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/caching/CatalogCache.java b/catalog/src/main/java/org/killbill/billing/catalog/caching/CatalogCache.java
index d8cc70f..979b5cb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/caching/CatalogCache.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/caching/CatalogCache.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -18,15 +18,14 @@
 package org.killbill.billing.catalog.caching;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 
 public interface CatalogCache {
 
     public void loadDefaultCatalog(final String url) throws CatalogApiException;
 
-    public VersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, InternalTenantContext tenantContext) throws CatalogApiException;
+    public DefaultVersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, InternalTenantContext tenantContext) throws CatalogApiException;
 
     public void clearCatalog(InternalTenantContext tenantContext);
-
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
index a424197..09b6eef 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheCatalogCache.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -25,9 +25,9 @@ import org.joda.time.DateTime;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.io.VersionedCatalogLoader;
@@ -55,7 +55,7 @@ public class EhCacheCatalogCache implements CatalogCache {
 
     private final Logger logger = LoggerFactory.getLogger(EhCacheCatalogCache.class);
 
-    private final CacheController<Long, Catalog> cacheController;
+    private final CacheController<Long, DefaultVersionedCatalog> cacheController;
     private final VersionedCatalogLoader loader;
     private final CacheLoaderArgument cacheLoaderArgumentWithTemplateFiltering;
     private final CacheLoaderArgument cacheLoaderArgument;
@@ -64,7 +64,7 @@ public class EhCacheCatalogCache implements CatalogCache {
     private final PriceOverride priceOverride;
     private final InternalCallContextFactory internalCallContextFactory;
 
-    private VersionedCatalog defaultCatalog;
+    private DefaultVersionedCatalog defaultCatalog;
 
     @Inject
     public EhCacheCatalogCache(final OSGIServiceRegistration<CatalogPluginApi> pluginRegistry,
@@ -92,7 +92,7 @@ public class EhCacheCatalogCache implements CatalogCache {
     }
 
     @Override
-    public VersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, final InternalTenantContext tenantContext) throws CatalogApiException {
+    public DefaultVersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, final InternalTenantContext tenantContext) throws CatalogApiException {
 
         //
         // This is used by Kill Bill services (subscription/invoice/... creation/change)
@@ -101,10 +101,10 @@ public class EhCacheCatalogCache implements CatalogCache {
         // specific pieces of catalog for certain account). In such a scenario plugin would have to make sure that Kill Bill does not cache the catalog (since this is only cached at the tenant level)
         //
         if (internalUse) {
-            Preconditions.checkState(tenantContext.getAccountRecordId() !=null, "Unexpected null accountRecordId in context issued from internal Kill Bill service");
+            Preconditions.checkState(tenantContext.getAccountRecordId() != null, "Unexpected null accountRecordId in context issued from internal Kill Bill service");
         }
 
-        final VersionedCatalog pluginVersionedCatalog = getCatalogFromPlugins(tenantContext);
+        final DefaultVersionedCatalog pluginVersionedCatalog = getCatalogFromPlugins(tenantContext);
         if (pluginVersionedCatalog != null) {
             return pluginVersionedCatalog;
         }
@@ -115,12 +115,12 @@ public class EhCacheCatalogCache implements CatalogCache {
         // The cache loader might choke on some bad xml -- unlikely since we check its validity prior storing it,
         // but to be on the safe side;;
         try {
-            VersionedCatalog tenantCatalog = (VersionedCatalog) cacheController.get(tenantContext.getTenantRecordId(),
-                                                                                    filterTemplateCatalog ? cacheLoaderArgumentWithTemplateFiltering : cacheLoaderArgument);
+            DefaultVersionedCatalog tenantCatalog = cacheController.get(tenantContext.getTenantRecordId(),
+                                                                        filterTemplateCatalog ? cacheLoaderArgumentWithTemplateFiltering : cacheLoaderArgument);
             // It means we are using a default catalog in a multi-tenant deployment, that does not really match a real use case, but we want to support it
             // for test purpose.
             if (useDefaultCatalog && tenantCatalog == null) {
-                tenantCatalog = new VersionedCatalog(defaultCatalog.getClock());
+                tenantCatalog = new DefaultVersionedCatalog(defaultCatalog.getClock());
                 for (final StandaloneCatalog cur : defaultCatalog.getVersions()) {
                     final StandaloneCatalogWithPriceOverride curWithOverride = new StandaloneCatalogWithPriceOverride(cur, priceOverride, tenantContext.getTenantRecordId(), internalCallContextFactory);
                     tenantCatalog.add(curWithOverride);
@@ -140,7 +140,7 @@ public class EhCacheCatalogCache implements CatalogCache {
         }
     }
 
-    private VersionedCatalog getCatalogFromPlugins(final InternalTenantContext internalTenantContext) throws CatalogApiException {
+    private DefaultVersionedCatalog getCatalogFromPlugins(final InternalTenantContext internalTenantContext) throws CatalogApiException {
         final TenantContext tenantContext = internalCallContextFactory.createTenantContext(internalTenantContext);
         for (final String service : pluginRegistry.getAllServices()) {
             final CatalogPluginApi plugin = pluginRegistry.getServiceForName(service);
@@ -156,7 +156,7 @@ public class EhCacheCatalogCache implements CatalogCache {
             // A null latestCatalogUpdatedDate by passing caching, by fetching full catalog from plugin below (compatibility mode with 0.18.x or non optimized plugin api mode)
             //
             if (latestCatalogUpdatedDate != null) {
-                final VersionedCatalog tenantCatalog = (VersionedCatalog) cacheController.get(internalTenantContext.getTenantRecordId(), cacheLoaderArgument);
+                final DefaultVersionedCatalog tenantCatalog = cacheController.get(internalTenantContext.getTenantRecordId(), cacheLoaderArgument);
                 if (tenantCatalog != null) {
                     if (tenantCatalog.getEffectiveDate().compareTo(latestCatalogUpdatedDate.toDate()) == 0) {
                         // Current cached version matches the one from the plugin
@@ -169,7 +169,7 @@ public class EhCacheCatalogCache implements CatalogCache {
             // First plugin that gets something (for that tenant) returns it
             if (pluginCatalog != null) {
                 logger.info("Returning catalog from plugin {} on tenant {} ", service, internalTenantContext.getTenantRecordId());
-                final VersionedCatalog resolvedPluginCatalog = versionedCatalogMapper.toVersionedCatalog(pluginCatalog, internalTenantContext);
+                final DefaultVersionedCatalog resolvedPluginCatalog = versionedCatalogMapper.toVersionedCatalog(pluginCatalog, internalTenantContext);
                 cacheController.remove(internalTenantContext.getTenantRecordId());
                 cacheController.putIfAbsent(internalTenantContext.getTenantRecordId(), resolvedPluginCatalog);
                 return resolvedPluginCatalog;
@@ -203,7 +203,7 @@ public class EhCacheCatalogCache implements CatalogCache {
             // Provided in the classpath
             this.defaultCatalog = loader.loadDefaultCatalog("EmptyCatalog.xml");
         } catch (final CatalogApiException e) {
-            this.defaultCatalog = new VersionedCatalog();
+            this.defaultCatalog = new DefaultVersionedCatalog();
             logger.error("Exception loading EmptyCatalog - should never happen!", e);
         }
     }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
index 66e6a7d..b9f1dc8 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/caching/EhCacheOverriddenPlanCache.java
@@ -72,7 +72,7 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
         this.loaderCallback = new LoaderCallback() {
             @Override
             public Plan loadPlan(final String planName, final StaticCatalog catalog, final InternalTenantContext context) throws CatalogApiException {
-                return loadOverriddenPlan(planName, catalog, context);
+                return loadOverriddenPlan(planName, (StandaloneCatalog) catalog, context);
             }
         };
     }
@@ -94,8 +94,7 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
         cacheController.putIfAbsent(planName, plan);
     }
 
-    private DefaultPlan loadOverriddenPlan(final String planName, final StaticCatalog catalog, final InternalTenantContext context) throws CatalogApiException {
-
+    private DefaultPlan loadOverriddenPlan(final String planName, final StandaloneCatalog catalog, final InternalTenantContext context) throws CatalogApiException {
         final Matcher m = DefaultPriceOverride.CUSTOM_PLAN_NAME_PATTERN.matcher(planName);
         if (!m.matches()) {
             throw new CatalogApiException(ErrorCode.CAT_NO_SUCH_PLAN, planName);
@@ -104,10 +103,10 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
         final Long planDefRecordId = Long.parseLong(m.group(2));
 
         final List<CatalogOverridePhaseDefinitionModelDao> phaseDefs = overrideDao.getOverriddenPlanPhases(planDefRecordId, context);
-        final DefaultPlan defaultPlan = (DefaultPlan) catalog.findCurrentPlan(parentPlanName);
+        final DefaultPlan defaultPlan = catalog.findCurrentPlan(parentPlanName);
         final PlanPhasePriceOverride[] overrides = createOverrides(defaultPlan, phaseDefs, context);
-        final DefaultPlan result = new DefaultPlan(planName, defaultPlan, overrides);
-        result.initialize((StandaloneCatalog) catalog, ((StandaloneCatalog) catalog).getCatalogURI());
+        final DefaultPlan result = new DefaultPlan(catalog, planName, defaultPlan, overrides);
+        result.initialize(catalog, catalog.getCatalogURI());
         return result;
     }
 
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java b/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
index 6f53186..9af1819 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/CatalogUpdater.java
@@ -130,7 +130,7 @@ public class CatalogUpdater {
 
         if (plan == null) {
 
-            plan = new DefaultPlan();
+            plan = new DefaultPlan(catalog);
             plan.setName(desc.getPlanId());
             plan.setPriceListName(PriceListSet.DEFAULT_PRICELIST_NAME);
             plan.setProduct(product);
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
index 8733dd2..5dbd140 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultCatalogService.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -21,10 +21,8 @@ package org.killbill.billing.catalog;
 import javax.inject.Named;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogService;
-import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.catalog.caching.CatalogCache;
 import org.killbill.billing.catalog.glue.CatalogModule;
 import org.killbill.billing.platform.api.KillbillService;
@@ -45,12 +43,10 @@ public class DefaultCatalogService implements KillbillService, CatalogService {
     private static final String CATALOG_SERVICE_NAME = "catalog-service";
 
     private final CatalogConfig config;
-    private boolean isInitialized;
-
     private final TenantInternalApi tenantInternalApi;
-
     private final CatalogCache catalogCache;
     private final CacheInvalidationCallback cacheInvalidationCallback;
+    private boolean isInitialized;
 
     @Inject
     public DefaultCatalogService(final CatalogConfig config,
@@ -74,7 +70,7 @@ public class DefaultCatalogService implements KillbillService, CatalogService {
                     log.info("Successfully loaded the default catalog {}", config.getCatalogURI());
                 }
                 isInitialized = true;
-            } catch (Exception e) {
+            } catch (final Exception e) {
                 throw new ServiceException(e);
             }
         }
@@ -91,26 +87,16 @@ public class DefaultCatalogService implements KillbillService, CatalogService {
     }
 
     @Override
-    public Catalog getFullCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
-        return getCatalog(useDefaultCatalog, filterTemplateCatalog, false, context);
-    }
-
-    @Override
-    public Catalog getFullCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
-        return getCatalog(useDefaultCatalog, filterTemplateCatalog, true, context);
-    }
-
-    @Override
-    public StaticCatalog getCurrentCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
+    public DefaultVersionedCatalog getFullCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
         return getCatalog(useDefaultCatalog, filterTemplateCatalog, false, context);
     }
 
     @Override
-    public StaticCatalog getCurrentCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
+    public DefaultVersionedCatalog getFullCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final InternalTenantContext context) throws CatalogApiException {
         return getCatalog(useDefaultCatalog, filterTemplateCatalog, true, context);
     }
 
-    private VersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, final InternalTenantContext context) throws CatalogApiException {
+    private DefaultVersionedCatalog getCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, final boolean internalUse, final InternalTenantContext context) throws CatalogApiException {
         return catalogCache.getCatalog(useDefaultCatalog, filterTemplateCatalog, internalUse, context);
     }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
index f47f3a0..d248450 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlan.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2017 Groupon, Inc
- * Copyright 2014-2017 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -50,6 +50,7 @@ import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.Recurring;
+import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.catalog.api.TimeUnit;
 import org.killbill.billing.util.cache.ExternalizableInput;
 import org.killbill.billing.util.cache.ExternalizableOutput;
@@ -58,6 +59,8 @@ import org.killbill.xmlloader.ValidatingConfig;
 import org.killbill.xmlloader.ValidationError;
 import org.killbill.xmlloader.ValidationErrors;
 
+import com.google.common.annotations.VisibleForTesting;
+
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements Plan, Externalizable {
 
@@ -97,14 +100,22 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements 
 
     private String priceListName;
 
-    private DateTime catalogEffectiveDate;
+    // Not exposed in XML
+    @VisibleForTesting
+    StandaloneCatalog staticCatalog;
 
     // For deserialization
     public DefaultPlan() {
         initialPhases = new DefaultPlanPhase[0];
     }
 
-    public DefaultPlan(final String planName, final DefaultPlan in, final PlanPhasePriceOverride[] overrides) {
+    public DefaultPlan(final StandaloneCatalog staticCatalog) {
+        this.staticCatalog = staticCatalog;
+        initialPhases = new DefaultPlanPhase[0];
+    }
+
+    public DefaultPlan(final StandaloneCatalog staticCatalog, final String planName, final DefaultPlan in, final PlanPhasePriceOverride[] overrides) {
+        this.staticCatalog = staticCatalog;
         this.name = planName;
         this.effectiveDateForExistingSubscriptions = in.getEffectiveDateForExistingSubscriptions();
         this.product = (DefaultProduct) in.getProduct();
@@ -124,6 +135,11 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements 
     }
 
     @Override
+    public StaticCatalog getCatalog() {
+        return staticCatalog;
+    }
+
+    @Override
     public BillingMode getRecurringBillingMode() {
         return recurringBillingMode;
     }
@@ -221,7 +237,7 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements 
         }
 
         this.priceListName = this.priceListName != null ? this.priceListName : findPriceListForPlan(catalog);
-        this.catalogEffectiveDate = new DateTime(catalog.getEffectiveDate());
+        this.staticCatalog = catalog;
     }
 
     @Override
@@ -405,8 +421,4 @@ public class DefaultPlan extends ValidatingConfig<StandaloneCatalog> implements 
     public void writeExternal(final ObjectOutput oo) throws IOException {
         MapperHolder.mapper().writeValue(new ExternalizableOutput(oo), this);
     }
-
-    public DateTime getCatalogEffectiveDate() {
-        return catalogEffectiveDate;
-    }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
index b2508a5..502fa83 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
@@ -68,7 +68,7 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
     @XmlElement(name = "usage", required = false)
     private DefaultUsage[] usages;
 
-    //Not exposed in XML
+    // Not exposed in XML
     private Plan plan;
 
     public DefaultPlanPhase() {
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/io/CatalogLoader.java b/catalog/src/main/java/org/killbill/billing/catalog/io/CatalogLoader.java
index 953dfe3..d3c5501 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/io/CatalogLoader.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/io/CatalogLoader.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -18,11 +18,10 @@
 
 package org.killbill.billing.catalog.io;
 
-import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 
 public interface CatalogLoader {
 
-    public abstract VersionedCatalog loadDefaultCatalog(String urlString)
-            throws CatalogApiException;
+    public DefaultVersionedCatalog loadDefaultCatalog(String urlString) throws CatalogApiException;
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
index edfdf88..86085c2 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/io/VersionedCatalogLoader.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -32,16 +32,15 @@ import javax.xml.bind.JAXBException;
 import javax.xml.transform.TransformerException;
 
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.InvalidConfigException;
 import org.killbill.billing.catalog.override.PriceOverride;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.clock.Clock;
 import org.killbill.xmlloader.UriAccessor;
-import org.killbill.xmlloader.ValidationErrors;
 import org.killbill.xmlloader.ValidationException;
 import org.killbill.xmlloader.XMLLoader;
 import org.slf4j.Logger;
@@ -70,7 +69,7 @@ public class VersionedCatalogLoader implements CatalogLoader {
     }
 
     @Override
-    public VersionedCatalog loadDefaultCatalog(final String uriString) throws CatalogApiException {
+    public DefaultVersionedCatalog loadDefaultCatalog(final String uriString) throws CatalogApiException {
         try {
             final List<URI> xmlURIs;
             if (uriString.endsWith(XML_EXTENSION)) { // Assume its an xml file
@@ -82,7 +81,7 @@ public class VersionedCatalogLoader implements CatalogLoader {
                 xmlURIs = findXmlReferences(directoryContents, url);
             }
 
-            final VersionedCatalog result = new VersionedCatalog(clock);
+            final DefaultVersionedCatalog result = new DefaultVersionedCatalog(clock);
             for (final URI u : xmlURIs) {
                 final StandaloneCatalog catalog = XMLLoader.getObjectFromUri(u, StandaloneCatalog.class);
                 result.add(new StandaloneCatalogWithPriceOverride(catalog, priceOverride, InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID, internalCallContextFactory));
@@ -96,7 +95,7 @@ public class VersionedCatalogLoader implements CatalogLoader {
         } catch (final JAXBException e) {
             logger.warn("Failed to load default catalog", e);
             throw new CatalogApiException(e, ErrorCode.CAT_INVALID_DEFAULT, uriString);
-        } catch(IllegalArgumentException e) {
+        } catch (IllegalArgumentException e) {
             logger.warn("Failed to load default catalog", e);
             throw new CatalogApiException(e, ErrorCode.CAT_INVALID_DEFAULT, uriString);
         } catch (Exception e) {
@@ -115,8 +114,8 @@ public class VersionedCatalogLoader implements CatalogLoader {
         return Resources.getResource(urlString);
     }
 
-    public VersionedCatalog load(final Iterable<String> catalogXMLs, final boolean filterTemplateCatalog, final Long tenantRecordId) throws CatalogApiException {
-        final VersionedCatalog result = new VersionedCatalog(clock);
+    public DefaultVersionedCatalog load(final Iterable<String> catalogXMLs, final boolean filterTemplateCatalog, final Long tenantRecordId) throws CatalogApiException {
+        final DefaultVersionedCatalog result = new DefaultVersionedCatalog(clock);
         final URI uri;
         try {
             uri = new URI("/tenantCatalog");
@@ -131,25 +130,25 @@ public class VersionedCatalogLoader implements CatalogLoader {
             XMLLoader.initializeAndValidate(uri, result);
             return result;
         } catch (final ValidationException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new CatalogApiException(e, ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
         } catch (final JAXBException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new CatalogApiException(e, ErrorCode.CAT_INVALID_FOR_TENANT, tenantRecordId);
         } catch (final IOException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new IllegalStateException(e);
         } catch (final TransformerException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new IllegalStateException(e);
         } catch (final URISyntaxException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new IllegalStateException(e);
         } catch (final SAXException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new IllegalStateException(e);
         } catch (final InvalidConfigException e) {
-            logger.warn("Failed to load catalog for tenantRecordId='{}'",  tenantRecordId, e);
+            logger.warn("Failed to load catalog for tenantRecordId='{}'", tenantRecordId, e);
             throw new IllegalStateException(e);
         }
     }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
index edf0252..56ae3fb 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/override/DefaultPriceOverride.java
@@ -127,7 +127,7 @@ public class DefaultPriceOverride implements PriceOverride {
             planName = new StringBuffer(parentPlan.getName()).append("-dryrun-").append(DRY_RUN_PLAN_IDX.incrementAndGet()).toString();
         }
 
-        final DefaultPlan result = new DefaultPlan(planName, (DefaultPlan) parentPlan, resolvedOverride);
+        final DefaultPlan result = new DefaultPlan(standaloneCatalog, planName, (DefaultPlan) parentPlan, resolvedOverride);
         result.initialize(standaloneCatalog, standaloneCatalog.getCatalogURI());
         if (context == null) {
             overriddenPlanCache.addDryRunPlan(planName, result);
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/plugin/StandaloneCatalogMapper.java b/catalog/src/main/java/org/killbill/billing/catalog/plugin/StandaloneCatalogMapper.java
index c8bf3d4..e6cedcd 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/plugin/StandaloneCatalogMapper.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/plugin/StandaloneCatalogMapper.java
@@ -56,6 +56,7 @@ import org.killbill.billing.catalog.api.Price;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.Recurring;
+import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.catalog.api.Tier;
 import org.killbill.billing.catalog.api.TieredBlock;
 import org.killbill.billing.catalog.api.Unit;
@@ -108,7 +109,7 @@ public class StandaloneCatalogMapper {
         result.setCatalogName(catalogName);
         result.setEffectiveDate(pluginCatalog.getEffectiveDate().toDate());
         result.setProducts(toDefaultProducts(pluginCatalog.getProducts()));
-        result.setPlans(toDefaultPlans(pluginCatalog.getPlans()));
+        result.setPlans(toDefaultPlans(result, pluginCatalog.getPlans()));
         result.setPriceLists(toDefaultPriceListSet(pluginCatalog.getDefaultPriceList(), pluginCatalog.getChildrenPriceList()));
         result.setSupportedCurrencies(toArray(pluginCatalog.getCurrencies()));
         result.setUnits(toDefaultUnits(pluginCatalog.getUnits()));
@@ -283,10 +284,10 @@ public class StandaloneCatalogMapper {
         return filteredAndOrdered;
     }
 
-    private Iterable<Plan> toDefaultPlans(final Iterable<Plan> input) {
+    private Iterable<Plan> toDefaultPlans(final StaticCatalog staticCatalog, final Iterable<Plan> input) {
         if (tmpDefaultPlans == null) {
             final Map<String, Plan> map = new HashMap<String, Plan>();
-            for (final Plan plan : input) map.put(plan.getName(), toDefaultPlan(plan));
+            for (final Plan plan : input) map.put(plan.getName(), toDefaultPlan(staticCatalog, plan));
             tmpDefaultPlans = map;
         }
         return tmpDefaultPlans.values();
@@ -389,7 +390,7 @@ public class StandaloneCatalogMapper {
         return result;
     }
 
-    private Plan toDefaultPlan(final Plan input) {
+    private Plan toDefaultPlan(final StaticCatalog staticCatalog, final Plan input) {
         if (tmpDefaultPlans != null) {
             final Plan existingPlan = tmpDefaultPlans.get(input.getName());
             if (existingPlan == null) throw new IllegalStateException("Unknown plan " + input.getName());
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/plugin/VersionedCatalogMapper.java b/catalog/src/main/java/org/killbill/billing/catalog/plugin/VersionedCatalogMapper.java
index eb170ce..bdbab8a 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/plugin/VersionedCatalogMapper.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/plugin/VersionedCatalogMapper.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -17,14 +17,12 @@
 
 package org.killbill.billing.catalog.plugin;
 
-import java.util.List;
-
 import javax.inject.Inject;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.override.PriceOverride;
 import org.killbill.billing.catalog.plugin.api.StandalonePluginCatalog;
@@ -32,10 +30,6 @@ import org.killbill.billing.catalog.plugin.api.VersionedPluginCatalog;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.clock.Clock;
 
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
 public class VersionedCatalogMapper {
 
     private final Clock clock;
@@ -50,8 +44,8 @@ public class VersionedCatalogMapper {
         this.internalCallContextFactory = internalCallContextFactory;
     }
 
-    public VersionedCatalog toVersionedCatalog(final VersionedPluginCatalog pluginCatalog, final InternalTenantContext internalTenantContext) throws CatalogApiException {
-        final VersionedCatalog result = new VersionedCatalog(clock);
+    public DefaultVersionedCatalog toVersionedCatalog(final VersionedPluginCatalog pluginCatalog, final InternalTenantContext internalTenantContext) throws CatalogApiException {
+        final DefaultVersionedCatalog result = new DefaultVersionedCatalog(clock);
         for (final StandalonePluginCatalog cur : pluginCatalog.getStandalonePluginCatalogs()) {
             result.add(toStandaloneCatalogWithPriceOverride(pluginCatalog, cur, internalTenantContext));
         }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java b/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
index f03a6a1..fa3b3e4 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/caching/TestEhCacheCatalogCache.java
@@ -29,12 +29,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.CatalogTestSuiteNoDB;
-import org.killbill.billing.catalog.DefaultProduct;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
 import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.xmlloader.UriAccessor;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
@@ -83,13 +83,13 @@ public class TestEhCacheCatalogCache extends CatalogTestSuiteNoDB {
     public void testDefaultCatalog() throws CatalogApiException {
         catalogCache.loadDefaultCatalog(Resources.getResource("SpyCarBasic.xml").toExternalForm());
 
-        final VersionedCatalog result = catalogCache.getCatalog(true, true, false, internalCallContext);
+        final DefaultVersionedCatalog result = catalogCache.getCatalog(true, true, false, internalCallContext);
         Assert.assertNotNull(result);
         final Collection<Product> products = result.getProducts(clock.getUTCNow());
         Assert.assertEquals(products.size(), 3);
 
         // Verify the lookup with other contexts
-        final VersionedCatalog resultForMultiTenantContext = new VersionedCatalog(result.getClock());
+        final DefaultVersionedCatalog resultForMultiTenantContext = new DefaultVersionedCatalog(result.getClock());
         for (final StandaloneCatalog cur : result.getVersions()) {
             resultForMultiTenantContext.add(new StandaloneCatalogWithPriceOverride(cur, priceOverride, multiTenantContext.getTenantRecordId(), internalCallContextFactory));
         }
@@ -155,13 +155,13 @@ public class TestEhCacheCatalogCache extends CatalogTestSuiteNoDB {
         catalogCache.loadDefaultCatalog(Resources.getResource("SpyCarBasic.xml").toExternalForm());
 
         // Verify the lookup for this tenant
-        final VersionedCatalog result = catalogCache.getCatalog(true, true, false, multiTenantContext);
+        final DefaultVersionedCatalog result = catalogCache.getCatalog(true, true, false, multiTenantContext);
         Assert.assertNotNull(result);
         final Collection<Product> products = result.getProducts(clock.getUTCNow());
         Assert.assertEquals(products.size(), 6);
 
         // Verify the lookup for another tenant
-        final VersionedCatalog otherResult = catalogCache.getCatalog(true, true, false, otherMultiTenantContext);
+        final DefaultVersionedCatalog otherResult = catalogCache.getCatalog(true, true, false, otherMultiTenantContext);
         Assert.assertNotNull(otherResult);
         final Collection<Product> otherProducts = otherResult.getProducts(clock.getUTCNow());
         Assert.assertEquals(otherProducts.size(), 3);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
index b3f5bd0..128bb65 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/io/TestVersionedCatalogLoader.java
@@ -24,14 +24,13 @@ import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.Iterator;
 import java.util.List;
 
 import org.joda.time.DateTime;
 import org.killbill.billing.catalog.CatalogTestSuiteNoDB;
-import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -113,23 +112,22 @@ public class TestVersionedCatalogLoader extends CatalogTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testLoad() throws CatalogApiException {
-        final VersionedCatalog c = loader.loadDefaultCatalog(Resources.getResource("versionedCatalog").toString());
-        Assert.assertEquals(c.size(), 4);
-        final Iterator<StandaloneCatalog> it = c.iterator();
+        final DefaultVersionedCatalog c = loader.loadDefaultCatalog(Resources.getResource("versionedCatalog").toString());
+        Assert.assertEquals(c.getVersions().size(), 4);
         DateTime dt = new DateTime("2011-01-01T00:00:00+00:00");
-        Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
+        Assert.assertEquals(c.getVersions().get(0).getEffectiveDate(), dt.toDate());
         dt = new DateTime("2011-02-02T00:00:00+00:00");
-        Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
+        Assert.assertEquals(c.getVersions().get(1).getEffectiveDate(), dt.toDate());
         dt = new DateTime("2011-02-03T00:00:00+00:00");
-        Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
+        Assert.assertEquals(c.getVersions().get(2).getEffectiveDate(), dt.toDate());
         dt = new DateTime("2011-03-03T00:00:00+00:00");
-        Assert.assertEquals(it.next().getEffectiveDate(), dt.toDate());
+        Assert.assertEquals(c.getVersions().get(3).getEffectiveDate(), dt.toDate());
     }
 
     @Test(groups = "fast")
     public void testLoadCatalogFromClasspathResourceFolder() throws CatalogApiException {
         final VersionedCatalog c = loader.loadDefaultCatalog("SpyCarBasic.xml");
-        Assert.assertEquals(c.size(), 1);
+        Assert.assertEquals(c.getVersions().size(), 1);
         final DateTime dt = new DateTime("2013-02-08T00:00:00+00:00");
         Assert.assertEquals(c.getEffectiveDate(), dt.toDate());
         Assert.assertEquals(c.getCatalogName(), "SpyCarBasic");
@@ -142,8 +140,8 @@ public class TestVersionedCatalogLoader extends CatalogTestSuiteNoDB {
 
     @Test(groups = "fast")
     public void testLoadCatalogFromInsideResourceFolder() throws CatalogApiException {
-        final VersionedCatalog c = loader.loadDefaultCatalog("com/acme/SpyCarCustom.xml");
-        Assert.assertEquals(c.size(), 1);
+        final DefaultVersionedCatalog c = loader.loadDefaultCatalog("com/acme/SpyCarCustom.xml");
+        Assert.assertEquals(c.getVersions().size(), 1);
         final DateTime dt = new DateTime("2015-10-04T00:00:00+00:00");
         Assert.assertEquals(c.getEffectiveDate(), dt.toDate());
         Assert.assertEquals(c.getCatalogName(), "SpyCarCustom");
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/io/TestXMLWriter.java b/catalog/src/test/java/org/killbill/billing/catalog/io/TestXMLWriter.java
index 7a3c905..de3d3da 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/io/TestXMLWriter.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/io/TestXMLWriter.java
@@ -33,9 +33,8 @@ import org.killbill.billing.catalog.DefaultPrice;
 import org.killbill.billing.catalog.DefaultPriceListSet;
 import org.killbill.billing.catalog.DefaultProduct;
 import org.killbill.billing.catalog.DefaultRecurring;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.StandaloneCatalogWithPriceOverride;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Currency;
@@ -44,30 +43,27 @@ import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.catalog.api.TimeUnit;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.xmlloader.XMLLoader;
 import org.killbill.xmlloader.XMLWriter;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableList;
 import com.google.common.io.Resources;
 
 import static org.testng.Assert.assertEquals;
 
 public class TestXMLWriter extends CatalogTestSuiteNoDB {
 
-
     // Verifies we can generate the XML associated with a VersionedCatalog
     @Test(groups = "fast")
     public void testVersionedCatalog() throws Exception {
         final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarAdvanced.xml").toExternalForm(), StandaloneCatalog.class);
-        final VersionedCatalog versionedCatalog = new VersionedCatalog(clock);
+        final DefaultVersionedCatalog versionedCatalog = new DefaultVersionedCatalog(clock);
         versionedCatalog.add(catalog);
-        final String newCatalogStr = XMLWriter.writeXML(versionedCatalog, VersionedCatalog.class);
+        final String newCatalogStr = XMLWriter.writeXML(versionedCatalog, DefaultVersionedCatalog.class);
         //System.err.println(newCatalogStr);
     }
 
-
     // Verify we can marshall/unmarshall a (fairly complex catalog) catalog and get back the same result (Required to support catalog update)
     @Test(groups = "fast")
     public void testMarshallUnmarshall() throws Exception {
@@ -80,9 +76,6 @@ public class TestXMLWriter extends CatalogTestSuiteNoDB {
         assertEquals(oldCatalogStr2, oldCatalogStr);
     }
 
-
-
-
     @Test(groups = "fast")
     public void testAddPlan() throws Exception {
         final StandaloneCatalog catalog = XMLLoader.getObjectFromString(Resources.getResource("SpyCarBasic.xml").toExternalForm(), StandaloneCatalog.class);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
index 1e76d64..fbd72fa 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogModule.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014 Groupon, Inc
- * Copyright 2014 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -19,10 +19,10 @@
 package org.killbill.billing.catalog;
 
 import org.killbill.billing.callcontext.InternalCallContext;
-import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogInternalApi;
 import org.killbill.billing.catalog.api.CatalogService;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.KillBillModule;
 import org.mockito.Mockito;
@@ -35,18 +35,17 @@ public class MockCatalogModule extends KillBillModule {
 
     @Override
     protected void configure() {
-        final Catalog catalog = Mockito.mock(Catalog.class);
-
         final CatalogService catalogService = Mockito.mock(CatalogService.class);
         final CatalogInternalApi catalogInternalApi = Mockito.mock(CatalogInternalApi.class);
         try {
-            Mockito.when(catalogService.getCurrentCatalogForInternalUse(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(new MockCatalog());
-            Mockito.when(catalogService.getFullCatalogForInternalUse(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(catalog);
-            Mockito.when(catalogService.getCurrentCatalog(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(new MockCatalog());
-            Mockito.when(catalogService.getFullCatalog(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(catalog);
+            final DefaultVersionedCatalog mockVersionedCatalog = new DefaultVersionedCatalog();
+            final MockCatalog mockCatalog = new MockCatalog();
+            mockVersionedCatalog.add(mockCatalog);
+            Mockito.when(catalogService.getFullCatalogForInternalUse(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(mockVersionedCatalog);
+            Mockito.when(catalogService.getFullCatalog(Mockito.any(Boolean.class), Mockito.any(Boolean.class), Mockito.any(InternalCallContext.class))).thenReturn(mockVersionedCatalog);
             bind(CatalogService.class).toInstance(catalogService);
             bind(CatalogInternalApi.class).toInstance(catalogInternalApi);
-        } catch (CatalogApiException e) {
+        } catch (final CatalogApiException e) {
             throw new RuntimeException(e);
         }
     }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
index 37fae0c..1092f06 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockCatalogService.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -17,15 +19,13 @@
 package org.killbill.billing.catalog;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.catalog.api.Catalog;
-import org.killbill.billing.catalog.api.StaticCatalog;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
 
 public class MockCatalogService extends DefaultCatalogService {
 
-    private final MockCatalog catalog;
+    private final DefaultVersionedCatalog catalog;
 
-    public MockCatalogService(final MockCatalog catalog, final CacheControllerDispatcher cacheControllerDispatcher) {
+    public MockCatalogService(final DefaultVersionedCatalog catalog, final CacheControllerDispatcher cacheControllerDispatcher) {
         super(null, null, null, null);
         this.catalog = catalog;
     }
@@ -40,23 +40,12 @@ public class MockCatalogService extends DefaultCatalogService {
     }
 
     @Override
-    public Catalog getFullCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
+    public DefaultVersionedCatalog getFullCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
         return catalog;
     }
 
     @Override
-    public StaticCatalog getCurrentCatalogForInternalUse(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
+    public DefaultVersionedCatalog getFullCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
         return catalog;
     }
-
-    @Override
-    public Catalog getFullCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
-        return catalog;
-    }
-
-    @Override
-    public StaticCatalog getCurrentCatalog(final boolean useDefaultCatalog, final boolean filterTemplateCatalog, InternalTenantContext context) {
-        return catalog;
-    }
-
 }
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java b/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
index e4ed959..cd4d0cc 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/MockPlan.java
@@ -17,7 +17,9 @@
 package org.killbill.billing.catalog;
 
 import java.util.Collection;
+import java.util.Date;
 
+import org.joda.time.DateTime;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.Plan;
 
@@ -90,6 +92,7 @@ public class MockPlan extends DefaultPlan {
     }
 
     public MockPlan(final String name, final DefaultProduct product, final DefaultPlanPhase[] planPhases, final DefaultPlanPhase finalPhase, final int plansAllowedInBundle) {
+        this.staticCatalog = new StandaloneCatalog(new Date());
         setName(name);
         setProduct(product);
         setFinalPhase(finalPhase);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
index 4bcee55..6ed50a6 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestVersionedCatalog.java
@@ -45,7 +45,7 @@ public class TestVersionedCatalog extends CatalogTestSuiteNoDB {
     // WeaponsHireSmall-3.xml
     final DateTime dt3 = new DateTime("2011-03-03T00:01:00+00:00");
 
-    private VersionedCatalog vc;
+    private DefaultVersionedCatalog vc;
 
     @BeforeClass(groups = "fast")
     public void beforeClass() throws Exception {

currency/pom.xml 2(+1 -1)

diff --git a/currency/pom.xml b/currency/pom.xml
index 7f0c1dc..62eccd6 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-currency</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 2275a68..9b8039f 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index eb45952..5cc9052 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>

jaxrs/pom.xml 6(+1 -5)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index d16c5bd..9f37902 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>
@@ -93,10 +93,6 @@
         </dependency>
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
-            <artifactId>killbill-catalog</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.kill-bill.billing</groupId>
             <artifactId>killbill-internal-api</artifactId>
         </dependency>
         <dependency>
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
index 1cb6d7b..51820bb 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/CatalogJson.java
@@ -28,8 +28,8 @@ import java.util.List;
 import java.util.Map;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.catalog.VersionedCatalog;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.CurrencyValueNull;
@@ -54,7 +54,6 @@ import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
 
 @ApiModel(value="Catalog")
 public class CatalogJson {
@@ -81,8 +80,7 @@ public class CatalogJson {
         this.priceLists = priceLists;
     }
 
-
-    public CatalogJson(final VersionedCatalog catalog, final DateTime requestedDate) throws CatalogApiException {
+    public CatalogJson(final Catalog catalog, final DateTime requestedDate) throws CatalogApiException {
         name = catalog.getCatalogName();
         effectiveDate = catalog.getStandaloneCatalogEffectiveDate(requestedDate);
         currencies = Arrays.asList(catalog.getSupportedCurrencies(requestedDate));
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceJson.java
index 4c2647e..bb99060 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceJson.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -23,35 +23,19 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
-import com.google.common.base.Preconditions;
-import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
-import org.killbill.billing.catalog.DefaultTierPriceOverride;
-import org.killbill.billing.catalog.DefaultTieredBlockPriceOverride;
-import org.killbill.billing.catalog.DefaultUsagePriceOverride;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.billing.catalog.api.PhaseType;
-import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
-import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
-import org.killbill.billing.catalog.api.PlanSpecifier;
 import org.killbill.billing.catalog.api.Tier;
-import org.killbill.billing.catalog.api.TierPriceOverride;
 import org.killbill.billing.catalog.api.TieredBlock;
-import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
 import org.killbill.billing.catalog.api.Usage;
-import org.killbill.billing.catalog.api.UsagePriceOverride;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import io.swagger.annotations.ApiModel;
 
-@ApiModel(value="PhasePrice")
+@ApiModel(value = "PhasePrice")
 public class PhasePriceJson {
 
-
     private final String planName;
     private final String phaseName;
     private final String phaseType;
@@ -89,19 +73,17 @@ public class PhasePriceJson {
         this.usagePrices = new LinkedList<UsagePriceJson>();
 
         for (final Usage usage : usagePrices) {
-            List <TierPriceJson> usageTierPrices = new LinkedList<TierPriceJson>();
-             for(final Tier tier :usage.getTiers())
-             {
-                 List <BlockPriceJson> blockPrices = new LinkedList<BlockPriceJson>();
-
-                 for(final TieredBlock block : tier.getTieredBlocks())
-                 {
-                     BlockPriceJson blockPriceJson = new BlockPriceJson(block.getUnit().getName(), block.getSize(), block.getPrice().getPrice(currency), block.getMax());
-                     blockPrices.add(blockPriceJson);
-                 }
-                     TierPriceJson tierPriceJson = new TierPriceJson(blockPrices);
-                     usageTierPrices.add(tierPriceJson);
-             }
+            List<TierPriceJson> usageTierPrices = new LinkedList<TierPriceJson>();
+            for (final Tier tier : usage.getTiers()) {
+                List<BlockPriceJson> blockPrices = new LinkedList<BlockPriceJson>();
+
+                for (final TieredBlock block : tier.getTieredBlocks()) {
+                    BlockPriceJson blockPriceJson = new BlockPriceJson(block.getUnit().getName(), block.getSize(), block.getPrice().getPrice(currency), block.getMax());
+                    blockPrices.add(blockPriceJson);
+                }
+                TierPriceJson tierPriceJson = new TierPriceJson(blockPrices);
+                usageTierPrices.add(tierPriceJson);
+            }
             final UsagePriceJson usagePriceJson = new UsagePriceJson(usage.getName(), usage.getUsageType(), usage.getBillingMode(), usage.getTierBlockPolicy(), usageTierPrices);
             this.usagePrices.add(usagePriceJson);
         }
@@ -132,7 +114,6 @@ public class PhasePriceJson {
         return usagePrices;
     }
 
-
     @Override
     public String toString() {
         return "PhasePriceJson{" +
@@ -156,7 +137,6 @@ public class PhasePriceJson {
 
         final PhasePriceJson that = (PhasePriceJson) o;
 
-
         if (fixedPrice != null ? fixedPrice.compareTo(that.fixedPrice) != 0 : that.fixedPrice != null) {
             return false;
         }
@@ -188,48 +168,4 @@ public class PhasePriceJson {
         result = 31 * result + (usagePrices != null ? usagePrices.hashCode() : 0);
         return result;
     }
-
-    public static List<PlanPhasePriceOverride> toPlanPhasePriceOverrides(final List<PhasePriceJson> priceOverrides, final PlanSpecifier spec, final Currency currency) {
-        if (priceOverrides == null || priceOverrides.isEmpty()) {
-            return ImmutableList.<PlanPhasePriceOverride>of();
-        }
-        return ImmutableList.copyOf(Iterables.transform(priceOverrides, new Function<PhasePriceJson, PlanPhasePriceOverride>() {
-            @Nullable
-            @Override
-            public PlanPhasePriceOverride apply(@Nullable final PhasePriceJson input) {
-
-                List <UsagePriceOverride> usagePrices = new LinkedList<UsagePriceOverride>();
-                Preconditions.checkNotNull(input);
-                if(input.getUsagePrices() != null) {
-                    for (final UsagePriceJson usageOverrideJson : input.getUsagePrices()) {
-                        List<TierPriceOverride> tierPriceOverrides = new LinkedList<TierPriceOverride>();
-                        for (final TierPriceJson tierPriceJson : usageOverrideJson.getTierPrices()) {
-                            List<TieredBlockPriceOverride> blockPriceOverrides = new LinkedList<TieredBlockPriceOverride>();
-                            for (final BlockPriceJson block : tierPriceJson.getBlockPrices()) {
-                                DefaultTieredBlockPriceOverride tieredBlockPriceOverride = new DefaultTieredBlockPriceOverride( block.getUnitName(), block.getSize(), block.getPrice(),currency, block.getMax());
-                                blockPriceOverrides.add(tieredBlockPriceOverride);
-                            }
-                            DefaultTierPriceOverride tierPriceOverride = new DefaultTierPriceOverride(blockPriceOverrides);
-                            tierPriceOverrides.add(tierPriceOverride);
-                        }
-                        final DefaultUsagePriceOverride usageOverride = new DefaultUsagePriceOverride(usageOverrideJson.getUsageName(), usageOverrideJson.getUsageType(), tierPriceOverrides);
-                        usagePrices.add(usageOverride);
-                    }
-                }
-
-                if (input.getPhaseName() != null) {
-                    return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice(), usagePrices);
-                } else {
-                    final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
-
-                    final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanName() != null ?
-                                                                  new PlanPhaseSpecifier(spec.getPlanName(), phaseType) :
-                                                                  new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
-                    final Currency resolvedCurrency = input.getFixedPrice() != null || input.getRecurringPrice() != null ? currency : null;
-                    return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, resolvedCurrency, input.getFixedPrice(), input.getRecurringPrice(), usagePrices);
-                }
-            }
-        }));
-
-    }
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
index 356ea48..95bea49 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/CatalogResource.java
@@ -18,6 +18,7 @@
 
 package org.killbill.billing.jaxrs.resources;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -40,19 +41,21 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.AccountUserApi;
-import org.killbill.billing.catalog.StandaloneCatalog;
-import org.killbill.billing.catalog.VersionedCatalog;
+import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.CatalogUserApi;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.CurrencyValueNull;
 import org.killbill.billing.catalog.api.Listing;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.catalog.api.SimplePlanDescriptor;
 import org.killbill.billing.catalog.api.StaticCatalog;
-import org.killbill.billing.catalog.api.user.DefaultSimplePlanDescriptor;
+import org.killbill.billing.catalog.api.TimeUnit;
+import org.killbill.billing.catalog.api.VersionedCatalog;
 import org.killbill.billing.entitlement.api.Subscription;
 import org.killbill.billing.entitlement.api.SubscriptionApi;
 import org.killbill.billing.entitlement.api.SubscriptionApiException;
@@ -134,20 +137,11 @@ public class CatalogResource extends JaxRsResourceBase {
                                             DATE_TIME_FORMATTER.parseDateTime(requestedDate).toDateTime(DateTimeZone.UTC) :
                                             null;
 
-        final VersionedCatalog catalog = (VersionedCatalog) catalogUserApi.getCatalog(catalogName, tenantContext);
-        final String result;
-        if (catalogDateVersion != null) {
-            final VersionedCatalog oneVersionCatalog = new VersionedCatalog();
-            for (final StandaloneCatalog v : catalog.getVersions()) {
-                if (v.getEffectiveDate().compareTo(catalogDateVersion.toDate()) >= 0) {
-                    oneVersionCatalog.add(v);
-                    break;
-                }
-            }
-            result = XMLWriter.writeXML(oneVersionCatalog, VersionedCatalog.class);
-        } else {
-            result = XMLWriter.writeXML(catalog, VersionedCatalog.class);
-        }
+        final VersionedCatalog<? extends StaticCatalog> catalog = catalogUserApi.getCatalog(catalogName, catalogDateVersion, tenantContext);
+
+        // This assumes serializableClass has the right JAXB annotations
+        final Class serializableClass = catalog.getClass();
+        final String result = XMLWriter.writeXML(catalog, serializableClass);
 
         return Response.status(Status.OK).entity(result).build();
     }
@@ -214,14 +208,13 @@ public class CatalogResource extends JaxRsResourceBase {
                                             DATE_TIME_FORMATTER.parseDateTime(requestedDate).toDateTime(DateTimeZone.UTC) :
                                             null;
 
-        // Yack...
-        final VersionedCatalog catalog = (VersionedCatalog) catalogUserApi.getCatalog(catalogName, tenantContext);
+        final VersionedCatalog<? extends StaticCatalog> catalog = catalogUserApi.getCatalog(catalogName, null, tenantContext);
 
         final List<CatalogJson> result = new ArrayList<CatalogJson>();
         if (catalogDateVersion != null) {
             result.add(new CatalogJson(catalog, catalogDateVersion));
         } else {
-            for (final StandaloneCatalog v : catalog.getVersions()) {
+            for (final StaticCatalog v : catalog.getVersions()) {
                 result.add(new CatalogJson(catalog, new DateTime(v.getEffectiveDate())));
             }
         }
@@ -239,10 +232,10 @@ public class CatalogResource extends JaxRsResourceBase {
         final TenantContext tenantContext = accountId != null ?
                                             context.createTenantContextWithAccountId(accountId, request) :
                                             context.createTenantContextNoAccountId(request);
-        final VersionedCatalog catalog = (VersionedCatalog) catalogUserApi.getCatalog(catalogName, tenantContext);
+        final VersionedCatalog<? extends StaticCatalog> catalog = catalogUserApi.getCatalog(catalogName, null, tenantContext);
 
         final List<DateTime> result = new ArrayList<DateTime>();
-        for (final StandaloneCatalog v : catalog.getVersions()) {
+        for (final StaticCatalog v : catalog.getVersions()) {
             result.add(new DateTime(v.getEffectiveDate()));
         }
 
@@ -454,15 +447,53 @@ public class CatalogResource extends JaxRsResourceBase {
                                   @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
         final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
 
-        final SimplePlanDescriptor desc = new DefaultSimplePlanDescriptor(simplePlan.getPlanId(),
-                                                                          simplePlan.getProductName(),
-                                                                          simplePlan.getProductCategory(),
-                                                                          simplePlan.getCurrency(),
-                                                                          simplePlan.getAmount(),
-                                                                          simplePlan.getBillingPeriod(),
-                                                                          simplePlan.getTrialLength(),
-                                                                          simplePlan.getTrialTimeUnit(),
-                                                                          simplePlan.getAvailableBaseProducts());
+        final SimplePlanDescriptor desc = new SimplePlanDescriptor() {
+            @Override
+            public String getPlanId() {
+                return simplePlan.getPlanId();
+            }
+
+            @Override
+            public String getProductName() {
+                return simplePlan.getProductName();
+            }
+
+            @Override
+            public ProductCategory getProductCategory() {
+                return simplePlan.getProductCategory();
+            }
+
+            @Override
+            public List<String> getAvailableBaseProducts() {
+                return simplePlan.getAvailableBaseProducts();
+            }
+
+            @Override
+            public Currency getCurrency() {
+                return simplePlan.getCurrency();
+            }
+
+            @Override
+            public BigDecimal getAmount() {
+                return simplePlan.getAmount();
+            }
+
+            @Override
+            public BillingPeriod getBillingPeriod() {
+                return simplePlan.getBillingPeriod();
+            }
+
+            @Override
+            public Integer getTrialLength() {
+                return simplePlan.getTrialLength();
+            }
+
+            @Override
+            public TimeUnit getTrialTimeUnit() {
+                return simplePlan.getTrialTimeUnit();
+            }
+        };
+
         catalogUserApi.addSimplePlan(desc, null, callContext);
         return uriBuilder.buildResponse(uriInfo, CatalogResource.class, null, null, request);
     }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index 543ee93..35b1ec6 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -236,6 +236,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Account or payment not found")})
     public Response createChargeback(@PathParam("paymentId") final UUID paymentId,
                                      final InvoicePaymentTransactionJson json,
+                                     @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
                                      @HeaderParam(HDR_COMMENT) final String comment,
@@ -244,14 +245,22 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json, "InvoicePaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getAmount(), "InvoicePaymentTransactionJson amount needs to be set");
 
-        final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
-        final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
+        final CallContext callContextNoAccountId = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContextNoAccountId);
+        final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContextNoAccountId);
+        final CallContext callContext = context.createCallContextWithAccountId(account.getId(), createdBy, reason, comment, request);
         final String transactionExternalKey = json.getTransactionExternalKey() != null ? json.getTransactionExternalKey() : UUIDs.randomUUID().toString();
 
-        final Payment result = paymentApi.createChargebackWithPaymentControl(account, payment.getId(), json.getAmount(), account.getCurrency(), json.getEffectiveDate(),
-                                                                             transactionExternalKey, createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
+        invoicePaymentApi.createChargebackForInvoicePayment(account,
+                                                            payment.getId(),
+                                                            json.getAmount(),
+                                                            account.getCurrency(),
+                                                            json.getEffectiveDate(),
+                                                            transactionExternalKey,
+                                                            extractPluginProperties(pluginPropertiesString),
+                                                            createInvoicePaymentControlPluginApiPaymentOptions(false),
+                                                            callContext);
+        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", payment.getId(), request);
     }
 
     @TimedResource
@@ -265,6 +274,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Account or payment not found")})
     public Response createChargebackReversal(@PathParam("paymentId") final UUID paymentId,
                                              final InvoicePaymentTransactionJson json,
+                                             @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                              @HeaderParam(HDR_REASON) final String reason,
                                              @HeaderParam(HDR_COMMENT) final String comment,
@@ -273,12 +283,19 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
         verifyNonNullOrEmpty(json, "InvoicePaymentTransactionJson body should be specified");
         verifyNonNullOrEmpty(json.getTransactionExternalKey(), "InvoicePaymentTransactionJson transactionExternalKey needs to be set");
 
-        final CallContext callContext = context.createCallContextNoAccountId(createdBy, reason, comment, request);
-        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContext);
-        final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContext);
+        final CallContext callContextNoAccountId = context.createCallContextNoAccountId(createdBy, reason, comment, request);
+        final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), callContextNoAccountId);
+        final Account account = accountUserApi.getAccountById(payment.getAccountId(), callContextNoAccountId);
+        final CallContext callContext = context.createCallContextWithAccountId(account.getId(), createdBy, reason, comment, request);
 
-        final Payment result = paymentApi.createChargebackReversalWithPaymentControl(account, payment.getId(), json.getEffectiveDate(), json.getTransactionExternalKey(), createInvoicePaymentControlPluginApiPaymentOptions(false), callContext);
-        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId(), request);
+        invoicePaymentApi.createChargebackReversalForInvoicePayment(account,
+                                                                    payment.getId(),
+                                                                    json.getEffectiveDate(),
+                                                                    json.getTransactionExternalKey(),
+                                                                    extractPluginProperties(pluginPropertiesString),
+                                                                    createInvoicePaymentControlPluginApiPaymentOptions(false),
+                                                                    callContext);
+        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", paymentId, request);
     }
 
     @TimedResource(name = "completeInvoicePaymentTransaction")
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 d086be5..128a0e0 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
@@ -56,7 +56,6 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
-import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
@@ -77,7 +76,6 @@ import org.killbill.billing.jaxrs.json.InvoiceDryRunJson;
 import org.killbill.billing.jaxrs.json.InvoiceItemJson;
 import org.killbill.billing.jaxrs.json.InvoiceJson;
 import org.killbill.billing.jaxrs.json.InvoicePaymentJson;
-import org.killbill.billing.jaxrs.json.PhasePriceJson;
 import org.killbill.billing.jaxrs.json.TagJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
@@ -124,6 +122,7 @@ import io.swagger.annotations.ApiResponses;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static javax.ws.rs.core.MediaType.TEXT_HTML;
 import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static org.killbill.billing.jaxrs.resources.SubscriptionResourceHelpers.buildPlanPhasePriceOverrides;
 
 @Path(JaxrsResource.INVOICES_PATH)
 @Api(value = JaxrsResource.INVOICES_PATH, description = "Operations on invoices", tags="Invoice")
@@ -1121,19 +1120,10 @@ public class InvoiceResource extends JaxRsResourceBase {
                                                                                      input.getPriceListName(),
                                                                                      input.getPhaseType() != null ? input.getPhaseType() : null) :
                                                               null;
-                final List<PlanPhasePriceOverride> overrides = input.getPriceOverrides() != null ?
-                                 ImmutableList.copyOf(Iterables.transform(input.getPriceOverrides(), new Function<PhasePriceJson, PlanPhasePriceOverride>() {
-                                     @Nullable
-                                     @Override
-                                     public PlanPhasePriceOverride apply(@Nullable final PhasePriceJson input) {
-                                         if (input.getPhaseName() != null) {
-
-                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice(), null);
-                                         } else {
-                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice(), null);
-                                         }
-                                     }
-                                 })) : ImmutableList.<PlanPhasePriceOverride>of();
+                final List<PlanPhasePriceOverride> overrides = buildPlanPhasePriceOverrides(input.getPriceOverrides(),
+                                                                                            account.getCurrency(),
+                                                                                            planPhaseSpecifier);
+
                 this.specifier = new EntitlementSpecifier() {
                     @Override
                     public PlanPhaseSpecifier getPlanPhaseSpecifier() {
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 b17197c..48f0cf3 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
@@ -28,7 +28,6 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeoutException;
 
-import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -52,7 +51,6 @@ import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.CatalogApiException;
-import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
@@ -81,7 +79,6 @@ import org.killbill.billing.jaxrs.json.BlockingStateJson;
 import org.killbill.billing.jaxrs.json.BulkSubscriptionsBundleJson;
 import org.killbill.billing.jaxrs.json.BundleJson;
 import org.killbill.billing.jaxrs.json.CustomFieldJson;
-import org.killbill.billing.jaxrs.json.PhasePriceJson;
 import org.killbill.billing.jaxrs.json.SubscriptionJson;
 import org.killbill.billing.jaxrs.json.TagJson;
 import org.killbill.billing.jaxrs.util.Context;
@@ -116,6 +113,9 @@ import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.killbill.billing.jaxrs.resources.SubscriptionResourceHelpers.buildBaseEntitlementWithAddOnsSpecifier;
+import static org.killbill.billing.jaxrs.resources.SubscriptionResourceHelpers.buildEntitlementSpecifier;
+import static org.killbill.billing.jaxrs.resources.SubscriptionResourceHelpers.buildPlanPhasePriceOverrides;
 
 @Path(JaxrsResource.SUBSCRIPTIONS_PATH)
 @Api(value = JaxrsResource.SUBSCRIPTIONS_PATH, description = "Operations on subscriptions", tags = "Subscription")
@@ -353,85 +353,6 @@ public class SubscriptionResource extends JaxRsResourceBase {
         return callCompletionCreation.withSynchronization(callback, timeoutSec, callCompletion, callContext);
     }
 
-    private void buildEntitlementSpecifier(final SubscriptionJson subscriptionJson,
-                                           final Currency currency,
-                                           final Collection<EntitlementSpecifier> entitlementSpecifierList) {
-        if (subscriptionJson.getPlanName() == null &&
-            (subscriptionJson.getProductName() == null ||
-             subscriptionJson.getProductCategory() == null ||
-             subscriptionJson.getBillingPeriod() == null ||
-             subscriptionJson.getPriceList() == null)) {
-            return;
-        }
-
-        final PlanPhaseSpecifier planPhaseSpecifier = subscriptionJson.getPlanName() != null ?
-                                                      new PlanPhaseSpecifier(subscriptionJson.getPlanName(), null) :
-                                                      new PlanPhaseSpecifier(subscriptionJson.getProductName(),
-                                                                             subscriptionJson.getBillingPeriod(),
-                                                                             subscriptionJson.getPriceList(),
-                                                                             subscriptionJson.getPhaseType());
-        final List<PlanPhasePriceOverride> overrides = PhasePriceJson.toPlanPhasePriceOverrides(subscriptionJson.getPriceOverrides(),
-                                                                                                planPhaseSpecifier,
-                                                                                                currency);
-
-        final EntitlementSpecifier specifier = new EntitlementSpecifier() {
-            @Override
-            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
-                return planPhaseSpecifier;
-            }
-
-            @Override
-            public Integer getBillCycleDay() {
-                return null;
-            }
-
-            @Override
-            public List<PlanPhasePriceOverride> getOverrides() {
-                return overrides;
-            }
-        };
-        entitlementSpecifierList.add(specifier);
-    }
-
-    private BaseEntitlementWithAddOnsSpecifier buildBaseEntitlementWithAddOnsSpecifier(final Iterable<EntitlementSpecifier> entitlementSpecifierList,
-                                                                                       final LocalDate resolvedEntitlementDate,
-                                                                                       final LocalDate resolvedBillingDate,
-                                                                                       @Nullable final UUID bundleId,
-                                                                                       @Nullable final String bundleExternalKey,
-                                                                                       final Boolean isMigrated) {
-        return new BaseEntitlementWithAddOnsSpecifier() {
-            @Override
-            public UUID getBundleId() {
-                return bundleId;
-            }
-
-            @Override
-            public String getExternalKey() {
-                return bundleExternalKey;
-            }
-
-            @Override
-            public Iterable<EntitlementSpecifier> getEntitlementSpecifier() {
-                return entitlementSpecifierList;
-            }
-
-            @Override
-            public LocalDate getEntitlementEffectiveDate() {
-                return resolvedEntitlementDate;
-            }
-
-            @Override
-            public LocalDate getBillingEffectiveDate() {
-                return resolvedBillingDate;
-            }
-
-            @Override
-            public boolean isMigrated() {
-                return isMigrated;
-            }
-        };
-    }
-
     private Map<String, String> buildQueryParams(final Iterable<String> bundleIdList) {
         Map<String, String> queryParams = new HashMap<String, String>();
         String value = "";
@@ -534,7 +455,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                                                     new PlanPhaseSpecifier(entitlement.getPlanName(), phaseType) :
                                                     new PlanPhaseSpecifier(entitlement.getProductName(),
                                                                            entitlement.getBillingPeriod(), entitlement.getPriceList(), phaseType);
-                final List<PlanPhasePriceOverride> overrides = PhasePriceJson.toPlanPhasePriceOverrides(entitlement.getPriceOverrides(), planSpec, account.getCurrency());
+                final List<PlanPhasePriceOverride> overrides = buildPlanPhasePriceOverrides(entitlement.getPriceOverrides(), account.getCurrency(), planSpec);
 
                 if (requestedDate == null && billingPolicy == null) {
                     newEntitlement = current.changePlan(new DefaultEntitlementSpecifier(planSpec, null, overrides), pluginProperties, ctx);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResourceHelpers.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResourceHelpers.java
new file mode 100644
index 0000000..c958959
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResourceHelpers.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs.resources;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.PhaseType;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.PlanSpecifier;
+import org.killbill.billing.catalog.api.TierPriceOverride;
+import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
+import org.killbill.billing.catalog.api.UsagePriceOverride;
+import org.killbill.billing.catalog.api.UsageType;
+import org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier;
+import org.killbill.billing.entitlement.api.EntitlementSpecifier;
+import org.killbill.billing.jaxrs.json.BlockPriceJson;
+import org.killbill.billing.jaxrs.json.PhasePriceJson;
+import org.killbill.billing.jaxrs.json.SubscriptionJson;
+import org.killbill.billing.jaxrs.json.TierPriceJson;
+import org.killbill.billing.jaxrs.json.UsagePriceJson;
+
+import com.google.common.base.Preconditions;
+
+public class SubscriptionResourceHelpers {
+
+    public static void buildEntitlementSpecifier(final SubscriptionJson subscriptionJson,
+                                                 final Currency currency,
+                                                 final Collection<EntitlementSpecifier> entitlementSpecifierList) {
+        if (subscriptionJson.getPlanName() == null &&
+            (subscriptionJson.getProductName() == null ||
+             subscriptionJson.getProductCategory() == null ||
+             subscriptionJson.getBillingPeriod() == null ||
+             subscriptionJson.getPriceList() == null)) {
+            return;
+        }
+
+        final PlanPhaseSpecifier planPhaseSpecifier = subscriptionJson.getPlanName() != null ?
+                                                      new PlanPhaseSpecifier(subscriptionJson.getPlanName(), null) :
+                                                      new PlanPhaseSpecifier(subscriptionJson.getProductName(),
+                                                                             subscriptionJson.getBillingPeriod(),
+                                                                             subscriptionJson.getPriceList(),
+                                                                             subscriptionJson.getPhaseType());
+
+        final List<PlanPhasePriceOverride> overrides = buildPlanPhasePriceOverrides(subscriptionJson.getPriceOverrides(), currency, planPhaseSpecifier);
+
+        final EntitlementSpecifier specifier = new EntitlementSpecifier() {
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                return planPhaseSpecifier;
+            }
+
+            @Override
+            public Integer getBillCycleDay() {
+                return null;
+            }
+
+            @Override
+            public List<PlanPhasePriceOverride> getOverrides() {
+                return overrides;
+            }
+        };
+        entitlementSpecifierList.add(specifier);
+    }
+
+    public static List<PlanPhasePriceOverride> buildPlanPhasePriceOverrides(final Iterable<PhasePriceJson> priceOverrides,
+                                                                            final Currency currency,
+                                                                            final PlanPhaseSpecifier planPhaseSpecifier) {
+        final List<PlanPhasePriceOverride> overrides = new LinkedList<PlanPhasePriceOverride>();
+        if (priceOverrides != null) {
+            for (final PhasePriceJson input : priceOverrides) {
+                Preconditions.checkNotNull(input);
+
+                final List<UsagePriceOverride> usagePrices = new LinkedList<UsagePriceOverride>();
+                if (input.getUsagePrices() != null) {
+                    buildUsagePrices(currency, input, usagePrices);
+                }
+
+                overrides.add(buildPlanPhasePriceOverride(planPhaseSpecifier, currency, input, usagePrices));
+            }
+        }
+        return overrides;
+    }
+
+    private static void buildUsagePrices(final Currency currency,
+                                         final PhasePriceJson input,
+                                         final Collection<UsagePriceOverride> usagePrices) {
+        for (final UsagePriceJson usageOverrideJson : input.getUsagePrices()) {
+            final List<TierPriceOverride> tierPriceOverrides = new LinkedList<TierPriceOverride>();
+            for (final TierPriceJson tierPriceJson : usageOverrideJson.getTierPrices()) {
+                final List<TieredBlockPriceOverride> blockPriceOverrides = new LinkedList<TieredBlockPriceOverride>();
+                for (final BlockPriceJson block : tierPriceJson.getBlockPrices()) {
+                    blockPriceOverrides.add(new TieredBlockPriceOverride() {
+
+                        @Override
+                        public String getUnitName() {
+                            return block.getUnitName();
+                        }
+
+                        @Override
+                        public Double getSize() {
+                            return block.getSize();
+                        }
+
+                        @Override
+                        public BigDecimal getPrice() {
+                            return block.getPrice();
+                        }
+
+                        @Override
+                        public Currency getCurrency() {
+                            return currency;
+                        }
+
+                        @Override
+                        public Double getMax() {
+                            return block.getMax();
+                        }
+                    });
+                }
+
+                tierPriceOverrides.add(new TierPriceOverride() {
+
+                    @Override
+                    public List<TieredBlockPriceOverride> getTieredBlockPriceOverrides() {
+                        return blockPriceOverrides;
+                    }
+                });
+            }
+            usagePrices.add(new UsagePriceOverride() {
+                @Override
+                public String getName() {
+                    return usageOverrideJson.getUsageName();
+                }
+
+                @Override
+                public UsageType getUsageType() {
+                    return usageOverrideJson.getUsageType();
+                }
+
+                @Override
+                public List<TierPriceOverride> getTierPriceOverrides() {
+                    return tierPriceOverrides;
+                }
+            });
+        }
+    }
+
+    private static PlanPhasePriceOverride buildPlanPhasePriceOverride(final PlanSpecifier spec,
+                                                                      final Currency currency,
+                                                                      final PhasePriceJson input,
+                                                                      final List<UsagePriceOverride> usagePrices) {
+        if (input.getPhaseName() != null) {
+            return new PlanPhasePriceOverride() {
+                @Override
+                public String getPhaseName() {
+                    return input.getPhaseName();
+                }
+
+                @Override
+                public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                    return null;
+                }
+
+                @Override
+                public Currency getCurrency() {
+                    return currency;
+                }
+
+                @Override
+                public BigDecimal getFixedPrice() {
+                    return input.getFixedPrice();
+                }
+
+                @Override
+                public BigDecimal getRecurringPrice() {
+                    return input.getRecurringPrice();
+                }
+
+                @Override
+                public List<UsagePriceOverride> getUsagePriceOverrides() {
+                    return usagePrices;
+                }
+            };
+        }
+
+        final PhaseType phaseType = input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null;
+
+        final PlanPhaseSpecifier planPhaseSpecifier = spec.getPlanName() != null ?
+                                                      new PlanPhaseSpecifier(spec.getPlanName(), phaseType) :
+                                                      new PlanPhaseSpecifier(spec.getProductName(), spec.getBillingPeriod(), spec.getPriceListName(), phaseType);
+        final Currency resolvedCurrency = input.getFixedPrice() != null || input.getRecurringPrice() != null ? currency : null;
+
+        return new PlanPhasePriceOverride() {
+
+            @Override
+            public String getPhaseName() {
+                return null;
+            }
+
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                return planPhaseSpecifier;
+            }
+
+            @Override
+            public Currency getCurrency() {
+                return resolvedCurrency;
+            }
+
+            @Override
+            public BigDecimal getFixedPrice() {
+                return input.getFixedPrice();
+            }
+
+            @Override
+            public BigDecimal getRecurringPrice() {
+                return input.getRecurringPrice();
+            }
+
+            @Override
+            public List<UsagePriceOverride> getUsagePriceOverrides() {
+                return usagePrices;
+            }
+        };
+    }
+
+    public static BaseEntitlementWithAddOnsSpecifier buildBaseEntitlementWithAddOnsSpecifier(final Iterable<EntitlementSpecifier> entitlementSpecifierList,
+                                                                                             final LocalDate resolvedEntitlementDate,
+                                                                                             final LocalDate resolvedBillingDate,
+                                                                                             @Nullable final UUID bundleId,
+                                                                                             @Nullable final String bundleExternalKey,
+                                                                                             final Boolean isMigrated) {
+        return new BaseEntitlementWithAddOnsSpecifier() {
+            @Override
+            public UUID getBundleId() {
+                return bundleId;
+            }
+
+            @Override
+            public String getExternalKey() {
+                return bundleExternalKey;
+            }
+
+            @Override
+            public Iterable<EntitlementSpecifier> getEntitlementSpecifier() {
+                return entitlementSpecifierList;
+            }
+
+            @Override
+            public LocalDate getEntitlementEffectiveDate() {
+                return resolvedEntitlementDate;
+            }
+
+            @Override
+            public LocalDate getBillingEffectiveDate() {
+                return resolvedBillingDate;
+            }
+
+            @Override
+            public boolean isMigrated() {
+                return isMigrated;
+            }
+        };
+    }
+}
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestPlanDetailJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestPlanDetailJson.java
index 243d97f..7c34cc0 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestPlanDetailJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestPlanDetailJson.java
@@ -18,17 +18,16 @@ package org.killbill.billing.jaxrs.json;
 
 import java.util.UUID;
 
-import org.killbill.billing.catalog.DefaultPrice;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.InternationalPrice;
 import org.killbill.billing.catalog.api.Listing;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.Price;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.Recurring;
 import org.killbill.billing.jaxrs.JaxrsTestSuiteNoDB;
-import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -65,7 +64,8 @@ public class TestPlanDetailJson extends JaxrsTestSuiteNoDB {
         Mockito.when(product.getName()).thenReturn(UUID.randomUUID().toString());
 
         final InternationalPrice price = Mockito.mock(InternationalPrice.class);
-        Mockito.when(price.getPrices()).thenReturn(new DefaultPrice[0]);
+        final Price[] mock = {};
+        Mockito.when(price.getPrices()).thenReturn(mock);
         final PlanPhase planPhase = Mockito.mock(PlanPhase.class);
         final Recurring recurring = Mockito.mock(Recurring.class);
         Mockito.when(recurring.getRecurringPrice()).thenReturn(price);

junction/pom.xml 3(+2 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index bfc8c82..a0f850e 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>
@@ -91,6 +91,7 @@
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
             <artifactId>killbill-catalog</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
index f7285c5..ebc9f21 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -24,7 +24,6 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.catalog.DefaultPlan;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -91,8 +90,7 @@ public class DefaultBillingEvent implements BillingEvent {
             final PlanPhase prevPlanPhase = (prevPhaseName != null && prevPlan != null) ? prevPlan.findPhase(prevPhaseName) : null;
             this.billingPeriod = getRecurringBillingPeriod(prevPlanPhase);
         }
-        // TODO It would be nice to have an Plan api to get that date; actually the following would be nice
-        this.catalogEffectiveDate = ((DefaultPlan) plan).getCatalogEffectiveDate();
+        this.catalogEffectiveDate = plan == null ? null : new DateTime(plan.getCatalog().getEffectiveDate());
 
         this.billCycleDayLocal = billCycleDayLocal;
         this.catalog = catalog;
@@ -113,7 +111,7 @@ public class DefaultBillingEvent implements BillingEvent {
                                final BillingPeriod billingPeriod, final int billCycleDayLocal,
                                final String description, final long totalOrdering, final SubscriptionBaseTransitionType type,
                                final Catalog catalog,
-                               final boolean isDisableEvent) {
+                               final boolean isDisableEvent) throws CatalogApiException {
         this.catalog = catalog;
         this.subscription = subscription;
         this.effectiveDate = effectiveDate;
@@ -129,8 +127,7 @@ public class DefaultBillingEvent implements BillingEvent {
         this.usages = initializeUsage(isActive);
         this.isDisableEvent = isDisableEvent;
         this.nextPlanPhase = isDisableEvent ? null : planPhase;
-        this.catalogEffectiveDate = plan != null ? ((DefaultPlan) plan).getCatalogEffectiveDate() : null;
-
+        this.catalogEffectiveDate = plan != null ? new DateTime(plan.getCatalog().getEffectiveDate()) : null;
     }
 
     @Override
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
index 4f7e151..481343e 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBillingApi.java
@@ -30,6 +30,7 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.MockCatalog;
 import org.killbill.billing.catalog.api.BillingAlignment;
 import org.killbill.billing.catalog.api.Catalog;
@@ -67,6 +68,7 @@ import org.testng.annotations.Test;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
@@ -109,11 +111,11 @@ public class TestBillingApi extends JunctionTestSuiteNoDB {
         Mockito.when(subscriptionInternalApi.getBillingTransitions(Mockito.<SubscriptionBase>any(),  Mockito.<InternalTenantContext>any())).thenReturn(effectiveSubscriptionTransitions);
         Mockito.when(subscriptionInternalApi.getAllTransitions(Mockito.<SubscriptionBase>any(), Mockito.<InternalTenantContext>any())).thenReturn(effectiveSubscriptionTransitions);
 
-        catalog = ((MockCatalog) catalogService.getCurrentCatalog(true, true, internalCallContext));
-        Mockito.when(catalogService.getFullCatalog(true, true, internalCallContext)).thenReturn(catalog);
+        final DefaultVersionedCatalog versionedCatalog = catalogService.getFullCatalog(true, true, internalCallContext);
+        catalog = (MockCatalog) Iterables.getLast(versionedCatalog.getVersions());
+        Mockito.when(catalogService.getFullCatalog(true, true, internalCallContext)).thenReturn(versionedCatalog);
 
         Mockito.when(catalogInternalApi.getFullCatalog(true, true, internalCallContext)).thenReturn(catalog);
-        Mockito.when(catalogInternalApi.getCurrentCatalog(true, true, internalCallContext)).thenReturn(catalog);
         // Set a default alignment
         catalog.setBillingAlignment(BillingAlignment.ACCOUNT);
 
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
index fa0af58..58d299b 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -668,7 +668,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
     private class MockBillingEvent extends DefaultBillingEvent {
 
-        public MockBillingEvent() {
+        public MockBillingEvent() throws CatalogApiException {
             super(subscription1, clock.getUTCNow(), true, null, null, BigDecimal.ZERO, Currency.USD, BillingPeriod.ANNUAL,
                   4, "", 3L, SubscriptionBaseTransitionType.CREATE, null, false);
         }
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
index e146464..05ff9dd 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -97,7 +98,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testEventOrderingSubscription() {
+    public void testEventOrderingSubscription() throws CatalogApiException {
         final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
         final BillingEvent event1 = createEvent(subscription(ID_ONE), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
         final BillingEvent event2 = createEvent(subscription(ID_TWO), new DateTime("2012-01-31T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
@@ -115,7 +116,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testEventOrderingDate() {
+    public void testEventOrderingDate() throws CatalogApiException {
         final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
         final BillingEvent event1 = createEvent(subscription(ID_ZERO), new DateTime("2012-02-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
         final BillingEvent event2 = createEvent(subscription(ID_ZERO), new DateTime("2012-03-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
@@ -133,7 +134,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testEventTotalOrdering() {
+    public void testEventTotalOrdering() throws CatalogApiException {
         final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE, 1L);
         final BillingEvent event1 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CANCEL, 2L);
         final BillingEvent event2 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CANCEL, 3L);
@@ -151,7 +152,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
     }
 
     @Test(groups = "fast")
-    public void testEventOrderingMix() {
+    public void testEventOrderingMix() throws CatalogApiException {
         final BillingEvent event0 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CREATE);
         final BillingEvent event1 = createEvent(subscription(ID_ZERO), new DateTime("2012-01-02T00:02:04.000Z"), SubscriptionBaseTransitionType.CHANGE);
         final BillingEvent event2 = createEvent(subscription(ID_ONE), new DateTime("2012-01-01T00:02:04.000Z"), SubscriptionBaseTransitionType.CANCEL);
@@ -175,17 +176,16 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
         Assert.assertEquals(event.toString(), "DefaultBillingEvent{type=CREATE, effectiveDate=2012-01-01T00:02:04.000Z, planPhaseName=Test-trial, subscriptionId=00000000-0000-0000-0000-000000000000, totalOrdering=1}");
     }
 
-    private BillingEvent createEvent(final SubscriptionBase sub, final DateTime effectiveDate, final SubscriptionBaseTransitionType type) {
+    private BillingEvent createEvent(final SubscriptionBase sub, final DateTime effectiveDate, final SubscriptionBaseTransitionType type) throws CatalogApiException {
         return createEvent(sub, effectiveDate, type, 1L);
     }
 
-    private BillingEvent createEvent(final SubscriptionBase sub, final DateTime effectiveDate, final SubscriptionBaseTransitionType type, final long totalOrdering) {
+    private BillingEvent createEvent(final SubscriptionBase sub, final DateTime effectiveDate, final SubscriptionBaseTransitionType type, final long totalOrdering) throws CatalogApiException {
         final int billCycleDay = 1;
 
         final Plan shotgun = new MockPlan();
         final PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, BigDecimal.ZERO, PhaseType.TRIAL);
 
-        final Account account = new MockAccountBuilder().build();
         return new DefaultBillingEvent(sub, effectiveDate, true,
                                        shotgun, shotgunMonthly, BigDecimal.ZERO,
                                        Currency.USD, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 6e4b786..7a943d4 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index 0cb605a..bf4d92b 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultInvoicePaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultInvoicePaymentApi.java
index c836e97..037298a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultInvoicePaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultInvoicePaymentApi.java
@@ -150,6 +150,50 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
     }
 
     @Override
+    public InvoicePayment createChargebackForInvoicePayment(final Account account,
+                                                            final UUID paymentId,
+                                                            final BigDecimal amount,
+                                                            final Currency currency,
+                                                            final DateTime effectiveDate,
+                                                            final String originalPaymentTransactionExternalKey,
+                                                            final Iterable<PluginProperty> properties,
+                                                            final PaymentOptions paymentOptions,
+                                                            final CallContext context) throws PaymentApiException {
+        final String paymentTransactionExternalKey = MoreObjects.firstNonNull(originalPaymentTransactionExternalKey, UUIDs.randomUUID().toString());
+        paymentApi.createChargebackWithPaymentControl(account,
+                                                      paymentId,
+                                                      amount,
+                                                      currency,
+                                                      effectiveDate,
+                                                      paymentTransactionExternalKey,
+                                                      // properties, // TODO API change?
+                                                      InvoicePaymentPaymentOptions.create(paymentOptions),
+                                                      context);
+
+        return invoiceInternalApi.getInvoicePaymentByCookieId(paymentTransactionExternalKey, context);
+    }
+
+    @Override
+    public InvoicePayment createChargebackReversalForInvoicePayment(final Account account,
+                                                                    final UUID paymentId,
+                                                                    final DateTime effectiveDate,
+                                                                    final String originalPaymentTransactionExternalKey,
+                                                                    final Iterable<PluginProperty> properties,
+                                                                    final PaymentOptions paymentOptions,
+                                                                    final CallContext context) throws PaymentApiException {
+        final String paymentTransactionExternalKey = MoreObjects.firstNonNull(originalPaymentTransactionExternalKey, UUIDs.randomUUID().toString());
+        paymentApi.createChargebackReversalWithPaymentControl(account,
+                                                              paymentId,
+                                                              effectiveDate,
+                                                              paymentTransactionExternalKey,
+                                                              // properties, // TODO API change?
+                                                              InvoicePaymentPaymentOptions.create(paymentOptions),
+                                                              context);
+
+        return invoiceInternalApi.getInvoicePaymentByCookieId(paymentTransactionExternalKey, context);
+    }
+
+    @Override
     public List<InvoicePayment> getInvoicePayments(final UUID paymentId, final TenantContext context) {
         return invoiceInternalApi.getInvoicePayments(paymentId, context);
     }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
index ff535d7..40010f2 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
@@ -212,19 +212,17 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
                 break;
             case UNKNOWN:
             default:
-                if (transactionStatus != paymentTransaction.getTransactionStatus()) {
-                    log.info("Unable to repair paymentId='{}', paymentTransactionId='{}', currentTransactionStatus='{}', newTransactionStatus='{}'",
-                             payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionStatus(), transactionStatus);
-                }
                 // We can't get anything interesting from the plugin...
+                log.info("Unable to repair paymentId='{}', paymentTransactionId='{}', currentTransactionStatus='{}', newTransactionStatus='{}'",
+                         payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionStatus(), transactionStatus);
                 insertNewNotificationForUnresolvedTransactionIfNeeded(paymentTransaction.getId(), transactionStatus, attemptNumber, userToken, internalTenantContext.getAccountRecordId(), internalTenantContext.getTenantRecordId());
                 return false;
         }
 
         // Our status did not change, so we just insert a new notification (attemptNumber will be incremented)
         if (transactionStatus == paymentTransaction.getTransactionStatus()) {
-            log.debug("Janitor IncompletePaymentTransactionTask repairing payment {}, transaction {}, transitioning transactionStatus from {} -> {}",
-                      payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionStatus(), transactionStatus);
+            log.info("Unable to repair paymentId='{}', paymentTransactionId='{}', currentTransactionStatus='{}', newTransactionStatus='{}'",
+                     payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionStatus(), transactionStatus);
             insertNewNotificationForUnresolvedTransactionIfNeeded(paymentTransaction.getId(), transactionStatus, attemptNumber, userToken, internalTenantContext.getAccountRecordId(), internalTenantContext.getTenantRecordId());
             return false;
         }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index e3bfbfa..2074576 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -707,6 +707,8 @@ public class PaymentProcessor extends ProcessorBase {
                     newPaymentModelDao = paymentDao.getPayment(newPaymentModelDao.getId(), internalTenantContext);
                     newPaymentTransactionModelDao = paymentDao.getPaymentTransaction(newPaymentTransactionModelDao.getId(), internalTenantContext);
                 }
+            } else {
+                log.warn("Unable to find transaction={} from pluginTransactions={}", curPaymentTransactionModelDao, pluginTransactions);
             }
 
             transactionsModelDao.add(newPaymentTransactionModelDao);

pom.xml 4(+2 -2)

diff --git a/pom.xml b/pom.xml
index db1a440..a818085 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,10 +21,10 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.141.87</version>
+        <version>0.141.90</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.19.17-SNAPSHOT</version>
+    <version>0.19.18-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
diff --git a/profiles/killbill/pom.xml b/profiles/killbill/pom.xml
index cd35f59..409af5d 100644
--- a/profiles/killbill/pom.xml
+++ b/profiles/killbill/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killbill</artifactId>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
index 49193af..d4b4778 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestChargeback.java
@@ -140,6 +140,11 @@ public class TestChargeback extends TestJaxrsBase {
     }
 
     private void createAndVerifyChargeback(final InvoicePayment payment) throws KillBillClientException {
+        List<Invoice> invoices = accountApi.getInvoicesForAccount(payment.getAccountId(), null, requestOptions);
+        // We should have two invoices, one for the trial (zero dollar amount) and one for the first month
+        Assert.assertEquals(invoices.size(), 2);
+        Assert.assertEquals(invoices.get(1).getBalance().compareTo(BigDecimal.ZERO), 0);
+
         // Create the chargeback
         final InvoicePaymentTransaction chargeback = new InvoicePaymentTransaction();
         chargeback.setPaymentId(payment.getPaymentId());
@@ -158,6 +163,11 @@ public class TestChargeback extends TestJaxrsBase {
         Assert.assertEquals(transactions.size(), 1);
         assertEquals(transactions.get(0).getAmount().compareTo(chargeback.getAmount()), 0);
         assertEquals(transactions.get(0).getPaymentId(), chargeback.getPaymentId());
+
+        // Verify invoice balance
+        invoices = accountApi.getInvoicesForAccount(payment.getAccountId(), null, requestOptions);
+        Assert.assertEquals(invoices.size(), 2);
+        Assert.assertEquals(invoices.get(1).getBalance().compareTo(BigDecimal.ZERO), 1);
     }
 
     private InvoicePayment createAccountWithInvoiceAndPayment() throws Exception {
diff --git a/profiles/killpay/pom.xml b/profiles/killpay/pom.xml
index 3e633c1..753f3e7 100644
--- a/profiles/killpay/pom.xml
+++ b/profiles/killpay/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killpay</artifactId>

profiles/pom.xml 2(+1 -1)

diff --git a/profiles/pom.xml b/profiles/pom.xml
index c22c3d7..155d41e 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles</artifactId>
diff --git a/subscription/pom.xml b/subscription/pom.xml
index 49f6e88..677e4ec 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>
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 9c3818b..f874505 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
@@ -20,22 +20,15 @@ package org.killbill.billing.subscription.api.transfer;
 
 import java.util.List;
 import java.util.UUID;
-import java.util.regex.Matcher;
 
 import org.joda.time.DateTime;
-import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.catalog.api.CatalogInternalApi;
-import org.killbill.billing.catalog.api.DefaultCatalogInternalApi;
-import org.killbill.billing.catalog.override.DefaultPriceOverride;
-import org.mockito.Mockito;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
+import org.killbill.billing.catalog.DefaultVersionedCatalog;
 import org.killbill.billing.catalog.MockCatalog;
 import org.killbill.billing.catalog.MockCatalogService;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogInternalApi;
 import org.killbill.billing.catalog.api.CatalogService;
+import org.killbill.billing.catalog.api.DefaultCatalogInternalApi;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.PriceListSet;
@@ -52,9 +45,10 @@ import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
 import org.killbill.billing.subscription.events.SubscriptionBaseEvent.EventType;
 import org.killbill.billing.subscription.events.user.ApiEventTransfer;
 import org.killbill.billing.subscription.events.user.ApiEventType;
-import org.killbill.billing.util.cache.CacheControllerDispatcher;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.dao.NonEntityDao;
+import org.mockito.Mockito;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
 
@@ -67,15 +61,17 @@ public class TestDefaultSubscriptionTransferApi extends SubscriptionTestSuiteNoD
     @BeforeMethod(groups = "fast")
     public void beforeMethod() throws Exception {
         super.beforeMethod();
-        final NonEntityDao nonEntityDao = Mockito.mock(NonEntityDao.class);
         final SubscriptionDao dao = Mockito.mock(SubscriptionDao.class);
-        final CatalogService catalogService = new MockCatalogService(new MockCatalog(), cacheControllerDispatcher);
-        final CatalogInternalApi catalogInternalApiWithMockCatalogService = new DefaultCatalogInternalApi(catalogService, internalCallContextFactory);
+        final DefaultVersionedCatalog versionedCatalog = new DefaultVersionedCatalog();
+        final MockCatalog mockCatalog = new MockCatalog();
+        versionedCatalog.add(mockCatalog);
+        final CatalogService catalogService = new MockCatalogService(versionedCatalog, cacheControllerDispatcher);
+        final CatalogInternalApi catalogInternalApiWithMockCatalogService = new DefaultCatalogInternalApi(catalogService);
         final SubscriptionBaseApiService apiService = Mockito.mock(SubscriptionBaseApiService.class);
         final SubscriptionBaseTimelineApi timelineApi = Mockito.mock(SubscriptionBaseTimelineApi.class);
         transferApi = new DefaultSubscriptionBaseTransferApi(clock, dao, timelineApi, catalogInternalApiWithMockCatalogService, subscriptionInternalApi, apiService, internalCallContextFactory);
-        // Overrride catalog with our Mock CatalogService
-        this.catalog = catalogInternalApiWithMockCatalogService.getFullCatalog(true, true, internalCallContext);
+        // Overrride catalog with our MockCatalog
+        this.catalog = mockCatalog;
     }
 
     @Test(groups = "fast")
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
index 8da169d..9186d88 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/DefaultSubscriptionTestInitializer.java
@@ -55,7 +55,6 @@ public class DefaultSubscriptionTestInitializer implements SubscriptionTestIniti
     }
 
     public Catalog initCatalog(final CatalogService catalogService, final InternalTenantContext context) throws Exception {
-
         ((DefaultCatalogService) catalogService).loadCatalog();
         final Catalog catalog = catalogService.getFullCatalog(true, true, context);
         assertNotNull(catalog);

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index e6ee859..a21a0d1 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 63470d8..001e0d4 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 1998e34..004ea09 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.19.17-SNAPSHOT</version>
+        <version>0.19.18-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/test/java/org/killbill/billing/mock/MockPlan.java b/util/src/test/java/org/killbill/billing/mock/MockPlan.java
index d02457c..735ce46 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockPlan.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockPlan.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -27,10 +29,11 @@ import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
-import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
+import org.killbill.billing.catalog.api.StaticCatalog;
 
 public class MockPlan implements Plan {
+
     private final String name;
     private final Product product;
 
@@ -44,6 +47,11 @@ public class MockPlan implements Plan {
     }
 
     @Override
+    public StaticCatalog getCatalog() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public BillingMode getRecurringBillingMode() {
         return BillingMode.IN_ADVANCE;
     }