killbill-aplcache

invoice: Fix issue for usage detail computation prevously

2/7/2018 11:50:26 PM

Details

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
index d391b05..b9df9a5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -194,35 +195,48 @@ public class ContiguousIntervalUsageInArrear {
         }
 
         final List<RolledUpUsage> allUsage = getRolledUpUsage();
+        // Each RolledUpUsage 'ru' is for a specific time period and across all units
         for (final RolledUpUsage ru : allUsage) {
 
+            //
+            // Previously billed items:
+            //
+            // 1. Retrieves current price amount billed for that period of time (and usage section)
+            final Iterable<InvoiceItem> billedItems = getBilledItems(ru.getStart(), ru.getEnd(), existingUsage);
+            // 2. Verify whether previously built items have the item_details section
+            final boolean areAllBilledItemsWithDetails = areAllBilledItemsWithDetails(billedItems);
+            // 3. Computes total billed usage amount
+            final BigDecimal billedUsage = computeBilledUsage(billedItems);
+
             List<UsageInArrearDetail> toBeBilledUsageDetails = Lists.newLinkedList();
-            BigDecimal toBeBilledUsage = BigDecimal.ZERO;
+            BigDecimal toBeBilledUsage;
             if (usage.getUsageType() == UsageType.CAPACITY) {
-                toBeBilledUsageDetails.addAll(computeToBeBilledCapacityInArrear(ru.getRolledUpUnits()));
+                // In CAPACITY mode we build across units
+                toBeBilledUsageDetails.addAll(computeToBeBilledCapacityInArrear(ru.getRolledUpUnits(), areAllBilledItemsWithDetails));
             } else /* UsageType.CONSUMABLE */{
-
-                // Compute total price amount that should be billed for that period of time (and usage section) across unitTypes.
+                // In CONSUMABLE mode we build for each unit independently, hence *for* loop
                 for (final RolledUpUnit cur : ru.getRolledUpUnits()) {
                     if (!unitTypes.contains(cur.getUnitType())) {
                         log.warn("ContiguousIntervalConsumableInArrear is skipping unitType " + cur.getUnitType());
                         continue;
                     }
-
-                    toBeBilledUsageDetails.addAll(computeToBeBilledConsumableInArrear(cur));
+                    toBeBilledUsageDetails.addAll(computeToBeBilledConsumableInArrear(cur, areAllBilledItemsWithDetails));
                 }
-
             }
+            // Based on details computed, compute total (proposed) amount
             toBeBilledUsage = toBeBilledForUnit(toBeBilledUsageDetails);
 
-            // Retrieves current price amount billed for that period of time (and usage section)
-            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.
+            // Compute final amount by subtracting  amount that was already billed.
             if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
-                toBeBilledUsageDetails = reconcileExistedBilledWithToBeBilled(billedItems, toBeBilledUsageDetails);
-                final BigDecimal amountToBill = toBeBilledForUnit(toBeBilledUsageDetails);
+                final BigDecimal amountToBill;
+                if (areAllBilledItemsWithDetails) {
+                    toBeBilledUsageDetails = reconcileExistedBilledWithToBeBilled(billedItems, toBeBilledUsageDetails);
+                    amountToBill = toBeBilledForUnit(toBeBilledUsageDetails);
+                } else {
+                    // If we don't have details from previous already billed usage, we can't reconcile each of the usage detail, so we just compute the overall price
+                    amountToBill = toBeBilledForUnit(toBeBilledUsageDetails).subtract(billedUsage);
+                }
 
                 if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
                     if (UsageDetailMode.DETAIL == usageDetailMode && usage.getUsageType() == UsageType.CONSUMABLE){
@@ -244,6 +258,17 @@ public class ContiguousIntervalUsageInArrear {
         return new UsageInArrearItemsAndNextNotificationDate(result, nextNotificationdate);
     }
 
+
+    private boolean areAllBilledItemsWithDetails(final Iterable<InvoiceItem> billedItems) {
+        boolean atLeastOneItemWithoutDetails = Iterables.any(billedItems, new Predicate<InvoiceItem>() {
+            @Override
+            public boolean apply(final InvoiceItem input) {
+                return input.getItemDetails() == null || input.getItemDetails().isEmpty();
+            }
+        });
+        return !atLeastOneItemWithoutDetails;
+    }
+
     private LocalDate computeNextNotificationDate() {
         LocalDate result = null;
         final Iterator<BillingEvent> eventIt = billingEvents.iterator();
@@ -386,7 +411,7 @@ public class ContiguousIntervalUsageInArrear {
      * @throws CatalogApiException
      */
     @VisibleForTesting
-    List<UsageInArrearDetail> computeToBeBilledCapacityInArrear(final List<RolledUpUnit> roUnits) throws CatalogApiException {
+    List<UsageInArrearDetail> computeToBeBilledCapacityInArrear(final List<RolledUpUnit> roUnits, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
         Preconditions.checkState(isBuilt.get());
 
         final List<Tier> tiers = getCapacityInArrearTier(usage);
@@ -405,7 +430,7 @@ public class ContiguousIntervalUsageInArrear {
                     complies = false;
                 } else {
                     if (!perUnitTypeDetailTierLevel.contains(ro.getUnitType())) {
-                        toBeBilledDetails.add(new UsageInArrearDetail(tierNum, ro.getUnitType(), cur.getRecurringPrice().getPrice(getCurrency()), ro.getAmount().intValue(), BigDecimal.ZERO, BigDecimal.ZERO, ""));
+                        toBeBilledDetails.add(new UsageInArrearDetail(tierNum, ro.getUnitType(), cur.getRecurringPrice().getPrice(getCurrency()), ro.getAmount().intValue(), BigDecimal.ZERO, BigDecimal.ZERO, areAllBilledItemsWithDetails, ""));
                         perUnitTypeDetailTierLevel.add(ro.getUnitType());
                     }
                 }
@@ -428,23 +453,23 @@ public class ContiguousIntervalUsageInArrear {
      * @throws CatalogApiException
      */
     @VisibleForTesting
-    List<UsageInArrearDetail> computeToBeBilledConsumableInArrear(final RolledUpUnit roUnit) throws CatalogApiException {
+    List<UsageInArrearDetail> computeToBeBilledConsumableInArrear(final RolledUpUnit roUnit, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
 
         Preconditions.checkState(isBuilt.get());
         final List<TieredBlock> tieredBlocks = getConsumableInArrearTieredBlocks(usage, roUnit.getUnitType());
 
         switch (usage.getTierBlockPolicy()) {
             case ALL_TIERS:
-                return computeToBeBilledConsumableInArrearWith_ALL_TIERS(tieredBlocks, roUnit.getAmount());
+                return computeToBeBilledConsumableInArrearWith_ALL_TIERS(tieredBlocks, roUnit.getAmount(), areAllBilledItemsWithDetails);
             case TOP_TIER:
-                return Arrays.asList(computeToBeBilledConsumableInArrearWith_TOP_TIER(tieredBlocks, roUnit.getAmount()));
+                return Arrays.asList(computeToBeBilledConsumableInArrearWith_TOP_TIER(tieredBlocks, roUnit.getAmount(), areAllBilledItemsWithDetails));
             default:
                 throw new IllegalStateException("Unknown TierBlockPolicy " + usage.getTierBlockPolicy());
         }
     }
 
 
-    List<UsageInArrearDetail> computeToBeBilledConsumableInArrearWith_ALL_TIERS(final List<TieredBlock> tieredBlocks, final Long units) throws CatalogApiException {
+    List<UsageInArrearDetail> computeToBeBilledConsumableInArrearWith_ALL_TIERS(final List<TieredBlock> tieredBlocks, final Long units, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
 
         List<UsageInArrearDetail> toBeBilledDetails = Lists.newLinkedList();
         int remainingUnits = units.intValue();
@@ -464,13 +489,13 @@ public class ContiguousIntervalUsageInArrear {
             }
 
             if (nbUsedTierBlocks > 0) {
-                toBeBilledDetails.add(new UsageInArrearDetail(tierNum, tieredBlock.getUnit().getName(), tieredBlock.getPrice().getPrice(getCurrency()), nbUsedTierBlocks));
+                toBeBilledDetails.add(new UsageInArrearDetail(tierNum, tieredBlock.getUnit().getName(), tieredBlock.getPrice().getPrice(getCurrency()), nbUsedTierBlocks, areAllBilledItemsWithDetails));
             }
         }
         return toBeBilledDetails;
     }
 
-    UsageInArrearDetail computeToBeBilledConsumableInArrearWith_TOP_TIER(final List<TieredBlock> tieredBlocks, final Long units) throws CatalogApiException {
+    UsageInArrearDetail computeToBeBilledConsumableInArrearWith_TOP_TIER(final List<TieredBlock> tieredBlocks, final Long units, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
 
         int remainingUnits = units.intValue();
 
@@ -495,7 +520,7 @@ public class ContiguousIntervalUsageInArrear {
         final int lastBlockTierSize = targetBlock.getSize().intValue();
         final int nbBlocks = units.intValue() / lastBlockTierSize + (units.intValue() % lastBlockTierSize == 0 ? 0 : 1);
 
-        return new UsageInArrearDetail(targetTierNum, targetBlock.getUnit().getName(), targetBlock.getPrice().getPrice(getCurrency()), nbBlocks);
+        return new UsageInArrearDetail(targetTierNum, targetBlock.getUnit().getName(), targetBlock.getPrice().getPrice(getCurrency()), nbBlocks, areAllBilledItemsWithDetails);
     }
 
 
@@ -515,10 +540,10 @@ public class ContiguousIntervalUsageInArrear {
         return billedAmount;
     }
 
-    Iterable<InvoiceItem> getBilledItems(final LocalDate startDate, final LocalDate endDate, final List<InvoiceItem> existingUsage) {
+    List<InvoiceItem> getBilledItems(final LocalDate startDate, final LocalDate endDate, final List<InvoiceItem> existingUsage) {
 
         Preconditions.checkState(isBuilt.get());
-        return Iterables.filter(existingUsage, new Predicate<InvoiceItem>() {
+        final Iterable<InvoiceItem> filteredResult = Iterables.filter(existingUsage, new Predicate<InvoiceItem>() {
             @Override
             public boolean apply(final InvoiceItem input) {
                 if (input.getInvoiceItemType() != InvoiceItemType.USAGE) {
@@ -531,6 +556,7 @@ public class ContiguousIntervalUsageInArrear {
                        usageInput.getEndDate().compareTo(endDate) <= 0;
             }
         });
+        return ImmutableList.copyOf(filteredResult);
     }
 
     @VisibleForTesting
@@ -610,34 +636,27 @@ public class ContiguousIntervalUsageInArrear {
         return result;
     }
 
-    private List<UsageInArrearDetail> reconcileExistedBilledWithToBeBilled(Iterable<InvoiceItem> billedItems, List<UsageInArrearDetail> toBeBilledUsageInArrearDetails) {
+    private List<UsageInArrearDetail> reconcileExistedBilledWithToBeBilled(final Iterable<InvoiceItem> billedItems, final List<UsageInArrearDetail> toBeBilledUsageInArrearDetails) {
         for (final InvoiceItem bi : billedItems) {
             List<UsageInArrearDetail> billedUsageItemDetails = fromJson(bi.getItemDetails());
 
-            if (billedUsageItemDetails != null && billedUsageItemDetails.size() > 0) {
+            Preconditions.checkState(billedUsageItemDetails != null && billedUsageItemDetails.size() > 0);
 
-                for (final UsageInArrearDetail toBeBilledConsumable : toBeBilledUsageInArrearDetails) {
-                    billedUsageItemDetails = toBeBilledConsumable.reconcile(billedUsageItemDetails);
-                }
+            for (final UsageInArrearDetail toBeBilledConsumable : toBeBilledUsageInArrearDetails) {
+                billedUsageItemDetails = toBeBilledConsumable.reconcile(billedUsageItemDetails);
+            }
 
-                if (billedUsageItemDetails != null && billedUsageItemDetails.size() > 0) {
-                    for (final UsageInArrearDetail billedUsage : billedUsageItemDetails) {
-                        toBeBilledUsageInArrearDetails.add(new UsageInArrearDetail(billedUsage.getTier(), billedUsage.getTierUnit(), billedUsage.getTierPrice(),
-                                                                                   billedUsage.getQuantity() * -1, billedUsage.getAmount().negate(), null, bi.getId().toString()));
-                    }
+            if (billedUsageItemDetails != null && billedUsageItemDetails.size() > 0) {
+                for (final UsageInArrearDetail billedUsage : billedUsageItemDetails) {
+                    toBeBilledUsageInArrearDetails.add(new UsageInArrearDetail(billedUsage.getTier(), billedUsage.getTierUnit(), billedUsage.getTierPrice(),
+                                                                               billedUsage.getQuantity() * -1, billedUsage.getAmount().negate(), null, true, bi.getId().toString()));
                 }
-            } else {
-                toBeBilledUsageInArrearDetails.get(0).setAmount(toBeBilledUsageInArrearDetails.get(0).getAmount().subtract(bi.getAmount()));
-                toBeBilledUsageInArrearDetails.get(0).setQuantity(toBeBilledUsageInArrearDetails.get(0).getQuantity() - (bi.getQuantity() == null ? 0 : bi.getQuantity()));
-                toBeBilledUsageInArrearDetails.get(0).setExistingUsageAmount(toBeBilledUsageInArrearDetails.get(0).getExistingUsageAmount().add(bi.getAmount()));
-                toBeBilledUsageInArrearDetails.get(0).setReference(toBeBilledUsageInArrearDetails.get(0).getReference().concat(":").concat(bi.getId().toString()));
             }
         }
-
         return toBeBilledUsageInArrearDetails;
     }
 
-    private static final String toJson(List<UsageInArrearDetail> toBeBilledUsageInArrearDetails) {
+    private static String toJson(final List<UsageInArrearDetail> toBeBilledUsageInArrearDetails) {
         String result = null;
         if (toBeBilledUsageInArrearDetails != null && toBeBilledUsageInArrearDetails.size() > 0){
             try {
@@ -649,7 +668,7 @@ public class ContiguousIntervalUsageInArrear {
         return result;
     }
 
-    private static final List<UsageInArrearDetail> fromJson(String itemDetails){
+    private static List<UsageInArrearDetail> fromJson(String itemDetails){
         List<UsageInArrearDetail> toBeBilledUsageInArrearDetails = null;
         if (itemDetails != null){
             try {
@@ -669,28 +688,30 @@ public class ContiguousIntervalUsageInArrear {
         private final BigDecimal tierPrice;
         private Integer quantity;
         private String reference;
-        private BigDecimal existingUsageAmount;
+        private BigDecimal previousBilledAmount;
+        private boolean isPreviousBilledAmountAvailable;
         private BigDecimal amount;
 
-        public UsageInArrearDetail(BigDecimal tierPrice, Integer quantity, BigDecimal existingUsageAmount, String reference) {
-            this(0, null, tierPrice, quantity, existingUsageAmount, BigDecimal.ZERO, reference);
-        }
-
-        public UsageInArrearDetail(int tier, String tierUnit, BigDecimal tierPrice, Integer quantity) {
-            this(tier, tierUnit, tierPrice, quantity, tierPrice.multiply(new BigDecimal(quantity)), BigDecimal.ZERO, "");
+        public UsageInArrearDetail(int tier, String tierUnit, BigDecimal tierPrice, Integer quantity, boolean isPreviousBilledAmountAvailable) {
+            this(tier, tierUnit, tierPrice, quantity, tierPrice.multiply(new BigDecimal(quantity)), BigDecimal.ZERO, isPreviousBilledAmountAvailable, "");
         }
 
         @JsonCreator
-        public UsageInArrearDetail(@JsonProperty("tier") int tier, @JsonProperty("tierUnit") String tierUnit,
-                                   @JsonProperty("tierPrice") BigDecimal tierPrice, @JsonProperty("quantity") Integer quantity,
-                                   @JsonProperty("amount") BigDecimal amount, @JsonProperty("existingUsageAmount") BigDecimal existingUsageAmount,
+        public UsageInArrearDetail(@JsonProperty("tier") int tier,
+                                   @JsonProperty("tierUnit") String tierUnit,
+                                   @JsonProperty("tierPrice") BigDecimal tierPrice,
+                                   @JsonProperty("quantity") Integer quantity,
+                                   @JsonProperty("amount") BigDecimal amount,
+                                    @JsonProperty("previousBilledAmount") BigDecimal previousBilledAmount,
+                                   @JsonProperty("isPreviousBilledAmountAvailable") boolean isPreviousBilledAmountAvailable,
                                    @JsonProperty("reference") String reference) {
             this.tier = tier;
             this.tierUnit = tierUnit;
             this.tierPrice = tierPrice;
             this.quantity = quantity;
             this.amount = amount;
-            this.existingUsageAmount = existingUsageAmount;
+            this.previousBilledAmount = previousBilledAmount;
+            this.isPreviousBilledAmountAvailable = isPreviousBilledAmountAvailable;
             this.reference = reference;
         }
 
@@ -710,16 +731,24 @@ public class ContiguousIntervalUsageInArrear {
             return quantity;
         }
 
-        public BigDecimal getExistingUsageAmount() {
-            return existingUsageAmount;
+        public BigDecimal getPreviousBilledAmount() {
+            return previousBilledAmount;
         }
 
         public String getReference() {
             return reference;
         }
 
-        public void setExistingUsageAmount(BigDecimal existingUsageAmount) {
-            this.existingUsageAmount = existingUsageAmount;
+        public void setPreviousBilledAmount(BigDecimal previousBilledAmount) {
+            this.previousBilledAmount = previousBilledAmount;
+        }
+
+        public boolean isPreviousBilledAmountAvailable() {
+            return isPreviousBilledAmountAvailable;
+        }
+
+        public void setPreviousBilledAmountAvailable(final boolean previousBilledAmountAvailable) {
+            isPreviousBilledAmountAvailable = previousBilledAmountAvailable;
         }
 
         public BigDecimal getAmount() {
@@ -738,13 +767,14 @@ public class ContiguousIntervalUsageInArrear {
             this.reference = reference;
         }
 
-        public List<UsageInArrearDetail> reconcile(List<UsageInArrearDetail> billedUsageItemDetails) {
-            List<UsageInArrearDetail> unreconciledUsage = Lists.newLinkedList();
+        public List<UsageInArrearDetail> reconcile(final List<UsageInArrearDetail> billedUsageItemDetails) {
+
+            final List<UsageInArrearDetail> unreconciledUsage = Lists.newLinkedList();
             for (UsageInArrearDetail billedUsageDetail : billedUsageItemDetails) {
                 if (tierUnit.equals(billedUsageDetail.tierUnit)) {
-                    existingUsageAmount = billedUsageDetail.getAmount().abs();
+                    previousBilledAmount = billedUsageDetail.getAmount().abs();
                     quantity = quantity - billedUsageDetail.getQuantity();
-                    amount = amount.subtract(existingUsageAmount);
+                    amount = amount.subtract(previousBilledAmount);
                 } else {
                     unreconciledUsage.add(billedUsageDetail);
                 }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalCapacityInArrear.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalCapacityInArrear.java
index b29d079..357592f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalCapacityInArrear.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestContiguousIntervalCapacityInArrear.java
@@ -151,29 +151,29 @@ public class TestContiguousIntervalCapacityInArrear extends TestUsageInArrearBas
         // Tier 1 (both units from tier 1)
         List<UsageInArrearDetail> result = intervalCapacityInArrear.computeToBeBilledCapacityInArrear(ImmutableList.<RolledUpUnit>of(new DefaultRolledUpUnit("unit1", 100L),
                                                                                                                                      new DefaultRolledUpUnit("unit2", 1000L),
-                                                                                                                                     new DefaultRolledUpUnit("unit3", 50L)));
+                                                                                                                                     new DefaultRolledUpUnit("unit3", 50L)), true);
         assertEquals(result.size(), 3);
         assertTrue(intervalCapacityInArrear.toBeBilledForUnit(result).compareTo(BigDecimal.TEN) == 0);
 
         // Tier 2 (only one unit from tier 1)
         result = intervalCapacityInArrear.computeToBeBilledCapacityInArrear(ImmutableList.<RolledUpUnit>of(new DefaultRolledUpUnit("unit1", 100L),
-                                                                                                           new DefaultRolledUpUnit("unit2", 1001L)));
+                                                                                                           new DefaultRolledUpUnit("unit2", 1001L)), true);
         assertTrue(intervalCapacityInArrear.toBeBilledForUnit(result).compareTo(new BigDecimal("20.0")) == 0);
 
         // Tier 2 (only one unit from tier 1)
         result = intervalCapacityInArrear.computeToBeBilledCapacityInArrear(ImmutableList.<RolledUpUnit>of(new DefaultRolledUpUnit("unit1", 101L),
-                                                                                                           new DefaultRolledUpUnit("unit2", 1000L)));
+                                                                                                           new DefaultRolledUpUnit("unit2", 1000L)), true);
         assertTrue(intervalCapacityInArrear.toBeBilledForUnit(result).compareTo(new BigDecimal("20.0")) == 0);
 
 
         // Tier 2 (both units from tier 2)
         result = intervalCapacityInArrear.computeToBeBilledCapacityInArrear(ImmutableList.<RolledUpUnit>of(new DefaultRolledUpUnit("unit1", 101L),
-                                                                                                           new DefaultRolledUpUnit("unit2", 1001L)));
+                                                                                                           new DefaultRolledUpUnit("unit2", 1001L)), true);
         assertTrue(intervalCapacityInArrear.toBeBilledForUnit(result).compareTo(new BigDecimal("20.0")) == 0);
 
         // Tier 3 (only one unit from tier 3)
         result = intervalCapacityInArrear.computeToBeBilledCapacityInArrear(ImmutableList.<RolledUpUnit>of(new DefaultRolledUpUnit("unit1", 10L),
-                                                                                                           new DefaultRolledUpUnit("unit2", 2001L)));
+                                                                                                           new DefaultRolledUpUnit("unit2", 2001L)), true);
         assertTrue(intervalCapacityInArrear.toBeBilledForUnit(result).compareTo(new BigDecimal("30.0")) == 0);
     }
 
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 3c63a05..8c81715 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
@@ -65,6 +65,7 @@ import com.google.common.collect.Ordering;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.AssertJUnit.assertFalse;
 
 public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearBase {
 
@@ -149,7 +150,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
                                                                                                                                              Collections.<Usage>emptyList())
                                                                                                                      );
 
-        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L));
+        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), true);
         assertEquals(result.size(), 3);
         // 111 = 10 (tier1) + 100 (tier2) + 1 (tier3) => 10 * 1.5 + 100 * 1 + 1 * 0.5 = 115.5
         assertEquals(result.get(0).getAmount(), new BigDecimal("15.0"));
@@ -177,7 +178,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
                                                                                                                                              Collections.<Usage>emptyList())
                                                                                                                      );
 
-        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 5325L));
+        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 5325L), true);
         assertEquals(result.size(), 2);
 
         // 5000 = 1000 (tier1) + 4325 (tier2) => 10 + 5 = 15
@@ -211,23 +212,23 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         //
         // In this model unit amount is first used to figure out which tier we are in, and then we price all unit at that 'target' tier
         //
-        List<UsageInArrearDetail> inputTier1 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 1000L));
+        List<UsageInArrearDetail> inputTier1 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 1000L), true);
         assertEquals(inputTier1.size(), 1);
         // 1000 units => (tier1) : 1000 / 100 + 1000 % 100 = 10
         assertEquals(inputTier1.get(0).getAmount(), new BigDecimal("10"));
 
-        List<UsageInArrearDetail> inputTier2 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101000L));
+        List<UsageInArrearDetail> inputTier2 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101000L), true);
         assertEquals(inputTier2.size(), 1);
         // 101000 units => (tier2) :  101000 / 1000 + 101000 % 1000 = 101 + 0 = 101
         assertEquals(inputTier2.get(0).getAmount(), new BigDecimal("101"));
 
-        List<UsageInArrearDetail> inputTier3 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101001L));
+        List<UsageInArrearDetail> inputTier3 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101001L), true);
         assertEquals(inputTier3.size(), 1);
         // 101001 units => (tier3) : 101001 / 1000 + 101001 % 1000 = 101 + 1 = 102 units => $51
         assertEquals(inputTier3.get(0).getAmount(), new BigDecimal("51.0"));
 
         // If we pass the maximum of the last tier, we price all units at the last tier
-        List<UsageInArrearDetail> inputLastTier = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 300000L));
+        List<UsageInArrearDetail> inputLastTier = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 300000L), true);
         assertEquals(inputLastTier.size(), 1);
         // 300000 units => (tier3) : 300000 / 1000 + 300000 % 1000 = 300 units => $150
         assertEquals(inputLastTier.get(0).getAmount(), new BigDecimal("150.0"));
@@ -256,7 +257,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
                                                                                                                                              Collections.<Usage>emptyList())
                                                                                                                      );
 
-        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L));
+        List<UsageInArrearDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), true);
         assertEquals(result.size(), 1);
 
         // 111 = 111 * 0.5 =
@@ -325,7 +326,8 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         List<UsageInArrearDetail> itemDetails = objectMapper.readValue(result.get(0).getItemDetails(), new TypeReference<List<UsageInArrearDetail>>() {});
 
         assertEquals(itemDetails.size(), 1);
-        assertEquals(itemDetails.get(0).getAmount().compareTo(result.get(0).getAmount()),0);
+        assertFalse(itemDetails.get(0).isPreviousBilledAmountAvailable());
+        assertEquals(itemDetails.get(0).getAmount().compareTo(new BigDecimal("5.0")),0);
 
         // Invoiced for 1 BTC and used 199  => 2 blocks => 2 BTC so remaining piece should be 1 BTC
         assertEquals(result.get(1).getAmount().compareTo(new BigDecimal("1.0")), 0, String.format("%s != 1.0", result.get(0).getAmount()));
@@ -342,7 +344,8 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
         // check item detail
         List<UsageInArrearDetail> itemDetails2 = objectMapper.readValue(result.get(1).getItemDetails(), new TypeReference<List<UsageInArrearDetail>>() {});
         assertEquals(itemDetails2.size(), 1);
-        assertEquals(itemDetails2.get(0).getAmount().compareTo(result.get(1).getAmount()),0);
+        assertFalse(itemDetails2.get(0).isPreviousBilledAmountAvailable());
+        assertEquals(itemDetails2.get(0).getAmount().compareTo(new BigDecimal("2.0")),0);
     }
 
     @Test(groups = "fast")
@@ -459,8 +462,8 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
                                                                                                                                              Collections.<Usage>emptyList())
                                                                                                                      );
         List<UsageInArrearDetail> results = Lists.newArrayList();
-        results.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("cell-phone-minutes", 1000L)));
-        results.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("Mbytes", 30720L)));
+        results.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("cell-phone-minutes", 1000L), true));
+        results.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("Mbytes", 30720L), true));
         assertEquals(results.size(), 2);
 
         assertEquals(intervalConsumableInArrear.toBeBilledForUnit(results), new BigDecimal("18.5"));