killbill-aplcache

Changes

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
index c314ac2..3f81642 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationWithCatalogUpdate.java
@@ -201,7 +201,7 @@ public class TestIntegrationWithCatalogUpdate extends TestIntegrationBase {
         final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("bar-monthly", null);
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), account.getCurrency(), null, BigDecimal.ONE));
+        overrides.add(new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), account.getCurrency(), null, BigDecimal.ONE, null));
         final Entitlement baseEntitlement = createEntitlement(spec, overrides, true);
 
         List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, testCallContext);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
index b19e101..38ed77c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithEntilementPlugin.java
@@ -103,7 +103,7 @@ public class TestWithEntilementPlugin extends TestIntegrationBase {
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, BigDecimal.TEN));
+        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, BigDecimal.TEN, null));
 
         testEntitlementPluginApi.setPlanPhasePriceOverride(overrides);
 
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
index 0869e63..54de017 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithPriceOverride.java
@@ -57,7 +57,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-trial", account.getCurrency(), BigDecimal.ONE, null));
+        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-trial", account.getCurrency(), BigDecimal.ONE, null, null));
 
         final DefaultEntitlement bpSubscription = createBaseEntitlementWithPriceOverrideAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, overrides, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
         // Check bundle after BP got created otherwise we get an error from auditApi.
@@ -76,7 +76,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
         accountChecker.checkAccount(account.getId(), accountData, callContext);
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, BigDecimal.TEN));
+        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, BigDecimal.TEN, null));
 
         final DefaultEntitlement bpSubscription = createBaseEntitlementWithPriceOverrideAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, overrides, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
         // Check bundle after BP got created otherwise we get an error from auditApi.
@@ -118,7 +118,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
         invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, new BigDecimal("279.95")));
+        overrides.add(new DefaultPlanPhasePriceOverride("shotgun-monthly-evergreen", account.getCurrency(), null, new BigDecimal("279.95"), null));
 
         busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
         bpSubscription.changePlanOverrideBillingPolicy(new PlanSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), overrides, new LocalDate(2012, 5, 1), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
@@ -165,7 +165,7 @@ public class TestWithPriceOverride extends TestIntegrationBase {
         assertListenerStatus();
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        overrides.add(new DefaultPlanPhasePriceOverride("telescopic-scope-monthly-evergreen", account.getCurrency(), null, new BigDecimal("1200.00")));
+        overrides.add(new DefaultPlanPhasePriceOverride("telescopic-scope-monthly-evergreen", account.getCurrency(), null, new BigDecimal("1200.00"), null));
 
         busHandler.pushExpectedEvents(NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
         aoEntitlement.changePlanOverrideBillingPolicy(new PlanSpecifier("Telescopic-Scope", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), overrides, new LocalDate(2012, 5, 5), BillingActionPolicy.IMMEDIATE, ImmutableList.<PluginProperty>of(), callContext);
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 3b54252..cfe56a9 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
@@ -17,6 +17,7 @@
 
 package org.killbill.billing.catalog.caching;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Matcher;
 
@@ -27,14 +28,26 @@ import org.killbill.billing.ObjectType;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.DefaultPlan;
 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.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.StaticCatalog;
+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 org.killbill.billing.catalog.dao.CatalogOverrideBlockDefinitionModelDao;
 import org.killbill.billing.catalog.dao.CatalogOverrideDao;
 import org.killbill.billing.catalog.dao.CatalogOverridePhaseDefinitionModelDao;
+import org.killbill.billing.catalog.dao.CatalogOverrideTierDefinitionModelDao;
+import org.killbill.billing.catalog.dao.CatalogOverrideUsageDefinitionModelDao;
 import org.killbill.billing.catalog.override.DefaultPriceOverride;
 import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.cache.CacheController;
@@ -91,17 +104,15 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
 
         final List<CatalogOverridePhaseDefinitionModelDao> phaseDefs = overrideDao.getOverriddenPlanPhases(planDefRecordId, context);
         final DefaultPlan defaultPlan = (DefaultPlan) catalog.findCurrentPlan(parentPlanName);
-
-        final PlanPhasePriceOverride[] overrides = createOverrides(defaultPlan, phaseDefs);
+        final PlanPhasePriceOverride[] overrides = createOverrides(defaultPlan, phaseDefs, context);
         return new DefaultPlan(planName, defaultPlan, overrides);
     }
 
-    private PlanPhasePriceOverride[] createOverrides(final Plan defaultPlan, final List<CatalogOverridePhaseDefinitionModelDao> phaseDefs) {
+    private PlanPhasePriceOverride[] createOverrides(final Plan defaultPlan, final List<CatalogOverridePhaseDefinitionModelDao> phaseDefs, final InternalTenantContext context) {
 
         final PlanPhasePriceOverride[] result = new PlanPhasePriceOverride[defaultPlan.getAllPhases().length];
 
         for (int i = 0; i < defaultPlan.getAllPhases().length; i++) {
-
             final PlanPhase curPhase = defaultPlan.getAllPhases()[i];
             final CatalogOverridePhaseDefinitionModelDao overriddenPhase = Iterables.tryFind(phaseDefs, new Predicate<CatalogOverridePhaseDefinitionModelDao>() {
                 @Override
@@ -109,10 +120,100 @@ public class EhCacheOverriddenPlanCache implements OverriddenPlanCache {
                     return input.getParentPhaseName().equals(curPhase.getName());
                 }
             }).orNull();
-            result[i] = (overriddenPhase != null) ?
-                        new DefaultPlanPhasePriceOverride(curPhase.getName(), Currency.valueOf(overriddenPhase.getCurrency()), overriddenPhase.getFixedPrice(), overriddenPhase.getRecurringPrice()) :
-                        null;
+
+            if(overriddenPhase != null) {
+              List<UsagePriceOverride> usagePriceOverrides =  getUsagePriceOverrides(curPhase, overriddenPhase, context);
+              result[i] = new DefaultPlanPhasePriceOverride(curPhase.getName(), Currency.valueOf(overriddenPhase.getCurrency()), overriddenPhase.getFixedPrice(), overriddenPhase.getRecurringPrice(), usagePriceOverrides);
+            }
+            else {
+                result[i] = null;
+            }
         }
         return result;
     }
+
+    List<UsagePriceOverride> getUsagePriceOverrides(PlanPhase curPhase, CatalogOverridePhaseDefinitionModelDao overriddenPhase, final InternalTenantContext context) {
+
+        final List<UsagePriceOverride> usagePriceOverrides = new ArrayList<UsagePriceOverride>();
+        final List<CatalogOverrideUsageDefinitionModelDao> usageDefs = overrideDao.getOverriddenPhaseUsages(overriddenPhase.getRecordId(), context);
+
+        for(int i = 0; i < curPhase.getUsages().length; i++){
+            final Usage curUsage = curPhase.getUsages()[i];
+            final CatalogOverrideUsageDefinitionModelDao overriddenUsage = Iterables.tryFind(usageDefs, new Predicate<CatalogOverrideUsageDefinitionModelDao>() {
+                @Override
+                public boolean apply(final CatalogOverrideUsageDefinitionModelDao input) {
+                    return input.getParentUsageName().equals(curUsage.getName());
+                }
+            }).orNull();
+
+            if(overriddenUsage != null) {
+                List<TierPriceOverride> tierPriceOverrides = getTierPriceOverrides(curUsage, overriddenUsage, context);
+                usagePriceOverrides.add(new DefaultUsagePriceOverride(overriddenUsage.getParentUsageName(), curUsage.getUsageType(),tierPriceOverrides));
+            }
+        }
+        return usagePriceOverrides;
+    }
+
+    List<TierPriceOverride> getTierPriceOverrides(Usage curUsage, CatalogOverrideUsageDefinitionModelDao overriddenUsage, final InternalTenantContext context) {
+
+        final List<TierPriceOverride> tierPriceOverrides = new ArrayList<TierPriceOverride>();
+
+        final List<CatalogOverrideTierDefinitionModelDao> tierDefs = overrideDao.getOverriddenUsageTiers(overriddenUsage.getRecordId(), context);
+        for(int i = 0; i < curUsage.getTiers().length; i++){
+            final Tier curTier = curUsage.getTiers()[i];
+            final TieredBlock[] curTieredBlocks = curTier.getTieredBlocks();
+
+            final CatalogOverrideTierDefinitionModelDao overriddenTier = Iterables.tryFind(tierDefs, new Predicate<CatalogOverrideTierDefinitionModelDao>() {
+                @Override
+                public boolean apply(final CatalogOverrideTierDefinitionModelDao input) {
+                    final List<CatalogOverrideBlockDefinitionModelDao> blockDefs = overrideDao.getOverriddenTierBlocks(input.getRecordId(), context);
+                     for(CatalogOverrideBlockDefinitionModelDao blockDef : blockDefs) {
+                         String unitName = blockDef.getParentUnitName();
+                         Double max = blockDef.getMax();
+                         Double size = blockDef.getSize();
+
+                         for(TieredBlock curTieredBlock : curTieredBlocks) {
+                             if (unitName.equals(curTieredBlock.getUnit().getName()) &&
+                                     Double.compare(size, curTieredBlock.getSize()) == 0 &&
+                                     Double.compare(max, curTieredBlock.getMax()) == 0) {
+                                 return true;
+                             }
+                         }
+                     }
+                    return false;
+                }
+
+            }).orNull();
+
+            if(overriddenTier != null) {
+                List<TieredBlockPriceOverride> tieredBlockPriceOverrides = getTieredBlockPriceOverrides(curTier, overriddenTier, context);
+                tierPriceOverrides.add(new DefaultTierPriceOverride(tieredBlockPriceOverrides));
+            }
+        }
+        return tierPriceOverrides;
+    }
+
+    List<TieredBlockPriceOverride> getTieredBlockPriceOverrides(Tier curTier, CatalogOverrideTierDefinitionModelDao overriddenTier, final InternalTenantContext context) {
+
+        final List<TieredBlockPriceOverride> blockPriceOverrides = new ArrayList<TieredBlockPriceOverride>();
+        final List<CatalogOverrideBlockDefinitionModelDao> blockDefs = overrideDao.getOverriddenTierBlocks(overriddenTier.getRecordId(), context);
+
+        for(int i = 0; i < curTier.getTieredBlocks().length; i++){
+            final TieredBlock curTieredBlock = curTier.getTieredBlocks()[i];
+            final CatalogOverrideBlockDefinitionModelDao overriddenTierBlock = Iterables.tryFind(blockDefs, new Predicate<CatalogOverrideBlockDefinitionModelDao>() {
+                @Override
+                public boolean apply(final CatalogOverrideBlockDefinitionModelDao input) {
+                    return (input.getParentUnitName().equals(curTieredBlock.getUnit().getName()) &&
+                            Double.compare(input.getSize(), curTieredBlock.getSize()) == 0 &&
+                            Double.compare(input.getMax(), curTieredBlock.getMax()) == 0);
+
+                }
+            }).orNull();
+
+            if(overriddenTierBlock != null) {
+                blockPriceOverrides.add(new DefaultTieredBlockPriceOverride(overriddenTierBlock.getParentUnitName(), overriddenTierBlock.getSize(), overriddenTierBlock.getPrice(), overriddenTierBlock.getMax()));
+            }
+        }
+        return blockPriceOverrides;
+    }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionModelDao.java
new file mode 100644
index 0000000..543b0e0
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionModelDao.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.math.BigDecimal;
+
+import org.joda.time.DateTime;
+
+public class CatalogOverrideBlockDefinitionModelDao {
+
+    private Long recordId;
+    private String parentUnitName;
+    private String currency;
+    private BigDecimal price;
+    private String blockType;
+    private double size;
+    private double max;
+    private DateTime effectiveDate;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public String getParentUnitName() {
+        return parentUnitName;
+    }
+
+    public void setParentUnitName(String parentUnitName) {
+        this.parentUnitName = parentUnitName;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    public String getBlockType() {
+        return blockType;
+    }
+
+    public void setBlockType(String blockType) {
+        this.blockType = blockType;
+    }
+
+    public double getSize() {
+        return size;
+    }
+
+    public void setSize(double size) {
+        this.size = size;
+    }
+
+    public double getMax() {
+        return max;
+    }
+
+    public void setMax(double max) {
+        this.max = max;
+    }
+
+    public DateTime getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public void setEffectiveDate(DateTime effectiveDate) {
+        this.effectiveDate = effectiveDate;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+
+    public CatalogOverrideBlockDefinitionModelDao() {
+    }
+
+    public CatalogOverrideBlockDefinitionModelDao(String parentUnitName, String currency, BigDecimal price, double size, double max, DateTime effectiveDate) {
+        this.parentUnitName = parentUnitName;
+        this.currency = currency;
+        this.price = price;
+        this.size = size;
+        this.max = max;
+        this.effectiveDate = effectiveDate;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.java
new file mode 100644
index 0000000..a09b696
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverrideBlockDefinitionSqlDao extends Transactional<CatalogOverrideBlockDefinitionSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverrideBlockDefinitionModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverrideBlockDefinitionModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                                @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public CatalogOverrideBlockDefinitionModelDao getByAttributes(@Bind("parentUnitName") final String parentUnitName,
+                                                                  @Bind("currency") final String currency,
+                                                                  @Bind("price") final BigDecimal price,
+                                                                  @Bind("max") final double max,
+                                                                  @Bind("size") final double size,
+                                                                  @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<CatalogOverrideBlockDefinitionModelDao> getOverriddenTierBlocks(@Bind("targetTierDefRecordId") Long targetTierDefRecordId,
+                                                                                @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideDao.java
index eaef9b1..64ca132 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideDao.java
@@ -22,12 +22,19 @@ import java.util.List;
 import org.joda.time.DateTime;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 
 public interface CatalogOverrideDao {
 
-    public CatalogOverridePlanDefinitionModelDao getOrCreateOverridePlanDefinition(String parentPlanName, DateTime catalogEffectiveDate, PlanPhasePriceOverride[] resolvedOverride, InternalCallContext context);
+    public CatalogOverridePlanDefinitionModelDao getOrCreateOverridePlanDefinition(Plan parentPlan, DateTime catalogEffectiveDate, PlanPhasePriceOverride[] resolvedOverride, InternalCallContext context);
 
     public List<CatalogOverridePhaseDefinitionModelDao> getOverriddenPlanPhases(final Long planDefRecordId, final InternalTenantContext context);
 
+    public List<CatalogOverrideUsageDefinitionModelDao> getOverriddenPhaseUsages(final Long phaseDefRecordId, final InternalTenantContext context);
+
+    public List<CatalogOverrideTierDefinitionModelDao> getOverriddenUsageTiers(final Long usageDefRecordId, final InternalTenantContext context);
+
+    public List<CatalogOverrideBlockDefinitionModelDao> getOverriddenTierBlocks(final Long tierDefRecordId, final InternalTenantContext context);
+
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
index 87061c9..19164aa 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseDefinitionSqlDao.java
@@ -42,7 +42,7 @@ public interface CatalogOverridePhaseDefinitionSqlDao extends Transactional<Cata
                                                                 @SmartBindBean final InternalTenantContext context);
 
     @SqlQuery
-    public CatalogOverridePhaseDefinitionModelDao getByAttributes(@Bind("parentPhaseName") String parentPhaseName,
+    public List<CatalogOverridePhaseDefinitionModelDao> getByAttributes(@Bind("parentPhaseName") String parentPhaseName,
                                                                   @Bind("currency") String currency,
                                                                   @Bind("fixedPrice") BigDecimal fixedPrice,
                                                                   @Bind("recurringPrice") BigDecimal recurringPrice,
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageModelDao.java
new file mode 100644
index 0000000..b4e8f7f
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageModelDao.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import org.joda.time.DateTime;
+
+public class CatalogOverridePhaseUsageModelDao {
+
+    private Short usageNumber;
+    private Long recordId;
+    private Long usageDefRecordId;
+    private Long targetPhaseDefRecordId;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public CatalogOverridePhaseUsageModelDao() {
+    }
+
+    public CatalogOverridePhaseUsageModelDao(Short usageNumber, Long usageDefRecordId, Long targetPhaseDefRecordId) {
+        this.usageNumber = usageNumber;
+        this.usageDefRecordId = usageDefRecordId;
+        this.targetPhaseDefRecordId = targetPhaseDefRecordId;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public Short getUsageNumber() {
+        return usageNumber;
+    }
+
+    public Long getUsageDefRecordId() {
+        return usageDefRecordId;
+    }
+
+    public Long getTargetPhaseDefRecordId() {
+        return targetPhaseDefRecordId;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public void setUsageNumber(Short usageNumber) {
+        this.usageNumber = usageNumber;
+    }
+
+    public void setUsageDefRecordId(Long usageDefRecordId) {
+        this.usageDefRecordId = usageDefRecordId;
+    }
+
+    public void setTargetPhaseDefRecordId(Long targetPhaseDefRecordId) {
+        this.targetPhaseDefRecordId = targetPhaseDefRecordId;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.java
new file mode 100644
index 0000000..5c63d82
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverridePhaseUsageSqlDao extends Transactional<CatalogOverridePhaseUsageSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverridePhaseUsageModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverridePhaseUsageModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                          @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<Long> getTargetPhaseDefinition(@PhaseUsageKeysCollectionBinder final Collection<String> concatUsageNumAndUsageDefRecordId,
+                                               @Bind("targetCount") final Integer targetCount,
+                                               @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockModelDao.java
new file mode 100644
index 0000000..8235a08
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockModelDao.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import org.joda.time.DateTime;
+
+public class CatalogOverrideTierBlockModelDao {
+    private Short blockNumber;
+    private Long recordId;
+    private Long blockDefRecordId;
+    private Long targetTierRecordId;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public CatalogOverrideTierBlockModelDao() {
+    }
+
+    public CatalogOverrideTierBlockModelDao(Short blockNumber, Long blockDefRecordId, Long targetTierRecordId) {
+        this.blockNumber = blockNumber;
+        this.blockDefRecordId = blockDefRecordId;
+        this.targetTierRecordId = targetTierRecordId;
+    }
+
+    public Short getBlockNumber() {
+        return blockNumber;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public Long getBlockDefRecordId() {
+        return blockDefRecordId;
+    }
+
+    public Long getTargetTierRecordId() {
+        return targetTierRecordId;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+
+    public void setBlockNumber(Short blockNumber) {
+        this.blockNumber = blockNumber;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public void setBlockDefRecordId(Long blockDefRecordId) {
+        this.blockDefRecordId = blockDefRecordId;
+    }
+
+    public void setTargetTierRecordId(Long targetTierRecordId) {
+        this.targetTierRecordId = targetTierRecordId;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.java
new file mode 100644
index 0000000..998cb87
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.util.Collection;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverrideTierBlockSqlDao extends Transactional<CatalogOverrideTierBlockSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverrideTierBlockModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverrideTierBlockModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                                @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getTargetTierDefinition(@TierBlockKeysCollectionBinder final Collection<String> concatBlockNumAndBlockDefRecordId,
+                                        @Bind("targetCount") final Integer targetCount,
+                                        @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionModelDao.java
new file mode 100644
index 0000000..27c758e
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionModelDao.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import org.joda.time.DateTime;
+
+import java.math.BigDecimal;
+
+public class CatalogOverrideTierDefinitionModelDao {
+
+    private Long recordId;
+    private String currency;
+    private BigDecimal fixedPrice;
+    private BigDecimal recurringPrice;
+    private DateTime effectiveDate;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public CatalogOverrideTierDefinitionModelDao() {
+    }
+
+    public CatalogOverrideTierDefinitionModelDao( String currency, BigDecimal fixedPrice, BigDecimal recurringPrice, DateTime effectiveDate) {
+        this.currency = currency;
+        this.fixedPrice = fixedPrice;
+        this.recurringPrice = recurringPrice;
+        this.effectiveDate = effectiveDate;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    public BigDecimal getFixedPrice() {
+        return fixedPrice;
+    }
+
+    public void setFixedPrice(BigDecimal fixedPrice) {
+        this.fixedPrice = fixedPrice;
+    }
+
+    public BigDecimal getRecurringPrice() {
+        return recurringPrice;
+    }
+
+    public void setRecurringPrice(BigDecimal recurringPrice) {
+        this.recurringPrice = recurringPrice;
+    }
+
+    public DateTime getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public void setEffectiveDate(DateTime effectiveDate) {
+        this.effectiveDate = effectiveDate;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.java
new file mode 100644
index 0000000..eecf646
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverrideTierDefinitionSqlDao extends Transactional<CatalogOverrideTierDefinitionSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverrideTierDefinitionModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverrideTierDefinitionModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                               @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<CatalogOverrideTierDefinitionModelDao> getOverriddenUsageTiers(@Bind("targetUsageDefRecordId") Long targetUsageDefRecordId,
+                                                                               @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionModelDao.java
new file mode 100644
index 0000000..df9c010
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionModelDao.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import org.joda.time.DateTime;
+
+import java.math.BigDecimal;
+
+public class CatalogOverrideUsageDefinitionModelDao {
+
+    private Long recordId;
+    private String parentUsageName;
+    private String parentUsageType;
+    private String currency;
+    private BigDecimal fixedPrice;
+    private BigDecimal recurringPrice;
+    private DateTime effectiveDate;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public CatalogOverrideUsageDefinitionModelDao() {
+    }
+
+    public CatalogOverrideUsageDefinitionModelDao(String parentUsageName, String parentUsageType, String currency, BigDecimal fixedPrice, BigDecimal recurringPrice, DateTime effectiveDate) {
+
+        this.parentUsageName = parentUsageName;
+        this.parentUsageType = parentUsageType;
+        this.currency = currency;
+        this.fixedPrice = fixedPrice;
+        this.recurringPrice = recurringPrice;
+        this.effectiveDate = effectiveDate;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public void setParentUsageName(String parentUsageName) {
+        this.parentUsageName = parentUsageName;
+    }
+
+    public void setParentUsageType(String parentUsageType) {
+        this.parentUsageType = parentUsageType;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    public void setFixedPrice(BigDecimal fixedPrice) {
+        this.fixedPrice = fixedPrice;
+    }
+
+    public void setRecurringPrice(BigDecimal recurringPrice) {
+        this.recurringPrice = recurringPrice;
+    }
+
+    public void setEffectiveDate(DateTime effectiveDate) {
+        this.effectiveDate = effectiveDate;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+
+    public String getParentUsageName() {
+        return parentUsageName;
+    }
+
+    public String getParentUsageType() {
+        return parentUsageType;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public BigDecimal getFixedPrice() {
+        return fixedPrice;
+    }
+
+    public BigDecimal getRecurringPrice() {
+        return recurringPrice;
+    }
+
+    public DateTime getEffectiveDate() {
+        return effectiveDate;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.java
new file mode 100644
index 0000000..a54e776
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverrideUsageDefinitionSqlDao extends Transactional<CatalogOverrideUsageDefinitionSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverrideUsageDefinitionModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverrideUsageDefinitionModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                               @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<CatalogOverrideUsageDefinitionModelDao> getOverriddenPhaseUsages(@Bind("targetPhaseDefRecordId") Long targetPhaseDefRecordId,
+                                                                                @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<CatalogOverrideUsageDefinitionModelDao> getByAttributes(@Bind("parentUsageName") String parentPhaseName,
+                                                                        @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
\ No newline at end of file
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierModelDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierModelDao.java
new file mode 100644
index 0000000..ec05e28
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierModelDao.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import org.joda.time.DateTime;
+
+public class CatalogOverrideUsageTierModelDao {
+
+    private Long recordId;
+    private Short tierNumber;
+    private Long tierDefRecordId;
+    private Long targetUsageDefRecordId;
+    private DateTime createdDate;
+    private String createdBy;
+    private Long tenantRecordId;
+
+    public CatalogOverrideUsageTierModelDao() {
+    }
+
+    public CatalogOverrideUsageTierModelDao(Short tierNumber, Long tierDefRecordId, Long targetUsageDefRecordId) {
+        this.tierNumber = tierNumber;
+        this.tierDefRecordId = tierDefRecordId;
+        this.targetUsageDefRecordId = targetUsageDefRecordId;
+    }
+
+    public Long getRecordId() { return recordId; }
+
+    public Short getTierNumber() {
+        return tierNumber;
+    }
+
+    public void setTierNumber(Short tierNumber) {
+        this.tierNumber = tierNumber;
+    }
+
+    public Long getTierDefRecordId() {
+        return tierDefRecordId;
+    }
+
+    public Long getTargetUsageDefRecordId() {
+        return targetUsageDefRecordId;
+    }
+
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    public void setRecordId(Long recordId) {
+        this.recordId = recordId;
+    }
+
+    public void setTierDefRecordId(Long tierDefRecordId) {
+        this.tierDefRecordId = tierDefRecordId;
+    }
+
+    public void setTargetUsageDefRecordId(Long targetUsageDefRecordId) {
+        this.targetUsageDefRecordId = targetUsageDefRecordId;
+    }
+
+    public void setCreatedDate(DateTime createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public void setTenantRecordId(Long tenantRecordId) {
+        this.tenantRecordId = tenantRecordId;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public Long getTenantRecordId() {
+        return tenantRecordId;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.java
new file mode 100644
index 0000000..7665047
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.killbill.commons.jdbi.binder.SmartBindBean;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+
+@EntitySqlDaoStringTemplate
+public interface CatalogOverrideUsageTierSqlDao extends Transactional<CatalogOverrideUsageTierSqlDao>, CloseMe {
+
+    @SqlUpdate
+    public void create(@SmartBindBean final CatalogOverrideUsageTierModelDao entity,
+                       @SmartBindBean final InternalCallContext context);
+
+    @SqlQuery
+    public CatalogOverrideUsageTierModelDao getByRecordId(@Bind("recordId") final Long recordId,
+                                                          @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public List<Long> getTargetUsageDefinition(@UsageTierKeysCollectionBinder final Collection<String> concatTierNumAndTierDefRecordId,
+                                               @Bind("targetCount") final Integer targetCount,
+                                               @SmartBindBean final InternalTenantContext context);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/DefaultCatalogOverrideDao.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/DefaultCatalogOverrideDao.java
index 8b9f31c..1173418 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/dao/DefaultCatalogOverrideDao.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/DefaultCatalogOverrideDao.java
@@ -23,7 +23,15 @@ import java.util.List;
 import org.joda.time.DateTime;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.Tier;
+import org.killbill.billing.catalog.api.TierPriceOverride;
+import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
+import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.catalog.api.UsagePriceOverride;
 import org.killbill.clock.Clock;
 import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
 import org.skife.jdbi.v2.DBI;
@@ -47,10 +55,16 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
         ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverridePlanDefinitionModelDao.class));
         ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverridePhaseDefinitionModelDao.class));
         ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverridePlanPhaseModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideBlockDefinitionModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideTierBlockModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideTierDefinitionModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideUsageDefinitionModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideUsageTierModelDao.class));
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverridePhaseUsageModelDao.class));
     }
 
     @Override
-    public CatalogOverridePlanDefinitionModelDao getOrCreateOverridePlanDefinition(final String parentPlanName, final DateTime catalogEffectiveDate, final PlanPhasePriceOverride[] resolvedOverride, final InternalCallContext context) {
+    public CatalogOverridePlanDefinitionModelDao getOrCreateOverridePlanDefinition(final Plan parentPlan, final DateTime catalogEffectiveDate, final PlanPhasePriceOverride[] resolvedOverride, final InternalCallContext context) {
 
         return dbi.inTransaction(new TransactionCallback<CatalogOverridePlanDefinitionModelDao>() {
             @Override
@@ -60,7 +74,8 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
                 for (int i = 0; i < resolvedOverride.length; i++) {
                     final PlanPhasePriceOverride curOverride = resolvedOverride[i];
                     if (curOverride != null) {
-                        final CatalogOverridePhaseDefinitionModelDao createdOverridePhaseDefinitionModelDao = getOrCreateOverridePhaseDefinitionFromTransaction(curOverride.getPhaseName(), catalogEffectiveDate, curOverride, handle, context);
+                        PlanPhase parentPlanPhase = parentPlan.getAllPhases()[i];
+                        final CatalogOverridePhaseDefinitionModelDao createdOverridePhaseDefinitionModelDao = getOrCreateOverridePhaseDefinitionFromTransaction(parentPlanPhase, curOverride.getPhaseName(),curOverride.getCurrency(), catalogEffectiveDate, curOverride, handle, context);
                         overridePhaseDefinitionModelDaos[i] = createdOverridePhaseDefinitionModelDao;
                     }
                 }
@@ -71,7 +86,7 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
                     return sqlDao.getByRecordId(targetPlanDefinitionRecordId, context);
                 }
 
-                final CatalogOverridePlanDefinitionModelDao inputPlanDef = new CatalogOverridePlanDefinitionModelDao(parentPlanName, true, catalogEffectiveDate);
+                final CatalogOverridePlanDefinitionModelDao inputPlanDef = new CatalogOverridePlanDefinitionModelDao(parentPlan.getName(), true, catalogEffectiveDate);
                 sqlDao.create(inputPlanDef, context);
                 final Long recordId = sqlDao.getLastInsertId();
                 final CatalogOverridePlanDefinitionModelDao resultPlanDef = sqlDao.getByRecordId(recordId, context);
@@ -86,17 +101,6 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
         });
     }
 
-    @Override
-    public List<CatalogOverridePhaseDefinitionModelDao> getOverriddenPlanPhases(final Long planDefRecordId, final InternalTenantContext context) {
-        return dbi.inTransaction(new TransactionCallback<List<CatalogOverridePhaseDefinitionModelDao>>() {
-            @Override
-            public List<CatalogOverridePhaseDefinitionModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
-                final CatalogOverridePhaseDefinitionSqlDao sqlDao = handle.attach(CatalogOverridePhaseDefinitionSqlDao.class);
-                return sqlDao.getOverriddenPlanPhases(planDefRecordId, context);
-            }
-        });
-    }
-
     private Long getOverridePlanDefinitionFromTransaction(final CatalogOverridePhaseDefinitionModelDao[] overridePhaseDefinitionModelDaos, final Handle inTransactionHandle, final InternalCallContext context) {
         final CatalogOverridePlanPhaseSqlDao sqlDao = inTransactionHandle.attach(CatalogOverridePlanPhaseSqlDao.class);
 
@@ -105,11 +109,7 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
             final CatalogOverridePhaseDefinitionModelDao cur = overridePhaseDefinitionModelDaos[i];
             if (cur != null) {
                 // Each key is the concatenation of the phase_number, phase_definition_record_id
-                final StringBuffer key = new StringBuffer();
-                key.append(i);
-                key.append(",");
-                key.append(cur.getRecordId());
-                keys.add(key.toString());
+                keys.add(getConcatenatedKey(i, cur.getRecordId()).toString());
             }
         }
         return keys.size() > 0 ? sqlDao.getTargetPlanDefinition(keys, keys.size(), context) : null;
@@ -121,16 +121,270 @@ public class DefaultCatalogOverrideDao implements CatalogOverrideDao {
         sqlDao.create(modelDao, context);
     }
 
-    private CatalogOverridePhaseDefinitionModelDao getOrCreateOverridePhaseDefinitionFromTransaction(final String parentPhaseName, final DateTime catalogEffectiveDate, final PlanPhasePriceOverride override, final Handle inTransactionHandle, final InternalCallContext context) {
+    private CatalogOverridePhaseDefinitionModelDao getOrCreateOverridePhaseDefinitionFromTransaction(final PlanPhase parentPlanPhase, final String parentPhaseName, final Currency currency, final DateTime catalogEffectiveDate, final PlanPhasePriceOverride override, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverridePhaseDefinitionSqlDao sqlDao = inTransactionHandle.attach(CatalogOverridePhaseDefinitionSqlDao.class);
+
+        if(override.getUsagePriceOverrides() == null || (override.getUsagePriceOverrides() != null && isUsageOverrideListHasOnlyNull(override.getUsagePriceOverrides()))) {
+            return getOrCreatePhaseDefinitionFromTransactionWithoutUsageOverrides(parentPhaseName, catalogEffectiveDate, override, inTransactionHandle, context);
+        }
+
+        final CatalogOverrideUsageDefinitionModelDao[] overrideUsageDefinitionModelDaos = new CatalogOverrideUsageDefinitionModelDao[override.getUsagePriceOverrides().size()];
+         List<UsagePriceOverride> resolvedUsageOverrides = override.getUsagePriceOverrides();
+          for (int i = 0; i < resolvedUsageOverrides.size(); i++) {
+            final UsagePriceOverride curOverride = resolvedUsageOverrides.get(i);
+             if (curOverride != null) {
+                Usage parentUsage = parentPlanPhase.getUsages()[i];
+                final CatalogOverrideUsageDefinitionModelDao createdOverrideUsageDefinitionModelDao = getOrCreateOverrideUsageDefinitionFromTransaction(parentUsage, currency, catalogEffectiveDate, curOverride, inTransactionHandle, context);
+                overrideUsageDefinitionModelDaos[i] = createdOverrideUsageDefinitionModelDao;
+             }
+          }
+
+        final List<Long> targetPhaseDefinitionRecordIds = getOverridePhaseDefinitionFromTransaction(overrideUsageDefinitionModelDaos, inTransactionHandle, context);
+        List<CatalogOverridePhaseDefinitionModelDao> results = sqlDao.getByAttributes(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(), context);
+
+        for(CatalogOverridePhaseDefinitionModelDao phase : results) {
+            if (targetPhaseDefinitionRecordIds != null && targetPhaseDefinitionRecordIds.contains(phase.getRecordId())) {
+                return phase;
+            }
+        }
+
+        final CatalogOverridePhaseDefinitionModelDao inputPhaseDef = new CatalogOverridePhaseDefinitionModelDao(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(),
+                catalogEffectiveDate);
+        sqlDao.create(inputPhaseDef, context);
+        final Long recordId = sqlDao.getLastInsertId();
+        final CatalogOverridePhaseDefinitionModelDao resultPhaseDef = sqlDao.getByRecordId(recordId, context);
+
+        for (short i = 0; i < overrideUsageDefinitionModelDaos.length; i++) {
+            if (overrideUsageDefinitionModelDaos[i] != null) {
+                createCatalogOverridePhaseUsageFromTransaction(i, overrideUsageDefinitionModelDaos[i], resultPhaseDef, inTransactionHandle, context);
+            }
+        }
+        return resultPhaseDef;
+    }
+
+    private CatalogOverridePhaseDefinitionModelDao getOrCreatePhaseDefinitionFromTransactionWithoutUsageOverrides(String parentPhaseName,final DateTime catalogEffectiveDate, final PlanPhasePriceOverride override, final Handle inTransactionHandle, final InternalCallContext context) {
+
         final CatalogOverridePhaseDefinitionSqlDao sqlDao = inTransactionHandle.attach(CatalogOverridePhaseDefinitionSqlDao.class);
-        CatalogOverridePhaseDefinitionModelDao result = sqlDao.getByAttributes(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(), context);
+        List<CatalogOverridePhaseDefinitionModelDao> resultPhases = sqlDao.getByAttributes(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(), context);
+        for(CatalogOverridePhaseDefinitionModelDao resultPhase : resultPhases) {
+            if (resultPhase != null && getOverriddenPhaseUsages(resultPhase.getRecordId(), context).size() == 0) {
+                return resultPhase;
+            }
+        }
+
+        final CatalogOverridePhaseDefinitionModelDao phaseDef = new CatalogOverridePhaseDefinitionModelDao(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(),
+                catalogEffectiveDate);
+        sqlDao.create(phaseDef, context);
+        final Long recordId = sqlDao.getLastInsertId();
+        return sqlDao.getByRecordId(recordId, context);
+    }
+
+    private List<Long> getOverridePhaseDefinitionFromTransaction(final CatalogOverrideUsageDefinitionModelDao[] overrideUsageDefinitionModelDaos, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverridePhaseUsageSqlDao sqlDao = inTransactionHandle.attach(CatalogOverridePhaseUsageSqlDao.class);
+
+        final List<String> keys = new ArrayList<String>();
+        for (int i = 0; i < overrideUsageDefinitionModelDaos.length; i++) {
+            final CatalogOverrideUsageDefinitionModelDao cur = overrideUsageDefinitionModelDaos[i];
+            // Each key is the concatenation of the usage_number, usage_definition_record_id
+            if (cur != null) {
+                keys.add(getConcatenatedKey(i, cur.getRecordId()).toString());
+            }
+        }
+        return keys.size() > 0 ? sqlDao.getTargetPhaseDefinition(keys, keys.size(), context) : null;
+    }
+
+    private void createCatalogOverridePhaseUsageFromTransaction(final short usageNum, final CatalogOverrideUsageDefinitionModelDao usageDef, final CatalogOverridePhaseDefinitionModelDao phaseDef, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverridePhaseUsageSqlDao sqlDao = inTransactionHandle.attach(CatalogOverridePhaseUsageSqlDao.class);
+        final CatalogOverridePhaseUsageModelDao modelDao = new CatalogOverridePhaseUsageModelDao(usageNum, usageDef.getRecordId(), phaseDef.getRecordId());
+        sqlDao.create(modelDao, context);
+    }
+
+    private CatalogOverrideUsageDefinitionModelDao getOrCreateOverrideUsageDefinitionFromTransaction(final Usage parentUsage, Currency currency, final DateTime catalogEffectiveDate, final UsagePriceOverride override, final Handle inTransactionHandle, final InternalCallContext context){
+
+        final List<TierPriceOverride> resolvedTierOverrides = override.getTierPriceOverrides();
+
+        final CatalogOverrideTierDefinitionModelDao[] overrideTierDefinitionModelDaos = new CatalogOverrideTierDefinitionModelDao[resolvedTierOverrides.size()];
+        for (int i = 0; i < resolvedTierOverrides.size(); i++) {
+            final TierPriceOverride curOverride = resolvedTierOverrides.get(i);
+            if (curOverride != null) {
+                Tier parentTier = parentUsage.getTiers()[i];
+                final CatalogOverrideTierDefinitionModelDao createdOverrideTierDefinitionModelDao = getOrCreateOverrideTierDefinitionFromTransaction(parentTier, curOverride, currency, catalogEffectiveDate, inTransactionHandle, context);
+                overrideTierDefinitionModelDaos[i] = createdOverrideTierDefinitionModelDao;
+            }
+        }
+
+        final CatalogOverrideUsageDefinitionSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideUsageDefinitionSqlDao.class);
+        final List<Long> targetUsageDefinitionRecordIds = getOverrideUsageDefinitionFromTransaction(overrideTierDefinitionModelDaos, inTransactionHandle, context);
+
+        List<CatalogOverrideUsageDefinitionModelDao> results = sqlDao.getByAttributes(parentUsage.getName(), context);
+
+        for(CatalogOverrideUsageDefinitionModelDao usage : results) {
+            if (targetUsageDefinitionRecordIds != null && targetUsageDefinitionRecordIds.contains(usage.getRecordId())) {
+                return usage;
+            }
+        }
+
+        final CatalogOverrideUsageDefinitionModelDao inputUsageDef = new CatalogOverrideUsageDefinitionModelDao(parentUsage.getName(), parentUsage.getUsageType().name(), currency.name(), null, null, catalogEffectiveDate);
+        sqlDao.create(inputUsageDef, context);
+        final Long recordId = sqlDao.getLastInsertId();
+        final CatalogOverrideUsageDefinitionModelDao resultUsageDef = sqlDao.getByRecordId(recordId, context);
+
+        for (short i = 0; i < overrideTierDefinitionModelDaos.length; i++) {
+            if (overrideTierDefinitionModelDaos[i] != null) {
+                createCatalogOverrideUsageTierFromTransaction(i, overrideTierDefinitionModelDaos[i], resultUsageDef, inTransactionHandle, context);
+            }
+        }
+        return resultUsageDef;
+    }
+
+    private List<Long> getOverrideUsageDefinitionFromTransaction(final CatalogOverrideTierDefinitionModelDao[] overrideTierDefinitionModelDaos, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverrideUsageTierSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideUsageTierSqlDao.class);
+
+        final List<String> keys = new ArrayList<String>();
+        for (int i = 0; i < overrideTierDefinitionModelDaos.length; i++) {
+            final CatalogOverrideTierDefinitionModelDao cur = overrideTierDefinitionModelDaos[i];
+            if (cur != null) {
+                // Each key is the concatenation of the tier_number, tier_definition_record_id
+                keys.add(getConcatenatedKey(i, cur.getRecordId()).toString());
+            }
+        }
+        return keys.size() > 0 ? sqlDao.getTargetUsageDefinition(keys, keys.size(), context) : null;
+    }
+
+    private void createCatalogOverrideUsageTierFromTransaction(final short tierNum, final CatalogOverrideTierDefinitionModelDao tierDef, final CatalogOverrideUsageDefinitionModelDao usageDef, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverrideUsageTierSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideUsageTierSqlDao.class);
+        final CatalogOverrideUsageTierModelDao modelDao = new CatalogOverrideUsageTierModelDao(tierNum, tierDef.getRecordId(), usageDef.getRecordId());
+        sqlDao.create(modelDao, context);
+    }
+
+    private CatalogOverrideTierDefinitionModelDao getOrCreateOverrideTierDefinitionFromTransaction(final Tier parentTier, final TierPriceOverride tierPriceOverride,Currency currency, final DateTime catalogEffectiveDate,  final Handle inTransactionHandle, final InternalCallContext context){
+
+        final List<TieredBlockPriceOverride> resolvedTierBlockOverrides =  tierPriceOverride.getTieredBlockPriceOverrides();
+
+        final CatalogOverrideBlockDefinitionModelDao[] overrideBlockDefinitionModelDaos = new CatalogOverrideBlockDefinitionModelDao[resolvedTierBlockOverrides.size()];
+        for (int i = 0; i < resolvedTierBlockOverrides.size(); i++) {
+            final TieredBlockPriceOverride curOverride = resolvedTierBlockOverrides.get(i);
+            if (curOverride != null) {
+                final CatalogOverrideBlockDefinitionModelDao createdOverrideBlockDefinitionModelDao = getOrCreateOverriddenBlockDefinitionFromTransaction(curOverride,catalogEffectiveDate, currency.name(), inTransactionHandle, context);
+                overrideBlockDefinitionModelDaos[i] = createdOverrideBlockDefinitionModelDao;
+            }
+        }
+
+        final CatalogOverrideTierDefinitionSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideTierDefinitionSqlDao.class);
+        final Long targetTierDefinitionRecordId = getOverrideTierDefinitionFromTransaction(overrideBlockDefinitionModelDaos, inTransactionHandle, context);
+        if (targetTierDefinitionRecordId != null) {
+            return sqlDao.getByRecordId(targetTierDefinitionRecordId, context);
+        }
+
+        final CatalogOverrideTierDefinitionModelDao inputTierDef = new CatalogOverrideTierDefinitionModelDao(currency.name(), null, null, catalogEffectiveDate);
+        sqlDao.create(inputTierDef, context);
+        final Long recordId = sqlDao.getLastInsertId();
+        final CatalogOverrideTierDefinitionModelDao resultTierDef = sqlDao.getByRecordId(recordId, context);
+
+        for (short i = 0; i < overrideBlockDefinitionModelDaos.length; i++) {
+            if (overrideBlockDefinitionModelDaos[i] != null) {
+                createCatalogOverrideTierBlockFromTransaction(i, overrideBlockDefinitionModelDaos[i], resultTierDef, inTransactionHandle, context);
+            }
+        }
+        return resultTierDef;
+    }
+
+    private void createCatalogOverrideTierBlockFromTransaction(final short blockNum, final CatalogOverrideBlockDefinitionModelDao blockDef, final CatalogOverrideTierDefinitionModelDao tierDef, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverrideTierBlockSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideTierBlockSqlDao.class);
+        final CatalogOverrideTierBlockModelDao modelDao = new CatalogOverrideTierBlockModelDao(blockNum, blockDef.getRecordId(), tierDef.getRecordId());
+        sqlDao.create(modelDao, context);
+    }
+
+    private Long getOverrideTierDefinitionFromTransaction(final CatalogOverrideBlockDefinitionModelDao[] overrideBlockDefinitionModelDaos, final Handle inTransactionHandle, final InternalCallContext context) {
+        final CatalogOverrideTierBlockSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideTierBlockSqlDao.class);
+
+        final List<String> keys = new ArrayList<String>();
+        for (int i = 0; i < overrideBlockDefinitionModelDaos.length; i++) {
+            final CatalogOverrideBlockDefinitionModelDao cur = overrideBlockDefinitionModelDaos[i];
+            if (cur != null) {
+                // Each key is the concatenation of the block_number, block_definition_record_id
+                keys.add(getConcatenatedKey(i, cur.getRecordId()).toString());
+            }
+        }
+        return keys.size() > 0 ? sqlDao.getTargetTierDefinition(keys, keys.size(), context) : null;
+    }
+
+    private CatalogOverrideBlockDefinitionModelDao getOrCreateOverriddenBlockDefinitionFromTransaction(TieredBlockPriceOverride tieredBlockPriceOverride,final DateTime catalogEffectiveDate, String currency, final Handle inTransactionHandle, final InternalCallContext context)
+    {
+        final CatalogOverrideBlockDefinitionSqlDao sqlDao = inTransactionHandle.attach(CatalogOverrideBlockDefinitionSqlDao.class);
+
+        CatalogOverrideBlockDefinitionModelDao result = sqlDao.getByAttributes(tieredBlockPriceOverride.getUnitName(),
+                currency, tieredBlockPriceOverride.getPrice(), tieredBlockPriceOverride.getMax(),
+                tieredBlockPriceOverride.getSize(),context);
         if (result == null) {
-            final CatalogOverridePhaseDefinitionModelDao phaseDef = new CatalogOverridePhaseDefinitionModelDao(parentPhaseName, override.getCurrency().name(), override.getFixedPrice(), override.getRecurringPrice(),
-                                                                                                               catalogEffectiveDate);
-            sqlDao.create(phaseDef, context);
+            final CatalogOverrideBlockDefinitionModelDao blockDef = new CatalogOverrideBlockDefinitionModelDao(tieredBlockPriceOverride.getUnitName(),currency, tieredBlockPriceOverride.getPrice(),
+                    tieredBlockPriceOverride.getSize(),tieredBlockPriceOverride.getMax(), catalogEffectiveDate);
+            sqlDao.create(blockDef, context);
             final Long recordId = sqlDao.getLastInsertId();
             result = sqlDao.getByRecordId(recordId, context);
         }
         return result;
     }
+
+    @Override
+    public List<CatalogOverridePhaseDefinitionModelDao> getOverriddenPlanPhases(final Long planDefRecordId, final InternalTenantContext context) {
+        return dbi.inTransaction(new TransactionCallback<List<CatalogOverridePhaseDefinitionModelDao>>() {
+            @Override
+            public List<CatalogOverridePhaseDefinitionModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final CatalogOverridePhaseDefinitionSqlDao sqlDao = handle.attach(CatalogOverridePhaseDefinitionSqlDao.class);
+                return sqlDao.getOverriddenPlanPhases(planDefRecordId, context);
+            }
+        });
+    }
+
+    @Override
+    public List<CatalogOverrideUsageDefinitionModelDao> getOverriddenPhaseUsages(final Long phaseDefRecordId, final InternalTenantContext context) {
+        return dbi.inTransaction(new TransactionCallback<List<CatalogOverrideUsageDefinitionModelDao>>() {
+            @Override
+            public List<CatalogOverrideUsageDefinitionModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final CatalogOverrideUsageDefinitionSqlDao sqlDao = handle.attach(CatalogOverrideUsageDefinitionSqlDao.class);
+                return sqlDao.getOverriddenPhaseUsages(phaseDefRecordId, context);
+            }
+        });
+    }
+
+    @Override
+    public List<CatalogOverrideTierDefinitionModelDao> getOverriddenUsageTiers(final Long usageDefRecordId, final InternalTenantContext context) {
+        return dbi.inTransaction(new TransactionCallback<List<CatalogOverrideTierDefinitionModelDao>>() {
+            @Override
+            public List<CatalogOverrideTierDefinitionModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final CatalogOverrideTierDefinitionSqlDao sqlDao = handle.attach(CatalogOverrideTierDefinitionSqlDao.class);
+                return sqlDao.getOverriddenUsageTiers(usageDefRecordId, context);
+            }
+        });
+    }
+
+    @Override
+    public List<CatalogOverrideBlockDefinitionModelDao> getOverriddenTierBlocks(final Long tierDefRecordId, final InternalTenantContext context) {
+        return dbi.inTransaction(new TransactionCallback<List<CatalogOverrideBlockDefinitionModelDao>>() {
+            @Override
+            public List<CatalogOverrideBlockDefinitionModelDao> inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final CatalogOverrideBlockDefinitionSqlDao sqlDao = handle.attach(CatalogOverrideBlockDefinitionSqlDao.class);
+                return sqlDao.getOverriddenTierBlocks(tierDefRecordId, context);
+            }
+        });
+    }
+
+
+    private boolean isUsageOverrideListHasOnlyNull(List<UsagePriceOverride> usagePriceOverrides) {
+        for (UsagePriceOverride override : usagePriceOverrides) {
+            if (override != null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private StringBuffer getConcatenatedKey(int index, Long recordId) {
+        final StringBuffer key = new StringBuffer();
+        key.append(index);
+        key.append(",");
+        key.append(recordId);
+        return key;
+    }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/PhaseUsageKeysCollectionBinder.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/PhaseUsageKeysCollectionBinder.java
new file mode 100644
index 0000000..8460ec8
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/PhaseUsageKeysCollectionBinder.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collection;
+
+import org.killbill.billing.catalog.dao.PhaseUsageKeysCollectionBinder.PhaseUsageKeysCollectionBinderFactory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+@BindingAnnotation(PhaseUsageKeysCollectionBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PhaseUsageKeysCollectionBinder {
+
+    public static class PhaseUsageKeysCollectionBinderFactory implements BinderFactory {
+
+        @Override
+        public Binder build(Annotation annotation) {
+            return new Binder<PhaseUsageKeysCollectionBinder, Collection<String>>() {
+
+                @Override
+                public void bind(SQLStatement<?> query, PhaseUsageKeysCollectionBinder bind, Collection<String> keys) {
+                    query.define("keys", keys);
+                    int idx = 0;
+                    for (String state : keys) {
+                        query.bind("key_" + idx, state);
+                        idx++;
+                    }
+                }
+            };
+        }
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/TierBlockKeysCollectionBinder.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/TierBlockKeysCollectionBinder.java
new file mode 100644
index 0000000..e84ab84
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/TierBlockKeysCollectionBinder.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collection;
+
+import org.killbill.billing.catalog.dao.TierBlockKeysCollectionBinder.TierBlockKeysCollectionBinderFactory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+@BindingAnnotation(TierBlockKeysCollectionBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface TierBlockKeysCollectionBinder {
+
+    public static class TierBlockKeysCollectionBinderFactory implements BinderFactory {
+
+        @Override
+        public Binder build(Annotation annotation) {
+            return new Binder<TierBlockKeysCollectionBinder, Collection<String>>() {
+
+                @Override
+                public void bind(SQLStatement<?> query, TierBlockKeysCollectionBinder bind, Collection<String> keys) {
+                    query.define("keys", keys);
+                    int idx = 0;
+                    for (String state : keys) {
+                        query.bind("key_" + idx, state);
+                        idx++;
+                    }
+                }
+            };
+        }
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/dao/UsageTierKeysCollectionBinder.java b/catalog/src/main/java/org/killbill/billing/catalog/dao/UsageTierKeysCollectionBinder.java
new file mode 100644
index 0000000..2a5edfb
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/dao/UsageTierKeysCollectionBinder.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collection;
+
+import org.killbill.billing.catalog.dao.UsageTierKeysCollectionBinder.UsageTierKeysCollectionBinderFactory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+@BindingAnnotation(UsageTierKeysCollectionBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface UsageTierKeysCollectionBinder {
+
+    public static class UsageTierKeysCollectionBinderFactory implements BinderFactory {
+
+        @Override
+        public Binder build(Annotation annotation) {
+            return new Binder<UsageTierKeysCollectionBinder, Collection<String>>() {
+
+                @Override
+                public void bind(SQLStatement<?> query, UsageTierKeysCollectionBinder bind, Collection<String> keys) {
+                    query.define("keys", keys);
+
+                    int idx = 0;
+                    for (String state : keys) {
+                        query.bind("key_" + idx, state);
+                        idx++;
+                    }
+                }
+            };
+        }
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
index 784e577..46bee2d 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlock.java
@@ -17,6 +17,8 @@
 
 package org.killbill.billing.catalog;
 
+import java.math.BigDecimal;
+
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
@@ -27,6 +29,7 @@ import org.killbill.billing.ErrorCode;
 import org.killbill.billing.catalog.api.Block;
 import org.killbill.billing.catalog.api.BlockType;
 import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.InternationalPrice;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.Unit;
@@ -93,6 +96,15 @@ public class DefaultBlock extends ValidatingConfig<StandaloneCatalog> implements
         return errors;
     }
 
+    public DefaultBlock() {
+    }
+
+    public DefaultBlock(final DefaultUnit unit, final Double size, final DefaultInternationalPrice prices, final BigDecimal overriddenPrice, Currency currency) {
+        this.unit = unit;
+        this.size = size;
+        this.prices = prices != null ? new DefaultInternationalPrice(prices, overriddenPrice, currency) : null;
+    }
+
     public DefaultBlock setType(final BlockType type) {
         this.type = type;
         return this;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlockPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlockPriceOverride.java
new file mode 100644
index 0000000..e33faf2
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultBlockPriceOverride.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog;
+
+import java.math.BigDecimal;
+
+import org.killbill.billing.catalog.api.BlockPriceOverride;
+
+public class DefaultBlockPriceOverride implements BlockPriceOverride {
+
+    private String unitName;
+
+    private Double size;
+
+    private BigDecimal price;
+
+    @Override
+    public String getUnitName() {
+        return unitName;
+    }
+
+    @Override
+    public Double getSize() {
+        return size;
+    }
+
+    @Override
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public DefaultBlockPriceOverride( String unitName, Double size, BigDecimal price) {
+        this.unitName = unitName;
+        this.size = size;
+        this.price = price;
+    }
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
index 10040ba..1514278 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultInternationalPrice.java
@@ -16,13 +16,14 @@
 
 package org.killbill.billing.catalog;
 
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
 import java.math.BigDecimal;
 import java.net.URI;
 import java.util.Arrays;
 
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
@@ -65,6 +66,18 @@ public class DefaultInternationalPrice extends ValidatingConfig<StandaloneCatalo
         }
     }
 
+    public DefaultInternationalPrice(final DefaultInternationalPrice in, final BigDecimal overriddenPrice, final Currency currency) {
+        this.prices = in.getPrices() != null ? new DefaultPrice[in.getPrices().length] : null;
+        for (int i = 0; i < in.getPrices().length; i++) {
+            final DefaultPrice curPrice = (DefaultPrice)  in.getPrices()[i];
+            if (curPrice.getCurrency().equals(currency)){
+                prices[i] = new DefaultPrice(overriddenPrice, currency);
+            } else {
+                prices[i] = curPrice;
+            }
+        }
+    }
+
     /* (non-Javadoc)
       * @see org.killbill.billing.catalog.IInternationalPrice#getPrice(org.killbill.billing.catalog.api.Currency)
       */
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 bf451af..6c6c47f 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhase.java
@@ -38,10 +38,14 @@ import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.Recurring;
 import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.catalog.api.UsagePriceOverride;
 import org.killbill.xmlloader.ValidatingConfig;
 import org.killbill.xmlloader.ValidationError;
 import org.killbill.xmlloader.ValidationErrors;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implements PlanPhase {
 
@@ -75,7 +79,19 @@ public class DefaultPlanPhase extends ValidatingConfig<StandaloneCatalog> implem
         this.recurring = override != null && override.getRecurringPrice() != null ? new DefaultRecurring((DefaultRecurring) in.getRecurring(), override) : (DefaultRecurring) in.getRecurring();
         this.usages = new DefaultUsage[in.getUsages().length];
         for (int i = 0; i < in.getUsages().length; i++) {
-            usages[i] = (DefaultUsage) in.getUsages()[i];
+            final Usage curUsage = in.getUsages()[i];
+            if(override != null && override.getUsagePriceOverrides()!= null) {
+                final UsagePriceOverride usagePriceOverride = Iterables.tryFind(override.getUsagePriceOverrides(), new Predicate<UsagePriceOverride>() {
+                 @Override
+                 public boolean apply(final UsagePriceOverride input) {
+                     return input !=null && input.getName().equals(curUsage.getName());
+                 }
+                 }).orNull();
+                usages[i] = (usagePriceOverride !=null) ? new DefaultUsage(in.getUsages()[i], usagePriceOverride, override.getCurrency()) : (DefaultUsage)curUsage;
+            }
+            else {
+                usages[i] = (DefaultUsage)curUsage;
+            }
         }
         this.plan = parentPlan;
     }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhasePriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhasePriceOverride.java
index 2a1ee1c..aca3021 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhasePriceOverride.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultPlanPhasePriceOverride.java
@@ -18,10 +18,12 @@
 package org.killbill.billing.catalog;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
+import org.killbill.billing.catalog.api.UsagePriceOverride;
 
 public class DefaultPlanPhasePriceOverride implements PlanPhasePriceOverride {
 
@@ -30,21 +32,24 @@ public class DefaultPlanPhasePriceOverride implements PlanPhasePriceOverride {
     private final Currency currency;
     private final BigDecimal fixedPrice;
     private final BigDecimal recurringPrice;
+    private final List<UsagePriceOverride> usagePriceOverrides;
 
-    public DefaultPlanPhasePriceOverride(final PlanPhaseSpecifier planPhaseSpecifier, final Currency currency, final BigDecimal fixedPrice, final BigDecimal recurringPrice) {
+    public DefaultPlanPhasePriceOverride(final PlanPhaseSpecifier planPhaseSpecifier, final Currency currency, final BigDecimal fixedPrice, final BigDecimal recurringPrice, final List<UsagePriceOverride> usagePriceOverrides) {
         this.phaseName = null;
         this.planPhaseSpecifier = planPhaseSpecifier;
         this.currency = currency;
         this.fixedPrice = fixedPrice;
         this.recurringPrice = recurringPrice;
+        this.usagePriceOverrides = usagePriceOverrides;
     }
 
-    public DefaultPlanPhasePriceOverride(final String phaseName, final Currency currency, final BigDecimal fixedPrice, final BigDecimal recurringPrice) {
+    public DefaultPlanPhasePriceOverride(final String phaseName, final Currency currency, final BigDecimal fixedPrice, final BigDecimal recurringPrice, List<UsagePriceOverride> usagePriceOverrides) {
         this.phaseName = phaseName;
         this.planPhaseSpecifier = null;
         this.currency = currency;
         this.fixedPrice = fixedPrice;
         this.recurringPrice = recurringPrice;
+        this.usagePriceOverrides = usagePriceOverrides;
     }
 
     @Override
@@ -71,4 +76,9 @@ public class DefaultPlanPhasePriceOverride implements PlanPhasePriceOverride {
     public BigDecimal getRecurringPrice() {
         return recurringPrice;
     }
+
+    @Override
+    public List<UsagePriceOverride> getUsagePriceOverrides() {
+        return usagePriceOverrides;
+    }
 }
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
index 1baf1a3..b5e6c49 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTier.java
@@ -25,14 +25,23 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 
 import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.InternationalPrice;
 import org.killbill.billing.catalog.api.PlanPhase;
 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.UsageType;
 import org.killbill.xmlloader.ValidatingConfig;
 import org.killbill.xmlloader.ValidationError;
 import org.killbill.xmlloader.ValidationErrors;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+
+
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultTier extends ValidatingConfig<StandaloneCatalog> implements Tier {
 
@@ -62,6 +71,31 @@ public class DefaultTier extends ValidatingConfig<StandaloneCatalog> implements 
         blocks = new DefaultTieredBlock[0];
     }
 
+    public DefaultTier(Tier in, TierPriceOverride override, Currency currency) {
+        this.limits = (DefaultLimit[])in.getLimits();
+        this.blocks = new DefaultTieredBlock[in.getTieredBlocks().length];
+
+        for (int i = 0; i < in.getTieredBlocks().length; i++) {
+            if(override != null && override.getTieredBlockPriceOverrides() != null) {
+                final TieredBlock curTieredBlock = in.getTieredBlocks()[i];
+                final TieredBlockPriceOverride overriddenTierBlock = Iterables.tryFind(override.getTieredBlockPriceOverrides(), new Predicate<TieredBlockPriceOverride>() {
+                    @Override
+                    public boolean apply(final TieredBlockPriceOverride input) {
+                        return (input != null && input.getUnitName().equals(curTieredBlock.getUnit().getName()) &&
+                                Double.compare(input.getSize(), curTieredBlock.getSize()) == 0 &&
+                                Double.compare(input.getMax(), curTieredBlock.getMax()) == 0);
+                    }
+
+                }).orNull();
+                blocks[i] = (overriddenTierBlock != null) ? new DefaultTieredBlock(in.getTieredBlocks()[i], overriddenTierBlock, currency) :
+                        (DefaultTieredBlock) in.getTieredBlocks()[i];
+            }
+            else {
+                blocks[i] = (DefaultTieredBlock) in.getTieredBlocks()[i];
+            }
+        }
+    }
+
     @Override
     public DefaultLimit[] getLimits() {
         return limits;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlock.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlock.java
index ae39968..aa661ab 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlock.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlock.java
@@ -21,7 +21,9 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 
 import org.killbill.billing.catalog.api.BlockType;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.TieredBlock;
+import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
 
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultTieredBlock extends DefaultBlock implements TieredBlock {
@@ -39,6 +41,14 @@ public class DefaultTieredBlock extends DefaultBlock implements TieredBlock {
         return this;
     }
 
+    public DefaultTieredBlock() {
+    }
+
+    public DefaultTieredBlock(TieredBlock in, TieredBlockPriceOverride override, Currency currency) {
+        super((DefaultUnit)in.getUnit(), in.getSize(),(DefaultInternationalPrice)in.getPrice(), override.getPrice(),currency);
+        this.max = in.getMax();
+    }
+
     @Override
     public BlockType getType() {
         return BlockType.TIERED;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlockPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlockPriceOverride.java
new file mode 100644
index 0000000..2f58425
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTieredBlockPriceOverride.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog;
+
+import java.math.BigDecimal;
+
+import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
+
+public class DefaultTieredBlockPriceOverride extends DefaultBlockPriceOverride implements TieredBlockPriceOverride {
+
+    private Double max;
+
+    @Override
+    public Double getMax() {
+        return max;
+    }
+
+    public DefaultTieredBlockPriceOverride(String unitName, Double size, BigDecimal price, Double max) {
+        super(unitName, size, price);
+        this.max = max;
+    }
+
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultTierPriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTierPriceOverride.java
new file mode 100644
index 0000000..6735918
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultTierPriceOverride.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog;
+
+import org.killbill.billing.catalog.api.TierPriceOverride;
+import org.killbill.billing.catalog.api.TieredBlockPriceOverride;
+
+import java.util.List;
+
+public class DefaultTierPriceOverride implements TierPriceOverride {
+
+    List<TieredBlockPriceOverride> tieredBlockPriceOverrides;
+
+    public DefaultTierPriceOverride(List<TieredBlockPriceOverride> tieredBlockPriceOverrides) {
+        this.tieredBlockPriceOverrides = tieredBlockPriceOverrides;
+    }
+
+    public List<TieredBlockPriceOverride> getTieredBlockPriceOverrides() {
+        return tieredBlockPriceOverrides;
+    }
+
+}
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
index 1c6daa8..570b18e 100644
--- a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsage.java
@@ -19,6 +19,7 @@ package org.killbill.billing.catalog;
 
 import java.net.URI;
 import java.util.Arrays;
+import java.util.List;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -30,16 +31,25 @@ import javax.xml.bind.annotation.XmlID;
 import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Block;
+import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.InternationalPrice;
 import org.killbill.billing.catalog.api.Limit;
 import org.killbill.billing.catalog.api.PlanPhase;
 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 org.killbill.billing.catalog.api.UsageType;
 import org.killbill.xmlloader.ValidatingConfig;
 import org.killbill.xmlloader.ValidationError;
 import org.killbill.xmlloader.ValidationErrors;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+
 @XmlAccessorType(XmlAccessType.NONE)
 public class DefaultUsage extends ValidatingConfig<StandaloneCatalog> implements Usage {
 
@@ -88,6 +98,49 @@ public class DefaultUsage extends ValidatingConfig<StandaloneCatalog> implements
         tiers = new DefaultTier[0];
     }
 
+    public DefaultUsage(final Usage in, UsagePriceOverride override, Currency currency) {
+              this.name = in.getName();
+              this.usageType = in.getUsageType();
+              this.billingPeriod = in.getBillingPeriod();
+              this.billingMode = in.getBillingMode();
+              this.limits = (DefaultLimit[]) in.getLimits();
+              this.blocks = (DefaultBlock[]) in.getBlocks();
+              this.tiers = new DefaultTier[in.getTiers().length];
+
+              for (int i = 0; i < in.getTiers().length; i++) {
+                  if(override != null && override.getTierPriceOverrides()!=null) {
+                      final TieredBlock[] curTieredBlocks = in.getTiers()[i].getTieredBlocks();
+
+                      final TierPriceOverride overriddenTier = Iterables.tryFind(override.getTierPriceOverrides(), new Predicate<TierPriceOverride>() {
+                          @Override
+                          public boolean apply(final TierPriceOverride input) {
+
+                            if(input !=null) {
+                              final List<TieredBlockPriceOverride> blockPriceOverrides = input.getTieredBlockPriceOverrides();
+                              for (TieredBlockPriceOverride blockDef : blockPriceOverrides) {
+                                 String unitName = blockDef.getUnitName();
+                                 Double max = blockDef.getMax();
+                                 Double size = blockDef.getSize();
+                                 for (TieredBlock curTieredBlock : curTieredBlocks) {
+                                     if (unitName.equals(curTieredBlock.getUnit().getName()) &&
+                                             Double.compare(size, curTieredBlock.getSize()) == 0 &&
+                                             Double.compare(max, curTieredBlock.getMax()) == 0) {
+                                         return true;
+                                     }
+                                 }
+                               }
+                            }
+                            return false;
+                          }
+                      }).orNull();
+                      tiers[i] = (overriddenTier != null) ? new DefaultTier(in.getTiers()[i], overriddenTier, currency) : (DefaultTier)in.getTiers()[i] ;
+                  }
+                  else {
+                      tiers[i] = (DefaultTier) in.getTiers()[i];
+                  }
+              }
+    }
+
     @Override
     public String getName() {
         return name;
diff --git a/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsagePriceOverride.java b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsagePriceOverride.java
new file mode 100644
index 0000000..d427c24
--- /dev/null
+++ b/catalog/src/main/java/org/killbill/billing/catalog/DefaultUsagePriceOverride.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog;
+
+import java.util.List;
+
+import org.killbill.billing.catalog.api.TierPriceOverride;
+import org.killbill.billing.catalog.api.UsagePriceOverride;
+import org.killbill.billing.catalog.api.UsageType;
+
+public class DefaultUsagePriceOverride implements UsagePriceOverride {
+
+    String name;
+    UsageType usageType;
+    List<TierPriceOverride> tierPriceOverrides;
+
+    public DefaultUsagePriceOverride(String name, UsageType usageType, List<TierPriceOverride> tierPriceOverrides) {
+        this.name = name;
+        this.usageType = usageType;
+        this.tierPriceOverrides = tierPriceOverrides;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public UsageType getUsageType() {
+        return usageType;
+    }
+
+    @Override
+    public List<TierPriceOverride> getTierPriceOverrides() {
+        return tierPriceOverrides;
+    }
+
+
+}
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 86b8739..2e8b0ee 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
@@ -18,6 +18,7 @@
 package org.killbill.billing.catalog.override;
 
 import java.util.List;
+import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.regex.Pattern;
 
@@ -30,12 +31,21 @@ import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.DefaultPlan;
 import org.killbill.billing.catalog.DefaultPlanPhase;
 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.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.StaticCatalog;
+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 org.killbill.billing.catalog.caching.OverriddenPlanCache;
 import org.killbill.billing.catalog.dao.CatalogOverrideDao;
 import org.killbill.billing.catalog.dao.CatalogOverridePlanDefinitionModelDao;
@@ -80,9 +90,15 @@ public class DefaultPriceOverride implements PriceOverride {
                     return false;
                 }
             }).orNull();
-            resolvedOverride[index++] = curOverride != null ?
-                                        new DefaultPlanPhasePriceOverride(curPhase.getName(), curOverride.getCurrency(), curOverride.getFixedPrice(), curOverride.getRecurringPrice()) :
-                                        null;
+
+            if(curOverride != null) {
+                List<UsagePriceOverride> resolvedUsageOverrides = getResolvedUsageOverrides(curPhase.getUsages(), curOverride.getUsagePriceOverrides());
+                resolvedOverride[index++] = new DefaultPlanPhasePriceOverride(curPhase.getName(), curOverride.getCurrency(), curOverride.getFixedPrice(),
+                        curOverride.getRecurringPrice(), resolvedUsageOverrides);
+            }
+            else {
+                resolvedOverride[index++] = null;
+            }
         }
 
         for (int i = 0; i < resolvedOverride.length; i++) {
@@ -104,11 +120,12 @@ public class DefaultPriceOverride implements PriceOverride {
 
         final String planName;
         if (context != null) {
-            final CatalogOverridePlanDefinitionModelDao overriddenPlan = overrideDao.getOrCreateOverridePlanDefinition(parentPlan.getName(), catalogEffectiveDate, resolvedOverride, context);
+            final CatalogOverridePlanDefinitionModelDao overriddenPlan = overrideDao.getOrCreateOverridePlanDefinition(parentPlan, catalogEffectiveDate, resolvedOverride, context);
             planName = new StringBuffer(parentPlan.getName()).append("-").append(overriddenPlan.getRecordId()).toString();
         } else {
             planName = new StringBuffer(parentPlan.getName()).append("-dryrun-").append(DRY_RUN_PLAN_IDX.incrementAndGet()).toString();
         }
+
         final DefaultPlan result = new DefaultPlan(planName, (DefaultPlan) parentPlan, resolvedOverride);
         if (context == null) {
             overriddenPlanCache.addDryRunPlan(planName, result);
@@ -116,6 +133,94 @@ public class DefaultPriceOverride implements PriceOverride {
         return result;
     }
 
+    public List<UsagePriceOverride> getResolvedUsageOverrides(Usage[] usages, List<UsagePriceOverride> usagePriceOverrides) throws CatalogApiException{
+        List<UsagePriceOverride> resolvedUsageOverrides = new ArrayList<UsagePriceOverride>();
+
+        for (final Usage curUsage : usages) {
+            final UsagePriceOverride curOverride = Iterables.tryFind(usagePriceOverrides, new Predicate<UsagePriceOverride>() {
+                @Override
+                public boolean apply(final UsagePriceOverride input) {
+                    return input.getName() != null && input.getName().equals(curUsage.getName());
+                }
+            }).orNull();
+              if(curOverride != null) {
+                  List<TierPriceOverride>  tierPriceOverrides = getResolvedTierOverrides(curUsage.getTiers(), curOverride.getTierPriceOverrides());
+                  resolvedUsageOverrides.add(new DefaultUsagePriceOverride(curUsage.getName(), curUsage.getUsageType(),tierPriceOverrides));
+              } else {
+                  resolvedUsageOverrides.add(null);
+              }
+        }
+
+        return resolvedUsageOverrides;
+    }
+
+    public List<TierPriceOverride> getResolvedTierOverrides(Tier[] tiers, List<TierPriceOverride> tierPriceOverrides) throws CatalogApiException{
+        List<TierPriceOverride> resolvedTierOverrides = new ArrayList<TierPriceOverride>();
+
+        for (final Tier curTier : tiers) {
+            final TierPriceOverride curOverride = Iterables.tryFind(tierPriceOverrides, new Predicate<TierPriceOverride>() {
+                @Override
+                public boolean apply(final TierPriceOverride input) {
+
+                    if (input.getTieredBlockPriceOverrides() != null) {
+                        for (TieredBlockPriceOverride blockPriceOverride : input.getTieredBlockPriceOverrides()) {
+                            String unitName = blockPriceOverride.getUnitName();
+                            Double max = blockPriceOverride.getMax();
+                            Double size = blockPriceOverride.getSize();
+
+                            for (int i = 0; i < curTier.getTieredBlocks().length; i++) {
+                                TieredBlock curTieredBlock = curTier.getTieredBlocks()[i];
+                                if (unitName.equals(curTieredBlock.getUnit().getName()) &&
+                                        Double.compare(size, curTieredBlock.getSize()) == 0 &&
+                                        Double.compare(max, curTieredBlock.getMax()) == 0) {
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                    return false;
+                }
+            }).orNull();
+
+            if(curOverride != null) {
+                List<TieredBlockPriceOverride> tieredBlockPriceOverrides = getResolvedTieredBlockPriceOverrides(curTier.getTieredBlocks(),
+                        curOverride.getTieredBlockPriceOverrides());
+                resolvedTierOverrides.add(new DefaultTierPriceOverride(tieredBlockPriceOverrides));
+            }
+            else {
+                resolvedTierOverrides.add(null);
+            }
+        }
+
+        return resolvedTierOverrides;
+    }
+
+    public List<TieredBlockPriceOverride> getResolvedTieredBlockPriceOverrides(TieredBlock[] tieredBlocks, List<TieredBlockPriceOverride> tieredBlockPriceOverrides) throws CatalogApiException {
+        List<TieredBlockPriceOverride> resolvedTieredBlockPriceOverrides = new ArrayList<TieredBlockPriceOverride>();
+
+        for (final TieredBlock curTieredBlock : tieredBlocks) {
+
+            final TieredBlockPriceOverride curOverride = Iterables.tryFind(tieredBlockPriceOverrides, new Predicate<TieredBlockPriceOverride>() {
+                @Override
+                public boolean apply(final TieredBlockPriceOverride input) {
+                    return input.getUnitName() != null && input.getSize() != null && input.getMax() != null &&
+                            (input.getUnitName().equals(curTieredBlock.getUnit().getName()) &&
+                             Double.compare(input.getSize(), curTieredBlock.getSize()) == 0 &&
+                             Double.compare(input.getMax(), curTieredBlock.getMax()) == 0);
+                }
+            }).orNull();
+
+            if(curOverride != null) {
+                resolvedTieredBlockPriceOverrides.add(new DefaultTieredBlockPriceOverride(curTieredBlock.getUnit().getName(), curOverride.getSize(), curOverride.getPrice(), curOverride.getMax())) ;
+            }
+            else {
+                resolvedTieredBlockPriceOverrides.add(null);
+            }
+        }
+        return resolvedTieredBlockPriceOverrides;
+    }
+
+
     @Override
     public DefaultPlan getOverriddenPlan(final String planName, final StaticCatalog catalog, final InternalTenantContext context) throws CatalogApiException {
         return overriddenPlanCache.getOverriddenPlan(planName, catalog, context);
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.sql.stg
new file mode 100644
index 0000000..217209a
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideBlockDefinitionSqlDao.sql.stg
@@ -0,0 +1,81 @@
+group CatalogOverrideBlockDefinitionSqlDao;
+
+tableName() ::= "catalog_override_block_definition"
+
+tableFields(prefix) ::= <<
+  <prefix>parent_unit_name
+, <prefix>size
+, <prefix>max
+, <prefix>currency
+, <prefix>price
+, <prefix>effective_date
+, <prefix>created_date
+, <prefix>created_by
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :parentUnitName
+, :size
+, :max
+, :currency
+, :price
+, :effectiveDate
+, :createdDate
+, :createdBy
+, :tenantRecordId
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()> (
+<tableFields()>
+)
+values (
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from <tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getByAttributes() ::= <<
+select <allTableFields()>
+from <tableName()>
+where parent_unit_name = :parentUnitName
+and currency = :currency
+and price = :price
+and max = :max
+and size = :size;
+>>
+
+getOverriddenTierBlocks() ::= <<
+select <allTableFields("bdef.")>
+from <tableName()> bdef
+join catalog_override_tier_block tb
+on bdef.record_id = tb.block_def_record_id
+where
+tb.target_tier_def_record_id = :targetTierDefRecordId
+and tb.tenant_record_id = :tenantRecordId
+;
+>>
+
+getLastInsertId() ::= <<
+select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.sql.stg
new file mode 100644
index 0000000..127e89b
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverridePhaseUsageSqlDao.sql.stg
@@ -0,0 +1,73 @@
+group CatalogOverridePhaseUsageSqlDao;
+
+tableName() ::= "catalog_override_phase_usage"
+
+tableFields(prefix) ::= <<
+  <prefix>usage_number
+, <prefix>usage_def_record_id
+, <prefix>target_phase_def_record_id
+, <prefix>created_date
+, <prefix>created_by
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :usageNumber
+, :usageDefRecordId
+, :targetPhaseDefRecordId
+, :createdDate
+, :createdBy
+, :tenantRecordId
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()> (
+<tableFields()>
+)
+values (
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from
+<tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getTargetPhaseDefinition(keys) ::= <<
+select
+target_phase_def_record_id
+from (select
+      target_phase_def_record_id
+      , count(*) count
+      from
+      <tableName()>
+      where
+      concat_ws(',', usage_number, usage_def_record_id) in (<keys: {key | :key_<i0>}; separator="," >)
+      and tenant_record_id = :tenantRecordId
+      group by target_phase_def_record_id) tmp
+where
+1=1
+and tmp.count = :targetCount
+;
+>>
+
+getLastInsertId() ::= <<
+select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.sql.stg
new file mode 100644
index 0000000..34e52da
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierBlockSqlDao.sql.stg
@@ -0,0 +1,73 @@
+group CatalogOverrideTierBlockSqlDao;
+
+tableName() ::= "catalog_override_tier_block"
+
+tableFields(prefix) ::= <<
+  <prefix>block_number
+, <prefix>block_def_record_id
+, <prefix>target_tier_def_record_id
+, <prefix>created_date
+, <prefix>created_by
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :blockNumber
+, :blockDefRecordId
+, :targetTierRecordId
+, :createdDate
+, :createdBy
+, :tenantRecordId
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()> (
+<tableFields()>
+)
+values (
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from
+<tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getTargetTierDefinition(keys) ::= <<
+select
+target_tier_def_record_id
+from (select
+      target_tier_def_record_id
+      , count(*) count
+      from
+      <tableName()>
+      where
+      concat_ws(',', block_number, block_def_record_id) in (<keys: {key | :key_<i0>}; separator="," >)
+      and tenant_record_id = :tenantRecordId
+      group by target_tier_def_record_id) tmp
+where
+1=1
+and tmp.count = :targetCount
+;
+>>
+
+getLastInsertId() ::= <<
+select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.sql.stg
new file mode 100644
index 0000000..dbf1b54
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideTierDefinitionSqlDao.sql.stg
@@ -0,0 +1,67 @@
+group CatalogOverrideTierDefinitionSqlDao;
+
+tableName() ::= "catalog_override_tier_definition"
+
+tableFields(prefix) ::= <<
+  <prefix>fixed_price
+, <prefix>recurring_price
+, <prefix>effective_date
+, <prefix>created_date
+, <prefix>created_by
+, <prefix>currency
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :fixedPrice
+, :recurringPrice
+, :effectiveDate
+, :createdDate
+, :createdBy
+, :currency
+, :tenantRecordId
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()> (
+<tableFields()>
+)
+values (
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from <tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getOverriddenUsageTiers() ::= <<
+select <allTableFields("tdef.")>
+from <tableName()> tdef
+join catalog_override_usage_tier ut
+on tdef.record_id = ut.tier_def_record_id
+where
+ut.target_usage_def_record_id = :targetUsageDefRecordId
+and ut.tenant_record_id = :tenantRecordId
+;
+>>
+
+getLastInsertId() ::= <<
+    select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.sql.stg
new file mode 100644
index 0000000..9455c49
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageDefinitionSqlDao.sql.stg
@@ -0,0 +1,83 @@
+group CatalogOverrideUsageDefinitionSqlDao;
+
+tableName() ::= "catalog_override_usage_definition"
+
+tableFields(prefix) ::= <<
+  <prefix>parent_usage_name
+, <prefix>type
+, <prefix>fixed_price
+, <prefix>recurring_price
+, <prefix>effective_date
+, <prefix>currency
+, <prefix>created_by
+, <prefix>created_date
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+
+tableValues() ::= <<
+  :parentUsageName
+, :parentUsageType
+, :fixedPrice
+, :recurringPrice
+, :effectiveDate
+, :currency
+, :createdBy
+, :createdDate
+, :tenantRecordId
+>>
+
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()>(
+<tableFields()>
+)
+values(
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from <tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getByAttributes() ::= <<
+select <allTableFields()>
+from <tableName()>
+where parent_usage_name = :parentUsageName
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getOverriddenPhaseUsages() ::= <<
+select <allTableFields("udef.")>
+from <tableName()> udef
+join catalog_override_phase_usage pu
+on udef.record_id = pu.usage_def_record_id
+where
+pu.target_phase_def_record_id = :targetPhaseDefRecordId
+and pu.tenant_record_id = :tenantRecordId
+order by pu.usage_number asc
+;
+>>
+
+
+getLastInsertId() ::= <<
+    select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.sql.stg b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.sql.stg
new file mode 100644
index 0000000..18aa401
--- /dev/null
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/dao/CatalogOverrideUsageTierSqlDao.sql.stg
@@ -0,0 +1,73 @@
+group CatalogOverrideUsageTierSqlDao;
+
+tableName() ::= "catalog_override_usage_tier"
+
+tableFields(prefix) ::= <<
+  <prefix>tier_number
+, <prefix>tier_def_record_id
+, <prefix>target_usage_def_record_id
+, <prefix>created_date
+, <prefix>created_by
+, <prefix>tenant_record_id
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :tierNumber
+, :tierDefRecordId
+, :targetUsageDefRecordId
+, :createdDate
+, :createdBy
+, :tenantRecordId
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+create() ::= <<
+insert into <tableName()> (
+<tableFields()>
+)
+values (
+<tableValues()>
+)
+;
+>>
+
+getByRecordId() ::= <<
+select <allTableFields()>
+from
+<tableName()>
+where record_id = :recordId
+and tenant_record_id = :tenantRecordId
+;
+>>
+
+getTargetUsageDefinition(keys) ::= <<
+select
+target_usage_def_record_id
+from (select
+      target_usage_def_record_id
+      , count(*) count
+      from
+      <tableName()>
+      where
+      concat_ws(',', tier_number, tier_def_record_id) in (<keys: {key | :key_<i0>}; separator="," >)
+      and tenant_record_id = :tenantRecordId
+      group by target_usage_def_record_id) tmp
+where
+1=1
+and tmp.count = :targetCount
+;
+>>
+
+getLastInsertId() ::= <<
+select LAST_INSERT_ID();
+>>
+
diff --git a/catalog/src/main/resources/org/killbill/billing/catalog/ddl.sql b/catalog/src/main/resources/org/killbill/billing/catalog/ddl.sql
index fce5967..0bbd08d 100644
--- a/catalog/src/main/resources/org/killbill/billing/catalog/ddl.sql
+++ b/catalog/src/main/resources/org/killbill/billing/catalog/ddl.sql
@@ -41,3 +41,99 @@ CREATE TABLE catalog_override_plan_phase (
     PRIMARY KEY(record_id)
 ) /*! CHARACTER SET utf8 COLLATE utf8_bin */;
 CREATE INDEX catalog_override_plan_phase_idx ON catalog_override_plan_phase(tenant_record_id, phase_number, phase_def_record_id);
+
+DROP TABLE IF EXISTS catalog_override_usage_definition;
+create table catalog_override_usage_definition
+(
+record_id serial unique,
+parent_usage_name varchar(255) NOT NULL,
+type varchar(255) NOT NULL,
+fixed_price decimal(15,9) NULL,
+recurring_price decimal(15,9) NULL,
+currency varchar(3) NOT NULL,
+effective_date datetime NOT NULL,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ not null default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_usage_definition_idx ON catalog_override_usage_definition(tenant_record_id, parent_usage_name, currency);
+
+
+DROP TABLE IF EXISTS catalog_override_tier_definition;
+create table catalog_override_tier_definition
+(
+record_id serial unique,
+fixed_price decimal(15,9) NULL,
+recurring_price decimal(15,9) NULL,
+currency varchar(3) NOT NULL,
+effective_date datetime NOT NULL,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ not null default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_tier_definition_idx ON catalog_override_usage_definition(tenant_record_id, currency);
+
+DROP TABLE IF EXISTS catalog_override_block_definition;
+create table catalog_override_block_definition
+(
+record_id serial unique,
+parent_unit_name varchar(255) NOT NULL,
+size double NOT NULL,
+max double NULL,
+currency varchar(3) NOT NULL,
+price decimal(15,9) NOT NULL,
+effective_date datetime NOT NULL,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ not null default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_block_definition_idx ON catalog_override_block_definition(tenant_record_id, parent_unit_name, currency);
+
+
+DROP TABLE IF EXISTS catalog_override_phase_usage;
+create table catalog_override_phase_usage
+(
+record_id serial unique,
+usage_number smallint(5) unsigned,
+usage_def_record_id  bigint /*! unsigned */ not null,
+target_phase_def_record_id bigint /*! unsigned */ not null,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ not null default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_phase_usage_idx ON catalog_override_phase_usage(tenant_record_id, usage_number, usage_def_record_id);
+
+DROP TABLE IF EXISTS catalog_override_usage_tier;
+create table catalog_override_usage_tier
+(
+record_id serial unique,
+tier_number smallint(5) unsigned,
+tier_def_record_id bigint /*! unsigned */ not null,
+target_usage_def_record_id bigint /*! unsigned */ not null,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ not null default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_usage_tier_idx ON catalog_override_usage_tier(tenant_record_id, tier_number, tier_def_record_id);
+
+
+DROP TABLE IF EXISTS catalog_override_tier_block;
+create table catalog_override_tier_block
+(
+record_id serial unique,
+block_number smallint(5) unsigned,
+block_def_record_id bigint /*! unsigned */ not null,
+target_tier_def_record_id bigint /*! unsigned */ not null,
+created_date datetime NOT NULL,
+created_by varchar(50) NOT NULL,
+tenant_record_id bigint /*! unsigned */ NOT NULL default 0,
+PRIMARY KEY(record_id)
+);
+CREATE INDEX catalog_override_tier_block_idx ON catalog_override_tier_block(tenant_record_id, block_number, block_def_record_id);
+
+
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideBlockDefinitionSqlDao.java b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideBlockDefinitionSqlDao.java
new file mode 100644
index 0000000..591a6ef
--- /dev/null
+++ b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideBlockDefinitionSqlDao.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.catalog.dao;
+
+import java.math.BigDecimal;
+
+import org.killbill.billing.catalog.CatalogTestSuiteWithEmbeddedDB;
+import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+public class TestCatalogOverrideBlockDefinitionSqlDao extends CatalogTestSuiteWithEmbeddedDB {
+
+    @BeforeClass(groups = "slow")
+    public void beforeClass() throws Exception {
+        super.beforeClass();
+        ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(CatalogOverrideBlockDefinitionModelDao.class));
+    }
+
+    @Test(groups = "slow")
+    public void testBasic() throws Exception {
+
+        final CatalogOverrideBlockDefinitionModelDao obj1 = new CatalogOverrideBlockDefinitionModelDao("p1","USD" ,BigDecimal.ONE ,1 ,1 , clock.getUTCNow());
+
+        performTestInTransaction(new WithCatalogOverrideBlockDefinitionSqlDaoTransaction<Void>() {
+            @Override
+            public Void doTransaction(final CatalogOverrideBlockDefinitionSqlDao sqlDao) {
+                sqlDao.create(obj1, internalCallContext);
+                final Long lastInserted = sqlDao.getLastInsertId();
+
+                final CatalogOverrideBlockDefinitionModelDao rehydrated = sqlDao.getByRecordId(lastInserted, internalCallContext);
+                assertEquals(rehydrated.getParentUnitName(), obj1.getParentUnitName());
+                assertEquals(rehydrated.getCurrency().compareTo(obj1.getCurrency()), 0);
+                assertEquals(rehydrated.getPrice().compareTo(obj1.getPrice()), 0);
+                assertEquals(rehydrated.getSize(), obj1.getSize());
+                assertEquals(rehydrated.getMax(), obj1.getMax());
+                return null;
+            }
+        });
+    }
+
+    @Test(groups = "slow")
+    public void testGetByAttributes() throws Exception {
+
+        final CatalogOverrideBlockDefinitionModelDao objWithNoNullPrice = new CatalogOverrideBlockDefinitionModelDao("p2", "USD", BigDecimal.ONE, 1, 5, clock.getUTCNow());
+
+        performTestInTransaction(new WithCatalogOverrideBlockDefinitionSqlDaoTransaction<Void>() {
+            @Override
+            public Void doTransaction(final CatalogOverrideBlockDefinitionSqlDao sqlDao) {
+                sqlDao.create(objWithNoNullPrice, internalCallContext);
+                final Long lastInserted = sqlDao.getLastInsertId();
+                checkRehydrated(objWithNoNullPrice, sqlDao);
+
+                return null;
+            }
+
+            private void checkRehydrated(final CatalogOverrideBlockDefinitionModelDao obj, final CatalogOverrideBlockDefinitionSqlDao sqlDao) {
+                final CatalogOverrideBlockDefinitionModelDao rehydrated = sqlDao.getByAttributes(obj.getParentUnitName(), obj.getCurrency(), obj.getPrice(), obj.getSize(),obj.getMax(), internalCallContext);
+               /* assertEquals(rehydrated.getParentUnitName(), obj.getParentUnitName());
+                assertEquals(rehydrated.getCurrency(), obj.getCurrency());
+                assertEquals(rehydrated.getPrice(), obj.getPrice());
+                assertEquals(rehydrated.getSize(), obj.getSize());
+                assertEquals(rehydrated.getMax(), obj.getMax()); */
+            }
+        });
+    }
+
+  private interface WithCatalogOverrideBlockDefinitionSqlDaoTransaction<T> {
+
+        public <T> T doTransaction(final CatalogOverrideBlockDefinitionSqlDao sqlDao);
+    }
+
+
+
+    private <T> T performTestInTransaction(final WithCatalogOverrideBlockDefinitionSqlDaoTransaction<T> callback) {
+        return dbi.inTransaction(new TransactionCallback<T>() {
+            @Override
+            public T inTransaction(final Handle handle, final TransactionStatus status) throws Exception {
+                final CatalogOverrideBlockDefinitionSqlDao sqlDao = handle.attach(CatalogOverrideBlockDefinitionSqlDao.class);
+                return callback.doTransaction(sqlDao);
+            }
+        });
+    }
+
+}
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideDao.java b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideDao.java
index cbff820..39d6c3f 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideDao.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverrideDao.java
@@ -45,8 +45,8 @@ public class TestCatalogOverrideDao extends CatalogTestSuiteWithEmbeddedDB {
 
         final PlanPhasePriceOverride[] resolvedOverrides = new PlanPhasePriceOverride[plan.getAllPhases().length];
         resolvedOverrides[0] = null;
-        resolvedOverrides[1] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, new BigDecimal("128.76"));
-        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan.getName(), new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
+        resolvedOverrides[1] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, new BigDecimal("128.76"), null);
+        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan, new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
         assertEquals(newPlan.getParentPlanName(), "standard-monthly");
         assertTrue(newPlan.getIsActive());
     }
@@ -58,10 +58,11 @@ public class TestCatalogOverrideDao extends CatalogTestSuiteWithEmbeddedDB {
         final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
 
         final PlanPhasePriceOverride[] resolvedOverrides = new PlanPhasePriceOverride[plan.getAllPhases().length];
-        resolvedOverrides[0] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.TEN, null);
+        resolvedOverrides[0] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.TEN, null, null);
         resolvedOverrides[1] = null;
-        resolvedOverrides[2] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, new BigDecimal("348.64"));
-        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan.getName(), new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
+        resolvedOverrides[2] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, null, new BigDecimal("348.64"), null);
+        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan, new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
+
         assertEquals(newPlan.getParentPlanName(), "discount-standard-monthly");
         assertTrue(newPlan.getIsActive());
 
@@ -76,11 +77,11 @@ public class TestCatalogOverrideDao extends CatalogTestSuiteWithEmbeddedDB {
         final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
 
         final PlanPhasePriceOverride[] resolvedOverrides = new PlanPhasePriceOverride[plan.getAllPhases().length];
-        resolvedOverrides[0] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.TEN, BigDecimal.ONE);
-        resolvedOverrides[1] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[1].getName(), Currency.USD, BigDecimal.ONE, BigDecimal.TEN);
-        resolvedOverrides[2] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, BigDecimal.ZERO, new BigDecimal("348.64"));
+        resolvedOverrides[0] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.TEN, BigDecimal.ONE, null);
+        resolvedOverrides[1] = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[1].getName(), Currency.USD, BigDecimal.ONE, BigDecimal.TEN, null);
+        resolvedOverrides[2] = new DefaultPlanPhasePriceOverride(plan.getFinalPhase().getName(), Currency.USD, BigDecimal.ZERO, new BigDecimal("348.64"), null);
 
-        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan.getName(), new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
+        final CatalogOverridePlanDefinitionModelDao newPlan = catalogOverrideDao.getOrCreateOverridePlanDefinition(plan, new DateTime(catalog.getEffectiveDate()), resolvedOverrides, internalCallContext);
 
         final List<CatalogOverridePhaseDefinitionModelDao> phases = catalogOverrideDao.getOverriddenPlanPhases(newPlan.getRecordId(), internalCallContext);
         assertEquals(phases.size(), 3);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverridePhaseDefinitionSqlDao.java b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverridePhaseDefinitionSqlDao.java
index aa2dc48..6090a65 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverridePhaseDefinitionSqlDao.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/dao/TestCatalogOverridePhaseDefinitionSqlDao.java
@@ -103,7 +103,7 @@ public class TestCatalogOverridePhaseDefinitionSqlDao extends CatalogTestSuiteWi
             }
 
             private void checkRehydrated(final CatalogOverridePhaseDefinitionModelDao obj, final CatalogOverridePhaseDefinitionSqlDao sqlDao) {
-                final CatalogOverridePhaseDefinitionModelDao rehydrated = sqlDao.getByAttributes(obj.getParentPhaseName(), obj.getCurrency(), obj.getFixedPrice(), obj.getRecurringPrice(), internalCallContext);
+                final CatalogOverridePhaseDefinitionModelDao rehydrated = sqlDao.getByAttributes(obj.getParentPhaseName(), obj.getCurrency(), obj.getFixedPrice(), obj.getRecurringPrice(), internalCallContext).get(0);
                 assertEquals(rehydrated.getParentPhaseName(), obj.getParentPhaseName());
                 if (obj.getFixedPrice() != null) {
                     assertEquals(rehydrated.getFixedPrice().compareTo(obj.getFixedPrice()), 0);
diff --git a/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java b/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
index 858dde8..325b7a2 100644
--- a/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
+++ b/catalog/src/test/java/org/killbill/billing/catalog/TestDefaultPriceOverride.java
@@ -51,9 +51,9 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
         final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.ONE, null);
+        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.ONE, null,null);
         overrides.add(phase1);
-        final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"));
+        final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"),null);
         overrides.add(phase3);
 
         final DefaultPlan overriddenPlan = priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
@@ -104,7 +104,7 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
         final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, null, BigDecimal.ONE);
+        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, null, BigDecimal.ONE,null);
         overrides.add(phase1);
 
         priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
@@ -118,9 +118,9 @@ public class TestDefaultPriceOverride extends CatalogTestSuiteWithEmbeddedDB {
         final Plan plan = catalog.findCurrentPlan("discount-standard-monthly");
 
         final List<PlanPhasePriceOverride> overrides = new ArrayList<PlanPhasePriceOverride>();
-        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.ONE, null);
+        final PlanPhasePriceOverride phase1 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[0].getName(), Currency.USD, BigDecimal.ONE, null, null);
         overrides.add(phase1);
-        final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"));
+        final PlanPhasePriceOverride phase3 = new DefaultPlanPhasePriceOverride(plan.getAllPhases()[2].getName(), Currency.USD, null, new BigDecimal("142.41"),null);
         overrides.add(phase3);
 
         final DefaultPlan overriddenPlanCreated = priceOverride.getOrCreateOverriddenPlan(plan, new DateTime(catalog.getEffectiveDate()), overrides, internalCallContext);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java
new file mode 100644
index 0000000..e24a727
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/BlockPriceOverrideJson.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.json;
+
+import java.math.BigDecimal;
+
+import javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class BlockPriceOverrideJson {
+
+    private String unitName;
+
+    private Double size;
+
+    private BigDecimal price;
+
+    private Double max;
+
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public Double getSize() {
+        return size;
+    }
+
+    public String getUnitName() {
+        return unitName;
+    }
+
+    public Double getMax() {
+        return max;
+    }
+
+    @JsonCreator
+    public BlockPriceOverrideJson(@Nullable @JsonProperty("unitName") final String unitName,
+                                  @Nullable @JsonProperty("size") final Double size,
+                                  @Nullable @JsonProperty("price") final BigDecimal price,
+                                  @Nullable @JsonProperty("max") final Double max) {
+        this.unitName = unitName;
+        this.size = size;
+        this.price = price;
+        this.max = max;
+    }
+
+    @Override
+    public String toString() {
+        return "BlockPriceOverrideJson{" +
+              "unitName='" + unitName + '\'' +
+                ",size=" + size +
+                ",price=" + price +
+                ",max=" + max +
+                '}';
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof BlockPriceOverrideJson)) {
+            return false;
+        }
+
+        final BlockPriceOverrideJson that = (BlockPriceOverrideJson) o;
+
+
+        if (unitName != null ? !unitName.equals(that.unitName) : that.unitName != null) {
+            return false;
+        }
+        if (size != null ? size.compareTo(that.size) != 0 : that.size != null) {
+            return false;
+        }
+
+        if (price != null ? price.compareTo(that.price) != 0 : that.price != null) {
+            return false;
+        }
+
+        if (max != null ? max.compareTo(that.max) != 0 : that.max != null) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
index d83acaa..379536e 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/PhasePriceOverrideJson.java
@@ -18,16 +18,28 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
+import java.util.LinkedList;
 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;
@@ -41,16 +53,51 @@ public class PhasePriceOverrideJson {
     private final String phaseType;
     private final BigDecimal fixedPrice;
     private final BigDecimal recurringPrice;
+    private final List<UsagePriceOverrideJson> usagePriceOverrides;
 
     @JsonCreator
     public PhasePriceOverrideJson(@JsonProperty("phaseName") final String phaseName,
                                   @JsonProperty("phaseType") final String phaseType,
                                   @Nullable @JsonProperty("fixedPrice") final BigDecimal fixedPrice,
-                                  @Nullable @JsonProperty("recurringPrice") final BigDecimal recurringPrice) {
+                                  @Nullable @JsonProperty("recurringPrice") final BigDecimal recurringPrice,
+                                  @Nullable @JsonProperty("usageOverrides") final List<UsagePriceOverrideJson> usagePriceOverrides) {
         this.phaseName = phaseName;
         this.phaseType = phaseType;
         this.fixedPrice = fixedPrice;
         this.recurringPrice = recurringPrice;
+        this.usagePriceOverrides = usagePriceOverrides;
+    }
+
+    public PhasePriceOverrideJson(final String phaseName,
+                                  final String phaseType,
+                                  final BigDecimal fixedPrice,
+                                  final BigDecimal recurringPrice,
+                                  final Usage[] usagePriceOverrides,
+                                  final Currency currency) throws CatalogApiException {
+        this.phaseName = phaseName;
+        this.phaseType = phaseType;
+        this.fixedPrice = fixedPrice;
+        this.recurringPrice = recurringPrice;
+        this.usagePriceOverrides = new LinkedList<UsagePriceOverrideJson>();
+
+        for (final Usage usage : usagePriceOverrides) {
+            List <TierPriceOverrideJson> tierPriceOverridesJson = new LinkedList<TierPriceOverrideJson>();
+             for(final Tier tier :usage.getTiers())
+             {
+                 List <BlockPriceOverrideJson> blockPriceOverridesJson = new LinkedList<BlockPriceOverrideJson>();
+
+                 for(final TieredBlock block : tier.getTieredBlocks())
+                 {
+                     BlockPriceOverrideJson blockPriceOverrideJson = new BlockPriceOverrideJson(block.getUnit().getName(), block.getSize(), block.getPrice().getPrice(currency), block.getMax());
+                     blockPriceOverridesJson.add(blockPriceOverrideJson);
+                 }
+                     TierPriceOverrideJson tierPriceOverrideJson  = new TierPriceOverrideJson(blockPriceOverridesJson);
+                     tierPriceOverridesJson.add(tierPriceOverrideJson);
+             }
+            final UsagePriceOverrideJson usagePriceOverrideJson = new UsagePriceOverrideJson(usage.getName(), usage.getUsageType(),usage.getBillingMode(), tierPriceOverridesJson);
+            this.usagePriceOverrides.add(usagePriceOverrideJson);
+        }
+
     }
 
     public BigDecimal getFixedPrice() {
@@ -69,6 +116,11 @@ public class PhasePriceOverrideJson {
         return phaseType;
     }
 
+    public List<UsagePriceOverrideJson> getUsagePriceOverrides() {
+        return usagePriceOverrides;
+    }
+
+
     @Override
     public String toString() {
         return "PhasePriceOverrideJson{" +
@@ -76,6 +128,7 @@ public class PhasePriceOverrideJson {
                "phaseType='" + phaseType + '\'' +
                ", fixedPrice=" + fixedPrice +
                ", recurringPrice=" + recurringPrice +
+                ", usageOverrides=" + usagePriceOverrides +
                '}';
     }
 
@@ -103,6 +156,9 @@ public class PhasePriceOverrideJson {
         if (recurringPrice != null ? recurringPrice.compareTo(that.recurringPrice) != 0 : that.recurringPrice != null) {
             return false;
         }
+        if (usagePriceOverrides != null ? !usagePriceOverrides.equals(that.usagePriceOverrides)  : that.usagePriceOverrides != null) {
+            return false;
+        }
         return true;
     }
 
@@ -112,6 +168,7 @@ public class PhasePriceOverrideJson {
         result = 31 * result + (recurringPrice != null ? recurringPrice.hashCode() : 0);
         result = 31 * result + (phaseType != null ? phaseType.hashCode() : 0);
         result = 31 * result + (recurringPrice != null ? recurringPrice.hashCode() : 0);
+        result = 31 * result + (usagePriceOverrides != null ? usagePriceOverrides.hashCode() : 0);
         return result;
     }
 
@@ -123,14 +180,36 @@ public class PhasePriceOverrideJson {
             @Nullable
             @Override
             public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
+
+                List <UsagePriceOverride> usagePriceOverrides = new LinkedList<UsagePriceOverride>();
+                Preconditions.checkNotNull(input);
+                if(input.getUsagePriceOverrides()!= null) {
+                    for (final UsagePriceOverrideJson usageOverrideJson : input.getUsagePriceOverrides()) {
+                        List<TierPriceOverride> tierPriceOverrides = new LinkedList<TierPriceOverride>();
+                        for (final TierPriceOverrideJson tierPriceOverrideJson : usageOverrideJson.getTierPriceOverrides()) {
+                            List<TieredBlockPriceOverride> blockPriceOverrides = new LinkedList<TieredBlockPriceOverride>();
+                            for (final BlockPriceOverrideJson block : tierPriceOverrideJson.getBlockPriceOverrides()) {
+                                DefaultTieredBlockPriceOverride tieredBlockPriceOverride = new DefaultTieredBlockPriceOverride( block.getUnitName(), block.getSize(), block.getPrice(), block.getMax());
+                                blockPriceOverrides.add(tieredBlockPriceOverride);
+                            }
+                            DefaultTierPriceOverride tierPriceOverride = new DefaultTierPriceOverride(blockPriceOverrides);
+                            tierPriceOverrides.add(tierPriceOverride);
+                        }
+                        final DefaultUsagePriceOverride usageOverride = new DefaultUsagePriceOverride(usageOverrideJson.getUsageName(), usageOverrideJson.getUsageType(), tierPriceOverrides);
+                        usagePriceOverrides.add(usageOverride);
+                    }
+                }
+
                 if (input.getPhaseName() != null) {
-                    return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+                    return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice(), usagePriceOverrides);
                 } 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);
-                    return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+                    return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice(), usagePriceOverrides);
+
                 }
             }
         }));
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
index fd64e0a..13e4b82 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionJson.java
@@ -389,7 +389,7 @@ public class SubscriptionJson extends JsonBase {
                 for (final PlanPhase cur : plan.getAllPhases()) {
                     final BigDecimal fixedPrice = cur.getFixed() != null ? cur.getFixed().getPrice().getPrice(currency) : null;
                     final BigDecimal recurringPrice = cur.getRecurring() != null ? cur.getRecurring().getRecurringPrice().getPrice(currency) : null;
-                    final PhasePriceOverrideJson phase = new PhasePriceOverrideJson(cur.getName(), cur.getPhaseType().toString(), fixedPrice, recurringPrice);
+                    final PhasePriceOverrideJson phase = new PhasePriceOverrideJson(cur.getName(), cur.getPhaseType().toString(), fixedPrice, recurringPrice, cur.getUsages(),currency);
                     priceOverrides.add(phase);
                 }
             }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java
new file mode 100644
index 0000000..c60c499
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/TierPriceOverrideJson.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.json;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class TierPriceOverrideJson {
+
+    private final List<BlockPriceOverrideJson> blockPriceOverrides;
+
+    @JsonCreator
+    public TierPriceOverrideJson(@JsonProperty("blockPriceOverrides") final List<BlockPriceOverrideJson> blockPriceOverrides) {
+        this.blockPriceOverrides = blockPriceOverrides;
+    }
+
+    public List<BlockPriceOverrideJson> getBlockPriceOverrides() {
+        return blockPriceOverrides;
+    }
+
+    @Override
+    public String toString() {
+        return "TierPriceOverrideJson{" +
+                "blockPriceOverrides='" + blockPriceOverrides + '\'' +
+                '}';
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof TierPriceOverrideJson)) {
+            return false;
+        }
+
+        final TierPriceOverrideJson that = (TierPriceOverrideJson) o;
+
+        if (blockPriceOverrides != null ? !blockPriceOverrides.equals(that.blockPriceOverrides) : that.blockPriceOverrides != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = blockPriceOverrides != null ? blockPriceOverrides.hashCode() : 0;
+        result = 31 * result + (blockPriceOverrides != null ? blockPriceOverrides.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java
new file mode 100644
index 0000000..c101f63
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsagePriceOverrideJson.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 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.json;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.UsageType;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class UsagePriceOverrideJson {
+
+    private final String usageName;
+
+    private final UsageType usageType;
+
+    private final BillingMode billingMode;
+
+    private final List<TierPriceOverrideJson> tierPriceOverrides;
+
+    @JsonCreator
+    public UsagePriceOverrideJson(@JsonProperty("usageName") final String usageName,
+                             @Nullable @JsonProperty("usageType") final UsageType usageType,
+                             @Nullable @JsonProperty("billingMode") final BillingMode billingMode,
+                             @Nullable @JsonProperty("tierPriceOverrides") final List<TierPriceOverrideJson> tierPriceOverrides ) {
+        this.usageName = usageName;
+        this.usageType = usageType;
+        this.billingMode = billingMode;
+        this.tierPriceOverrides = tierPriceOverrides;
+    }
+
+    public String getUsageName() {
+        return usageName;
+    }
+
+    public UsageType getUsageType() {
+        return usageType;
+    }
+
+    public BillingMode getBillingMode() {
+        return billingMode;
+    }
+
+    public List<TierPriceOverrideJson> getTierPriceOverrides() {
+        return tierPriceOverrides;
+    }
+
+    @Override
+    public String toString() {
+        return "UsagePriceOverrideJson{" +
+                "usageName='" + usageName + '\'' +
+                "usageType='" + usageType + '\'' +
+                ", billingMode=" + billingMode +
+                ", tierPriceOverrides=" + tierPriceOverrides +
+                '}';
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof UsagePriceOverrideJson)) {
+            return false;
+        }
+
+        final UsagePriceOverrideJson that = (UsagePriceOverrideJson) o;
+
+        if (usageName != null ? !usageName.equals(that.usageName) : that.usageName != null) {
+            return false;
+        }
+        if (usageType != null ? !usageType.equals(that.usageType) : that.usageType != null) {
+            return false;
+        }
+        if (billingMode != null ? !billingMode.equals(that.billingMode) : that.billingMode != null) {
+            return false;
+        }
+        if (tierPriceOverrides != null ? !tierPriceOverrides.equals(that.tierPriceOverrides)  : that.tierPriceOverrides != null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = usageName != null ? usageName.hashCode() : 0;
+        result = 31 * result + (usageType != null ? usageType.hashCode() : 0);
+        result = 31 * result + (billingMode != null ? billingMode.hashCode() : 0);
+        result = 31 * result + (tierPriceOverrides != null ? tierPriceOverrides.hashCode() : 0);
+        return result;
+    }
+
+}
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 2b6f285..7a0e59c 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
@@ -1059,9 +1059,10 @@ public class InvoiceResource extends JaxRsResourceBase {
                                      @Override
                                      public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
                                          if (input.getPhaseName() != null) {
-                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
+
+                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice(), null);
                                          } else {
-                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
+                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice(), null);
                                          }
                                      }
                                  })) : ImmutableList.<PlanPhasePriceOverride>of();
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
index 3dcd46f..3230c8b 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestBundleJsonWithSubscriptions.java
@@ -55,7 +55,7 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
                                                                       UUID.randomUUID().toString(),
                                                                       null);
 
-        final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson(null, "somePhaseType", BigDecimal.ONE, null);
+        final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson(null, "somePhaseType", BigDecimal.ONE, null, null);
 
         final SubscriptionJson subscription = new SubscriptionJson(UUID.randomUUID().toString(),
                                                                    UUID.randomUUID().toString(),
@@ -88,5 +88,6 @@ public class TestBundleJsonWithSubscriptions extends JaxrsTestSuiteNoDB {
         final String asJson = mapper.writeValueAsString(bundleJson);
         final BundleJson fromJson = mapper.readValue(asJson, BundleJson.class);
         Assert.assertEquals(fromJson, bundleJson);
-    }
+
+      }
 }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
index f9e58bb..adceb4a 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestEntitlementJsonWithEvents.java
@@ -19,6 +19,7 @@
 package org.killbill.billing.jaxrs.json;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -49,6 +50,7 @@ public class TestEntitlementJsonWithEvents extends JaxrsTestSuiteNoDB {
         final DateTime effectiveDate = DefaultClock.toUTCDateTime(new DateTime(DateTimeZone.UTC));
         final UUID eventId = UUID.randomUUID();
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
+
         final EventSubscriptionJson newEvent = new EventSubscriptionJson(eventId.toString(),
                                                                          BillingPeriod.NO_BILLING_PERIOD.toString(),
                                                                          effectiveDate.toLocalDate(),
@@ -62,7 +64,7 @@ public class TestEntitlementJsonWithEvents extends JaxrsTestSuiteNoDB {
                                                                          PhaseType.DISCOUNT.toString(),
                                                                          auditLogs);
 
-        final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson("bar", null, BigDecimal.TEN, BigDecimal.ONE);
+        final PhasePriceOverrideJson priceOverride = new PhasePriceOverrideJson("bar", null, BigDecimal.TEN, BigDecimal.ONE,null);
 
         final SubscriptionJson entitlementJsonWithEvents = new SubscriptionJson(accountId,
                                                                                 bundleId,
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
index fe19bb1..54c6495 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestEntitlement.java
@@ -224,7 +224,7 @@ public class TestEntitlement extends TestJaxrsBase {
         input.setBillingPeriod(BillingPeriod.MONTHLY);
         input.setPriceList(PriceListSet.DEFAULT_PRICELIST_NAME);
         final List<PhasePriceOverride> overrides = new ArrayList<PhasePriceOverride>();
-        overrides.add(new PhasePriceOverride(null, PhaseType.TRIAL.toString(), BigDecimal.TEN, null));
+        overrides.add(new PhasePriceOverride(null, PhaseType.TRIAL.toString(), BigDecimal.TEN, null, null));
         input.setPriceOverrides(overrides);
 
         final Subscription subscription = killBillClient.createSubscription(input, null, DEFAULT_WAIT_COMPLETION_TIMEOUT_SEC, basicRequestOptions());