killbill-memoizeit
Changes
invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalCapacityUsageInArrear.java 23(+7 -16)
invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableUsageInArrear.java 71(+40 -31)
invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalUsageInArrear.java 18(+2 -16)
Details
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalCapacityUsageInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalCapacityUsageInArrear.java
index e5321fe..90385f7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalCapacityUsageInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalCapacityUsageInArrear.java
@@ -37,7 +37,6 @@ import org.killbill.billing.invoice.usage.details.UsageInArrearTierUnitDetail;
import org.killbill.billing.usage.RawUsage;
import org.killbill.billing.usage.api.RolledUpUnit;
import org.killbill.billing.util.config.definition.InvoiceConfig.UsageDetailMode;
-import org.killbill.billing.util.jackson.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
@@ -50,8 +49,6 @@ public class ContiguousIntervalCapacityUsageInArrear extends ContiguousIntervalU
private static final Joiner joiner = Joiner.on(", ");
- private static final ObjectMapper objectMapper = new ObjectMapper();
-
public ContiguousIntervalCapacityUsageInArrear(final Usage usage,
final UUID accountId,
final UUID invoiceId,
@@ -63,25 +60,19 @@ public class ContiguousIntervalCapacityUsageInArrear extends ContiguousIntervalU
super(usage, accountId, invoiceId, rawSubscriptionUsage, targetDate, rawUsageStartDate, usageDetailMode, internalTenantContext);
}
-
-
@Override
- protected void populateResults(final LocalDate startDate, final LocalDate endDate, final Iterable<InvoiceItem> billedItems, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result) {
+ protected void populateResults(final LocalDate startDate, final LocalDate endDate, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result) {
// Compute final amount by subtracting amount that was already billed.
- if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
- final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
+ final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
- if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
- final String itemDetails = areAllBilledItemsWithDetails ? toJson(toBeBilledUsageDetails) : null;
- final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
- getPhaseName(), usage.getName(), startDate, endDate, amountToBill, null, getCurrency(), null, itemDetails);
- result.add(item);
- }
+ if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
+ final String itemDetails = areAllBilledItemsWithDetails ? toJson(toBeBilledUsageDetails) : null;
+ final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
+ getPhaseName(), usage.getName(), startDate, endDate, amountToBill, null, getCurrency(), null, itemDetails);
+ result.add(item);
}
-
}
-
@Override
protected UsageInArrearDetail getToBeBilledUsageDetails(final List<RolledUpUnit> rolledUpUnits, final Iterable<InvoiceItem> billedItems, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
return computeToBeBilledCapacityInArrear(rolledUpUnits);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableUsageInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableUsageInArrear.java
index 04073ba..2898217 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableUsageInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableUsageInArrear.java
@@ -24,11 +24,13 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import java.util.UUID;
import org.joda.time.LocalDate;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.CatalogApiException;
+import org.killbill.billing.catalog.api.TierBlockPolicy;
import org.killbill.billing.catalog.api.TieredBlock;
import org.killbill.billing.catalog.api.Usage;
import org.killbill.billing.invoice.api.InvoiceItem;
@@ -48,6 +50,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
import static org.killbill.billing.invoice.usage.UsageUtils.getConsumableInArrearTieredBlocks;
@@ -67,29 +70,25 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
}
@Override
- protected void populateResults(final LocalDate startDate, final LocalDate endDate, final Iterable<InvoiceItem> billedItems, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result) {
- // Compute final amount by subtracting amount that was already billed.
- if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
- // In the case past invoice items showed the details (areAllBilledItemsWithDetails=true), billed usage has already been taken into account
- // as it part of the reconciliation logic, so no need to subtract it here
- final BigDecimal amountToBill = areAllBilledItemsWithDetails ? toBeBilledUsage : toBeBilledUsage.subtract(billedUsage);
-
- if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
- if (UsageDetailMode.DETAIL == usageDetailMode) {
- for (UsageConsumableInArrearTierUnitDetail toBeBilledUsageDetail : ((UsageConsumableInArrearDetail) toBeBilledUsageDetails).getTierDetails()) {
- final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
- getPhaseName(), usage.getName(), startDate, endDate, toBeBilledUsageDetail.getAmount(), toBeBilledUsageDetail.getTierPrice(), getCurrency(), toBeBilledUsageDetail.getQuantity(), null);
- result.add(item);
- }
- } else {
- final String itemDetails = toJson(toBeBilledUsageDetails);
+ protected void populateResults(final LocalDate startDate, final LocalDate endDate, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result) {
+ // In the case past invoice items showed the details (areAllBilledItemsWithDetails=true), billed usage has already been taken into account
+ // as it part of the reconciliation logic, so no need to subtract it here
+ final BigDecimal amountToBill = (usage.getTierBlockPolicy() == TierBlockPolicy.ALL_TIERS && areAllBilledItemsWithDetails) ? toBeBilledUsage : toBeBilledUsage.subtract(billedUsage);
+
+ if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
+ if (UsageDetailMode.DETAIL == usageDetailMode) {
+ for (UsageConsumableInArrearTierUnitDetail toBeBilledUsageDetail : ((UsageConsumableInArrearDetail) toBeBilledUsageDetails).getTierDetails()) {
final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
- getPhaseName(), usage.getName(), startDate, endDate, amountToBill, null, getCurrency(), null, itemDetails);
+ getPhaseName(), usage.getName(), startDate, endDate, toBeBilledUsageDetail.getAmount(), toBeBilledUsageDetail.getTierPrice(), getCurrency(), toBeBilledUsageDetail.getQuantity(), null);
result.add(item);
}
+ } else {
+ final String itemDetails = toJson(toBeBilledUsageDetails);
+ final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
+ getPhaseName(), usage.getName(), startDate, endDate, amountToBill, null, getCurrency(), null, itemDetails);
+ result.add(item);
}
}
-
}
@Override
@@ -99,7 +98,7 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
if (areAllBilledItemsWithDetails) {
previousUnitsUsage = new HashMap<String, List<UsageConsumableInArrearTierUnitDetail>>();
for (RolledUpUnit cur : rolledUpUnits) {
- final List<UsageConsumableInArrearTierUnitDetail> usageInArrearDetailForUnitType = getUsageConsumableInArrearDetailForUnitType(billedItems, cur.getUnitType());
+ final List<UsageConsumableInArrearTierUnitDetail> usageInArrearDetailForUnitType = getBilledDetailsForUnitType(billedItems, cur.getUnitType());
previousUnitsUsage.put(cur.getUnitType(), usageInArrearDetailForUnitType);
}
} else {
@@ -114,29 +113,39 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
}
final List<UsageConsumableInArrearTierUnitDetail> previousUsage = previousUnitsUsage.containsKey(cur.getUnitType()) ? previousUnitsUsage.get(cur.getUnitType()) : ImmutableList.<UsageConsumableInArrearTierUnitDetail>of();
- usageConsumableInArrearTierUnitDetails.addAll(computeToBeBilledConsumableInArrear(cur, previousUsage, areAllBilledItemsWithDetails));
+ final List<UsageConsumableInArrearTierUnitDetail> toBeBilledConsumableInArrear = computeToBeBilledConsumableInArrear(cur, previousUsage);
+ usageConsumableInArrearTierUnitDetails.addAll(toBeBilledConsumableInArrear);
}
final UsageInArrearDetail toBeBilledUsageDetails = new UsageConsumableInArrearDetail(usageConsumableInArrearTierUnitDetails);
return toBeBilledUsageDetails;
}
- private List<UsageConsumableInArrearTierUnitDetail> getUsageConsumableInArrearDetailForUnitType(final Iterable<InvoiceItem> billedItems, final String unitType) {
+ @VisibleForTesting
+ List<UsageConsumableInArrearTierUnitDetail> getBilledDetailsForUnitType(final Iterable<InvoiceItem> billedItems, final String unitType) {
- final List<UsageConsumableInArrearTierUnitDetail> result = new ArrayList<UsageConsumableInArrearTierUnitDetail>();
+ // Aggregate on a per-tier level, will return a list with item per level -- for this 'unitType'
+ final Map<Integer, UsageConsumableInArrearTierUnitDetail> resultMap = new TreeMap<Integer, UsageConsumableInArrearTierUnitDetail>(Ordering.<Integer>natural());
for (final InvoiceItem bi : billedItems) {
final UsageConsumableInArrearDetail usageDetail = fromJson(bi.getItemDetails());
for (final UsageConsumableInArrearTierUnitDetail curDetail : usageDetail.getTierDetails()) {
+
if (curDetail.getTierUnit().equals(unitType)) {
- result.add(curDetail);
+
+ if (!resultMap.containsKey(curDetail.getTier())) {
+ resultMap.put(curDetail.getTier(), curDetail);
+ } else {
+ final UsageConsumableInArrearTierUnitDetail perTierDetail = resultMap.get(curDetail.getTier());
+ perTierDetail.updateQuantityAndAmount(perTierDetail.getQuantity() + curDetail.getQuantity());
+ }
}
}
}
- return result;
+ return ImmutableList.copyOf(resultMap.values());
}
@VisibleForTesting
- List<UsageConsumableInArrearTierUnitDetail> computeToBeBilledConsumableInArrear(final RolledUpUnit roUnit, final List<UsageConsumableInArrearTierUnitDetail> previousUsage, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
+ List<UsageConsumableInArrearTierUnitDetail> computeToBeBilledConsumableInArrear(final RolledUpUnit roUnit, final List<UsageConsumableInArrearTierUnitDetail> previousUsage) throws CatalogApiException {
Preconditions.checkState(isBuilt.get());
final List<TieredBlock> tieredBlocks = getConsumableInArrearTieredBlocks(usage, roUnit.getUnitType());
@@ -145,7 +154,7 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
case ALL_TIERS:
return computeToBeBilledConsumableInArrearWith_ALL_TIERS(tieredBlocks, previousUsage, roUnit.getAmount());
case TOP_TIER:
- return Arrays.asList(computeToBeBilledConsumableInArrearWith_TOP_TIER(tieredBlocks, previousUsage, roUnit.getAmount(), areAllBilledItemsWithDetails));
+ return Arrays.asList(computeToBeBilledConsumableInArrearWith_TOP_TIER(tieredBlocks, previousUsage, roUnit.getAmount()));
default:
throw new IllegalStateException("Unknown TierBlockPolicy " + usage.getTierBlockPolicy());
}
@@ -178,11 +187,11 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
if (hasPreviousUsage) {
final Integer previousUsageQuantity = tierNum <= lastPreviousUsageTier ? previousUsage.get(tierNum - 1).getQuantity() : 0;
if (tierNum < lastPreviousUsageTier) {
- Preconditions.checkState(nbUsedTierBlocks == previousUsageQuantity, String.format("Expected usage for tier='%d', unit='%s' to be full, instead found units='[%d/%d]'",
- tierNum, tieredBlock.getUnit().getName(), nbUsedTierBlocks, previousUsageQuantity));
+ Preconditions.checkState(nbUsedTierBlocks == previousUsageQuantity, "Expected usage for tier='%d', unit='%s' to be full, instead found units='[%d/%d]'",
+ tierNum, tieredBlock.getUnit().getName(), nbUsedTierBlocks, previousUsageQuantity);
} else {
- Preconditions.checkState(nbUsedTierBlocks - previousUsageQuantity >= 0, String.format("Expected usage for tier='%d', unit='%s' to contain at least as mush as current usage, instead found units='[%d/%d]",
- tierNum, tieredBlock.getUnit().getName(), nbUsedTierBlocks, previousUsageQuantity));
+ Preconditions.checkState(nbUsedTierBlocks - previousUsageQuantity >= 0, "Expected usage for tier='%d', unit='%s' to contain at least as mush as current usage, instead found units='[%d/%d]",
+ tierNum, tieredBlock.getUnit().getName(), nbUsedTierBlocks, previousUsageQuantity);
}
nbUsedTierBlocks = nbUsedTierBlocks - previousUsageQuantity;
}
@@ -194,7 +203,7 @@ public class ContiguousIntervalConsumableUsageInArrear extends ContiguousInterva
return toBeBilledDetails;
}
- UsageConsumableInArrearTierUnitDetail computeToBeBilledConsumableInArrearWith_TOP_TIER(final List<TieredBlock> tieredBlocks, final List<UsageConsumableInArrearTierUnitDetail> previousUsage, final Long units, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
+ UsageConsumableInArrearTierUnitDetail computeToBeBilledConsumableInArrearWith_TOP_TIER(final List<TieredBlock> tieredBlocks, final List<UsageConsumableInArrearTierUnitDetail> previousUsage, final Long units) throws CatalogApiException {
int remainingUnits = units.intValue();
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 7dfba4f..766d5dc 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
@@ -30,7 +30,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import org.joda.time.LocalDate;
-import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.BillingMode;
import org.killbill.billing.catalog.api.CatalogApiException;
@@ -201,26 +200,13 @@ public abstract class ContiguousIntervalUsageInArrear {
final UsageInArrearDetail toBeBilledUsageDetails = getToBeBilledUsageDetails(rolledUpUnits, billedItems, areAllBilledItemsWithDetails);
final BigDecimal toBeBilledUsage = toBeBilledUsageDetails.getAmount();
-
- final int billedUsageDelta = billedUsage.compareTo(toBeBilledUsage);
- // We built more in the past than what we find now, data usage vanished?
- if (billedUsageDelta > 0) {
- /*
- throw new InvoiceApiException(ErrorCode.UNEXPECTED_ERROR,
- String.format("ILLEGAL INVOICING STATE: Usage period start='%s', end='%s', previously billed amount='%.2f', new proposed amount='%.2f'",
- ru.getStart(), ru.getEnd(), billedUsage, toBeBilledUsage));
- */
- // Something remains to be billed
- } else if (billedUsageDelta < 0) {
- populateResults(ru.getStart(), ru.getEnd(), billedItems, billedUsage, toBeBilledUsage, toBeBilledUsageDetails, areAllBilledItemsWithDetails, result);
- }
+ populateResults(ru.getStart(), ru.getEnd(), billedUsage, toBeBilledUsage, toBeBilledUsageDetails, areAllBilledItemsWithDetails, result);
}
final LocalDate nextNotificationDate = computeNextNotificationDate();
return new UsageInArrearItemsAndNextNotificationDate(result, nextNotificationDate);
}
- protected abstract void populateResults(final LocalDate startDate, final LocalDate endDate, final Iterable<InvoiceItem> billedItems, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result);
-
+ protected abstract void populateResults(final LocalDate startDate, final LocalDate endDate, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearDetail toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final List<InvoiceItem> result);
protected abstract UsageInArrearDetail getToBeBilledUsageDetails(final List<RolledUpUnit> rolledUpUnits, final Iterable<InvoiceItem> billedItems, final boolean areAllBilledItemsWithDetails) throws CatalogApiException;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/details/UsageConsumableInArrearTierUnitDetail.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/details/UsageConsumableInArrearTierUnitDetail.java
index de7b59b..5b275f7 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/details/UsageConsumableInArrearTierUnitDetail.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/details/UsageConsumableInArrearTierUnitDetail.java
@@ -28,7 +28,7 @@ public class UsageConsumableInArrearTierUnitDetail extends UsageInArrearTierUnit
private BigDecimal amount;
public UsageConsumableInArrearTierUnitDetail(int tier, String tierUnit, BigDecimal tierPrice, Integer tierBlockSize, Integer quantity) {
- this(tier, tierUnit, tierPrice, tierBlockSize, quantity, tierPrice.multiply(new BigDecimal(quantity)));
+ this(tier, tierUnit, tierPrice, tierBlockSize, quantity, computeAmount(tierPrice, quantity));
}
@JsonCreator
@@ -70,4 +70,13 @@ public class UsageConsumableInArrearTierUnitDetail extends UsageInArrearTierUnit
public int getTierBlockSize() {
return tierBlockSize;
}
+
+ public void updateQuantityAndAmount(final Integer targetQuantity) {
+ this.quantity = targetQuantity;
+ this.amount = computeAmount(tierPrice, targetQuantity);
+ }
+
+ private static BigDecimal computeAmount(final BigDecimal targetTierPrice, final Integer targetQuantity) {
+ return targetTierPrice.multiply(new BigDecimal(targetQuantity));
+ }
}
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 c7ebfa4..7fd4e71 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
@@ -52,6 +52,7 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
@@ -85,6 +86,49 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
super.beforeMethod();
}
+
+ @Test(groups = "fast")
+ public void testBilledDetailsForUnitType() throws JsonProcessingException {
+
+ final LocalDate startDate = new LocalDate(2014, 03, 20);
+ final LocalDate targetDate = startDate.plusDays(1);
+
+ final DefaultTieredBlock block = createDefaultTieredBlock("unit", 100, 1000, BigDecimal.ONE);
+ final DefaultTier tier = createDefaultTierWithBlocks(block);
+ final DefaultUsage usage = createConsumableInArrearUsage(usageName, BillingPeriod.MONTHLY, TierBlockPolicy.ALL_TIERS, tier);
+ final ContiguousIntervalConsumableUsageInArrear intervalConsumableInArrear = createContiguousIntervalConsumableInArrear(usage, ImmutableList.<RawUsage>of(), targetDate, false,
+ createMockBillingEvent(targetDate.toDateTimeAtStartOfDay(DateTimeZone.UTC),
+ BillingPeriod.MONTHLY,
+ Collections.<Usage>emptyList()));
+
+ final UsageConsumableInArrearTierUnitDetail detail1 = new UsageConsumableInArrearTierUnitDetail(3, "FOO", new BigDecimal("0.50"), 1, 700);
+ final UsageConsumableInArrearTierUnitDetail detail2 = new UsageConsumableInArrearTierUnitDetail(2, "FOO", BigDecimal.ONE, 1, 500);
+ final UsageConsumableInArrearTierUnitDetail detail3 = new UsageConsumableInArrearTierUnitDetail(1, "FOO", BigDecimal.TEN, 1, 10);
+ final UsageConsumableInArrearTierUnitDetail detail4 = new UsageConsumableInArrearTierUnitDetail(2, "FOO", BigDecimal.ONE, 1, 50);
+ final UsageConsumableInArrearTierUnitDetail detail5 = new UsageConsumableInArrearTierUnitDetail(1, "FOO", BigDecimal.TEN, 1, 100);
+
+ final List<UsageConsumableInArrearTierUnitDetail> existingUsage = ImmutableList.of(detail1, detail2, detail3, detail4, detail5);
+
+ final UsageConsumableInArrearDetail usageConsumableInArrearDetail = new UsageConsumableInArrearDetail(existingUsage);
+
+ final String existingUsageJson = objectMapper.writeValueAsString(usageConsumableInArrearDetail);
+
+ final List<InvoiceItem> existingItems = new ArrayList<InvoiceItem>();
+ final InvoiceItem ii1 = new UsageInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, usageName, new LocalDate(2014, 03, 20), new LocalDate(2014, 04, 15), new BigDecimal("570.00"), null, currency, null, existingUsageJson);
+ existingItems.add(ii1);
+
+
+ final List<UsageConsumableInArrearTierUnitDetail> aggregateDetails = intervalConsumableInArrear.getBilledDetailsForUnitType(existingItems, "FOO");
+ assertEquals(aggregateDetails.size(), 3);
+ assertEquals(aggregateDetails.get(0).getTier(), 1);
+ assertEquals(aggregateDetails.get(0).getQuantity().intValue(), 110);
+ assertEquals(aggregateDetails.get(1).getTier(), 2);
+ assertEquals(aggregateDetails.get(1).getQuantity().intValue(), 550);
+ assertEquals(aggregateDetails.get(2).getTier(), 3);
+ assertEquals(aggregateDetails.get(2).getQuantity().intValue(), 700);
+
+ }
+
@Test(groups = "fast")
public void testComputeToBeBilledUsage() {
@@ -147,7 +191,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
Collections.<Usage>emptyList())
);
- List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
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"));
@@ -175,7 +219,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
Collections.<Usage>emptyList())
);
- List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 5325L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 5325L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
assertEquals(result.size(), 2);
// 5000 = 1000 (tier1) + 4325 (tier2) => 10 + 5 = 15
@@ -209,23 +253,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<UsageConsumableInArrearTierUnitDetail> inputTier1 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 1000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> inputTier1 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 1000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
assertEquals(inputTier1.size(), 1);
// 1000 units => (tier1) : 1000 / 100 + 1000 % 100 = 10
assertEquals(inputTier1.get(0).getAmount(), new BigDecimal("10"));
- List<UsageConsumableInArrearTierUnitDetail> inputTier2 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> inputTier2 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
assertEquals(inputTier2.size(), 1);
// 101000 units => (tier2) : 101000 / 1000 + 101000 % 1000 = 101 + 0 = 101
assertEquals(inputTier2.get(0).getAmount(), new BigDecimal("101"));
- List<UsageConsumableInArrearTierUnitDetail> inputTier3 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101001L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> inputTier3 = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 101001L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
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<UsageConsumableInArrearTierUnitDetail> inputLastTier = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 300000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> inputLastTier = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 300000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
assertEquals(inputLastTier.size(), 1);
// 300000 units => (tier3) : 300000 / 1000 + 300000 % 1000 = 300 units => $150
assertEquals(inputLastTier.get(0).getAmount(), new BigDecimal("150.0"));
@@ -254,7 +298,7 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
Collections.<Usage>emptyList())
);
- List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true);
+ List<UsageConsumableInArrearTierUnitDetail> result = intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("unit", 111L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of());
assertEquals(result.size(), 1);
// 111 = 111 * 0.5 =
@@ -464,8 +508,8 @@ public class TestContiguousIntervalConsumableInArrear extends TestUsageInArrearB
Collections.<Usage>emptyList())
);
final List<UsageConsumableInArrearTierUnitDetail> tierUnitDetails = Lists.newArrayList();
- tierUnitDetails.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("cell-phone-minutes", 1000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true));
- tierUnitDetails.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("Mbytes", 30720L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of(), true));
+ tierUnitDetails.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("cell-phone-minutes", 1000L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of()));
+ tierUnitDetails.addAll(intervalConsumableInArrear.computeToBeBilledConsumableInArrear(new DefaultRolledUpUnit("Mbytes", 30720L), ImmutableList.<UsageConsumableInArrearTierUnitDetail>of()));
assertEquals(tierUnitDetails.size(), 2);
final UsageConsumableInArrearDetail details = new UsageConsumableInArrearDetail(tierUnitDetails);