killbill-uncached

Changes

invoice/pom.xml 5(+5 -0)

Details

diff --git a/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java b/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
index ed46527..e782366 100644
--- a/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
+++ b/api/src/main/java/org/killbill/billing/glue/InvoiceModule.java
@@ -18,11 +18,11 @@ package org.killbill.billing.glue;
 
 public interface InvoiceModule {
 
-    public abstract void installInvoiceUserApi();
+    public void installInvoiceUserApi();
 
-    public abstract void installInvoicePaymentApi();
+    public void installInvoicePaymentApi();
 
-    public abstract void installInvoiceMigrationApi();
+    public void installInvoiceMigrationApi();
 
-    public abstract void installInvoiceInternalApi();
+    public void installInvoiceInternalApi();
 }
diff --git a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
index e75e6ce..cfc0ea4 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
@@ -17,6 +17,7 @@
 package org.killbill.billing.junction;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -27,6 +28,7 @@ import org.killbill.billing.catalog.api.BillingPeriod;
 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.Usage;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 
@@ -105,7 +107,13 @@ public interface BillingEvent extends Comparable<BillingEvent> {
     public Long getTotalOrdering();
 
     /**
-     * @return The TimeZone of the account
+     * @return the TimeZone of the account
      */
     public DateTimeZone getTimeZone();
+
+    /**
+     *
+     * @return the list of {@code Usage} section
+     */
+    public List<Usage> getUsages();
 }

invoice/pom.xml 5(+5 -0)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 8f29a64..dd3b8a2 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -94,6 +94,11 @@
         </dependency>
         <dependency>
             <groupId>org.kill-bill.billing</groupId>
+            <artifactId>killbill-usage</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.kill-bill.billing</groupId>
             <artifactId>killbill-util</artifactId>
         </dependency>
         <dependency>
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
index 14ffe3f..472b796 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/calculator/InvoiceCalculatorUtils.java
@@ -60,6 +60,7 @@ public abstract class InvoiceCalculatorUtils {
     public static boolean isCharge(final InvoiceItem invoiceItem) {
         return InvoiceItemType.EXTERNAL_CHARGE.equals(invoiceItem.getInvoiceItemType()) ||
                InvoiceItemType.FIXED.equals(invoiceItem.getInvoiceItemType()) ||
+               InvoiceItemType.USAGE.equals(invoiceItem.getInvoiceItemType()) ||
                InvoiceItemType.RECURRING.equals(invoiceItem.getInvoiceItemType());
     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 5818562..3a57387 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -18,6 +18,7 @@ package org.killbill.billing.invoice.generator;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
@@ -26,18 +27,17 @@ import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
 import org.joda.time.Months;
-import org.killbill.billing.catalog.api.BillingMode;
-import org.killbill.billing.invoice.model.BillingModeGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
+import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
-import org.killbill.clock.Clock;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.model.BillingModeGenerator;
 import org.killbill.billing.invoice.model.DefaultInvoice;
 import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
 import org.killbill.billing.invoice.model.InAdvanceBillingMode;
@@ -45,11 +45,21 @@ import org.killbill.billing.invoice.model.InvalidDateSequenceException;
 import org.killbill.billing.invoice.model.RecurringInvoiceItem;
 import org.killbill.billing.invoice.model.RecurringInvoiceItemData;
 import org.killbill.billing.invoice.tree.AccountItemTree;
+import org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear;
 import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.junction.BillingEventSet;
+import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.util.config.InvoiceConfig;
 import org.killbill.billing.util.currency.KillBillMoney;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.inject.Inject;
 
 public class DefaultInvoiceGenerator implements InvoiceGenerator {
@@ -58,11 +68,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
     private final Clock clock;
     private final InvoiceConfig config;
+    private final UsageUserApi usageApi;
 
     @Inject
-    public DefaultInvoiceGenerator(final Clock clock, final InvoiceConfig config) {
+    public DefaultInvoiceGenerator(final Clock clock, final UsageUserApi usageApi, final InvoiceConfig config) {
         this.clock = clock;
         this.config = config;
+        this.usageApi = usageApi;
     }
 
     /*
@@ -72,7 +84,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     public Invoice generateInvoice(final UUID accountId, @Nullable final BillingEventSet events,
                                    @Nullable final List<Invoice> existingInvoices,
                                    final LocalDate targetDate,
-                                   final Currency targetCurrency) throws InvoiceApiException {
+                                   final Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException {
         if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
             return null;
         }
@@ -86,19 +98,78 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
         final List<InvoiceItem> inAdvanceItems = generateInAdvanceInvoiceItems(accountId, invoiceId, events, existingInvoices, adjustedTargetDate, targetCurrency);
         invoice.addInvoiceItems(inAdvanceItems);
 
+        final List<InvoiceItem> usageItems = generateUsageInvoiceItems(invoiceId, events, existingInvoices, targetDate, context);
+        invoice.addInvoiceItems(usageItems);
+
         return inAdvanceItems.size() != 0 ? invoice : null;
     }
 
-    private List<InvoiceItem> generateInAdvanceInvoiceItems(final UUID accountId, final UUID invoiceId, @Nullable final BillingEventSet events,
-                                               @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
-                                               final Currency targetCurrency) throws InvoiceApiException {
+    // STEPH_USAGE Only deals with consumable in arrear usage billing.
+    private List<InvoiceItem> generateUsageInvoiceItems(final UUID invoiceId, final BillingEventSet eventSet,
+                                                        @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+                                                        final InternalCallContext context) throws InvoiceApiException {
+
+        try {
+
+            final List<InvoiceItem> items = Lists.newArrayList();
+            final Iterator<BillingEvent> events = eventSet.iterator();
+
+            final List<BillingEvent> curEvents = Lists.newArrayList();
+            UUID curSubscriptionId = null;
+            while (events.hasNext()) {
+                final BillingEvent event = events.next();
+                final UUID subscriptionId = event.getSubscription().getId();
+                if (curSubscriptionId != null && !curSubscriptionId.equals(subscriptionId)) {
+                    //
+                    // STEPH_USAGE unitType issue
+                    // STEPH_USAGE context needs tenantId , hum...
+                    final UUID tenantId = UUID.randomUUID();
+                    SubscriptionConsumableInArrear foo = new SubscriptionConsumableInArrear(invoiceId, "foo", curEvents, usageApi, targetDate, context.toTenantContext(tenantId));
+                    items.addAll(foo.computeMissingUsageInvoiceItems(extractUsageItemsForSubscription(subscriptionId, existingInvoices)));
+                    curEvents.clear();
+                }
+                curSubscriptionId = subscriptionId;
+                curEvents.add(event);
+            }
+
+            return items;
+
+        } catch (CatalogApiException e) {
+            throw new InvoiceApiException(e);
+        }
+    }
+
+    private List<InvoiceItem> extractUsageItemsForSubscription(final UUID subscriptionId, @Nullable final List<Invoice> existingInvoices) {
+
+        if (existingInvoices == null) {
+            return Collections.emptyList();
+        }
+
+        final Iterable usageItems = Iterables.concat(Iterables.transform(existingInvoices, new Function<Invoice, Iterable<InvoiceItem>>() {
+            @Override
+            public Iterable<InvoiceItem> apply(final Invoice input) {
+
+                return Iterables.filter(input.getInvoiceItems(), new Predicate<InvoiceItem>() {
+                    @Override
+                    public boolean apply(final InvoiceItem input) {
+                        return input.getInvoiceItemType() == InvoiceItemType.USAGE && input.getSubscriptionId().equals(subscriptionId);
+                    }
+                });
+            }
+        }));
+        return ImmutableList.<InvoiceItem>copyOf(usageItems);
+    }
+
+    private List<InvoiceItem> generateInAdvanceInvoiceItems(final UUID accountId, final UUID invoiceId, final BillingEventSet eventSet,
+                                                            @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
+                                                            final Currency targetCurrency) throws InvoiceApiException {
         final AccountItemTree accountItemTree = new AccountItemTree(accountId);
         if (existingInvoices != null) {
             for (final Invoice invoice : existingInvoices) {
                 for (final InvoiceItem item : invoice.getInvoiceItems()) {
                     if (item.getSubscriptionId() == null || // Always include migration invoices, credits, external charges etc.
-                        !events.getSubscriptionIdsWithAutoInvoiceOff()
-                               .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
+                        !eventSet.getSubscriptionIdsWithAutoInvoiceOff()
+                                 .contains(item.getSubscriptionId())) { //don't add items with auto_invoice_off tag
                         accountItemTree.addExistingItem(item);
                     }
                 }
@@ -106,7 +177,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
         }
 
         // Generate list of proposed invoice items based on billing events from junction-- proposed items are ALL items since beginning of time
-        final List<InvoiceItem> proposedItems = generateInAdvanceInvoiceItems(invoiceId, accountId, events, targetDate, targetCurrency);
+        final List<InvoiceItem> proposedItems = generateInAdvanceInvoiceItems(invoiceId, accountId, eventSet, targetDate, targetCurrency);
 
         accountItemTree.mergeWithProposedItems(proposedItems);
         return accountItemTree.getResultingItemList();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
index 014dbcd..e0d6b21 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceGenerator.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
 
 import org.joda.time.LocalDate;
 
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceApiException;
@@ -31,5 +32,5 @@ import org.killbill.billing.junction.BillingEventSet;
 public interface InvoiceGenerator {
 
     public Invoice generateInvoice(UUID accountId, @Nullable BillingEventSet events, @Nullable List<Invoice> existingInvoices,
-                                   LocalDate targetDate, Currency targetCurrency) throws InvoiceApiException;
+                                   LocalDate targetDate, Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException;
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 66c6efb..1dba77c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -190,7 +190,7 @@ public class InvoiceDispatcher {
             final Currency targetCurrency = account.getCurrency();
 
             final LocalDate targetDate = dateAndTimeZoneContext != null ? dateAndTimeZoneContext.computeTargetDate(targetDateTime) : null;
-            final Invoice invoice = targetDate != null ? generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency) : null;
+            final Invoice invoice = targetDate != null ? generator.generateInvoice(accountId, billingEvents, invoices, targetDate, targetCurrency, context) : null;
             boolean isRealInvoiceWithItems = false;
             if (invoice == null) {
                 log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
index 46538b3..de3bf99 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
@@ -78,6 +78,10 @@ public class InvoiceItemFactory {
             case ITEM_ADJ:
                 item = new ItemAdjInvoiceItem(id, createdDate, invoiceId, accountId, startDate, amount, currency, linkedItemId);
                 break;
+            case USAGE:
+                // STEPH USAGE should we add unitType in schema pr override fields (planName,..) Same for unitAmount
+                item = new UsageInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency,"unitType");
+                break;
             default:
                 throw new RuntimeException("Unexpected type of event item " + type);
         }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java b/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java
new file mode 100644
index 0000000..9b6489e
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/UsageInvoiceItem.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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.invoice.model;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+
+public class UsageInvoiceItem extends InvoiceItemBase {
+
+    private final String unitType;
+
+    public UsageInvoiceItem(final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId, @Nullable final UUID subscriptionId,
+                            final String planName, final String phaseName,
+                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency, final String unitType) {
+        this(UUID.randomUUID(), null, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, unitType);
+    }
+
+    public UsageInvoiceItem(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, final UUID bundleId,
+                            final UUID subscriptionId, final String planName, final String phaseName,
+                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency, final String unitType) {
+        super(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
+        this.unitType = unitType;
+    }
+
+    @Override
+    public InvoiceItemType getInvoiceItemType() {
+        return InvoiceItemType.USAGE;
+    }
+
+    @Override
+    public String getDescription() {
+        return String.format("%s (usage item)", unitType);
+    }
+
+    public String getUnitType() {
+        return unitType;
+    }
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
index 57c6bb1..be44a10 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
@@ -97,6 +97,7 @@ public class AccountItemTree {
             case CBA_ADJ:
             case CREDIT_ADJ:
             case REFUND_ADJ:
+            case USAGE:
                 return;
 
             case RECURRING:
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java
new file mode 100644
index 0000000..405306e
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousInArrearUsageInterval.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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.invoice.usage;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.catalog.api.TieredBlock;
+import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.generator.BillingIntervalDetail;
+import org.killbill.billing.invoice.model.UsageInvoiceItem;
+import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.UsageUserApi;
+import org.killbill.billing.util.callcontext.TenantContext;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import static org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear.getTieredBlocks;
+import static org.killbill.billing.invoice.usage.SubscriptionConsumableInArrear.localDateToEndOfDayInAccountTimezone;
+
+public class ContiguousInArrearUsageInterval {
+
+    private final List<LocalDate> transitionTimes;
+    private final List<BillingEvent> billingEvents;
+
+    private final Usage usage;
+    private final String unitType;
+    private final UsageUserApi usageApi;
+    private final LocalDate targetDate;
+    private final UUID invoiceId;
+    private final TenantContext context;
+
+    public ContiguousInArrearUsageInterval(final Usage usage, final UUID invoiceId, final String unitType, final UsageUserApi usageApi, final LocalDate targetDate, final TenantContext context) {
+        this.usage = usage;
+        this.invoiceId = invoiceId;
+        this.unitType = unitType;
+        this.usageApi = usageApi;
+        this.targetDate = targetDate;
+        this.context = context;
+        this.billingEvents = Lists.newLinkedList();
+        this.transitionTimes = Lists.newLinkedList();
+    }
+
+    public void addBillingEvent(final BillingEvent event) {
+        billingEvents.add(event);
+    }
+
+    public Usage getUsage() {
+        return usage;
+    }
+
+    public int getBCD() {
+        return billingEvents.get(0).getBillCycleDayLocal();
+    }
+
+    public UUID getAccountId() {
+        return billingEvents.get(0).getAccount().getId();
+    }
+
+    public UUID getBundleId() {
+        return billingEvents.get(0).getSubscription().getBundleId();
+    }
+
+    public UUID getSubscriptionId() {
+        return billingEvents.get(0).getSubscription().getId();
+    }
+
+    // STEPH_USAGE planName/phaseName,BCD,... might not be correct if we changed plan but Usage section was exactly similar
+    public String getPlanName() {
+        return billingEvents.get(0).getPlan().getName();
+    }
+
+    public String getPhaseName() {
+        return billingEvents.get(0).getPlanPhase().getName();
+    }
+
+    public Currency getCurrency() {
+        return billingEvents.get(0).getCurrency();
+    }
+
+    public DateTimeZone getAccountTimeZone() {
+        return billingEvents.get(0).getTimeZone();
+    }
+
+
+
+    public ContiguousInArrearUsageInterval build(final boolean closedInterval) {
+
+        Preconditions.checkState((!closedInterval && billingEvents.size() >= 1) ||
+                                 (closedInterval && billingEvents.size() >= 2));
+
+        final LocalDate startDate = new LocalDate(billingEvents.get(0).getEffectiveDate(), getAccountTimeZone());
+        if (targetDate.isBefore(startDate)) {
+            return this;
+        }
+
+        final LocalDate endDate = closedInterval ? new LocalDate(billingEvents.get(billingEvents.size() - 1), getAccountTimeZone()) : targetDate;
+
+        final BillingIntervalDetail bid = new BillingIntervalDetail(startDate, endDate, targetDate, getBCD(), usage.getBillingPeriod());
+
+        int numberOfPeriod = 0;
+        // First billingCycleDate prior startDate
+        LocalDate nextBillCycleDate = bid.getFutureBillingDateFor(numberOfPeriod);
+        transitionTimes.add(startDate);
+        while (!nextBillCycleDate.isAfter(endDate)) {
+            if (nextBillCycleDate.isAfter(startDate)) {
+                transitionTimes.add(nextBillCycleDate);
+            }
+            numberOfPeriod++;
+            nextBillCycleDate = bid.getFutureBillingDateFor(numberOfPeriod);
+        }
+        return this;
+    }
+
+    public List<InvoiceItem> computeMissingItems(final List<InvoiceItem> existingUsage) throws CatalogApiException {
+
+        final List<InvoiceItem> result = Lists.newLinkedList();
+
+        final List<RolledUpUsage> rolledUpUsages = getRolledUpUsage();
+        for (RolledUpUsage ru : rolledUpUsages) {
+            final LocalDate startRolledUpDate = new LocalDate(ru.getStartTime(), getAccountTimeZone());
+            final LocalDate endRolledUpDate = new LocalDate(ru.getEndTime(), getAccountTimeZone());
+            final BigDecimal billedUsage = computeBilledUsage(startRolledUpDate, endRolledUpDate, existingUsage);
+            final BigDecimal toBeBilledUsage = computeToBeBilledUsage(ru.getAmount());
+            if (billedUsage.compareTo(toBeBilledUsage) < 0) {
+                InvoiceItem item = new UsageInvoiceItem(invoiceId, getAccountId(), getBundleId(), getSubscriptionId(), getPlanName(),
+                                                        getPhaseName(), startRolledUpDate, endRolledUpDate, toBeBilledUsage.subtract(billedUsage), getCurrency(), unitType);
+                result.add(item);
+            }
+        }
+        return result;
+    }
+
+    private List<RolledUpUsage> getRolledUpUsage() {
+
+        final Iterable<DateTime> transitions = Iterables.transform(transitionTimes, new Function<LocalDate, DateTime>() {
+            @Override
+            public DateTime apply(final LocalDate input) {
+                return localDateToEndOfDayInAccountTimezone(input, getAccountTimeZone());
+            }
+        });
+        final List<RolledUpUsage> usagesForInterval = usageApi.getAllUsageForSubscription(getSubscriptionId(), unitType, ImmutableList.copyOf(transitions), context);
+        return usagesForInterval;
+    }
+
+    private final BigDecimal computeToBeBilledUsage(final BigDecimal units) throws CatalogApiException {
+
+        // STEPH_USAGE need to review catalog xml which defines block tiers, ...
+        final int blockSize = 0x1000;
+        final int nbBlocks = units.intValue() / blockSize + ((units.intValue() % blockSize == 0) ? 0 : 1);
+
+        // STEPH_USAGE this is wrong should use from each tier.
+        final List<TieredBlock> tieredBlocks = getTieredBlocks(usage, unitType);
+        for (TieredBlock tier : tieredBlocks) {
+            if (tier.getMax() >= units.doubleValue()) {
+                return tier.getPrice().getPrice(getCurrency());
+            }
+        }
+        // Return from last tier
+        return tieredBlocks.get(tieredBlocks.size() - 1).getPrice().getPrice(getCurrency());
+    }
+
+    private final BigDecimal computeBilledUsage(final LocalDate startDate, final LocalDate endDate, final List<InvoiceItem> existingUsage) {
+        final Iterable<InvoiceItem> filteredUsageForInterval = Iterables.filter(existingUsage, new Predicate<InvoiceItem>() {
+            @Override
+            public boolean apply(final InvoiceItem input) {
+                // STEPH_USAGE what happens if we discover usage period that overlap (one side or both side) the [startDate, endDate] interval
+                // STEPH_USAGE how to distinguish different usage charges (maybe different sections.) (needs to at least of the unitType in usage element
+                return input.getInvoiceItemType() == InvoiceItemType.USAGE &&
+                       input.getStartDate().compareTo(startDate) >= 0 &&
+                       input.getEndDate().compareTo(endDate) <= 0;
+            }
+        });
+
+        final BigDecimal billedAmount = BigDecimal.ZERO;
+        for (InvoiceItem ii : filteredUsageForInterval) {
+            billedAmount.add(ii.getAmount());
+        }
+        // Return the billed $ amount (not the # of units)
+        return billedAmount;
+    }
+
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
new file mode 100644
index 0000000..14f932a
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014 The Billing Project, Inc.
+ *
+ * Ning 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.invoice.usage;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.Tier;
+import org.killbill.billing.catalog.api.TieredBlock;
+import org.killbill.billing.catalog.api.Usage;
+import org.killbill.billing.catalog.api.UsageType;
+import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.model.UsageInvoiceItem;
+import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.usage.api.UsageUserApi;
+import org.killbill.billing.util.callcontext.TenantContext;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+public class SubscriptionConsumableInArrear {
+
+    private UUID invoiceId;
+    private final String unitType;
+    private final List<BillingEvent> subscriptionBillingEvents;
+    private final UsageUserApi usageApi;
+    private final LocalDate targetDate;
+    private final TenantContext context;
+
+    public SubscriptionConsumableInArrear(final UUID invoiceId, final String unitType, final List<BillingEvent> subscriptionBillingEvents, final UsageUserApi usageApi, final LocalDate targetDate, final TenantContext context) {
+        this.invoiceId = invoiceId;
+        this.unitType = unitType;
+        this.subscriptionBillingEvents = subscriptionBillingEvents;
+        this.usageApi = usageApi;
+        this.targetDate = targetDate;
+        this.context = context;
+    }
+
+    public List<InvoiceItem> computeMissingUsageInvoiceItems(final List<InvoiceItem> existingUsage) throws CatalogApiException {
+
+        final List<InvoiceItem> result = Lists.newLinkedList();
+        final List<ContiguousInArrearUsageInterval> billingEventTransitionTimePeriods = computeBillingEventTransitionTimePeriods();
+        for (ContiguousInArrearUsageInterval usageInterval : billingEventTransitionTimePeriods) {
+            result.addAll(usageInterval.computeMissingItems(existingUsage));
+        }
+        return result;
+    }
+
+
+    static List<TieredBlock> getTieredBlocks(final Usage usage, final String unitType) {
+
+        Preconditions.checkArgument(usage.getTiers().length > 0);
+
+        final List<TieredBlock> result = Lists.newLinkedList();
+        for (Tier tier : usage.getTiers()) {
+
+            for (TieredBlock tierBlock : tier.getTieredBlocks()) {
+                if (tierBlock.getUnit().getName().equals(unitType)) {
+                    result.add(tierBlock);
+                }
+            }
+        }
+        return result;
+    }
+
+    static DateTime localDateToEndOfDayInAccountTimezone(final LocalDate input, final DateTimeZone accountTimeZone) {
+        final DateTime dateTimeInAccountTimeZone = new DateTime(input.getYear(), input.getMonthOfYear(), input.getDayOfMonth(), 23, 59, 59, accountTimeZone);
+        return new DateTime(dateTimeInAccountTimeZone, DateTimeZone.UTC);
+    }
+
+
+    private List<ContiguousInArrearUsageInterval> computeBillingEventTransitionTimePeriods() {
+
+        final List<ContiguousInArrearUsageInterval> usageInterval = Lists.newLinkedList();
+
+        ContiguousInArrearUsageInterval existingInterval = null;
+        for (BillingEvent event : subscriptionBillingEvents) {
+            final Usage usage = findUsage(event);
+            if (usage == null || !usage.equals(existingInterval.getUsage())) {
+                if (existingInterval != null) {
+                    usageInterval.add(existingInterval.build(true));
+                    existingInterval = null;
+                }
+            }
+
+            if (usage != null) {
+                if (existingInterval == null) {
+                    existingInterval = new ContiguousInArrearUsageInterval(usage, invoiceId, unitType, usageApi, targetDate, context);
+                }
+                existingInterval.addBillingEvent(event);
+            }
+        }
+        if (existingInterval != null) {
+            usageInterval.add(existingInterval.build(false));
+        }
+        return usageInterval;
+    }
+
+    private Usage findUsage(final BillingEvent event) {
+        if (event.getUsages().size() == 0) {
+            return null;
+        }
+        for (Usage usage : event.getUsages()) {
+            if (usage.getUsageType() != UsageType.CONSUMABLE ||
+                usage.getBillingMode() != BillingMode.IN_ARREAR) {
+                continue;
+            }
+
+            List<TieredBlock> tieredBlock = getTieredBlocks(usage, unitType);
+            if (tieredBlock.size() > 0) {
+                return usage;
+            }
+        }
+        return null;
+    }
+
+    private void addMissingTransitionTimes(final List<LocalDate> transitionTimes, final List<UsageInvoiceItem> existingUsage) {
+
+        Preconditions.checkArgument(transitionTimes.size() > 0);
+
+        final LocalDate startDate = transitionTimes.get(0);
+        final LocalDate endDate = transitionTimes.get(transitionTimes.size() - 1);
+
+        for (UsageInvoiceItem ii : existingUsage) {
+            if (ii.getEndDate().compareTo(startDate) <= 0 || ii.getStartDate().compareTo(endDate) >= 0) {
+                continue;
+            }
+            if (ii.getStartDate().compareTo(startDate) < 0 && ii.getEndDate().compareTo(endDate) <= 0) {
+                transitionTimes.add(ii.getEndDate());
+            } else if (ii.getStartDate().compareTo(startDate) >= 0 && ii.getEndDate().compareTo(endDate) > 0) {
+                transitionTimes.add(ii.getStartDate());
+            } else {
+                transitionTimes.add(ii.getStartDate());
+                transitionTimes.add(ii.getEndDate());
+            }
+        }
+
+        final Set<LocalDate> uniqueTransitions = new HashSet<LocalDate>(transitionTimes);
+        transitionTimes.clear();
+        transitionTimes.addAll(uniqueTransitions);
+        Collections.sort(transitionTimes);
+    }
+
+}
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index ac44bc7..051ec3d 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -1099,7 +1099,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final BillingEventSet events = new MockBillingEventSet();
         events.add(event1);
 
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, context);
         assertEquals(invoice1.getBalance(), KillBillMoney.of(TEN, invoice1.getCurrency()));
         invoiceList.add(invoice1);
 
@@ -1117,7 +1117,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // second invoice should be for one half (14/28 days) the difference between the rate plans
         // this is a temporary state, since it actually contains an adjusting item that properly belong to invoice 1
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, context);
         assertEquals(invoice2.getBalance(), KillBillMoney.of(FIVE, invoice2.getCurrency()));
         invoiceList.add(invoice2);
 
@@ -1149,7 +1149,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         events.add(event);
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 15);
-        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, context);
 
         // expect one pro-ration item and one full-period item
         assertEquals(invoice.getNumberOfItems(), 2);
@@ -1192,7 +1192,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         events.add(event1);
 
         final UUID accountId = account.getId();
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate(effectiveDate1), Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate(effectiveDate1), Currency.USD, context);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
         assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
@@ -1208,7 +1208,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                        "testEvent2", 2L, SubscriptionBaseTransitionType.PHASE);
         events.add(event2);
 
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate2), Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate2), Currency.USD, context);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 1);
         assertEquals(invoice2.getBalance().compareTo(cheapAmount), 0);
@@ -1218,7 +1218,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         //invoiceUtil.createInvoice(invoice2, invoice2.getTargetDate().getDayOfMonth(), callcontext);
 
         final DateTime effectiveDate3 = effectiveDate2.plusMonths(1);
-        final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate3), Currency.USD);
+        final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate(effectiveDate3), Currency.USD, context);
         assertNotNull(invoice3);
         assertEquals(invoice3.getNumberOfItems(), 1);
         assertEquals(invoice3.getBalance().compareTo(cheapAmount), 0);
@@ -1229,7 +1229,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testInvoiceForEmptyEventSet() throws InvoiceApiException {
         final BillingEventSet events = new MockBillingEventSet();
-        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(), Currency.USD);
+        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(), Currency.USD, context);
         assertNull(invoice);
     }
 
@@ -1263,7 +1263,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                        "testEvent2", 2L, SubscriptionBaseTransitionType.CHANGE);
         events.add(event2);
 
-        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(effectiveDate2), Currency.USD);
+        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new LocalDate(effectiveDate2), Currency.USD, context);
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
         assertEquals(invoice.getBalance().compareTo(cheapAmount), 0);
@@ -1334,7 +1334,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                        BillingPeriod.MONTHLY, 31, BillingMode.IN_ADVANCE,
                                                                        "new-event", 1L, SubscriptionBaseTransitionType.CREATE);
         events.add(event1);
-        final Invoice newInvoice = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate, Currency.USD);
+        final Invoice newInvoice = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate, Currency.USD, context);
         invoiceUtil.createInvoice(newInvoice, true, context);
 
         // VERIFY THAT WE STILL HAVE ONLY 2 ITEMS, MEANING THERE WERE NO REPAIR AND NO CBA GENERATED
@@ -1369,7 +1369,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                        "testEvent1", 1L, SubscriptionBaseTransitionType.CHANGE);
         events.add(event1);
 
-        Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate1), Currency.USD);
+        Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate1), Currency.USD, context);
         invoices.add(invoice1);
         invoiceUtil.createInvoice(invoice1, true, context);
         invoice1 = new DefaultInvoice(invoiceDao.getById(invoice1.getId(), context));
@@ -1380,7 +1380,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                        BillingPeriod.MONTHLY, 31, BillingMode.IN_ADVANCE,
                                                                        "testEvent2", 2L, SubscriptionBaseTransitionType.CHANGE);
         events.add(event2);
-        Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate2), Currency.USD);
+        Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, new LocalDate(targetDate2), Currency.USD, context);
         invoiceUtil.createInvoice(invoice2, true, context);
         invoice2 = new DefaultInvoice(invoiceDao.getById(invoice2.getId(), context));
         assertNotNull(invoice2.getInvoiceNumber());
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
index d030c81..20879e6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/generator/TestDefaultInvoiceGenerator.java
@@ -102,13 +102,13 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
                 return false;
             }
         };
-        this.generator = new DefaultInvoiceGenerator(clock, invoiceConfig);
+        this.generator = new DefaultInvoiceGenerator(clock, null, invoiceConfig);
     }
 
     @Test(groups = "fast")
     public void testWithNullEventSetAndNullInvoiceSet() throws InvoiceApiException {
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, null, null, clock.getUTCToday(), Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, null, null, clock.getUTCToday(), Currency.USD, internalCallContext);
         assertNull(invoice);
     }
 
@@ -116,7 +116,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
     public void testWithEmptyEventSet() throws InvoiceApiException {
         final BillingEventSet events = new MockBillingEventSet();
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, clock.getUTCToday(), Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, clock.getUTCToday(), Currency.USD, internalCallContext);
         assertNull(invoice);
     }
 
@@ -136,7 +136,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
@@ -174,7 +174,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         // Target date is the next BCD, in local time
         final LocalDate targetDate = invoiceUtil.buildDate(2012, 8, bcdLocal);
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
@@ -198,7 +198,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         // Set a target date of today (start date)
         final LocalDate targetDate = startDate;
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 1);
@@ -221,7 +221,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
@@ -254,7 +254,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
@@ -280,7 +280,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 4);
@@ -322,7 +322,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 4);
@@ -345,12 +345,12 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         LocalDate targetDate = invoiceUtil.buildDate(2011, 12, 1);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
         final List<Invoice> existingInvoices = new ArrayList<Invoice>();
         existingInvoices.add(invoice1);
 
         targetDate = invoiceUtil.buildDate(2011, 12, 3);
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, existingInvoices, targetDate, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, existingInvoices, targetDate, Currency.USD, internalCallContext);
 
         assertNull(invoice2);
     }
@@ -523,7 +523,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 1, 1);
         events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), targetDate, plan, planPhase, 1));
 
-        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
 
         assertEquals(invoice.getNumberOfItems(), 1);
     }
@@ -538,7 +538,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), startDate, plan, planPhase, startDate.getDayOfMonth()));
 
-        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
         final RecurringInvoiceItem item = (RecurringInvoiceItem) invoice.getInvoiceItems().get(0);
 
         // end date of the invoice item should be equal to exactly one month later (rounded)
@@ -575,13 +575,13 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         events.add(event2);
         events.add(event1);
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate("2012-02-01"), Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, new LocalDate("2012-02-01"), Currency.USD, internalCallContext);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
 
         final List<Invoice> invoiceList = new ArrayList<Invoice>();
         invoiceList.add(invoice1);
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate("2012-04-05"), Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, new LocalDate("2012-04-05"), Currency.USD, internalCallContext);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 1);
         final FixedPriceInvoiceItem item = (FixedPriceInvoiceItem) invoice2.getInvoiceItems().get(0);
@@ -606,7 +606,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(event1);
 
         // ensure both components are invoiced
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD, internalCallContext);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 2);
         assertEquals(invoice1.getBalance(), KillBillMoney.of(FIFTEEN, invoice1.getCurrency()));
@@ -618,7 +618,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final LocalDate currentDate = startDate.plusMonths(1);
 
         // ensure that only the recurring price is invoiced
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, currentDate, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, currentDate, Currency.USD, internalCallContext);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 1);
         assertEquals(invoice2.getBalance(), KillBillMoney.of(FIVE, invoice2.getCurrency()));
@@ -643,7 +643,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(event1);
 
         // ensure that a single invoice item is generated for the fixed cost
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, startDate, Currency.USD, internalCallContext);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
         assertEquals(invoice1.getBalance(), KillBillMoney.of(fixedCost1, invoice1.getCurrency()));
@@ -657,7 +657,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(event2);
 
         // ensure that a single invoice item is generated for the fixed cost
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, phaseChangeDate, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, phaseChangeDate, Currency.USD, internalCallContext);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 1);
         assertEquals(invoice2.getBalance(), KillBillMoney.of(fixedCost2, invoice2.getCurrency()));
@@ -690,7 +690,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final LocalDate discountPhaseEndDate = trialPhaseEndDate.plusMonths(6);
         events.add(createBillingEvent(subscriptionId, bundleId, discountPhaseEndDate, plan1, phase3, BILL_CYCLE_DAY));
 
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, creationDate, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, creationDate, Currency.USD, internalCallContext);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
         assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
@@ -698,7 +698,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final List<Invoice> invoiceList = new ArrayList<Invoice>();
         invoiceList.add(invoice1);
 
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, trialPhaseEndDate, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoiceList, trialPhaseEndDate, Currency.USD, internalCallContext);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 1);
         assertEquals(invoice2.getInvoiceItems().get(0).getStartDate(), trialPhaseEndDate);
@@ -706,7 +706,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         invoiceList.add(invoice2);
         LocalDate targetDate = new LocalDate(trialPhaseEndDate.getYear(), trialPhaseEndDate.getMonthOfYear(), BILL_CYCLE_DAY);
-        final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+        final Invoice invoice3 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, internalCallContext);
         assertNotNull(invoice3);
         assertEquals(invoice3.getNumberOfItems(), 1);
         assertEquals(invoice3.getInvoiceItems().get(0).getStartDate(), targetDate);
@@ -714,7 +714,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         invoiceList.add(invoice3);
         targetDate = targetDate.plusMonths(6);
-        final Invoice invoice4 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD);
+        final Invoice invoice4 = generator.generateInvoice(accountId, events, invoiceList, targetDate, Currency.USD, internalCallContext);
         assertNotNull(invoice4);
         assertEquals(invoice4.getNumberOfItems(), 7);
     }
@@ -726,7 +726,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final Plan plan1 = new MockPlan();
         final PlanPhase phase1 = createMockMonthlyPlanPhase(null, ZERO, PhaseType.TRIAL);
         events.add(createBillingEvent(UUID.randomUUID(), UUID.randomUUID(), clock.getUTCToday(), plan1, phase1, 1));
-        generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD);
+        generator.generateInvoice(UUID.randomUUID(), events, null, targetDate, Currency.USD, internalCallContext);
     }
 
     private MockPlanPhase createMockMonthlyPlanPhase() {
@@ -773,7 +773,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
                                        final LocalDate targetDate, final int expectedNumberOfItems,
                                        final BigDecimal expectedAmount) throws InvoiceApiException {
         final Currency currency = Currency.USD;
-        final Invoice invoice = generator.generateInvoice(accountId, events, existingInvoices, targetDate, currency);
+        final Invoice invoice = generator.generateInvoice(accountId, events, existingInvoices, targetDate, currency, internalCallContext);
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), expectedNumberOfItems);
         existingInvoices.add(invoice);
@@ -800,7 +800,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(createBillingEvent(baseSubscription.getId(), baseSubscription.getBundleId(), april25, basePlan, basePlanEvergreen, 25));
 
         // generate invoice
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD, internalCallContext);
         assertNotNull(invoice1);
         assertEquals(invoice1.getNumberOfItems(), 1);
         assertEquals(invoice1.getBalance().compareTo(TEN), 0);
@@ -821,7 +821,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(createBillingEvent(addOnSubscription2.getId(), baseSubscription.getBundleId(), april28, addOn2Plan, addOn2PlanPhaseEvergreen, 25));
 
         // generate invoice
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april28, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april28, Currency.USD, internalCallContext);
         invoices.add(invoice2);
         assertNotNull(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 2);
@@ -838,7 +838,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         // generate invoice
         final LocalDate may1 = new LocalDate(2012, 5, 1);
-        final Invoice invoice3 = generator.generateInvoice(accountId, newEvents, invoices, may1, Currency.USD);
+        final Invoice invoice3 = generator.generateInvoice(accountId, newEvents, invoices, may1, Currency.USD, internalCallContext);
         assertNotNull(invoice3);
         assertEquals(invoice3.getNumberOfItems(), 3);
         // -4.50 -18 - 10 (to correct the previous 2 invoices) + 4.50 + 13
@@ -861,7 +861,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final BillingEventSet events = new MockBillingEventSet();
         events.add(createBillingEvent(originalSubscription.getId(), originalSubscription.getBundleId(), april25, originalPlan, originalPlanEvergreen, 25));
 
-        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD);
+        final Invoice invoice1 = generator.generateInvoice(accountId, events, null, april25, Currency.USD, internalCallContext);
 
         printDetailInvoice(invoice1);
 
@@ -883,7 +883,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         events.add(createBillingEvent(newSubscription.getId(), originalSubscription.getBundleId(), april25, newPlan, newPlanEvergreen, 25));
 
         // generate a new invoice
-        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april25, Currency.USD);
+        final Invoice invoice2 = generator.generateInvoice(accountId, events, invoices, april25, Currency.USD, internalCallContext);
 
         printDetailInvoice(invoice2);
         assertEquals(invoice2.getNumberOfItems(), 2);
@@ -942,7 +942,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
 
         final LocalDate targetDate = invoiceUtil.buildDate(2011, 10, 3);
         final UUID accountId = UUID.randomUUID();
-        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
+        final Invoice invoice = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD, internalCallContext);
 
         assertNull(invoice);
     }
@@ -970,7 +970,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         eventSet.add(createBillingEvent(subscriptionId2, bundleId, startDate, plan2, plan2phase1, 1));
 
         // generate the first invoice
-        final Invoice invoice1 = generator.generateInvoice(accountId, eventSet, invoices, startDate, currency);
+        final Invoice invoice1 = generator.generateInvoice(accountId, eventSet, invoices, startDate, currency, internalCallContext);
         assertNotNull(invoice1);
         assertTrue(invoice1.getBalance().compareTo(FIFTEEN.add(TWELVE)) == 0);
         invoices.add(invoice1);
@@ -981,7 +981,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         eventSet.addSubscriptionWithAutoInvoiceOff(subscriptionId1);
 
         final LocalDate targetDate2 = startDate.plusMonths(1);
-        final Invoice invoice2 = generator.generateInvoice(accountId, eventSet, invoices, targetDate2, currency);
+        final Invoice invoice2 = generator.generateInvoice(accountId, eventSet, invoices, targetDate2, currency, internalCallContext);
         assertNotNull(invoice2);
         assertTrue(invoice2.getBalance().compareTo(TWELVE) == 0);
         invoices.add(invoice2);
@@ -989,7 +989,7 @@ public class TestDefaultInvoiceGenerator extends InvoiceTestSuiteNoDB {
         final LocalDate targetDate3 = targetDate2.plusMonths(1);
         eventSet.clearSubscriptionsWithAutoInvoiceOff();
         eventSet.add(subscription1creation);
-        final Invoice invoice3 = generator.generateInvoice(accountId, eventSet, invoices, targetDate3, currency);
+        final Invoice invoice3 = generator.generateInvoice(accountId, eventSet, invoices, targetDate3, currency, internalCallContext);
         assertNotNull(invoice3);
         assertTrue(invoice3.getBalance().compareTo(FIFTEEN.multiply(TWO).add(TWELVE)) == 0);
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
index e601ca8..e3a2942 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/glue/TestInvoiceModule.java
@@ -16,22 +16,21 @@
 
 package org.killbill.billing.invoice.glue;
 
-import org.killbill.billing.util.glue.MemoryGlobalLockerModule;
-import org.mockito.Mockito;
-import org.skife.config.ConfigSource;
-
 import org.killbill.billing.catalog.glue.CatalogModule;
 import org.killbill.billing.invoice.TestInvoiceHelper;
+import org.killbill.billing.junction.BillingInternalApi;
+import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
+import org.killbill.billing.usage.glue.UsageModule;
 import org.killbill.billing.util.email.EmailModule;
 import org.killbill.billing.util.email.templates.TemplateModule;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
 import org.killbill.billing.util.glue.CustomFieldModule;
+import org.killbill.billing.util.glue.MemoryGlobalLockerModule;
 import org.killbill.billing.util.glue.NotificationQueueModule;
 import org.killbill.billing.util.glue.TagStoreModule;
-import org.killbill.billing.junction.BillingInternalApi;
-import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
-
+import org.mockito.Mockito;
+import org.skife.config.ConfigSource;
 
 public class TestInvoiceModule extends DefaultInvoiceModule {
 
@@ -58,7 +57,7 @@ public class TestInvoiceModule extends DefaultInvoiceModule {
         install(new NotificationQueueModule(configSource));
         install(new TagStoreModule());
         install(new CustomFieldModule());
-
+        install(new UsageModule(configSource));
         installExternalApis();
 
         bind(TestInvoiceHelper.class).asEagerSingleton();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 5194fb8..3f51e54 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -17,6 +17,7 @@
 package org.killbill.billing.invoice;
 
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -27,6 +28,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.BillingMode;
+import org.killbill.billing.catalog.api.Usage;
 import org.mockito.Mockito;
 import org.skife.jdbi.v2.IDBI;
 import org.testng.Assert;
@@ -388,6 +390,11 @@ public class TestInvoiceHelper {
             }
 
             @Override
+            public List<Usage> getUsages() {
+                return Collections.emptyList();
+            }
+
+            @Override
             public int compareTo(final BillingEvent e1) {
                 if (!getSubscription().getId().equals(e1.getSubscription().getId())) { // First order by subscription
                     return getSubscription().getId().compareTo(e1.getSubscription().getId());
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 2394b96..54cffc5 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -17,6 +17,9 @@
 package org.killbill.billing.junction.plumbing.billing;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 import javax.annotation.Nullable;
 
@@ -31,11 +34,14 @@ 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.Usage;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
 import org.killbill.billing.junction.BillingEvent;
 
+import com.google.common.collect.Lists;
+
 public class DefaultBillingEvent implements BillingEvent {
     private final Account account;
     private final int billCycleDayLocal;
@@ -53,19 +59,21 @@ public class DefaultBillingEvent implements BillingEvent {
     private final Long totalOrdering;
     private final DateTimeZone timeZone;
 
+    private final List<Usage> usages;
+
     public DefaultBillingEvent(final Account account, final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
 
         this.account = account;
         this.billCycleDayLocal = billCycleDayLocal;
         this.subscription = subscription;
-        effectiveDate = transition.getEffectiveTransitionTime();
+        this.effectiveDate = transition.getEffectiveTransitionTime();
         final String planPhaseName = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ?
                 transition.getNextPhase() : transition.getPreviousPhase();
-        planPhase = (planPhaseName != null) ? catalog.findPhase(planPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+        this.planPhase = (planPhaseName != null) ? catalog.findPhase(planPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
 
         final String planName = (transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ?
                 transition.getNextPlan() : transition.getPreviousPlan();
-        plan = (planName != null) ? catalog.findPlan(planName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
+        this.plan = (planName != null) ? catalog.findPlan(planName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
 
         final String nextPhaseName = transition.getNextPhase();
         final PlanPhase nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
@@ -74,16 +82,17 @@ public class DefaultBillingEvent implements BillingEvent {
         final PlanPhase prevPhase = (prevPhaseName != null) ? catalog.findPhase(prevPhaseName, transition.getEffectiveTransitionTime(), transition.getSubscriptionStartDate()) : null;
 
 
-        fixedPrice = getFixedPrice(nextPhase, currency);
-        recurringPrice = getRecurringPrice(nextPhase, currency);
+        this.fixedPrice = getFixedPrice(nextPhase, currency);
+        this.recurringPrice = getRecurringPrice(nextPhase, currency);
 
         this.currency = currency;
-        description = transition.getTransitionType().toString();
-        billingMode = BillingMode.IN_ADVANCE;
-        billingPeriod = getRecurringBillingPeriod((transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase);
-        type = transition.getTransitionType();
-        totalOrdering = transition.getTotalOrdering();
-        timeZone = account.getTimeZone();
+        this.description = transition.getTransitionType().toString();
+        this.billingMode = BillingMode.IN_ADVANCE;
+        this.billingPeriod = getRecurringBillingPeriod((transition.getTransitionType() != SubscriptionBaseTransitionType.CANCEL) ? nextPhase : prevPhase);
+        this.type = transition.getTransitionType();
+        this.totalOrdering = transition.getTotalOrdering();
+        this.timeZone = account.getTimeZone();
+        this.usages = initializeUsage();
     }
 
 
@@ -106,6 +115,8 @@ public class DefaultBillingEvent implements BillingEvent {
         this.type = type;
         this.totalOrdering = totalOrdering;
         this.timeZone = timeZone;
+        this.usages = initializeUsage();
+
     }
 
     @Override
@@ -225,6 +236,17 @@ public class DefaultBillingEvent implements BillingEvent {
     }
 
     @Override
+    public DateTimeZone getTimeZone() {
+        return timeZone;
+    }
+
+    @Override
+    public List<Usage> getUsages() {
+        return usages;
+    }
+
+
+    @Override
     public String toString() {
         // Note: we don't use all fields here, as the output would be overwhelming
         // (these events are printed in the logs in junction and invoice).
@@ -320,10 +342,6 @@ public class DefaultBillingEvent implements BillingEvent {
         return result;
     }
 
-    @Override
-    public DateTimeZone getTimeZone() {
-        return timeZone;
-    }
 
     private BigDecimal getFixedPrice(@Nullable final PlanPhase nextPhase, final Currency currency) throws CatalogApiException {
         return (nextPhase != null && nextPhase.getFixed() != null && nextPhase.getFixed().getPrice() != null) ? nextPhase.getFixed().getPrice().getPrice(currency) : null;
@@ -339,4 +357,15 @@ public class DefaultBillingEvent implements BillingEvent {
         }
         return nextPhase.getRecurring() != null ? nextPhase.getRecurring().getBillingPeriod() : BillingPeriod.NO_BILLING_PERIOD;
     }
+
+    private List<Usage> initializeUsage() {
+        List<Usage> result = Collections.<Usage>emptyList();
+        if (planPhase != null) {
+            result = Lists.newArrayList();
+            for (Usage usage : planPhase.getUsages()) {
+                result.add(usage);
+            }
+        }
+        return result;
+    }
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
index 2ae8f34..c917a59 100644
--- a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
+++ b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultUsageUserApi.java
@@ -17,6 +17,7 @@
 package org.killbill.billing.usage.api.user;
 
 import java.math.BigDecimal;
+import java.util.List;
 import java.util.UUID;
 
 import javax.inject.Inject;
@@ -53,8 +54,14 @@ public class DefaultUsageUserApi implements UsageUserApi {
     }
 
     @Override
-    public RolledUpUsage getUsageForSubscription(final UUID subscriptionId, final TenantContext context) {
+    public RolledUpUsage getUsageForSubscription(final UUID subscriptionId,  final String unitType, final DateTime startTime, final DateTime endTime, final TenantContext context) {
         final RolledUpUsageModelDao usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, internalCallContextFactory.createInternalTenantContext(context));
         return new DefaultRolledUpUsage(usageForSubscription);
     }
+
+    @Override
+    public List<RolledUpUsage> getAllUsageForSubscription(final UUID subscriptionId, final String unitType, final List<DateTime> transitionTimes, final TenantContext tenantContext) {
+        // STEPH USAGE
+        return null;
+    }
 }