killbill-uncached

UsageApi change: * Allow to record usage in bulk * Change granularity

9/25/2014 11:24:26 PM

Changes

jaxrs/src/main/java/org/killbill/billing/jaxrs/json/UsageJson.java 111(+0 -111)

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
index 84f8329..b5096a2 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/usage/TestConsumableInArrear.java
@@ -35,17 +35,16 @@ import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.SubscriptionUsageRecord;
+import org.killbill.billing.usage.api.UnitUsageRecord;
+import org.killbill.billing.usage.api.UsageRecord;
 import org.killbill.billing.usage.api.UsageUserApi;
-import org.killbill.billing.usage.api.user.DefaultRolledUpUsage;
-import org.killbill.billing.usage.api.user.MockUsageUserApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
 import org.mockito.Mockito;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableList;
-
 public class TestConsumableInArrear extends TestIntegrationBase {
 
     @BeforeMethod(groups = "slow")
@@ -55,7 +54,7 @@ public class TestConsumableInArrear extends TestIntegrationBase {
 
     protected UsageUserApi createMockUsageUserApi(final List<RolledUpUsage> returnValue) {
         final UsageUserApi result = Mockito.mock(UsageUserApi.class);
-        Mockito.when(result.getAllUsageForSubscription(Mockito.<UUID>any(), Mockito.<Set<String>>any(), Mockito.<List<DateTime>>any(), Mockito.<TenantContext>any())).thenReturn(returnValue);
+        Mockito.when(result.getAllUsageForSubscription(Mockito.<UUID>any(), Mockito.<List<LocalDate>>any(), Mockito.<TenantContext>any())).thenReturn(returnValue);
         return result;
     }
 
@@ -85,8 +84,8 @@ public class TestConsumableInArrear extends TestIntegrationBase {
         //
         final DefaultEntitlement aoSubscription = addAOEntitlementAndCheckForCompletion(bpSubscription.getBundleId(), "Bullets", ProductCategory.ADD_ON, BillingPeriod.NO_BILLING_PERIOD, NextEvent.CREATE);
 
-        setUsage(aoSubscription.getId(), "bullets", new DateTime(2012, 4, 1, 1, 1, DateTimeZone.UTC), new DateTime(2012, 4, 15, 0, 0, DateTimeZone.UTC), new BigDecimal("99"), callContext);
-        setUsage(aoSubscription.getId(), "bullets", new DateTime(2012, 4, 15, 0, 0, DateTimeZone.UTC), new DateTime(2012, 4, 20, 1, 1, DateTimeZone.UTC), new BigDecimal("100"), callContext);
+        setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 1), 99L, callContext);
+        setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 4, 15), 100L, callContext);
 
         busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT);
         clock.setDay(new LocalDate(2012, 5, 1));
@@ -105,8 +104,8 @@ public class TestConsumableInArrear extends TestIntegrationBase {
                                     new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.USAGE, BigDecimal.ZERO));
 
 
-        setUsage(aoSubscription.getId(), "bullets", new DateTime(2012, 6, 1, 1, 1, DateTimeZone.UTC), new DateTime(2012, 6, 15, 1, 1, DateTimeZone.UTC), new BigDecimal("50"), callContext);
-        setUsage(aoSubscription.getId(), "bullets", new DateTime(2012, 6, 16, 1, 1, DateTimeZone.UTC), new DateTime(2012, 6, 20, 1, 1, DateTimeZone.UTC), new BigDecimal("300"), callContext);
+        setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 6, 1), 50L, callContext);
+        setUsage(aoSubscription.getId(), "bullets", new LocalDate(2012, 6, 16), 300L, callContext);
 
 
         busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT);
@@ -118,7 +117,12 @@ public class TestConsumableInArrear extends TestIntegrationBase {
 
     }
 
-    private void setUsage(final UUID subscriptionId, final String unitType, final DateTime startTime, final DateTime endTime, final BigDecimal amount, final CallContext context) {
-        usageUserApi.recordRolledUpUsage(subscriptionId, unitType, startTime, endTime, amount, context);
+    private void setUsage(final UUID subscriptionId, final String unitType, final LocalDate startDate, final Long amount, final CallContext context) {
+        final List<UsageRecord> usageRecords = new ArrayList<UsageRecord>();
+        usageRecords.add(new UsageRecord(startDate, amount));
+        final List<UnitUsageRecord> unitUsageRecords = new ArrayList<UnitUsageRecord>();
+        unitUsageRecords.add(new UnitUsageRecord(unitType, usageRecords));
+        final SubscriptionUsageRecord record = new SubscriptionUsageRecord(subscriptionId, unitUsageRecords);
+        usageUserApi.recordRolledUpUsage(record, context);
     }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
index dcb30e1..2b6349b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
@@ -18,15 +18,12 @@ package org.killbill.billing.invoice.usage;
 
 import java.math.BigDecimal;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
+import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -38,15 +35,16 @@ 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.RolledUpUnit;
 import org.killbill.billing.usage.api.RolledUpUsage;
 import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
-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;
 
@@ -59,6 +57,8 @@ import static org.killbill.billing.invoice.usage.UsageUtils.getConsumableInArrea
  */
 public class ContiguousIntervalConsumableInArrear {
 
+    private static final Logger log = LoggerFactory.getLogger(ContiguousIntervalConsumableInArrear.class);
+
     private final List<LocalDate> transitionTimes;
     private final List<BillingEvent> billingEvents;
 
@@ -136,19 +136,23 @@ public class ContiguousIntervalConsumableInArrear {
 
         final List<InvoiceItem> result = Lists.newLinkedList();
 
-        final RolledUpUsageForUnitTypesFactory factory = new RolledUpUsageForUnitTypesFactory(getRolledUpUsage(), unitTypes, getAccountTimeZone());
-
-        for (RolledUpUsageForUnitTypes ru : factory.getOrderedRolledUpUsageForUnitTypes()) {
+        final List<RolledUpUsage> allUsage = getRolledUpUsage();
+        for (final RolledUpUsage ru : allUsage) {
 
             // Compute total price amount that should be billed for that period of time (and usage section) across unitTypes.
             BigDecimal toBeBilledUsage = BigDecimal.ZERO;
-            for (final String unitType : unitTypes) {
-                final BigDecimal usageAmountForUnitType = ru.getUsageAmountForUnitType(unitType);
-                final BigDecimal toBeBilledForUnit = computeToBeBilledUsage(usageAmountForUnitType, unitType);
+            for (final RolledUpUnit cur : ru.getRolledUpUnit()) {
+                if (!unitTypes.contains(cur.getUnitType())) {
+                    log.warn("ContiguousIntervalConsumableInArrear is skipping unitType " + cur.getUnitType());
+                    continue;
+                }
+
+                final BigDecimal toBeBilledForUnit = computeToBeBilledUsage(cur.getAmount(), cur.getUnitType());
                 toBeBilledUsage = toBeBilledUsage.add(toBeBilledForUnit);
+
             }
             // Retrieves current price amount billed for that period of time (and usage section)
-            final Iterable<InvoiceItem> billedItems = getBilledItems(ru.getStartDate(), ru.getEndDate(), existingUsage);
+            final Iterable<InvoiceItem> billedItems = getBilledItems(ru.getStart(), ru.getEnd(), existingUsage);
             final BigDecimal billedUsage = computeBilledUsage(billedItems);
 
             // Compare the two and add the missing piece if required.
@@ -156,17 +160,15 @@ public class ContiguousIntervalConsumableInArrear {
                 final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
                 if (amountToBill.compareTo(BigDecimal.ZERO) > 0 || insertZeroAmountItems) {
                     InvoiceItem item = new UsageInvoiceItem(invoiceId, getAccountId(), getBundleId(), getSubscriptionId(), getPlanName(),
-                                                            getPhaseName(), usage.getName(), ru.getStartDate(), ru.getEndDate(), amountToBill, getCurrency());
+                                                            getPhaseName(), usage.getName(), ru.getStart(), ru.getEnd(), amountToBill, getCurrency());
                     result.add(item);
                 }
             }
-
         }
         return result;
     }
 
     /**
-     *
      * @return a list of {@code RolledUpUsage} for each period (between two transitions) * each unitType.
      */
     List<RolledUpUsage> getRolledUpUsage() {
@@ -174,25 +176,17 @@ public class ContiguousIntervalConsumableInArrear {
         if (transitionTimes.size() <= 1) {
             return Collections.emptyList();
         }
-
-        final Iterable<DateTime> transitions = Iterables.transform(transitionTimes, new Function<LocalDate, DateTime>() {
-            @Override
-            public DateTime apply(final LocalDate input) {
-                return localDateToEndOfDayInAccountTimezone(input, getAccountTimeZone());
-            }
-        });
-        return usageApi.getAllUsageForSubscription(getSubscriptionId(), unitTypes, ImmutableList.copyOf(transitions), context);
+        return usageApi.getAllUsageForSubscription(getSubscriptionId(), transitionTimes, context);
     }
 
     /**
-     *
      * @param nbUnits  the number of used units for a given period
      * @param unitType the type of unit
-     * @return  the price amount that should be billed for that period/unitType
+     * @return the price amount that should be billed for that period/unitType
      * @throws CatalogApiException
      */
     @VisibleForTesting
-    BigDecimal computeToBeBilledUsage(final BigDecimal nbUnits, final String unitType) throws CatalogApiException {
+    BigDecimal computeToBeBilledUsage(final Long nbUnits, final String unitType) throws CatalogApiException {
 
         Preconditions.checkState(isBuilt.get());
 
@@ -217,7 +211,6 @@ public class ContiguousIntervalConsumableInArrear {
     }
 
     /**
-     *
      * @param filteredUsageForInterval the list of invoiceItem to consider
      * @return the price amount that was already billed for that period and usage section (across unitTypes)
      */
@@ -242,7 +235,6 @@ public class ContiguousIntervalConsumableInArrear {
                 if (input.getInvoiceItemType() != InvoiceItemType.USAGE) {
                     return false;
                 }
-
                 // STEPH what happens if we discover usage period that overlap (one side or both side) the [startDate, endDate] interval
                 final UsageInvoiceItem usageInput = (UsageInvoiceItem) input;
                 return usageInput.getUsageName().equals(usage.getName()) &&
@@ -257,97 +249,6 @@ public class ContiguousIntervalConsumableInArrear {
         return transitionTimes;
     }
 
-    private static class RolledUpUsageForUnitTypesFactory {
-
-        private final Map<String, RolledUpUsageForUnitTypes> map;
-
-        public RolledUpUsageForUnitTypesFactory(final List<RolledUpUsage> rolledUpUsages, final Set<String> unitTypes, final DateTimeZone accountTimeZone) {
-            map = new HashMap<String, RolledUpUsageForUnitTypes>();
-            for (RolledUpUsage ru : rolledUpUsages) {
-
-                final LocalDate startRolledUpDate = new LocalDate(ru.getStartTime(), accountTimeZone);
-                final LocalDate endRolledUpDate = new LocalDate(ru.getEndTime(), accountTimeZone);
-                final String key = startRolledUpDate + "-" + endRolledUpDate;
-
-                RolledUpUsageForUnitTypes usageForUnitTypes = map.get(key);
-                if (usageForUnitTypes == null) {
-                    usageForUnitTypes = new RolledUpUsageForUnitTypes(startRolledUpDate, endRolledUpDate, unitTypes);
-                    map.put(key, usageForUnitTypes);
-                }
-                usageForUnitTypes.addUsageForUnit(ru.getUnitType(), ru.getAmount());
-            }
-        }
-
-        public List<RolledUpUsageForUnitTypes> getOrderedRolledUpUsageForUnitTypes() {
-            final LinkedList<RolledUpUsageForUnitTypes> result = new LinkedList<RolledUpUsageForUnitTypes>(map.values());
-            Collections.sort(result);
-            return result;
-        }
-    }
-
-    /**
-     * Internal classes to transform RolledUpUsage into a map of usage (types, amount) across each billable interval.
-     */
-    private static class RolledUpUsageForUnitTypes implements Comparable {
-
-        private final LocalDate startDate;
-        private final LocalDate endDate;
-        private final Map<String, BigDecimal> unitAmounts;
-
-        private RolledUpUsageForUnitTypes(final LocalDate startDate, final LocalDate endDate, final Set<String> unitTypes) {
-            this.endDate = endDate;
-            this.startDate = startDate;
-            this.unitAmounts = new HashMap<String, BigDecimal>();
-            for (final String type : unitTypes) {
-                unitAmounts.put(type, BigDecimal.ZERO);
-            }
-        }
-
-        public void addUsageForUnit(final String unitType, BigDecimal amount) {
-            final BigDecimal currentAmount = unitAmounts.get(unitType);
-            unitAmounts.put(unitType, currentAmount.add(amount));
-        }
-
-        public LocalDate getStartDate() {
-            return startDate;
-        }
-
-        public LocalDate getEndDate() {
-            return endDate;
-        }
-
-        public BigDecimal getUsageAmountForUnitType(final String unitType) {
-            return unitAmounts.get(unitType);
-        }
-
-        @Override
-        public int hashCode() {
-            int result = startDate != null ? startDate.hashCode() : 0;
-            result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
-            result = 31 * result + (unitAmounts != null ? unitAmounts.hashCode() : 0);
-            return result;
-        }
-
-        @Override
-        public int compareTo(final Object o) {
-
-            Preconditions.checkArgument(o instanceof RolledUpUsageForUnitTypes);
-            final RolledUpUsageForUnitTypes other = (RolledUpUsageForUnitTypes) o;
-            // We will check later intervals don't overlap.
-            int i = getEndDate().compareTo(other.getStartDate());
-            if (i != 0) {
-                return i;
-            } else {
-                i = getEndDate().compareTo(other.getEndDate());
-                if (i != 0) {
-                    return i;
-                } else {
-                    return getStartDate().compareTo(other.getStartDate());
-                }
-            }
-        }
-    }
-
     public void addBillingEvent(final BillingEvent event) {
         Preconditions.checkState(!isBuilt.get());
         billingEvents.add(event);
@@ -390,9 +291,4 @@ public class ContiguousIntervalConsumableInArrear {
         return billingEvents.get(0).getTimeZone();
     }
 
-    static DateTime localDateToEndOfDayInAccountTimezone(final LocalDate input, final DateTimeZone accountTimeZone) {
-        final DateTime dateTimeInAccountTimeZone = new DateTime(input.getYear(), input.getMonthOfYear(), input.getDayOfMonth(), 0, 0, 0, accountTimeZone);
-        return new DateTime(dateTimeInAccountTimeZone, DateTimeZone.UTC);
-    }
-
 }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
index 5cb31a9..d73bcbe 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalConsumableInArrear.java
@@ -35,6 +35,7 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
 import org.killbill.billing.invoice.model.UsageInvoiceItem;
 import org.killbill.billing.junction.BillingEvent;
+import org.killbill.billing.usage.api.RolledUpUnit;
 import org.killbill.billing.usage.api.RolledUpUsage;
 import org.killbill.billing.usage.api.user.DefaultRolledUpUsage;
 import org.testng.annotations.BeforeClass;
@@ -115,7 +116,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
                                                                                                                                                   Collections.<Usage>emptyList())
                                                                                                                           );
 
-        final BigDecimal result = intervalConsumableInArrear.computeToBeBilledUsage(new BigDecimal("5325"), "unit");
+        final BigDecimal result = intervalConsumableInArrear.computeToBeBilledUsage(5325L, "unit");
 
         // 5000 = 1000 (tier1) + 4325 (tier2) => 10 + 5 = 15
         assertEquals(result, new BigDecimal("15"));
@@ -129,13 +130,17 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         final LocalDate endDate = new LocalDate(2014, 05, 15);
 
         // 2 items for startDate - firstBCDDate
-        final RolledUpUsage usage1 = new DefaultRolledUpUsage(subscriptionId, "unit", startDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), firstBCDDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), new BigDecimal("130"));
-        final RolledUpUsage usage2 = new DefaultRolledUpUsage(subscriptionId, "unit", startDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), firstBCDDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), new BigDecimal("271"));
+        final List<RolledUpUnit> units1 = new ArrayList<RolledUpUnit>();
+        units1.add(createRolledUpUnit("unit", 130L));
+        units1.add(createRolledUpUnit("unit", 271L));
+        final RolledUpUsage usage1 = new DefaultRolledUpUsage(subscriptionId, startDate, firstBCDDate, units1);
 
         // 1 items for firstBCDDate - endDate
-        final RolledUpUsage usage3 = new DefaultRolledUpUsage(subscriptionId, "unit", firstBCDDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), endDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), new BigDecimal("199"));
+        final List<RolledUpUnit> units2 = new ArrayList<RolledUpUnit>();
+        units2.add(createRolledUpUnit("unit", 199L));
+        final RolledUpUsage usage3 = new DefaultRolledUpUsage(subscriptionId, firstBCDDate, endDate, units2);
 
-        final List<RolledUpUsage> usages = ImmutableList.<RolledUpUsage>builder().add(usage1).add(usage2).add(usage3).build();
+        final List<RolledUpUsage> usages = ImmutableList.<RolledUpUsage>builder().add(usage1).add(usage3).build();
         this.mockUsageUserApi = createMockUsageUserApi(usages);
 
         final DefaultTieredBlock block = createDefaultTieredBlock("unit", 100, 10, BigDecimal.ONE);
@@ -181,7 +186,18 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         assertEquals(result.get(1).getUsageName(), usage.getName());
         assertTrue(result.get(1).getStartDate().compareTo(firstBCDDate) == 0);
         assertTrue(result.get(1).getEndDate().compareTo(endDate) == 0);
-
     }
 
+    private RolledUpUnit createRolledUpUnit(final String unit, final Long amount) {
+        return new RolledUpUnit() {
+            @Override
+            public String getUnitType() {
+                return unit;
+            }
+            @Override
+            public Long getAmount() {
+                return amount;
+            }
+        };
+    }
 }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
index 222f938..6d66b40 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
@@ -78,7 +78,7 @@ public abstract class TestUsageInArrearBase extends InvoiceTestSuiteNoDB {
 
     protected UsageUserApi createMockUsageUserApi(final List<RolledUpUsage> returnValue) {
         final UsageUserApi result = Mockito.mock(UsageUserApi.class);
-        Mockito.when(result.getAllUsageForSubscription(Mockito.<UUID>any(), Mockito.<Set<String>>any(), Mockito.<List<DateTime>>any(), Mockito.<TenantContext>any())).thenReturn(returnValue);
+        Mockito.when(result.getAllUsageForSubscription(Mockito.<UUID>any(), Mockito.<List<LocalDate>>any(), Mockito.<TenantContext>any())).thenReturn(returnValue);
         return result;
     }
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java
new file mode 100644
index 0000000..98f6812
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/RolledUpUsageJson.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014 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.joda.time.LocalDate;
+import org.killbill.billing.usage.api.RolledUpUnit;
+import org.killbill.billing.usage.api.RolledUpUsage;
+
+import com.apple.jobjc.Invoke.FunCall;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class RolledUpUsageJson {
+
+    private final String subscriptionId;
+    private final LocalDate startDate;
+    private final LocalDate endDate;
+    private final List<RolledUpUnitJson> rolledUpUnits;
+
+    @JsonCreator
+    public RolledUpUsageJson(@JsonProperty("subscriptionId") final String subscriptionId,
+                             @JsonProperty("startDate") final LocalDate startDate,
+                             @JsonProperty("endDate") final LocalDate endDate,
+                             @JsonProperty("rolledUpUnit") final List<RolledUpUnitJson> rolledUpUnits) {
+        this.subscriptionId = subscriptionId;
+        this.startDate = startDate;
+        this.endDate = endDate;
+        this.rolledUpUnits = rolledUpUnits;
+    }
+
+    public RolledUpUsageJson(final RolledUpUsage input) {
+        this(input.getSubscriptionId().toString(), input.getStart(), input.getEnd(), ImmutableList.copyOf(Iterables.transform(input.getRolledUpUnit(), new Function<RolledUpUnit, RolledUpUnitJson>() {
+            @Override
+            public RolledUpUnitJson apply(final RolledUpUnit input) {
+                return new RolledUpUnitJson(input);
+            }
+        })));
+    }
+
+    public String getSubscriptionId() {
+        return subscriptionId;
+    }
+
+    public LocalDate getStartDate() {
+        return startDate;
+    }
+
+    public LocalDate getEndDate() {
+        return endDate;
+    }
+
+    public List<RolledUpUnitJson> getRolledUpUnits() {
+        return rolledUpUnits;
+    }
+
+    public static class RolledUpUnitJson {
+
+        private final String unitType;
+        private final Long amount;
+
+        @JsonCreator
+        public RolledUpUnitJson(@JsonProperty("unitType") final String unitType,
+                                @JsonProperty("amount") final Long amount) {
+            this.unitType = unitType;
+            this.amount = amount;
+        }
+
+        public RolledUpUnitJson(final RolledUpUnit input) {
+            this(input.getUnitType(), input.getAmount());
+        }
+
+        public String getUnitType() {
+            return unitType;
+        }
+
+        public Long getAmount() {
+            return amount;
+        }
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java
new file mode 100644
index 0000000..a7c5cd3
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/SubscriptionUsageRecordJson.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.LocalDate;
+import org.killbill.billing.usage.api.SubscriptionUsageRecord;
+import org.killbill.billing.usage.api.UnitUsageRecord;
+import org.killbill.billing.usage.api.UsageRecord;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class SubscriptionUsageRecordJson {
+
+    private final String subscriptionId;
+    private final List<UnitUsageRecordJson> unitUsageRecords;
+
+    @JsonCreator
+    public SubscriptionUsageRecordJson(@JsonProperty("subscriptionId") final String subscriptionId,
+                                   @JsonProperty("unitUsageRecords") final List<UnitUsageRecordJson> unitUsageRecords) {
+        this.subscriptionId = subscriptionId;
+        this.unitUsageRecords = unitUsageRecords;
+    }
+
+    public String getSubscriptionId() {
+        return subscriptionId;
+    }
+
+    public List<UnitUsageRecordJson> getUnitUsageRecords() {
+        return unitUsageRecords;
+    }
+
+    public static class UnitUsageRecordJson {
+
+        private final String unitType;
+        private final List<UsageRecordJson> usageRecords;
+
+        @JsonCreator
+        public UnitUsageRecordJson(@JsonProperty("unitType") final String unitType,
+                                    @JsonProperty("usageRecords") final List<UsageRecordJson> usageRecords) {
+            this.unitType = unitType;
+            this.usageRecords = usageRecords;
+        }
+
+        public String getUnitType() {
+            return unitType;
+        }
+
+        public List<UsageRecordJson> getUsageRecords() {
+            return usageRecords;
+        }
+
+        public UnitUsageRecord toUnitUsageRecord() {
+            final List<UsageRecord> tmp = ImmutableList.copyOf(Iterables.transform(usageRecords, new Function<UsageRecordJson, UsageRecord>() {
+                @Override
+                public UsageRecord apply(final UsageRecordJson input) {
+                    return input.toUsageRecord();
+                }
+            }));
+            return new UnitUsageRecord(unitType, tmp);
+        }
+    }
+
+    public static class UsageRecordJson {
+
+        private final LocalDate recordDate;
+        private final Long amount;
+
+        @JsonCreator
+        public UsageRecordJson(@JsonProperty("recordDate") final LocalDate recordDate,
+                               @JsonProperty("amount") final Long amount) {
+            this.recordDate = recordDate;
+            this.amount = amount;
+        }
+
+        public LocalDate getRecordDate() {
+            return recordDate;
+        }
+
+        public Long getAmount() {
+            return amount;
+        }
+
+        public UsageRecord toUsageRecord() {
+            return new UsageRecord(recordDate, amount);
+        }
+    }
+
+    public SubscriptionUsageRecord toSubscriptionUsageRecord() {
+        final List<UnitUsageRecord> tmp = ImmutableList.copyOf(Iterables.transform(unitUsageRecords, new Function<UnitUsageRecordJson, UnitUsageRecord>() {
+            @Override
+            public UnitUsageRecord apply(final UnitUsageRecordJson input) {
+                return input.toUnitUsageRecord();
+            }
+        }));
+        final SubscriptionUsageRecord result = new SubscriptionUsageRecord(UUID.fromString(subscriptionId), tmp);
+        return result;
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 5fa2d62..aeabae3 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -98,8 +98,8 @@ public interface JaxrsResource {
 
     public static final String QUERY_PLUGIN_PROPERTY = "pluginProperty";
 
-    public static final String QUERY_START_TIME = "startTime";
-    public static final String QUERY_END_TIME = "endTime";
+    public static final String QUERY_START_DATE = "startDate";
+    public static final String QUERY_END_DATE = "endDate";
 
     public static final String QUERY_BUNDLE_TRANSFER_ADDON = "transferAddOn";
     public static final String QUERY_BUNDLE_TRANSFER_CANCEL_IMM = "cancelImmediately";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
index bc07c8a..71ade06 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/UsageResource.java
@@ -16,8 +16,10 @@
 
 package org.killbill.billing.jaxrs.resources;
 
+import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.concurrent.Immutable;
 import javax.inject.Inject;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -32,13 +34,18 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
-import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
-import org.killbill.billing.jaxrs.json.UsageJson;
+import org.killbill.billing.entitlement.api.EntitlementApi;
+import org.killbill.billing.entitlement.api.EntitlementApiException;
+import org.killbill.billing.jaxrs.json.RolledUpUsageJson;
+import org.killbill.billing.jaxrs.json.SubscriptionUsageRecordJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.SubscriptionUsageRecord;
 import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldUserApi;
@@ -48,6 +55,8 @@ import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.clock.Clock;
 
 import com.codahale.metrics.annotation.Timed;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Singleton;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
@@ -56,6 +65,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 public class UsageResource extends JaxRsResourceBase {
 
     private final UsageUserApi usageUserApi;
+    private final EntitlementApi entitlementApi;
 
     @Inject
     public UsageResource(final JaxrsUriBuilder uriBuilder,
@@ -65,25 +75,35 @@ public class UsageResource extends JaxRsResourceBase {
                          final AccountUserApi accountUserApi,
                          final UsageUserApi usageUserApi,
                          final PaymentApi paymentApi,
+                         final EntitlementApi entitlementApi,
                          final Clock clock,
                          final Context context) {
         super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, clock, context);
         this.usageUserApi = usageUserApi;
+        this.entitlementApi = entitlementApi;
     }
 
     @Timed
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    public Response recordUsage(final UsageJson json,
+    public Response recordUsage(final SubscriptionUsageRecordJson json,
                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                   @HeaderParam(HDR_REASON) final String reason,
                                   @HeaderParam(HDR_COMMENT) final String comment,
                                   @javax.ws.rs.core.Context final HttpServletRequest request,
-                                  @javax.ws.rs.core.Context final UriInfo uriInfo)  {
+                                  @javax.ws.rs.core.Context final UriInfo uriInfo) throws EntitlementApiException, AccountApiException {
+
+        Preconditions.checkNotNull(json.getSubscriptionId());
+        Preconditions.checkNotNull(json.getUnitUsageRecords());
+        Preconditions.checkArgument(!json.getUnitUsageRecords().isEmpty());
 
         final CallContext callContext = context.createContext(createdBy, reason, comment, request);
-        usageUserApi.recordRolledUpUsage(UUID.fromString(json.getSubscriptionId()), json.getUnitType(), json.getStartTime(), json.getEndTime(), json.getAmount(), callContext);
+        // Verify subscription exists..
+        entitlementApi.getEntitlementForId(UUID.fromString(json.getSubscriptionId()), callContext);
+
+        final SubscriptionUsageRecord record = json.toSubscriptionUsageRecord();
+        usageUserApi.recordRolledUpUsage(record, callContext);
         return Response.status(Status.CREATED).build();
     }
 
@@ -92,18 +112,39 @@ public class UsageResource extends JaxRsResourceBase {
     @Path("/{subscriptionId:" + UUID_PATTERN + "}/{unitType}")
     @Produces(APPLICATION_JSON)
     public Response getUsage(@PathParam("subscriptionId") final String subscriptionId,
-                               @PathParam("unitType") final String unitType,
-                               @QueryParam(QUERY_START_TIME) final String startTime,
-                               @QueryParam(QUERY_END_TIME) final String endTime,
-                               @javax.ws.rs.core.Context final HttpServletRequest request)  {
+                             @PathParam("unitType") final String unitType,
+                             @QueryParam(QUERY_START_DATE) final String startDate,
+                             @QueryParam(QUERY_END_DATE) final String endDate,
+                             @javax.ws.rs.core.Context final HttpServletRequest request)  {
+
+        final TenantContext tenantContext = context.createContext(request);
+
+        final LocalDate usageStartDate = LOCAL_DATE_FORMATTER.parseLocalDate(startDate);
+        final LocalDate usageEndDate = LOCAL_DATE_FORMATTER.parseLocalDate(endDate);
+
+        final RolledUpUsage usage = usageUserApi.getUsageForSubscription(UUID.fromString(subscriptionId), unitType, usageStartDate, usageEndDate, tenantContext);
+        final RolledUpUsageJson result = new RolledUpUsageJson(usage);
+        return Response.status(Status.OK).entity(result).build();
+    }
+
+    @Timed
+    @GET
+    @Path("/{subscriptionId:" + UUID_PATTERN + "}")
+    @Produces(APPLICATION_JSON)
+    public Response getAllUsage(@PathParam("subscriptionId") final String subscriptionId,
+                             @QueryParam(QUERY_START_DATE) final String startDate,
+                             @QueryParam(QUERY_END_DATE) final String endDate,
+                             @javax.ws.rs.core.Context final HttpServletRequest request)  {
 
         final TenantContext tenantContext = context.createContext(request);
 
-        final DateTime usageStartTime = DATE_TIME_FORMATTER.parseDateTime(startTime);
-        final DateTime usageEndTime = DATE_TIME_FORMATTER.parseDateTime(endTime);
+        final LocalDate usageStartDate = LOCAL_DATE_FORMATTER.parseLocalDate(startDate);
+        final LocalDate usageEndDate = LOCAL_DATE_FORMATTER.parseLocalDate(endDate);
 
-        final RolledUpUsage usage = usageUserApi.getUsageForSubscription(UUID.fromString(subscriptionId), unitType, usageStartTime, usageEndTime, tenantContext);
-        final UsageJson result = new UsageJson(usage);
+        // The current JAXRS API only allows to look for one transition
+        final List<LocalDate> startEndDate = ImmutableList.<LocalDate>builder().add(usageStartDate).add(usageEndDate).build();
+        final List<RolledUpUsage> usage = usageUserApi.getAllUsageForSubscription(UUID.fromString(subscriptionId), startEndDate, tenantContext);
+        final RolledUpUsageJson result = new RolledUpUsageJson(usage.get(0));
         return Response.status(Status.OK).entity(result).build();
     }
 
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUnit.java b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUnit.java
new file mode 100644
index 0000000..50c7ac3
--- /dev/null
+++ b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUnit.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014 Groupon, Inc
+ * Copyright 2014 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.usage.api.user;
+
+import org.killbill.billing.usage.api.RolledUpUnit;
+
+public class DefaultRolledUpUnit implements RolledUpUnit {
+
+    private final String unitType;
+    private final Long amount;
+
+    public DefaultRolledUpUnit(final String unitType, final Long amount) {
+        this.unitType = unitType;
+        this.amount = amount;
+    }
+
+    @Override
+    public String getUnitType() {
+        return unitType;
+    }
+
+    @Override
+    public Long getAmount() {
+        return amount;
+    }
+}
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUsage.java b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUsage.java
index 3681acf..d28244c 100644
--- a/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUsage.java
+++ b/usage/src/main/java/org/killbill/billing/usage/api/user/DefaultRolledUpUsage.java
@@ -16,34 +16,25 @@
 
 package org.killbill.billing.usage.api.user;
 
-import java.math.BigDecimal;
+import java.util.List;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
+import org.joda.time.LocalDate;
+import org.killbill.billing.usage.api.RolledUpUnit;
 import org.killbill.billing.usage.api.RolledUpUsage;
-import org.killbill.billing.usage.dao.RolledUpUsageModelDao;
 
 public class DefaultRolledUpUsage implements RolledUpUsage {
 
     private final UUID subscriptionId;
-    private final String unitType;
-    private final DateTime startTime;
-    private final DateTime endTime;
-    private final BigDecimal amount;
+    private final LocalDate startDate;
+    private final LocalDate endDate;
+    private final List<RolledUpUnit> rolledUpUnits;
 
-    public DefaultRolledUpUsage(final UUID subscriptionId, final String unitType, final DateTime startTime, final DateTime endTime,
-                                final BigDecimal amount) {
+    public DefaultRolledUpUsage(final UUID subscriptionId, final LocalDate startDate, final LocalDate endDate, final List<RolledUpUnit> rolledUpUnits) {
         this.subscriptionId = subscriptionId;
-        this.unitType = unitType;
-        this.startTime = startTime;
-        this.endTime = endTime;
-        this.amount = amount;
-    }
-
-    public DefaultRolledUpUsage(final RolledUpUsageModelDao usageForSubscription) {
-        this(usageForSubscription.getSubscriptionId(), usageForSubscription.getUnitType(), usageForSubscription.getStartTime(),
-             usageForSubscription.getEndTime(), usageForSubscription.getAmount());
+        this.startDate = startDate;
+        this.endDate = endDate;
+        this.rolledUpUnits = rolledUpUnits;
     }
 
     @Override
@@ -51,75 +42,18 @@ public class DefaultRolledUpUsage implements RolledUpUsage {
         return subscriptionId;
     }
 
-    public String getUnitType() {
-        return unitType;
-    }
-
     @Override
-    public DateTime getStartTime() {
-        return startTime;
+    public LocalDate getStart() {
+        return startDate;
     }
 
     @Override
-    public DateTime getEndTime() {
-        return endTime;
-    }
-
-    @Override
-    public BigDecimal getAmount() {
-        return amount;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("DefaultRolledUpUsage");
-        sb.append("{subscriptionId=").append(subscriptionId);
-        sb.append(", unitType='").append(unitType).append('\'');
-        sb.append(", startTime=").append(startTime);
-        sb.append(", endTime=").append(endTime);
-        sb.append(", amount=").append(amount);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        final DefaultRolledUpUsage that = (DefaultRolledUpUsage) o;
-
-        if (amount != null ? !amount.equals(that.amount) : that.amount != null) {
-            return false;
-        }
-        if (endTime != null ? !endTime.equals(that.endTime) : that.endTime != null) {
-            return false;
-        }
-        if (unitType != null ? !unitType.equals(that.unitType) : that.unitType != null) {
-            return false;
-        }
-        if (startTime != null ? !startTime.equals(that.startTime) : that.startTime != null) {
-            return false;
-        }
-        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
-            return false;
-        }
-
-        return true;
+    public LocalDate getEnd() {
+        return endDate;
     }
 
     @Override
-    public int hashCode() {
-        int result = subscriptionId != null ? subscriptionId.hashCode() : 0;
-        result = 31 * result + (unitType != null ? unitType.hashCode() : 0);
-        result = 31 * result + (startTime != null ? startTime.hashCode() : 0);
-        result = 31 * result + (endTime != null ? endTime.hashCode() : 0);
-        result = 31 * result + (amount != null ? amount.hashCode() : 0);
-        return result;
+    public List<RolledUpUnit> getRolledUpUnit() {
+        return rolledUpUnits;
     }
 }
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 5b771d9..e1020f5 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
@@ -16,24 +16,27 @@
 
 package org.killbill.billing.usage.api.user;
 
-import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 import java.util.UUID;
 
 import javax.inject.Inject;
 
-import org.joda.time.DateTime;
-
+import org.joda.time.LocalDate;
 import org.killbill.billing.ObjectType;
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.usage.api.RolledUpUnit;
 import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.SubscriptionUsageRecord;
+import org.killbill.billing.usage.api.UnitUsageRecord;
+import org.killbill.billing.usage.api.UsageRecord;
 import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.usage.dao.RolledUpUsageDao;
 import org.killbill.billing.usage.dao.RolledUpUsageModelDao;
 import org.killbill.billing.util.callcontext.CallContext;
-import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
 
@@ -50,33 +53,49 @@ public class DefaultUsageUserApi implements UsageUserApi {
     }
 
     @Override
-    public void recordRolledUpUsage(final UUID subscriptionId, final String unitType, final DateTime startTime, final DateTime endTime,
-                                    final BigDecimal amount, final CallContext context) {
-        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(subscriptionId, ObjectType.SUBSCRIPTION, context);
-        rolledUpUsageDao.record(subscriptionId, unitType, startTime, endTime, amount, internalCallContext);
+    public void recordRolledUpUsage(final SubscriptionUsageRecord record, final CallContext callContext) {
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(record.getSubscriptionId(), ObjectType.SUBSCRIPTION, callContext);
+        for (UnitUsageRecord unitUsageRecord : record.getPerUnitUsage()) {
+            for (UsageRecord usageRecord : unitUsageRecord.getDailyAmount()) {
+                rolledUpUsageDao.record(record.getSubscriptionId(), unitUsageRecord.getUnitType(), usageRecord.getDate(), usageRecord.getAmount(), internalCallContext);
+            }
+        }
     }
 
     @Override
-    public RolledUpUsage getUsageForSubscription(final UUID subscriptionId,  final String unitType, final DateTime startTime, final DateTime endTime, final TenantContext context) {
-        final RolledUpUsageModelDao usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startTime, endTime, unitType, internalCallContextFactory.createInternalTenantContext(context));
-        return new DefaultRolledUpUsage(usageForSubscription);
+    public RolledUpUsage getUsageForSubscription(final UUID subscriptionId, final String unitType, final LocalDate startDate, final LocalDate endDate, final TenantContext tenantContext) {
+        final List<RolledUpUsageModelDao> usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContextFactory.createInternalTenantContext(tenantContext));
+        final List<RolledUpUnit> rolledUpAmount = getRolledUpUnits(usageForSubscription);
+        return new DefaultRolledUpUsage(subscriptionId, startDate, endDate, rolledUpAmount);
     }
 
     @Override
-    public List<RolledUpUsage> getAllUsageForSubscription(final UUID subscriptionId, final Set<String> unitTypes, final List<DateTime> transitionTimes, final TenantContext tenantContext) {
-
+    public List<RolledUpUsage> getAllUsageForSubscription(final UUID subscriptionId, final List<LocalDate> transitionTimes, final TenantContext tenantContext) {
         final InternalTenantContext internalCallContext = internalCallContextFactory.createInternalTenantContext(subscriptionId, ObjectType.SUBSCRIPTION, tenantContext);
         List<RolledUpUsage> result = new ArrayList<RolledUpUsage>();
-        DateTime prevDate = null;
-        for (DateTime curDate : transitionTimes) {
+        LocalDate prevDate = null;
+        for (LocalDate curDate : transitionTimes) {
             if (prevDate != null) {
-                for (String unitType : unitTypes) {
-                    final RolledUpUsageModelDao usageForSubscription = rolledUpUsageDao.getUsageForSubscription(subscriptionId, prevDate, curDate, unitType, internalCallContext);
-                    result.add(new DefaultRolledUpUsage(usageForSubscription));
-                }
+                final List<RolledUpUsageModelDao> usageForSubscription = rolledUpUsageDao.getAllUsageForSubscription(subscriptionId, prevDate, curDate, internalCallContext);
+                final List<RolledUpUnit> rolledUpAmount = getRolledUpUnits(usageForSubscription);
+                result.add(new DefaultRolledUpUsage(subscriptionId, prevDate, curDate, rolledUpAmount));
             }
             prevDate = curDate;
         }
         return result;
     }
+
+    private List<RolledUpUnit> getRolledUpUnits(final List<RolledUpUsageModelDao> usageForSubscription) {
+        final Map<String, Long> tmp = new HashMap<String, Long>();
+        for (RolledUpUsageModelDao cur : usageForSubscription) {
+            Long currentAmount = tmp.get(cur.getUnitType());
+            Long updatedAmount = (currentAmount != null) ? currentAmount + cur.getAmount() : cur.getAmount();
+            tmp.put(cur.getUnitType(), updatedAmount);
+        }
+        final List<RolledUpUnit> result = new ArrayList<RolledUpUnit>(tmp.size());
+        for (final String unitType : tmp.keySet()) {
+            result.add(new DefaultRolledUpUnit(unitType, tmp.get(unitType)));
+        }
+        return result;
+    }
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java
index 9c190c8..4923592 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/DefaultRolledUpUsageDao.java
@@ -18,18 +18,14 @@ package org.killbill.billing.usage.dao;
 
 import java.math.BigDecimal;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
 import javax.inject.Inject;
 
-import org.joda.time.DateTime;
-import org.killbill.billing.usage.api.RolledUpUsage;
-import org.killbill.billing.util.callcontext.TenantContext;
-import org.skife.jdbi.v2.IDBI;
-
+import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
+import org.skife.jdbi.v2.IDBI;
 
 public class DefaultRolledUpUsageDao implements RolledUpUsageDao {
 
@@ -41,17 +37,18 @@ public class DefaultRolledUpUsageDao implements RolledUpUsageDao {
     }
 
     @Override
-    public void record(final UUID subscriptionId, final String unitType, final DateTime startTime, final DateTime endTime,
-                       final BigDecimal amount, final InternalCallContext context) {
-        final RolledUpUsageModelDao rolledUpUsageModelDao = new RolledUpUsageModelDao(subscriptionId, unitType, startTime,
-                                                                                      endTime, amount
-        );
+    public void record(final UUID subscriptionId, final String unitType, final LocalDate date, final Long amount, final InternalCallContext context) {
+        final RolledUpUsageModelDao rolledUpUsageModelDao = new RolledUpUsageModelDao(subscriptionId, unitType, date, amount);
         rolledUpUsageSqlDao.create(rolledUpUsageModelDao, context);
     }
 
     @Override
-    public RolledUpUsageModelDao getUsageForSubscription(UUID subscriptionId, DateTime startTime, DateTime endTime, String unitType, InternalTenantContext context) {
-        final BigDecimal amount = rolledUpUsageSqlDao.getUsageForSubscription(subscriptionId, startTime.toDate(), endTime.toDate(), unitType, context);
-        return new RolledUpUsageModelDao(subscriptionId, unitType, startTime, endTime, amount != null ? amount : BigDecimal.ZERO);
+    public List<RolledUpUsageModelDao> getUsageForSubscription(final UUID subscriptionId, final LocalDate startDate, final LocalDate endDate, final String unitType, final InternalTenantContext context) {
+        return rolledUpUsageSqlDao.getUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), unitType, context);
+    }
+
+    @Override
+    public List<RolledUpUsageModelDao> getAllUsageForSubscription(final UUID subscriptionId, final LocalDate startDate, final LocalDate endDate, final InternalTenantContext context) {
+        return rolledUpUsageSqlDao.getAllUsageForSubscription(subscriptionId, startDate.toDate(), endDate.toDate(), context);
     }
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageDao.java
index 225b3c8..4144aed 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageDao.java
@@ -16,22 +16,19 @@
 
 package org.killbill.billing.usage.dao;
 
-import java.math.BigDecimal;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
+import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.usage.api.RolledUpUsage;
-import org.killbill.billing.util.callcontext.TenantContext;
 
 public interface RolledUpUsageDao {
 
-    void record(UUID subscriptionId, String unitType, DateTime startTime,
-                DateTime endTime, BigDecimal amount, InternalCallContext context);
+    void record(UUID subscriptionId, String unitType, LocalDate date,
+                Long amount, InternalCallContext context);
+
+    List<RolledUpUsageModelDao> getUsageForSubscription(UUID subscriptionId, LocalDate startDate, LocalDate endDate, String unitType, InternalTenantContext context);
 
-    RolledUpUsageModelDao getUsageForSubscription(UUID subscriptionId, DateTime startTime, DateTime endTime, String unitType, InternalTenantContext context);
+    List<RolledUpUsageModelDao> getAllUsageForSubscription(UUID subscriptionId, LocalDate startDate, LocalDate endDate, InternalTenantContext context);
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageModelDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageModelDao.java
index acffd5b..b9a5a62 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageModelDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageModelDao.java
@@ -16,34 +16,34 @@
 
 package org.killbill.billing.usage.dao;
 
-import java.math.BigDecimal;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.killbill.billing.util.dao.TableName;
+import org.killbill.billing.util.entity.Entity;
+import org.killbill.billing.util.entity.dao.EntityModelDao;
+import org.killbill.billing.util.entity.dao.EntityModelDaoBase;
 
-public class RolledUpUsageModelDao {
+public class RolledUpUsageModelDao extends EntityModelDaoBase implements EntityModelDao<Entity> {
 
-    private UUID id;
     private UUID subscriptionId;
     private String unitType;
-    private DateTime startTime;
-    private DateTime endTime;
-    private BigDecimal amount;
+    private LocalDate recordDate;
+    private Long amount;
 
     public RolledUpUsageModelDao() { /* For the DAO mapper */ }
 
-    public RolledUpUsageModelDao(final UUID subscriptionId, final String unitType, final DateTime startTime,
-                                 final DateTime endTime, final BigDecimal amount) {
-        this.id = UUID.randomUUID();
+    public RolledUpUsageModelDao(final UUID id, final DateTime createdDate, final DateTime updatedDate, final UUID subscriptionId, final String unitType, final LocalDate recordDate, final Long amount) {
+        super(id, createdDate, updatedDate);
         this.subscriptionId = subscriptionId;
         this.unitType = unitType;
-        this.startTime = startTime;
-        this.endTime = endTime;
+        this.recordDate = recordDate;
         this.amount = amount;
     }
 
-    public UUID getId() {
-        return id;
+    public RolledUpUsageModelDao(final UUID subscriptionId, final String unitType, final LocalDate recordDate, final Long amount) {
+        this(UUID.randomUUID(), null, null, subscriptionId, unitType, recordDate, amount);
     }
 
     public UUID getSubscriptionId() {
@@ -54,22 +54,18 @@ public class RolledUpUsageModelDao {
         return unitType;
     }
 
-    public DateTime getStartTime() {
-        return startTime;
+    public LocalDate getRecordDate() {
+        return recordDate;
     }
 
-    public DateTime getEndTime() {
-        return endTime;
+    public void setRecordDate(final LocalDate recordDate) {
+        this.recordDate = recordDate;
     }
 
-    public BigDecimal getAmount() {
+    public Long getAmount() {
         return amount;
     }
 
-    public void setId(final UUID id) {
-        this.id = id;
-    }
-
     public void setSubscriptionId(final UUID subscriptionId) {
         this.subscriptionId = subscriptionId;
     }
@@ -78,15 +74,7 @@ public class RolledUpUsageModelDao {
         this.unitType = unitType;
     }
 
-    public void setStartTime(final DateTime startTime) {
-        this.startTime = startTime;
-    }
-
-    public void setEndTime(final DateTime endTime) {
-        this.endTime = endTime;
-    }
-
-    public void setAmount(final BigDecimal amount) {
+    public void setAmount(final Long amount) {
         this.amount = amount;
     }
 
@@ -97,8 +85,7 @@ public class RolledUpUsageModelDao {
         sb.append("{id=").append(id);
         sb.append(", subscriptionId=").append(subscriptionId);
         sb.append(", unitType='").append(unitType).append('\'');
-        sb.append(", startTime=").append(startTime);
-        sb.append(", endTime=").append(endTime);
+        sb.append(", recordDate=").append(recordDate);
         sb.append(", amount=").append(amount);
         sb.append('}');
         return sb.toString();
@@ -118,7 +105,7 @@ public class RolledUpUsageModelDao {
         if (amount != null ? !amount.equals(that.amount) : that.amount != null) {
             return false;
         }
-        if (endTime != null ? !endTime.equals(that.endTime) : that.endTime != null) {
+        if (recordDate != null ? !recordDate.equals(that.recordDate) : that.recordDate != null) {
             return false;
         }
         if (id != null ? !id.equals(that.id) : that.id != null) {
@@ -127,9 +114,6 @@ public class RolledUpUsageModelDao {
         if (unitType != null ? !unitType.equals(that.unitType) : that.unitType != null) {
             return false;
         }
-        if (startTime != null ? !startTime.equals(that.startTime) : that.startTime != null) {
-            return false;
-        }
         if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
             return false;
         }
@@ -142,9 +126,18 @@ public class RolledUpUsageModelDao {
         int result = id != null ? id.hashCode() : 0;
         result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
         result = 31 * result + (unitType != null ? unitType.hashCode() : 0);
-        result = 31 * result + (startTime != null ? startTime.hashCode() : 0);
-        result = 31 * result + (endTime != null ? endTime.hashCode() : 0);
+        result = 31 * result + (recordDate != null ? recordDate.hashCode() : 0);
         result = 31 * result + (amount != null ? amount.hashCode() : 0);
         return result;
     }
+
+    @Override
+    public TableName getTableName() {
+        return TableName.ROLLED_UP_USAGE;
+    }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
index 4bfdb8a..b237eb2 100644
--- a/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
+++ b/usage/src/main/java/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.java
@@ -16,31 +16,38 @@
 
 package org.killbill.billing.usage.dao;
 
-import java.math.BigDecimal;
 import java.util.Date;
+import java.util.List;
 import java.util.UUID;
 
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.callcontext.InternalTenantContext;
+import org.killbill.billing.util.callcontext.InternalTenantContextBinder;
+import org.killbill.billing.util.entity.Entity;
+import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.BindBean;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
-import org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator;
 
-import org.killbill.billing.callcontext.InternalCallContext;
-import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.util.callcontext.InternalTenantContextBinder;
-
-@UseStringTemplate3StatementLocator()
-public interface RolledUpUsageSqlDao {
+@EntitySqlDaoStringTemplate()
+public interface RolledUpUsageSqlDao extends EntitySqlDao<RolledUpUsageModelDao, Entity> {
 
     @SqlUpdate
     public void create(@BindBean RolledUpUsageModelDao rolledUpUsage,
                        @InternalTenantContextBinder final InternalCallContext context);
 
     @SqlQuery
-    public BigDecimal getUsageForSubscription(@Bind("subscriptionId") final UUID subscriptionId,
-                                                         @Bind("startTime") final Date startTime,
-                                                         @Bind("endTime") final Date endTime,
-                                                         @Bind("unitType") final String unitType,
-                                                         @InternalTenantContextBinder final InternalTenantContext context);
+    public List<RolledUpUsageModelDao> getUsageForSubscription(@Bind("subscriptionId") final UUID subscriptionId,
+                                                               @Bind("startDate") final Date startDate,
+                                                               @Bind("endDate") final Date endDate,
+                                                               @Bind("unitType") final String unitType,
+                                                               @InternalTenantContextBinder final InternalTenantContext context);
+
+    @SqlQuery
+    public List<RolledUpUsageModelDao> getAllUsageForSubscription(@Bind("subscriptionId") final UUID subscriptionId,
+                                                                  @Bind("startDate") final Date startDate,
+                                                                  @Bind("endDate") final Date endDate,
+                                                                  @InternalTenantContextBinder final InternalTenantContext context);
 }
diff --git a/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg b/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
index 431d976..ea40a86 100644
--- a/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
+++ b/usage/src/main/resources/org/killbill/billing/usage/dao/RolledUpUsageSqlDao.sql.stg
@@ -1,54 +1,46 @@
-group RolledUpUsageSqlDao: EntitySqlDao;
+group RolledUpUsageSqlDao : EntitySqlDao;
 
 tableName() ::= "rolled_up_usage"
 
+
 tableFields(prefix) ::= <<
-  <prefix>id
-, <prefix>subscription_id
+  <prefix>subscription_id
 , <prefix>unit_type
-, <prefix>start_time
-, <prefix>end_time
+, <prefix>record_date
 , <prefix>amount
 , <prefix>created_by
 , <prefix>created_date
-, <prefix>account_record_id
-, <prefix>tenant_record_id
 >>
 
 tableValues() ::= <<
-  :id
-, :subscriptionId
+  :subscriptionId
 , :unitType
-, :startTime
-, :endTime
+, :recordDate
 , :amount
 , :userName
 , :createdDate
-, :accountRecordId
-, :tenantRecordId
 >>
 
-CHECK_TENANT(prefix) ::= "<prefix>tenant_record_id = :tenantRecordId"
-AND_CHECK_TENANT(prefix) ::= "and <CHECK_TENANT(prefix)>"
 
-create() ::= <<
-insert into <tableName()> (
-  <tableFields()>
-)
-values (
-  <tableValues()>
-)
+getUsageForSubscription() ::= <<
+select
+  <allTableFields()>
+from <tableName()>
+where subscription_id = :subscriptionId
+and record_date >= :startDate
+and record_date \< :endDate
+and unit_type = :unitType
+<AND_CHECK_TENANT()>
 ;
 >>
 
-getUsageForSubscription() ::= <<
+getAllUsageForSubscription() ::= <<
 select
-  sum(amount)
-from <tableName()> t
+  <allTableFields()>
+from <tableName()>
 where subscription_id = :subscriptionId
-and start_time >= :startTime
-and end_time \<= :endTime
-and unit_type = :unitType
+and record_date >= :startDate
+and record_date \< :endDate
 <AND_CHECK_TENANT()>
 ;
 >>
diff --git a/usage/src/main/resources/org/killbill/billing/usage/ddl.sql b/usage/src/main/resources/org/killbill/billing/usage/ddl.sql
index 2d8edc9..50b3f2d 100644
--- a/usage/src/main/resources/org/killbill/billing/usage/ddl.sql
+++ b/usage/src/main/resources/org/killbill/billing/usage/ddl.sql
@@ -6,9 +6,8 @@ CREATE TABLE rolled_up_usage (
     id char(36) NOT NULL,
     subscription_id char(36),
     unit_type varchar(50),
-    start_time datetime NOT NULL,
-    end_time datetime,
-    amount decimal(15,9) NOT NULL,
+    record_date date NOT NULL,
+    amount bigint NOT NULL,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
     account_record_id int(11) unsigned default null,
diff --git a/usage/src/test/java/org/killbill/billing/usage/api/user/MockUsageUserApi.java b/usage/src/test/java/org/killbill/billing/usage/api/user/MockUsageUserApi.java
index d3dd47a..4ec7e95 100644
--- a/usage/src/test/java/org/killbill/billing/usage/api/user/MockUsageUserApi.java
+++ b/usage/src/test/java/org/killbill/billing/usage/api/user/MockUsageUserApi.java
@@ -16,38 +16,38 @@
 
 package org.killbill.billing.usage.api.user;
 
-import java.math.BigDecimal;
 import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
 import org.killbill.billing.usage.api.RolledUpUsage;
+import org.killbill.billing.usage.api.SubscriptionUsageRecord;
 import org.killbill.billing.usage.api.UsageUserApi;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
 
-
 public class MockUsageUserApi implements UsageUserApi {
 
     private List<RolledUpUsage> result;
 
-    @Override
-    public void recordRolledUpUsage(final UUID uuid, final String s, final DateTime dateTime, final DateTime dateTime2, final BigDecimal bigDecimal, final CallContext callContext) {
-        throw new UnsupportedOperationException();
+    public void setAllUsageForSubscription(final List<RolledUpUsage> result) {
+        this.result = result;
     }
 
     @Override
-    public RolledUpUsage getUsageForSubscription(final UUID uuid, final String s, final DateTime dateTime, final DateTime dateTime2, final TenantContext tenantContext) {
-        throw new UnsupportedOperationException();
+    public void recordRolledUpUsage(final SubscriptionUsageRecord subscriptionUsageRecord, final CallContext callContext) {
+
     }
 
     @Override
-    public List<RolledUpUsage> getAllUsageForSubscription(final UUID uuid, final Set<String> strings, final List<DateTime> dateTimes, final TenantContext tenantContext) {
-        return result;
+    public RolledUpUsage getUsageForSubscription(final UUID uuid, final String s, final LocalDate localDate, final LocalDate localDate2, final TenantContext tenantContext) {
+        return null;
     }
 
-    public void setAllUsageForSubscription(final List<RolledUpUsage> result) {
-        this.result = result;
+    @Override
+    public List<RolledUpUsage> getAllUsageForSubscription(final UUID uuid, final List<LocalDate> localDates, final TenantContext tenantContext) {
+        return null;
     }
+
 }
diff --git a/usage/src/test/java/org/killbill/billing/usage/dao/TestDefaultRolledUpUsageDao.java b/usage/src/test/java/org/killbill/billing/usage/dao/TestDefaultRolledUpUsageDao.java
index fad80b4..7e9bca4 100644
--- a/usage/src/test/java/org/killbill/billing/usage/dao/TestDefaultRolledUpUsageDao.java
+++ b/usage/src/test/java/org/killbill/billing/usage/dao/TestDefaultRolledUpUsageDao.java
@@ -16,11 +16,10 @@
 
 package org.killbill.billing.usage.dao;
 
-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.usage.UsageTestSuiteWithEmbeddedDB;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -37,39 +36,72 @@ public class TestDefaultRolledUpUsageDao extends UsageTestSuiteWithEmbeddedDB {
     public void testSimple() {
         final UUID subscriptionId = UUID.randomUUID();
         final String unitType = "foo";
-        final DateTime startDate = new DateTime(2013, 1, 1, 0, 0, DateTimeZone.UTC);
-        final DateTime endDate = new DateTime(2013, 2, 1, 0, 0, DateTimeZone.UTC);
-        final BigDecimal amount1 = BigDecimal.TEN;
-        final BigDecimal amount2 = BigDecimal.TEN;
-
-        rolledUpUsageDao.record(subscriptionId, unitType, startDate, endDate, amount1, internalCallContext);
-        rolledUpUsageDao.record(subscriptionId, unitType, startDate, endDate, amount2, internalCallContext);
-
-        final RolledUpUsageModelDao result = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContext);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getStartTime().compareTo(startDate), 0);
-        assertEquals(result.getEndTime().compareTo(endDate), 0);
-        assertEquals(result.getUnitType(), unitType);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getAmount().compareTo(amount1.add(amount2)), 0);
+        final LocalDate startDate = new LocalDate(2013, 1, 1);
+        final LocalDate endDate = new LocalDate(2013, 2, 1);
+        final Long amount1 = 10L;
+        final Long amount2 = 5L;
+
+        rolledUpUsageDao.record(subscriptionId, unitType, startDate, amount1, internalCallContext);
+        rolledUpUsageDao.record(subscriptionId, unitType, endDate.minusDays(1), amount2, internalCallContext);
+
+        final List<RolledUpUsageModelDao> result = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContext);
+        assertEquals(result.size(), 2);
+        assertEquals(result.get(0).getSubscriptionId(), subscriptionId);
+        assertEquals(result.get(0).getRecordDate().compareTo(startDate), 0);
+        assertEquals(result.get(0).getUnitType(), unitType);
+        assertEquals(result.get(0).getAmount().compareTo(amount1), 0);
+        assertEquals(result.get(1).getSubscriptionId(), subscriptionId);
+        assertEquals(result.get(1).getRecordDate().compareTo(endDate.minusDays(1)), 0);
+        assertEquals(result.get(1).getUnitType(), unitType);
+        assertEquals(result.get(1).getAmount().compareTo(amount2), 0);
+    }
+
+
+    @Test(groups = "slow")
+    public void testMultipleUnits() {
+        final UUID subscriptionId = UUID.randomUUID();
+        final String unitType1 = "foo";
+        final String unitType2 = "bar";
+        final LocalDate startDate = new LocalDate(2013, 1, 1);
+        final LocalDate endDate = new LocalDate(2013, 2, 1);
+        final Long amount1 = 10L;
+        final Long amount2 = 5L;
+        final Long amount3 = 13L;
+
+        rolledUpUsageDao.record(subscriptionId, unitType1, startDate, amount1, internalCallContext);
+        rolledUpUsageDao.record(subscriptionId, unitType1, startDate.plusDays(1), amount2, internalCallContext);
+
+        rolledUpUsageDao.record(subscriptionId, unitType2, endDate.minusDays(1), amount3, internalCallContext);
+
+        final List<RolledUpUsageModelDao> result = rolledUpUsageDao.getAllUsageForSubscription(subscriptionId, startDate, endDate, internalCallContext);
+        assertEquals(result.size(), 3);
+        assertEquals(result.get(0).getSubscriptionId(), subscriptionId);
+        assertEquals(result.get(0).getRecordDate().compareTo(startDate), 0);
+        assertEquals(result.get(0).getUnitType(), unitType1);
+        assertEquals(result.get(0).getAmount().compareTo(amount1), 0);
+        assertEquals(result.get(1).getSubscriptionId(), subscriptionId);
+        assertEquals(result.get(1).getRecordDate().compareTo(startDate.plusDays(1)), 0);
+        assertEquals(result.get(1).getUnitType(), unitType1);
+        assertEquals(result.get(1).getAmount().compareTo(amount2), 0);
+        assertEquals(result.get(2).getSubscriptionId(), subscriptionId);
+        assertEquals(result.get(2).getRecordDate().compareTo(endDate.minusDays(1)), 0);
+        assertEquals(result.get(2).getUnitType(), unitType2);
+        assertEquals(result.get(2).getAmount().compareTo(amount3), 0);
     }
 
+
+
     @Test(groups = "slow")
     public void testNoEntries() {
         final UUID subscriptionId = UUID.randomUUID();
         final String unitType = "foo";
-        final DateTime startDate = new DateTime(2013, 1, 1, 0, 0, DateTimeZone.UTC);
-        final DateTime endDate = new DateTime(2013, 2, 1, 0, 0, DateTimeZone.UTC);
-
-        final RolledUpUsageModelDao result = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContext);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getStartTime().compareTo(startDate), 0);
-        assertEquals(result.getEndTime().compareTo(endDate), 0);
-        assertEquals(result.getUnitType(), unitType);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getSubscriptionId(), subscriptionId);
-        assertEquals(result.getAmount().compareTo(BigDecimal.ZERO), 0);
+        final LocalDate startDate = new LocalDate(2013, 1, 1);
+        final LocalDate endDate = new LocalDate(2013, 2, 1);
+
+        rolledUpUsageDao.record(subscriptionId, unitType, endDate, 9L, internalCallContext);
+
+        final List<RolledUpUsageModelDao> result = rolledUpUsageDao.getUsageForSubscription(subscriptionId, startDate, endDate, unitType, internalCallContext);
+        assertEquals(result.size(), 0);
     }
 
 }
diff --git a/util/src/main/java/org/killbill/billing/util/dao/TableName.java b/util/src/main/java/org/killbill/billing/util/dao/TableName.java
index bb75a51..54edeb3 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/TableName.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/TableName.java
@@ -52,7 +52,8 @@ public enum TableName {
     TAG_HISTORY("tag_history"),
     TENANT("tenants", ObjectType.TENANT),
     TENANT_KVS("tenant_kvs", ObjectType.TENANT_KVS),
-    TAG("tags", ObjectType.TAG, TAG_HISTORY);
+    TAG("tags", ObjectType.TAG, TAG_HISTORY),
+    ROLLED_UP_USAGE("rolled_up_usage");
 
     private final String tableName;
     private final ObjectType objectType;