use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.
the class ContiguousIntervalUsageInArrear method computeMissingItemsAndNextNotificationDate.
/**
* Compute the missing usage invoice items based on what should be billed and what has been billed ($ amount comparison).
*
* @param existingUsage existing on disk usage items for the subscription
* @throws CatalogApiException
*/
public UsageInArrearItemsAndNextNotificationDate computeMissingItemsAndNextNotificationDate(final List<InvoiceItem> existingUsage) throws CatalogApiException {
Preconditions.checkState(isBuilt.get());
if (transitionTimes.size() < 2) {
return new UsageInArrearItemsAndNextNotificationDate(ImmutableList.<InvoiceItem>of(), computeNextNotificationDate());
}
final List<InvoiceItem> result = Lists.newLinkedList();
// We start by generating 'marker' USAGE items with $0 that will allow to correctly insert the next notification for when there is no USAGE to bill.
// Those will be removed by the invoicing code later so as to not end up with superfluous $0 items
LocalDate prevDate = null;
for (final LocalDate curDate : transitionTimes) {
if (prevDate != null) {
final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(), getPhaseName(), usage.getName(), prevDate, curDate, BigDecimal.ZERO, getCurrency());
result.add(item);
}
prevDate = curDate;
}
final List<RolledUpUsage> allUsage = getRolledUpUsage();
for (final RolledUpUsage ru : allUsage) {
BigDecimal toBeBilledUsage = BigDecimal.ZERO;
if (usage.getUsageType() == UsageType.CAPACITY) {
toBeBilledUsage = computeToBeBilledCapacityInArrear(ru.getRolledUpUnits());
} else /* UsageType.CONSUMABLE */
{
// Compute total price amount that should be billed for that period of time (and usage section) across unitTypes.
for (final RolledUpUnit cur : ru.getRolledUpUnits()) {
if (!unitTypes.contains(cur.getUnitType())) {
log.warn("ContiguousIntervalConsumableInArrear is skipping unitType " + cur.getUnitType());
continue;
}
final BigDecimal toBeBilledForUnit = computeToBeBilledConsumableInArrear(cur);
toBeBilledUsage = toBeBilledUsage.add(toBeBilledForUnit);
}
}
// 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.
if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(), getPhaseName(), usage.getName(), ru.getStart(), ru.getEnd(), amountToBill, getCurrency());
result.add(item);
}
}
}
final LocalDate nextNotificationdate = computeNextNotificationDate();
return new UsageInArrearItemsAndNextNotificationDate(result, nextNotificationdate);
}
use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceUserApi method testPostExternalChargeForBundleOnNewInvoice.
@Test(groups = "slow")
public void testPostExternalChargeForBundleOnNewInvoice() throws Exception {
// Initial account balance
final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
// Post an external charge
final BigDecimal externalChargeAmount = BigDecimal.TEN;
final UUID bundleId = UUID.randomUUID();
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, accountId, bundleId, UUID.randomUUID().toString(), clock.getUTCToday(), externalChargeAmount, accountCurrency);
final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, callContext).get(0);
verifyExternalChargeOnNewInvoice(accountBalance, bundleId, externalChargeAmount, externalChargeInvoiceItem);
}
use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceUserApi method testPostExternalChargeForBundleOnExistingInvoice.
@Test(groups = "slow")
public void testPostExternalChargeForBundleOnExistingInvoice() throws Exception {
// Verify the initial invoice balance
final BigDecimal invoiceBalance = invoiceUserApi.getInvoice(invoiceId, callContext).getBalance();
Assert.assertEquals(invoiceBalance.compareTo(BigDecimal.ZERO), 1);
// Verify the initial account balance
final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
Assert.assertEquals(accountBalance, invoiceBalance);
// Post an external charge
final BigDecimal externalChargeAmount = BigDecimal.TEN;
final UUID bundleId = UUID.randomUUID();
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(invoiceId, accountId, bundleId, UUID.randomUUID().toString(), clock.getUTCToday(), externalChargeAmount, accountCurrency);
final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, callContext).get(0);
verifyExternalChargeOnExistingInvoice(invoiceBalance, bundleId, externalChargeAmount, externalChargeInvoiceItem);
}
use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceUserApi method testCantAdjustInvoiceItemWithNegativeAmount.
@Test(groups = "slow")
public void testCantAdjustInvoiceItemWithNegativeAmount() throws Exception {
final InvoiceItem invoiceItem = invoiceUserApi.getInvoice(invoiceId, callContext).getInvoiceItems().get(0);
try {
invoiceUserApi.insertInvoiceItemAdjustment(accountId, invoiceId, invoiceItem.getId(), clock.getUTCToday(), BigDecimal.TEN.negate(), accountCurrency, null, callContext);
Assert.fail("Should not have been able to adjust an item with a negative amount");
} catch (InvoiceApiException e) {
Assert.assertEquals(e.getCode(), ErrorCode.INVOICE_ITEM_ADJUSTMENT_AMOUNT_SHOULD_BE_POSITIVE.getCode());
}
}
use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceUserApi method testAdjustCommittedInvoice.
@Test(groups = "slow", expectedExceptions = InvoiceApiException.class, expectedExceptionsMessageRegExp = ".*it is already in COMMITTED status")
public void testAdjustCommittedInvoice() throws Exception {
// Verify the initial invoice balance
final BigDecimal invoiceBalance = invoiceUserApi.getInvoice(invoiceId, callContext).getBalance();
Assert.assertEquals(invoiceBalance.compareTo(BigDecimal.ZERO), 1);
// Verify the initial account balance
final BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
Assert.assertEquals(accountBalance, invoiceBalance);
// Adjust the invoice for the full amount
final InvoiceItem creditInvoiceItem = invoiceUserApi.insertCreditForInvoice(accountId, invoiceId, invoiceBalance, clock.getUTCToday(), accountCurrency, "some description", callContext);
Assert.assertEquals(creditInvoiceItem.getInvoiceId(), invoiceId);
Assert.assertEquals(creditInvoiceItem.getInvoiceItemType(), InvoiceItemType.CREDIT_ADJ);
Assert.assertEquals(creditInvoiceItem.getAccountId(), accountId);
Assert.assertEquals(creditInvoiceItem.getAmount().compareTo(invoiceBalance.negate()), 0);
Assert.assertEquals(creditInvoiceItem.getCurrency(), accountCurrency);
Assert.assertEquals(creditInvoiceItem.getDescription(), "some description");
Assert.assertNull(creditInvoiceItem.getLinkedItemId());
// Verify the adjusted invoice balance
final BigDecimal adjustedInvoiceBalance = invoiceUserApi.getInvoice(invoiceId, callContext).getBalance();
Assert.assertEquals(adjustedInvoiceBalance.compareTo(BigDecimal.ZERO), 0);
// Verify the adjusted account balance
final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId, callContext);
Assert.assertEquals(adjustedAccountBalance, adjustedInvoiceBalance);
}
Aggregations