@Override public UUID getInvoiceId() { return item.getInvoiceId(); }
@Nullable @Override public UUID apply(@Nullable final InvoiceItem input) { return input.getInvoiceId(); } }));
@GET @Path("/{creditId:" + UUID_PATTERN + "}") @Produces(APPLICATION_JSON) @ApiOperation(value = "Retrieve a credit by id", response = CreditJson.class) @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid credit id supplied"), @ApiResponse(code = 404, message = "Credit not found")}) public Response getCredit(@PathParam("creditId") final UUID creditId, @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, AccountApiException { final TenantContext tenantContext = context.createTenantContextNoAccountId(request); final InvoiceItem credit = invoiceUserApi.getCreditById(creditId, tenantContext); final Invoice invoice = invoiceUserApi.getInvoice(credit.getInvoiceId(), tenantContext); final CreditJson creditJson = new CreditJson(invoice, credit); return Response.status(Response.Status.OK).entity(creditJson).build(); }
public static boolean isInvoiceAdjustmentItem(final InvoiceItem invoiceItem, final Iterable<InvoiceItem> otherInvoiceItems) { // Invoice level credit, i.e. credit adj, but NOT on its on own invoice return (InvoiceItemType.CREDIT_ADJ.equals(invoiceItem.getInvoiceItemType()) && !(Iterables.size(otherInvoiceItems) == 1 && InvoiceItemType.CBA_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) && otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) && otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0)); }
private static BigDecimal computeInvoiceAmountAdjustedForAccountCredit(final Currency currency, final Iterable<InvoiceItem> invoiceItems) { BigDecimal amountAdjusted = BigDecimal.ZERO; if (invoiceItems == null || !invoiceItems.iterator().hasNext()) { return KillBillMoney.of(amountAdjusted, currency); } for (final InvoiceItem invoiceItem : invoiceItems) { final Iterable<InvoiceItem> otherInvoiceItems = Iterables.filter(invoiceItems, new Predicate<InvoiceItem>() { @Override public boolean apply(final InvoiceItem input) { return !input.getId().equals(invoiceItem.getId()); } }); if (InvoiceItemType.CREDIT_ADJ.equals(invoiceItem.getInvoiceItemType()) && (Iterables.size(otherInvoiceItems) == 1 && InvoiceItemType.CBA_ADJ.equals(otherInvoiceItems.iterator().next().getInvoiceItemType()) && otherInvoiceItems.iterator().next().getInvoiceId().equals(invoiceItem.getInvoiceId()) && otherInvoiceItems.iterator().next().getAmount().compareTo(invoiceItem.getAmount().negate()) == 0)) { amountAdjusted = amountAdjusted.add(invoiceItem.getAmount()); } } return KillBillMoney.of(amountAdjusted, currency); }
public ItemAdjInvoiceItem(final InvoiceItem linkedInvoiceItem, final LocalDate effectiveDate, final BigDecimal amount, final Currency currency) { this(UUIDs.randomUUID(), null, linkedInvoiceItem.getInvoiceId(), linkedInvoiceItem.getAccountId(), effectiveDate, linkedInvoiceItem.getDescription(), amount, currency, linkedInvoiceItem.getId(), null); }
private void verifyExternalChargeOnNewInvoice(final BigDecimal initialAccountBalance, @Nullable final UUID bundleId, final BigDecimal externalChargeAmount, final InvoiceItem externalChargeInvoiceItem) throws InvoiceApiException { Assert.assertNotNull(externalChargeInvoiceItem.getInvoiceId()); Assert.assertNotEquals(externalChargeInvoiceItem.getInvoiceId(), invoiceId); Assert.assertEquals(externalChargeInvoiceItem.getBundleId(), bundleId); Assert.assertEquals(externalChargeInvoiceItem.getInvoiceItemType(), InvoiceItemType.EXTERNAL_CHARGE); Assert.assertEquals(externalChargeInvoiceItem.getAccountId(), accountId); Assert.assertEquals(externalChargeInvoiceItem.getAmount().compareTo(externalChargeAmount), 0); Assert.assertEquals(externalChargeInvoiceItem.getCurrency(), accountCurrency); Assert.assertNull(externalChargeInvoiceItem.getLinkedItemId()); // Verify the adjusted invoice balance final BigDecimal adjustedInvoiceBalance = invoiceUserApi.getInvoice(externalChargeInvoiceItem.getInvoiceId(), callContext).getBalance(); Assert.assertEquals(adjustedInvoiceBalance.compareTo(externalChargeAmount), 0); // Verify the adjusted account balance final BigDecimal adjustedAccountBalance = invoiceUserApi.getAccountBalance(accountId, callContext); Assert.assertEquals(adjustedAccountBalance, initialAccountBalance.add(externalChargeAmount)); }
private void distributeItems(final List<Invoice> invoices) { final Map<UUID, Invoice> invoiceMap = new HashMap<UUID, Invoice>(); for (final Invoice invoice : invoices) { invoiceMap.put(invoice.getId(), invoice); } for (final Invoice invoice : invoices) { final Iterator<InvoiceItem> itemIterator = invoice.getInvoiceItems().iterator(); final UUID invoiceId = invoice.getId(); while (itemIterator.hasNext()) { final InvoiceItem item = itemIterator.next(); if (!item.getInvoiceId().equals(invoiceId)) { final Invoice thisInvoice = invoiceMap.get(item.getInvoiceId()); if (thisInvoice == null) { throw new NullPointerException(); } thisInvoice.addInvoiceItem(item); itemIterator.remove(); } } } }
@Test(groups = "slow") public void testOriginalAmountCharged() throws Exception { // Post an external charge final BigDecimal externalChargeAmount = BigDecimal.TEN; final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, accountId, null, UUID.randomUUID().toString(), clock.getUTCToday(), null, externalChargeAmount, accountCurrency, null); final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, null, callContext).get(0); final Invoice newInvoice = invoiceUserApi.getInvoice(externalChargeInvoiceItem.getInvoiceId(), callContext); final BigDecimal newAmountCharged = newInvoice.getChargedAmount(); Assert.assertEquals(newInvoice.getOriginalChargedAmount().compareTo(externalChargeAmount), 0); Assert.assertEquals(newAmountCharged.compareTo(externalChargeAmount), 0); }
public static InvoiceItem buildInvoiceItem(final Invoice invoice, final InvoiceItemType invoiceItemType, final BigDecimal amount, @Nullable final UUID linkedItemID) { final InvoiceItem invoiceItem = Mockito.mock(InvoiceItem.class); Mockito.when(invoiceItem.getId()).thenReturn(UUID.randomUUID()); Mockito.when(invoiceItem.getInvoiceItemType()).thenReturn(invoiceItemType); // To work-around org.mockito.exceptions.misusing.UnfinishedStubbingException final UUID accountId = invoice.getAccountId(); final UUID invoiceId = invoice.getId(); final Currency currency = invoice.getCurrency(); Mockito.when(invoiceItem.getAccountId()).thenReturn(accountId); Mockito.when(invoiceItem.getInvoiceId()).thenReturn(invoiceId); Mockito.when(invoiceItem.getLinkedItemId()).thenReturn(linkedItemID); Mockito.when(invoiceItem.getBundleId()).thenReturn(UUID.randomUUID()); Mockito.when(invoiceItem.getSubscriptionId()).thenReturn(UUID.randomUUID()); Mockito.when(invoiceItem.getPlanName()).thenReturn(UUID.randomUUID().toString()); Mockito.when(invoiceItem.getPhaseName()).thenReturn(UUID.randomUUID().toString()); Mockito.when(invoiceItem.getUsageName()).thenReturn(UUID.randomUUID().toString()); Mockito.when(invoiceItem.getAmount()).thenReturn(amount); Mockito.when(invoiceItem.getCurrency()).thenReturn(currency); return invoiceItem; }
public CreditJson(final Invoice invoice, final InvoiceItem credit, final List<AuditLog> auditLogs) { super(toAuditLogJson(auditLogs)); this.creditId = credit.getId(); this.accountId = credit.getAccountId(); this.creditAmount = credit.getAmount(); this.currency = credit.getCurrency(); this.invoiceId = credit.getInvoiceId(); this.invoiceNumber = invoice.getInvoiceNumber().toString(); this.effectiveDate = credit.getStartDate(); this.description = credit.getDescription(); this.itemDetails = credit.getItemDetails(); }
@Test(groups = "slow", description = "Verify invoice/account balance with a WRITTEN_OFF invoice. Verify behavior when WRITTEN_OFF tag is added after credit was added to invoice" ) public void testWrittenOffInvoiceWithAccountCredit() throws Exception { // Add credit on the account invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, null, null, callContext); 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); // 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("13.5"), accountCurrency, null)), true, null, callContext); assertEquals(items.size(), 1); final BigDecimal accountBalance1 = invoiceUserApi.getAccountBalance(accountId, callContext); assertEquals(accountBalance1.compareTo(new BigDecimal("3.5")), 0); final BigDecimal accountCBA1 = invoiceUserApi.getAccountCBA(accountId, callContext); assertEquals(accountCBA1.compareTo(BigDecimal.ZERO), 0); // Tag invoice with WRITTEN_OFF and expect balance to now show as Zero tagUserApi.addTag(items.get(0).getInvoiceId(), ObjectType.INVOICE, ControlTagType.WRITTEN_OFF.getId(), callContext); final BigDecimal accountBalance2 = invoiceUserApi.getAccountBalance(accountId, callContext); assertEquals(accountBalance2.compareTo(BigDecimal.ZERO), 0); final BigDecimal accountCBA2 = invoiceUserApi.getAccountCBA(accountId, callContext); assertEquals(accountCBA2.compareTo(BigDecimal.ZERO), 0); }
@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 invoiceUserApi.insertCredit(accountId, BigDecimal.TEN, null, accountCurrency, true, null, null, 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); }
@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", null, null, 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); }
@Test(groups = "fast") public void testBuildTaxItem() throws Exception { // Overrides Assert.assertEquals(invoice1TaxItem.getInvoiceItemType(), InvoiceItemType.TAX); Assert.assertEquals(invoice1TaxItem.getStartDate(), invoice1TaxableItem.getStartDate()); Assert.assertNull(invoice1TaxItem.getEndDate()); Assert.assertEquals(invoice1TaxItem.getAmount().compareTo(BigDecimal.ONE), 0); Assert.assertEquals(invoice1TaxItem.getDescription(), "TestNG tax"); Assert.assertEquals(invoice1TaxItem.getLinkedItemId(), invoice1TaxableItem.getId()); Assert.assertNull(invoice1TaxItem.getRate()); // Copies Assert.assertEquals(invoice1TaxItem.getInvoiceId(), invoice1TaxableItem.getInvoiceId()); Assert.assertEquals(invoice1TaxItem.getAccountId(), invoice1TaxableItem.getAccountId()); Assert.assertEquals(invoice1TaxItem.getCurrency(), invoice1TaxableItem.getCurrency()); Assert.assertEquals(invoice1TaxItem.getBundleId(), invoice1TaxableItem.getBundleId()); Assert.assertEquals(invoice1TaxItem.getSubscriptionId(), invoice1TaxableItem.getSubscriptionId()); Assert.assertEquals(invoice1TaxItem.getPlanName(), invoice1TaxableItem.getPlanName()); Assert.assertEquals(invoice1TaxItem.getPhaseName(), invoice1TaxableItem.getPhaseName()); Assert.assertEquals(invoice1TaxItem.getUsageName(), invoice1TaxableItem.getUsageName()); } }
@Override public InvoiceItem getCreditById(final UUID creditId, final TenantContext context) throws InvoiceApiException { final InvoiceItem creditItem = InvoiceItemFactory.fromModelDao(dao.getCreditById(creditId, internalCallContextFactory.createInternalTenantContext(creditId, ObjectType.INVOICE_ITEM, context))); if (creditItem == null) { throw new InvoiceApiException(ErrorCode.INVOICE_NO_SUCH_CREDIT, creditId); } return new CreditAdjInvoiceItem(creditItem.getId(), creditItem.getCreatedDate(), creditItem.getInvoiceId(), creditItem.getAccountId(), creditItem.getStartDate(), creditItem.getDescription(), creditItem.getAmount().negate(), creditItem.getCurrency(), creditItem.getItemDetails()); }
public Item(final InvoiceItem item, final LocalDate startDate, final LocalDate endDate, final UUID targetInvoiceId, final ItemAction action) { this.id = item.getId(); this.accountId = item.getAccountId(); this.bundleId = item.getBundleId(); this.subscriptionId = item.getSubscriptionId(); this.targetInvoiceId = targetInvoiceId; this.invoiceId = item.getInvoiceId(); this.productName = item.getProductName(); this.planName = item.getPlanName(); this.phaseName = item.getPhaseName(); this.startDate = startDate; this.endDate = endDate; this.amount = item.getAmount().abs(); this.rate = item.getRate(); this.currency = item.getCurrency(); this.linkedId = item.getLinkedItemId(); this.createdDate = item.getCreatedDate(); this.action = action; this.currentRepairedAmount = BigDecimal.ZERO; this.adjustedAmount = BigDecimal.ZERO; }
@Override public InvoiceItem getExternalChargeById(final UUID externalChargeId, final TenantContext context) throws InvoiceApiException { final InvoiceItem externalChargeItem = InvoiceItemFactory.fromModelDao(dao.getExternalChargeById(externalChargeId, internalCallContextFactory.createInternalTenantContext(externalChargeId, ObjectType.INVOICE_ITEM, context))); if (externalChargeItem == null) { throw new InvoiceApiException(ErrorCode.INVOICE_NO_SUCH_EXTERNAL_CHARGE, externalChargeId); } return new ExternalChargeInvoiceItem(externalChargeItem.getId(), externalChargeItem.getInvoiceId(), externalChargeItem.getAccountId(), externalChargeItem.getDescription(), externalChargeItem.getStartDate(), externalChargeItem.getEndDate(), externalChargeItem.getAmount(), externalChargeItem.getCurrency(), externalChargeItem.getItemDetails()); }
public InvoiceItemJson(final InvoiceItem item, final List<InvoiceItem> childItems, @Nullable final List<AuditLog> auditLogs) { this(item.getId(), item.getInvoiceId(), item.getLinkedItemId(), item.getAccountId(), item.getChildAccountId(), item.getBundleId(), item.getSubscriptionId(), item.getProductName(), item.getPlanName(), item.getPhaseName(), item.getUsageName(), item.getPrettyProductName(), item.getPrettyPlanName(), item.getPrettyPhaseName(), item.getPrettyUsageName(), item.getInvoiceItemType(), item.getDescription(), item.getStartDate(), item.getEndDate(), item.getAmount(), item.getRate(), item.getCurrency(), item.getQuantity(), item.getItemDetails(), toInvoiceItemJson(childItems), toAuditLogJson(auditLogs)); }
public InvoiceItemModelDao(final InvoiceItem invoiceItem) { this(invoiceItem.getId(), invoiceItem.getCreatedDate(), invoiceItem.getInvoiceItemType(), invoiceItem.getInvoiceId(), invoiceItem.getAccountId(), invoiceItem.getChildAccountId(), invoiceItem.getBundleId(), invoiceItem.getSubscriptionId(), invoiceItem.getDescription(), invoiceItem.getProductName(), invoiceItem.getPlanName(), invoiceItem.getPhaseName(), invoiceItem.getUsageName(), invoiceItem.getStartDate(), invoiceItem.getEndDate(), invoiceItem.getAmount(), invoiceItem.getRate(), invoiceItem.getCurrency(), invoiceItem.getLinkedItemId(), invoiceItem.getQuantity(), invoiceItem.getItemDetails()); }