use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.
the class TestDefaultInvoiceUserApi method testCreditWithoutDraftInvoice.
@Test(groups = "slow")
public void testCreditWithoutDraftInvoice() throws Exception {
final Account account = invoiceUtil.createAccount(callContext);
final UUID accountId = account.getId();
// Create an external charge invoice
final BigDecimal externalChargeAmount = new BigDecimal(300);
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, accountId, null, UUID.randomUUID().toString(), clock.getUTCToday(), null, externalChargeAmount, accountCurrency, null);
InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, null, callContext).get(0);
final Invoice externalChargeInvoice = invoiceUserApi.getInvoice(externalChargeInvoiceItem.getInvoiceId(), callContext);
Assert.assertEquals(externalChargeInvoice.getBalance().compareTo(externalChargeAmount), 0);
Assert.assertEquals(externalChargeInvoice.getChargedAmount().compareTo(externalChargeAmount), 0);
// Create a credit invoice
final InvoiceItem creditItem = new CreditAdjInvoiceItem(null, accountId, clock.getUTCToday(), "something", new BigDecimal("200.00"), accountCurrency, null);
final InvoiceItem creditInvoiceItem = invoiceUserApi.insertCredits(accountId, clock.getUTCToday(), ImmutableList.of(creditItem), true, null, callContext).get(0);
final Invoice creditInvoice = invoiceUserApi.getInvoice(creditInvoiceItem.getInvoiceId(), callContext);
Assert.assertEquals(creditInvoice.getBalance().compareTo(new BigDecimal(0)), 0);
Assert.assertEquals(creditInvoice.getChargedAmount().compareTo(new BigDecimal(0)), 0);
// Verify that invoice balance reflects the credit
final Invoice updatedExternalChargeInvoice = invoiceUserApi.getInvoice(externalChargeInvoiceItem.getInvoiceId(), callContext);
Assert.assertEquals(updatedExternalChargeInvoice.getBalance().compareTo(new BigDecimal(100)), 0);
// Verify that amountCharged DOES NOT reflect the credit since invoice is NOT in DRAFT status
Assert.assertEquals(updatedExternalChargeInvoice.getChargedAmount().compareTo(new BigDecimal(300)), 0);
}
use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.
the class TestInvoiceFlagBehaviors method testDraftInvoiceWithAccountCredit.
@Test(groups = "slow", description = "Verify invoice/account balance with DRAFT invoice. Verify that invoice/account balance are ZERO in DRAFT mode but becomes visible after it hasa been COMMITTED.")
public void testDraftInvoiceWithAccountCredit() throws Exception {
// Add credit on the account
final InvoiceItem inputCredit = new CreditAdjInvoiceItem(null, accountId, clock.getUTCToday(), "some description", BigDecimal.TEN, accountCurrency, null);
invoiceUserApi.insertCredits(accountId, clock.getUTCToday(), ImmutableList.of(inputCredit), true, null, callContext);
// Create new invoice with one charge and expect account credit to be used
final List<InvoiceItem> items = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(new ExternalChargeInvoiceItem(UUID.randomUUID(), clock.getUTCNow(), null, accountId, null, null, null, null, new BigDecimal("4.0"), accountCurrency, null)), false, null, callContext);
assertEquals(items.size(), 1);
final UUID invoiceId = items.get(0).getInvoiceId();
final Invoice invoice1 = invoiceUserApi.getInvoice(invoiceId, callContext);
assertEquals(invoice1.getStatus(), InvoiceStatus.DRAFT);
// Verify CBA was *NOT* applied against DRAFT invoice
assertEquals(invoice1.getInvoiceItems().size(), 1);
// And balance is ZERO because DRAFT mode
assertEquals(invoice1.getBalance().compareTo(BigDecimal.ZERO), 0);
// Verify credit is not applied against migration invoice
final BigDecimal accountBalance0 = invoiceUserApi.getAccountBalance(accountId, callContext);
assertEquals(accountBalance0.compareTo(new BigDecimal("-10.0")), 0);
final BigDecimal accountCBA0 = invoiceUserApi.getAccountCBA(accountId, callContext);
assertEquals(accountCBA0.compareTo(BigDecimal.TEN), 0);
invoiceUserApi.commitInvoice(invoiceId, callContext);
final Invoice invoice2 = invoiceUserApi.getInvoice(invoiceId, callContext);
assertEquals(invoice2.getStatus(), InvoiceStatus.COMMITTED);
// Verify this time credit was applied against COMMITTED invoice
assertEquals(invoice2.getBalance().compareTo(BigDecimal.ZERO), 0);
final BigDecimal accountBalance1 = invoiceUserApi.getAccountBalance(accountId, callContext);
assertEquals(accountBalance1.compareTo(new BigDecimal("-6.0")), 0);
final BigDecimal accountCBA1 = invoiceUserApi.getAccountCBA(accountId, callContext);
assertEquals(accountCBA1.compareTo(new BigDecimal("6.0")), 0);
}
use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.
the class TestIntegrationWithAutoInvoiceDraft method testAutoInvoicingReuseDraftBasic.
@Test(groups = "slow")
public void testAutoInvoicingReuseDraftBasic() throws Exception {
clock.setTime(new DateTime(2017, 6, 16, 18, 24, 42, 0));
// Set both AUTO_INVOICING_DRAFT and AUTO_INVOICING_REUSE_DRAFT
add_AUTO_INVOICING_DRAFT_Tag(account.getId(), ObjectType.ACCOUNT);
add_AUTO_INVOICING_REUSE_DRAFT_Tag(account.getId(), ObjectType.ACCOUNT);
// Create initial DRAFt invoice that will be reused by the system
final LocalDate startDate = clock.getUTCToday();
final LocalDate endDate = startDate.plusDays(5);
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, account.getId(), null, "Initial external charge", startDate, endDate, BigDecimal.TEN, Currency.USD, null);
invoiceUserApi.insertExternalCharges(account.getId(), clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), false, null, callContext).get(0);
List<Invoice> invoices;
invoices = invoiceApi.getInvoicesByAccount(account.getId(), false, false, callContext);
assertEquals(invoices.size(), 1);
assertEquals(invoices.get(0).getInvoiceItems().size(), 1);
assertEquals(invoices.get(0).getStatus(), InvoiceStatus.DRAFT);
final UUID invoiceId = invoices.get(0).getId();
final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK);
assertNotNull(bpEntitlement);
// Verify we see the new item on our existing DRAFT invoice
invoices = invoiceApi.getInvoicesByAccount(account.getId(), false, false, callContext);
assertEquals(invoices.size(), 1);
assertEquals(invoices.get(0).getId(), invoiceId);
assertEquals(invoices.get(0).getInvoiceItems().size(), 2);
assertEquals(invoices.get(0).getStatus(), InvoiceStatus.DRAFT);
// Move out of TRIAL
busHandler.pushExpectedEvents(NextEvent.PHASE);
clock.addDays(30);
assertListenerStatus();
// Verify again we see the new item on our existing DRAFT invoice
invoices = invoiceApi.getInvoicesByAccount(account.getId(), false, false, callContext);
assertEquals(invoices.size(), 1);
assertEquals(invoices.get(0).getId(), invoiceId);
assertEquals(invoices.get(0).getInvoiceItems().size(), 3);
assertEquals(invoices.get(0).getStatus(), InvoiceStatus.DRAFT);
// Remove AUTO_INVOICING_DRAFT, so next invoicing should commit DRAFt invoice
remove_AUTO_INVOICING_DRAFT_Tag(account.getId(), ObjectType.ACCOUNT);
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addMonths(1);
assertListenerStatus();
// Verify again we see the new item and this time invoice is in COMMITTED
invoices = invoiceApi.getInvoicesByAccount(account.getId(), false, false, callContext);
assertEquals(invoices.size(), 1);
assertEquals(invoices.get(0).getId(), invoiceId);
assertEquals(invoices.get(0).getInvoiceItems().size(), 4);
assertEquals(invoices.get(0).getStatus(), InvoiceStatus.COMMITTED);
// Verify we see a new invoice
busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
clock.addMonths(1);
assertListenerStatus();
invoices = invoiceApi.getInvoicesByAccount(account.getId(), false, false, callContext);
assertEquals(invoices.size(), 2);
assertEquals(invoices.get(1).getInvoiceItems().size(), 1);
assertEquals(invoices.get(1).getStatus(), InvoiceStatus.COMMITTED);
}
use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.
the class TestInvoicePayment method testPartialRefundsOnPartialPayments.
@Test(groups = "slow")
public void testPartialRefundsOnPartialPayments() throws Exception {
final AccountData accountData = getAccountData(1);
final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
add_AUTO_PAY_OFF_Tag(account.getId(), ObjectType.ACCOUNT);
clock.setDay(new LocalDate(2012, 4, 1));
busHandler.pushExpectedEvents(NextEvent.INVOICE);
final LocalDate startDate = clock.getUTCToday();
final LocalDate endDate = startDate.plusDays(5);
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, account.getId(), null, "Initial external charge", startDate, endDate, BigDecimal.TEN, Currency.USD, null);
final InvoiceItem item1 = invoiceUserApi.insertExternalCharges(account.getId(), clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, null, callContext).get(0);
assertListenerStatus();
// Verify service period for external charge -- seee #151
assertEquals(item1.getStartDate().compareTo(startDate), 0);
assertEquals(item1.getEndDate().compareTo(endDate), 0);
// Trigger first partial payment ($4) on first invoice
final Invoice invoice = invoiceUserApi.getInvoice(item1.getInvoiceId(), callContext);
Payment payment1 = createPaymentAndCheckForCompletion(account, invoice, new BigDecimal("4.00"), account.getCurrency(), NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
Invoice invoice1 = invoiceUserApi.getInvoice(item1.getInvoiceId(), callContext);
assertTrue(invoice1.getBalance().compareTo(new BigDecimal("6.00")) == 0);
assertTrue(invoice1.getPaidAmount().compareTo(new BigDecimal("4.00")) == 0);
assertTrue(invoice1.getChargedAmount().compareTo(BigDecimal.TEN) == 0);
BigDecimal accountBalance = invoiceUserApi.getAccountBalance(account.getId(), callContext);
assertTrue(accountBalance.compareTo(new BigDecimal("6.00")) == 0);
// Trigger second partial payment ($6) on first invoice
Payment payment2 = createPaymentAndCheckForCompletion(account, invoice, new BigDecimal("6.00"), account.getCurrency(), NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
invoice1 = invoiceUserApi.getInvoice(item1.getInvoiceId(), callContext);
assertTrue(invoice1.getBalance().compareTo(BigDecimal.ZERO) == 0);
assertTrue(invoice1.getPaidAmount().compareTo(BigDecimal.TEN) == 0);
assertTrue(invoice1.getChargedAmount().compareTo(BigDecimal.TEN) == 0);
accountBalance = invoiceUserApi.getAccountBalance(account.getId(), callContext);
assertTrue(accountBalance.compareTo(BigDecimal.ZERO) == 0);
// Refund first payment with item adjustment
final Map<UUID, BigDecimal> iias = new HashMap<UUID, BigDecimal>();
iias.put(item1.getId(), new BigDecimal("4.00"));
payment1 = refundPaymentWithInvoiceItemAdjAndCheckForCompletion(account, payment1, new BigDecimal("4.00"), Currency.USD, iias, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT, NextEvent.INVOICE_ADJUSTMENT);
invoice1 = invoiceUserApi.getInvoice(item1.getInvoiceId(), callContext);
assertTrue(invoice1.getBalance().compareTo(BigDecimal.ZERO) == 0);
accountBalance = invoiceUserApi.getAccountBalance(account.getId(), callContext);
assertTrue(accountBalance.compareTo(BigDecimal.ZERO) == 0);
// Refund second payment with item adjustment
iias.put(item1.getId(), new BigDecimal("6.00"));
payment2 = refundPaymentWithInvoiceItemAdjAndCheckForCompletion(account, payment2, new BigDecimal("6.00"), Currency.USD, iias, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT, NextEvent.INVOICE_ADJUSTMENT);
invoice1 = invoiceUserApi.getInvoice(item1.getInvoiceId(), callContext);
assertTrue(invoice1.getBalance().compareTo(BigDecimal.ZERO) == 0);
accountBalance = invoiceUserApi.getAccountBalance(account.getId(), callContext);
assertTrue(accountBalance.compareTo(BigDecimal.ZERO) == 0);
Assert.assertEquals(invoice1.getPayments().size(), 4);
// Verify links for payment 1
Assert.assertEquals(invoice1.getPayments().get(0).getAmount().compareTo(new BigDecimal("4.00")), 0);
Assert.assertNull(invoice1.getPayments().get(0).getLinkedInvoicePaymentId());
Assert.assertEquals(invoice1.getPayments().get(0).getPaymentCookieId(), payment1.getTransactions().get(0).getExternalKey());
Assert.assertEquals(invoice1.getPayments().get(0).getPaymentId(), payment1.getId());
Assert.assertEquals(invoice1.getPayments().get(0).getType(), InvoicePaymentType.ATTEMPT);
Assert.assertTrue(invoice1.getPayments().get(0).isSuccess());
// Verify links for payment 2
Assert.assertEquals(invoice1.getPayments().get(1).getAmount().compareTo(new BigDecimal("6.00")), 0);
Assert.assertNull(invoice1.getPayments().get(1).getLinkedInvoicePaymentId());
Assert.assertEquals(invoice1.getPayments().get(1).getPaymentCookieId(), payment2.getTransactions().get(0).getExternalKey());
Assert.assertEquals(invoice1.getPayments().get(1).getPaymentId(), payment2.getId());
Assert.assertEquals(invoice1.getPayments().get(1).getType(), InvoicePaymentType.ATTEMPT);
Assert.assertTrue(invoice1.getPayments().get(1).isSuccess());
// Verify links for refund 1
Assert.assertEquals(invoice1.getPayments().get(2).getAmount().compareTo(new BigDecimal("-4.00")), 0);
Assert.assertEquals(invoice1.getPayments().get(2).getLinkedInvoicePaymentId(), invoice1.getPayments().get(0).getId());
Assert.assertEquals(invoice1.getPayments().get(2).getPaymentCookieId(), payment1.getTransactions().get(1).getExternalKey());
Assert.assertEquals(invoice1.getPayments().get(2).getPaymentId(), payment1.getId());
Assert.assertEquals(invoice1.getPayments().get(2).getType(), InvoicePaymentType.REFUND);
Assert.assertTrue(invoice1.getPayments().get(2).isSuccess());
// Verify links for refund 2
Assert.assertEquals(invoice1.getPayments().get(3).getAmount().compareTo(new BigDecimal("-6.00")), 0);
Assert.assertEquals(invoice1.getPayments().get(3).getLinkedInvoicePaymentId(), invoice1.getPayments().get(1).getId());
Assert.assertEquals(invoice1.getPayments().get(3).getPaymentCookieId(), payment2.getTransactions().get(1).getExternalKey());
Assert.assertEquals(invoice1.getPayments().get(3).getPaymentId(), payment2.getId());
Assert.assertEquals(invoice1.getPayments().get(3).getType(), InvoicePaymentType.REFUND);
Assert.assertTrue(invoice1.getPayments().get(3).isSuccess());
}
use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.
the class DefaultInvoiceUserApi method insertExternalCharges.
@Override
public List<InvoiceItem> insertExternalCharges(final UUID accountId, final LocalDate effectiveDate, final Iterable<InvoiceItem> charges, final boolean autoCommit, final CallContext context) throws InvoiceApiException {
for (final InvoiceItem charge : charges) {
if (charge.getAmount() == null || charge.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
throw new InvoiceApiException(ErrorCode.EXTERNAL_CHARGE_AMOUNT_INVALID, charge.getAmount());
}
}
final WithAccountLock withAccountLock = new WithAccountLock() {
@Override
public Iterable<Invoice> prepareInvoices() throws InvoiceApiException {
final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, context);
final LocalDate invoiceDate = internalTenantContext.toLocalDate(context.getCreatedDate());
// Group all new external charges on the same invoice (per currency)
final Map<Currency, Invoice> newInvoicesForExternalCharges = new HashMap<Currency, Invoice>();
final Map<UUID, Invoice> existingInvoicesForExternalCharges = new HashMap<UUID, Invoice>();
for (final InvoiceItem charge : charges) {
final Invoice invoiceForExternalCharge;
final UUID invoiceIdForExternalCharge = charge.getInvoiceId();
// Create an invoice for that external charge if it doesn't exist
if (invoiceIdForExternalCharge == null) {
final Currency currency = charge.getCurrency();
if (newInvoicesForExternalCharges.get(currency) == null) {
final InvoiceStatus status = autoCommit ? InvoiceStatus.COMMITTED : InvoiceStatus.DRAFT;
final Invoice newInvoiceForExternalCharge = new DefaultInvoice(accountId, invoiceDate, effectiveDate, currency, status);
newInvoicesForExternalCharges.put(currency, newInvoiceForExternalCharge);
}
invoiceForExternalCharge = newInvoicesForExternalCharges.get(currency);
} else {
if (existingInvoicesForExternalCharges.get(invoiceIdForExternalCharge) == null) {
final Invoice existingInvoiceForExternalCharge = getInvoice(invoiceIdForExternalCharge, context);
existingInvoicesForExternalCharges.put(invoiceIdForExternalCharge, existingInvoiceForExternalCharge);
}
invoiceForExternalCharge = existingInvoicesForExternalCharges.get(invoiceIdForExternalCharge);
}
final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(UUIDs.randomUUID(), context.getCreatedDate(), invoiceForExternalCharge.getId(), accountId, charge.getBundleId(), charge.getDescription(), effectiveDate, charge.getAmount(), charge.getCurrency());
invoiceForExternalCharge.addInvoiceItem(externalCharge);
}
return Iterables.<Invoice>concat(newInvoicesForExternalCharges.values(), existingInvoicesForExternalCharges.values());
}
};
return invoiceApiHelper.dispatchToInvoicePluginsAndInsertItems(accountId, false, withAccountLock, context);
}
Aggregations