Search in sources :

Example 1 with UsageConsumableInArrearAggregate

use of org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate in project killbill by killbill.

the class TestContiguousIntervalConsumableInArrear method testMultipleItemsAndTiersWithExistingItemsAllTiers_AGGREGATE.

@Test(groups = "fast")
public void testMultipleItemsAndTiersWithExistingItemsAllTiers_AGGREGATE() throws Exception {
    // 
    // Let's assume we were already billed on the previous period
    // 
    // FOO : 10 (tier 1) + 40 (tier 2) = 50
    final UsageConsumableInArrearTierUnitAggregate existingFooUsageTier1 = new UsageConsumableInArrearTierUnitAggregate(1, "FOO", BigDecimal.ONE, 1L, 10L, new BigDecimal("10.00"));
    final UsageConsumableInArrearTierUnitAggregate existingFooUsageTier2 = new UsageConsumableInArrearTierUnitAggregate(2, "FOO", BigDecimal.TEN, 1L, 40L, new BigDecimal("400.00"));
    // BAR : 10 (tier 1) + 40 (tier 2)
    final UsageConsumableInArrearTierUnitAggregate existingBarUsageTier1 = new UsageConsumableInArrearTierUnitAggregate(1, "BAR", new BigDecimal("2.00"), 1L, 80L, new BigDecimal("160.00"));
    final List<UsageConsumableInArrearTierUnitAggregate> existingUsage = ImmutableList.of(existingFooUsageTier1, existingFooUsageTier2, existingBarUsageTier1);
    final UsageConsumableInArrearAggregate usageConsumableInArrearDetail = new UsageConsumableInArrearAggregate(existingUsage);
    final String existingUsageJson = objectMapper.writeValueAsString(usageConsumableInArrearDetail);
    // 
    // Create usage data points (will include already billed + add new usage data)
    // 
    List<RawUsageRecord> rawUsageRecords = new ArrayList<RawUsageRecord>();
    // tier 3
    rawUsageRecords.add(new DefaultRawUsage(subscriptionId, new LocalDate(2014, 03, 20), "FOO", 50L + /* already built */
    20L, "tracking-1"));
    // tier 2
    rawUsageRecords.add(new DefaultRawUsage(subscriptionId, new LocalDate(2014, 03, 21), "BAR", 80L + /* already built */
    120L, "tracking-1"));
    final List<InvoiceItem> existingItems = new ArrayList<InvoiceItem>();
    final InvoiceItem ii1 = new UsageInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, productName, planName, phaseName, usageName, null, new LocalDate(2014, 03, 20), new LocalDate(2014, 04, 15), new BigDecimal("570.00"), null, currency, null, existingUsageJson);
    existingItems.add(ii1);
    List<InvoiceItem> result = produceInvoiceItems(rawUsageRecords, TierBlockPolicy.ALL_TIERS, UsageDetailMode.AGGREGATE, existingItems);
    assertEquals(result.size(), 1);
    assertEquals(result.get(0).getAmount().compareTo(new BigDecimal("3140.00")), 0, String.format("%s != 3140.0", result.get(0).getAmount()));
    UsageConsumableInArrearAggregate usageDetail = objectMapper.readValue(result.get(0).getItemDetails(), new TypeReference<UsageConsumableInArrearAggregate>() {
    });
    List<UsageConsumableInArrearTierUnitAggregate> itemDetails = usageDetail.getTierDetails();
    // We get same total than AGGREGATE : 3140
    // BAR item detail
    assertEquals(itemDetails.get(0).getTierUnit(), "BAR");
    assertEquals(itemDetails.get(0).getTier(), 1);
    assertEquals(itemDetails.get(0).getTierBlockSize(), 1);
    assertEquals(itemDetails.get(0).getQuantity().intValue(), 20);
    assertEquals(itemDetails.get(0).getTierPrice().compareTo(new BigDecimal("2.00")), 0);
    assertEquals(itemDetails.get(0).getAmount().compareTo(new BigDecimal("40.00")), 0);
    assertEquals(itemDetails.get(1).getTierUnit(), "BAR");
    assertEquals(itemDetails.get(1).getTier(), 2);
    assertEquals(itemDetails.get(1).getTierBlockSize(), 1);
    assertEquals(itemDetails.get(1).getQuantity().intValue(), 100);
    assertEquals(itemDetails.get(1).getTierPrice().compareTo(new BigDecimal("20.00")), 0);
    assertEquals(itemDetails.get(1).getAmount().compareTo(new BigDecimal("2000.00")), 0);
    // FOO item detail
    assertEquals(itemDetails.get(2).getTierUnit(), "FOO");
    assertEquals(itemDetails.get(2).getTier(), 1);
    assertEquals(itemDetails.get(2).getTierBlockSize(), 1);
    assertEquals(itemDetails.get(2).getQuantity().intValue(), 0);
    assertEquals(itemDetails.get(2).getTierPrice().compareTo(new BigDecimal("1.00")), 0);
    assertEquals(itemDetails.get(2).getAmount().compareTo(new BigDecimal("0.00")), 0);
    assertEquals(itemDetails.get(3).getTierUnit(), "FOO");
    assertEquals(itemDetails.get(3).getTier(), 2);
    assertEquals(itemDetails.get(3).getTierBlockSize(), 1);
    assertEquals(itemDetails.get(3).getQuantity().intValue(), 10);
    assertEquals(itemDetails.get(3).getTierPrice().compareTo(new BigDecimal("10.00")), 0);
    assertEquals(itemDetails.get(3).getAmount().compareTo(new BigDecimal("100.00")), 0);
    assertEquals(itemDetails.get(4).getTierUnit(), "FOO");
    assertEquals(itemDetails.get(4).getTier(), 3);
    assertEquals(itemDetails.get(4).getTierBlockSize(), 1);
    assertEquals(itemDetails.get(4).getQuantity().intValue(), 10);
    assertEquals(itemDetails.get(4).getTierPrice().compareTo(new BigDecimal("100.00")), 0);
    assertEquals(itemDetails.get(4).getAmount().compareTo(new BigDecimal("1000.00")), 0);
}
Also used : UsageConsumableInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) ArrayList(java.util.ArrayList) LocalDate(org.joda.time.LocalDate) BigDecimal(java.math.BigDecimal) RawUsageRecord(org.killbill.billing.usage.api.RawUsageRecord) UsageConsumableInArrearTierUnitAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate) DefaultRawUsage(org.killbill.billing.usage.api.svcs.DefaultRawUsage) Test(org.testng.annotations.Test)

Example 2 with UsageConsumableInArrearAggregate

use of org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate in project killbill by killbill.

the class ContiguousIntervalConsumableUsageInArrear method getBilledDetailsForUnitType.

@VisibleForTesting
List<UsageConsumableInArrearTierUnitAggregate> getBilledDetailsForUnitType(final Iterable<InvoiceItem> billedItems, final String unitType) {
    // Aggregate on a per-tier level, will return a list with item per level -- for this 'unitType'
    final Map<Integer, UsageConsumableInArrearTierUnitAggregate> resultMap = new TreeMap<Integer, UsageConsumableInArrearTierUnitAggregate>(Ordering.<Integer>natural());
    List<UsageConsumableInArrearTierUnitAggregate> tierDetails = new ArrayList<UsageConsumableInArrearTierUnitAggregate>();
    for (final InvoiceItem bi : billedItems) {
        if (usageDetailMode == UsageDetailMode.DETAIL) {
            final UsageConsumableInArrearTierUnitAggregate targetTierUnitDetail = fromJson(bi.getItemDetails(), new TypeReference<UsageConsumableInArrearTierUnitAggregate>() {
            });
            if (targetTierUnitDetail.getTierUnit().equals(unitType)) {
                // See https://github.com/killbill/killbill/issues/1325
                final Long quantity = bi.getQuantity().longValue();
                tierDetails.add(new UsageConsumableInArrearTierUnitAggregate(targetTierUnitDetail.getTier(), targetTierUnitDetail.getTierUnit(), bi.getRate(), targetTierUnitDetail.getTierBlockSize(), quantity, bi.getAmount()));
            }
        } else {
            final UsageConsumableInArrearAggregate usageDetail = fromJson(bi.getItemDetails(), new TypeReference<UsageConsumableInArrearAggregate>() {
            });
            for (final UsageConsumableInArrearTierUnitAggregate unitAgg : usageDetail.getTierDetails()) {
                if (unitAgg.getTierUnit().equals(unitType)) {
                    tierDetails.add(unitAgg);
                }
            }
        }
    }
    for (final UsageConsumableInArrearTierUnitAggregate curDetail : tierDetails) {
        if (!resultMap.containsKey(curDetail.getTier())) {
            resultMap.put(curDetail.getTier(), curDetail);
        } else {
            final UsageConsumableInArrearTierUnitAggregate perTierDetail = resultMap.get(curDetail.getTier());
            perTierDetail.updateQuantityAndAmount(curDetail.getQuantity());
        }
    }
    return ImmutableList.copyOf(resultMap.values());
}
Also used : UsageConsumableInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) UsageConsumableInArrearTierUnitAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate) ArrayList(java.util.ArrayList) TreeMap(java.util.TreeMap) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 3 with UsageConsumableInArrearAggregate

use of org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate in project killbill by killbill.

the class ContiguousIntervalConsumableUsageInArrear method getToBeBilledUsageDetails.

@Override
protected UsageInArrearAggregate getToBeBilledUsageDetails(final LocalDate startDate, final LocalDate endDate, final List<RolledUpUnit> rolledUpUnits, final Iterable<InvoiceItem> billedItems, final boolean areAllBilledItemsWithDetails) throws CatalogApiException {
    final Map<String, List<UsageConsumableInArrearTierUnitAggregate>> previousUnitsUsage;
    if (usageDetailMode == UsageDetailMode.DETAIL || areAllBilledItemsWithDetails) {
        previousUnitsUsage = new HashMap<String, List<UsageConsumableInArrearTierUnitAggregate>>();
        for (RolledUpUnit cur : rolledUpUnits) {
            final List<UsageConsumableInArrearTierUnitAggregate> usageInArrearDetailForUnitType = getBilledDetailsForUnitType(billedItems, cur.getUnitType());
            previousUnitsUsage.put(cur.getUnitType(), usageInArrearDetailForUnitType);
        }
    } else {
        previousUnitsUsage = ImmutableMap.of();
    }
    final List<UsageConsumableInArrearTierUnitAggregate> usageConsumableInArrearTierUnitAggregates = new ArrayList<UsageConsumableInArrearTierUnitAggregate>();
    for (final RolledUpUnit cur : rolledUpUnits) {
        if (!unitTypes.contains(cur.getUnitType())) {
            log.warn("ContiguousIntervalConsumableInArrear is skipping unitType " + cur.getUnitType());
            continue;
        }
        final List<UsageConsumableInArrearTierUnitAggregate> previousUsage = previousUnitsUsage.containsKey(cur.getUnitType()) ? previousUnitsUsage.get(cur.getUnitType()) : ImmutableList.<UsageConsumableInArrearTierUnitAggregate>of();
        final List<UsageConsumableInArrearTierUnitAggregate> toBeBilledConsumableInArrear = computeToBeBilledConsumableInArrear(startDate, endDate, cur, previousUsage);
        usageConsumableInArrearTierUnitAggregates.addAll(toBeBilledConsumableInArrear);
    }
    final UsageInArrearAggregate toBeBilledUsageDetails = new UsageConsumableInArrearAggregate(usageConsumableInArrearTierUnitAggregates);
    return toBeBilledUsageDetails;
}
Also used : UsageConsumableInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate) RolledUpUnit(org.killbill.billing.usage.api.RolledUpUnit) UsageInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageInArrearAggregate) UsageConsumableInArrearTierUnitAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List)

Example 4 with UsageConsumableInArrearAggregate

use of org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate in project killbill by killbill.

the class ContiguousIntervalConsumableUsageInArrear method populateResults.

@Override
protected void populateResults(final LocalDate startDate, final LocalDate endDate, final DateTime catalogEffectiveDate, final BigDecimal billedUsage, final BigDecimal toBeBilledUsage, final UsageInArrearAggregate toBeBilledUsageDetails, final boolean areAllBilledItemsWithDetails, final boolean isPeriodPreviouslyBilled, final List<InvoiceItem> result) throws InvoiceApiException {
    // 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 (isDryRun || invoiceConfig.isUsageMissingLenient(internalTenantContext)) {
            return;
        } else {
            throw new InvoiceApiException(ErrorCode.UNEXPECTED_ERROR, String.format("ILLEGAL INVOICING STATE: Usage period start='%s', end='%s', amountToBill='%s', (previously billed amount='%s', new proposed amount='%s')", startDate, endDate, amountToBill, billedUsage, toBeBilledUsage));
        }
    } else /* amountToBill.compareTo(BigDecimal.ZERO) >= 0 */
    {
        if (!isPeriodPreviouslyBilled || amountToBill.compareTo(BigDecimal.ZERO) > 0) {
            if (UsageDetailMode.DETAIL == usageDetailMode) {
                for (UsageConsumableInArrearTierUnitAggregate toBeBilledUsageDetail : ((UsageConsumableInArrearAggregate) toBeBilledUsageDetails).getTierDetails()) {
                    final String itemDetails = toJson(toBeBilledUsageDetail);
                    // See https://github.com/killbill/killbill/issues/1325
                    // Our current sql schema limits to an int value ...
                    final Integer quantity = toBeBilledUsageDetail.getQuantity() <= Integer.MAX_VALUE ? toBeBilledUsageDetail.getQuantity().intValue() : -1;
                    final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getProductName(), getPlanName(), getPhaseName(), usage.getName(), catalogEffectiveDate, startDate, endDate, toBeBilledUsageDetail.getAmount(), toBeBilledUsageDetail.getTierPrice(), getCurrency(), quantity, itemDetails);
                    result.add(item);
                }
            } else {
                final String itemDetails = toJson(toBeBilledUsageDetails);
                final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getProductName(), getPlanName(), getPhaseName(), usage.getName(), catalogEffectiveDate, startDate, endDate, amountToBill, null, getCurrency(), null, itemDetails);
                result.add(item);
            }
        }
    }
}
Also used : UsageConsumableInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) UsageConsumableInArrearTierUnitAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) BigDecimal(java.math.BigDecimal)

Example 5 with UsageConsumableInArrearAggregate

use of org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate in project killbill by killbill.

the class TestContiguousIntervalConsumableInArrear method testBilledDetailsForUnitType.

@Test(groups = "fast")
public void testBilledDetailsForUnitType() throws Exception {
    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.<RawUsageRecord>of(), targetDate, false, createMockBillingEvent(targetDate.toDateTimeAtStartOfDay(DateTimeZone.UTC), BillingPeriod.MONTHLY, Collections.<Usage>emptyList(), catalogEffectiveDate));
    final UsageConsumableInArrearTierUnitAggregate detail1 = new UsageConsumableInArrearTierUnitAggregate(3, "FOO", new BigDecimal("0.50"), 1L, 700L);
    final UsageConsumableInArrearTierUnitAggregate detail2 = new UsageConsumableInArrearTierUnitAggregate(2, "FOO", BigDecimal.ONE, 1L, 500L);
    final UsageConsumableInArrearTierUnitAggregate detail3 = new UsageConsumableInArrearTierUnitAggregate(1, "FOO", BigDecimal.TEN, 1L, 10L);
    final UsageConsumableInArrearTierUnitAggregate detail4 = new UsageConsumableInArrearTierUnitAggregate(2, "FOO", BigDecimal.ONE, 1L, 50L);
    final UsageConsumableInArrearTierUnitAggregate detail5 = new UsageConsumableInArrearTierUnitAggregate(1, "FOO", BigDecimal.TEN, 1L, 100L);
    final List<UsageConsumableInArrearTierUnitAggregate> existingUsage = ImmutableList.of(detail1, detail2, detail3, detail4, detail5);
    final UsageConsumableInArrearAggregate usageConsumableInArrearDetail = new UsageConsumableInArrearAggregate(existingUsage);
    final String existingUsageJson = objectMapper.writeValueAsString(usageConsumableInArrearDetail);
    final List<InvoiceItem> existingItems = new ArrayList<InvoiceItem>();
    final InvoiceItem ii1 = new UsageInvoiceItem(invoiceId, accountId, bundleId, subscriptionId, productName, planName, phaseName, usageName, null, new LocalDate(2014, 03, 20), new LocalDate(2014, 04, 15), new BigDecimal("570.00"), null, currency, null, existingUsageJson);
    existingItems.add(ii1);
    final List<UsageConsumableInArrearTierUnitAggregate> 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);
}
Also used : UsageConsumableInArrearAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate) DefaultRawUsage(org.killbill.billing.usage.api.svcs.DefaultRawUsage) Usage(org.killbill.billing.catalog.api.Usage) DefaultUsage(org.killbill.billing.catalog.DefaultUsage) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) ArrayList(java.util.ArrayList) DefaultTieredBlock(org.killbill.billing.catalog.DefaultTieredBlock) LocalDate(org.joda.time.LocalDate) BigDecimal(java.math.BigDecimal) UsageConsumableInArrearTierUnitAggregate(org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate) DefaultUsage(org.killbill.billing.catalog.DefaultUsage) DefaultTier(org.killbill.billing.catalog.DefaultTier) Test(org.testng.annotations.Test)

Aggregations

UsageConsumableInArrearAggregate (org.killbill.billing.invoice.usage.details.UsageConsumableInArrearAggregate)9 UsageConsumableInArrearTierUnitAggregate (org.killbill.billing.invoice.usage.details.UsageConsumableInArrearTierUnitAggregate)9 BigDecimal (java.math.BigDecimal)7 ArrayList (java.util.ArrayList)7 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)7 UsageInvoiceItem (org.killbill.billing.invoice.model.UsageInvoiceItem)7 LocalDate (org.joda.time.LocalDate)6 DefaultRawUsage (org.killbill.billing.usage.api.svcs.DefaultRawUsage)6 Test (org.testng.annotations.Test)6 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)5 RawUsageRecord (org.killbill.billing.usage.api.RawUsageRecord)4 TypeReference (com.fasterxml.jackson.core.type.TypeReference)3 DefaultTier (org.killbill.billing.catalog.DefaultTier)3 DefaultTieredBlock (org.killbill.billing.catalog.DefaultTieredBlock)3 DefaultUsage (org.killbill.billing.catalog.DefaultUsage)3 Usage (org.killbill.billing.catalog.api.Usage)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 ImmutableList (com.google.common.collect.ImmutableList)1 List (java.util.List)1 TreeMap (java.util.TreeMap)1