Search in sources :

Example 56 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.

the class TestBundleTransfer method testBundleTransferWithBPMonthlyOnly.

@Test(groups = "slow")
public void testBundleTransferWithBPMonthlyOnly() throws Exception {
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    final DateTime initialDate = new DateTime(2012, 4, 1, 0, 15, 42, 0, testTimeZone);
    clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
    final String productName = "Shotgun";
    final BillingPeriod term = BillingPeriod.MONTHLY;
    final String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
    //
    // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE, NextEvent.BLOCK NextEvent.INVOICE
    //
    final DefaultEntitlement bpEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    assertNotNull(bpEntitlement);
    assertListenerStatus();
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, callContext).size(), 1);
    assertEquals(bpEntitlement.getSubscriptionBase().getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.MONTHLY);
    // Move out of trials for interesting invoices adjustments
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addDays(32);
    assertListenerStatus();
    // BUNDLE TRANSFER
    final Account newAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(0));
    busHandler.pushExpectedEvents(NextEvent.TRANSFER, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    transferApi.transferBundle(account.getId(), newAccount.getId(), "externalKey", clock.getUTCNow(), false, false, callContext);
    assertListenerStatus();
    // Verify the BCD of the new account
    final Integer oldBCD = accountUserApi.getAccountById(account.getId(), callContext).getBillCycleDayLocal();
    final Integer newBCD = accountUserApi.getAccountById(newAccount.getId(), callContext).getBillCycleDayLocal();
    assertEquals(oldBCD, (Integer) 1);
    // Day of the transfer
    assertEquals(newBCD, (Integer) 3);
    final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(newAccount.getId(), false, callContext);
    assertEquals(invoices.size(), 1);
    final List<InvoiceItem> invoiceItems = invoices.get(0).getInvoiceItems();
    assertEquals(invoiceItems.size(), 1);
    final InvoiceItem theItem = invoiceItems.get(0);
    assertTrue(theItem.getStartDate().compareTo(new LocalDate(2012, 5, 3)) == 0);
    assertTrue(theItem.getEndDate().compareTo(new LocalDate(2012, 6, 3)) == 0);
    assertTrue(theItem.getAmount().compareTo(new BigDecimal("249.95")) == 0);
    checkNoMoreInvoiceToGenerate(account);
}
Also used : Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 57 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.

the class TestIntegrationParentInvoice method testParentInvoiceGeneration.

@Test(groups = "slow")
public void testParentInvoiceGeneration() throws Exception {
    final int billingDay = 14;
    final DateTime initialCreationDate = new DateTime(2015, 5, 15, 0, 0, 0, 0, testTimeZone);
    // set clock to the initial start date
    clock.setTime(initialCreationDate);
    log.info("Beginning test with BCD of " + billingDay);
    final Account parentAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
    final Account child1Account = createAccountWithNonOsgiPaymentMethod(getChildAccountData(billingDay, parentAccount.getId(), true));
    final Account child2Account = createAccountWithNonOsgiPaymentMethod(getChildAccountData(billingDay, parentAccount.getId(), true));
    // CREATE SUBSCRIPTIONS AND EXPECT BOTH EVENTS EACH: NextEvent.CREATE NextEvent.INVOICE
    createBaseEntitlementAndCheckForCompletion(child1Account.getId(), "bundleKey1", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    createBaseEntitlementAndCheckForCompletion(child2Account.getId(), "bundleKey2", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    // First Parent invoice over TRIAL period
    List<Invoice> parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
    assertEquals(parentInvoices.size(), 1);
    Invoice parentInvoice = parentInvoices.get(0);
    assertEquals(parentInvoice.getNumberOfItems(), 2);
    assertEquals(parentInvoice.getStatus(), InvoiceStatus.DRAFT);
    assertTrue(parentInvoice.isParentInvoice());
    assertEquals(parentInvoice.getBalance().compareTo(BigDecimal.ZERO), 0);
    // Moving a day the NotificationQ calls the commitInvoice. No payment is expected
    busHandler.pushExpectedEvents(NextEvent.INVOICE);
    clock.addDays(1);
    assertListenerStatus();
    // reload parent invoice
    parentInvoice = invoiceUserApi.getInvoice(parentInvoice.getId(), callContext);
    assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
    // Move through time and verify new parent Invoice. No payments are expected yet.
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE);
    clock.addDays(29);
    assertListenerStatus();
    // Second Parent invoice over Recurring period
    parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), false, callContext);
    assertEquals(parentInvoices.size(), 2);
    parentInvoice = parentInvoices.get(1);
    assertEquals(parentInvoice.getNumberOfItems(), 2);
    assertEquals(parentInvoice.getStatus(), InvoiceStatus.DRAFT);
    assertTrue(parentInvoice.isParentInvoice());
    // balance is 0 because parent invoice status is DRAFT
    assertEquals(parentInvoice.getBalance().compareTo(BigDecimal.ZERO), 0);
    // total 279.95
    assertEquals(parentInvoice.getInvoiceItems().get(0).getInvoiceItemType(), InvoiceItemType.PARENT_SUMMARY);
    assertEquals(parentInvoice.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
    assertEquals(parentInvoice.getInvoiceItems().get(1).getInvoiceItemType(), InvoiceItemType.PARENT_SUMMARY);
    assertEquals(parentInvoice.getInvoiceItems().get(1).getAmount().compareTo(BigDecimal.valueOf(29.95)), 0);
    // Check Child Balance. It should be > 0 here because Parent invoice is unpaid yet.
    List<Invoice> child1Invoices = invoiceUserApi.getInvoicesByAccount(child1Account.getId(), false, callContext);
    assertEquals(child1Invoices.size(), 2);
    // child balance is 0 because parent invoice status is DRAFT at this point
    assertEquals(child1Invoices.get(1).getBalance().compareTo(BigDecimal.ZERO), 0);
    // Moving a day the NotificationQ calls the commitInvoice. Payment is expected.
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addDays(1);
    assertListenerStatus();
    parentInvoice = invoiceUserApi.getInvoice(parentInvoice.getId(), callContext);
    assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
    // Check Child Balance. It should be = 0 because parent invoice had already paid.
    child1Invoices = invoiceUserApi.getInvoicesByAccount(child1Account.getId(), false, callContext);
    assertEquals(child1Invoices.size(), 2);
    assertTrue(parentInvoice.getBalance().compareTo(BigDecimal.ZERO) == 0);
    assertTrue(child1Invoices.get(1).getBalance().compareTo(BigDecimal.ZERO) == 0);
    // load children invoice items
    final List<InvoiceItem> childrenInvoiceItems = invoiceUserApi.getInvoiceItemsByParentInvoice(parentInvoice.getId(), callContext);
    assertEquals(childrenInvoiceItems.size(), 2);
    assertEquals(childrenInvoiceItems.get(0).getAccountId(), child1Account.getId());
    assertEquals(childrenInvoiceItems.get(0).getAmount().compareTo(BigDecimal.valueOf(249.95)), 0);
    assertEquals(childrenInvoiceItems.get(1).getAccountId(), child2Account.getId());
    assertEquals(childrenInvoiceItems.get(1).getAmount().compareTo(BigDecimal.valueOf(29.95)), 0);
    // loading children items from non parent account should return empty list
    assertEquals(invoiceUserApi.getInvoiceItemsByParentInvoice(child1Invoices.get(1).getId(), callContext).size(), 0);
}
Also used : DefaultAccount(org.killbill.billing.account.api.DefaultAccount) Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 58 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.

the class DefaultInvoiceGenerator method generateInvoice.

/*
     * adjusts target date to the maximum invoice target date, if future invoices exist
     */
@Override
public InvoiceWithMetadata generateInvoice(final ImmutableAccountData account, @Nullable final BillingEventSet events, @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate, final Currency targetCurrency, final InternalCallContext context) throws InvoiceApiException {
    if ((events == null) || (events.size() == 0) || events.isAccountAutoInvoiceOff()) {
        return new InvoiceWithMetadata(null, ImmutableMap.<UUID, SubscriptionFutureNotificationDates>of());
    }
    validateTargetDate(targetDate, context);
    final LocalDate adjustedTargetDate = adjustTargetDate(existingInvoices, targetDate);
    final LocalDate invoiceDate = context.toLocalDate(context.getCreatedDate());
    final DefaultInvoice invoice = new DefaultInvoice(account.getId(), invoiceDate, adjustedTargetDate, targetCurrency);
    final UUID invoiceId = invoice.getId();
    final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates = new HashMap<UUID, SubscriptionFutureNotificationDates>();
    final List<InvoiceItem> fixedAndRecurringItems = recurringInvoiceItemGenerator.generateItems(account, invoiceId, events, existingInvoices, adjustedTargetDate, targetCurrency, perSubscriptionFutureNotificationDates, context);
    invoice.addInvoiceItems(fixedAndRecurringItems);
    final List<InvoiceItem> usageItems = usageInvoiceItemGenerator.generateItems(account, invoiceId, events, existingInvoices, adjustedTargetDate, targetCurrency, perSubscriptionFutureNotificationDates, context);
    invoice.addInvoiceItems(usageItems);
    return new InvoiceWithMetadata(invoice.getInvoiceItems().isEmpty() ? null : invoice, perSubscriptionFutureNotificationDates);
}
Also used : SubscriptionFutureNotificationDates(org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) HashMap(java.util.HashMap) UUID(java.util.UUID) LocalDate(org.joda.time.LocalDate) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice)

Example 59 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.

the class FixedAndRecurringInvoiceItemGenerator method processRecurringBillingEvents.

private void processRecurringBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events, final LocalDate targetDate, final Currency currency, final List<InvoiceItem> proposedItems, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate, @Nullable final List<Invoice> existingInvoices, final InternalCallContext internalCallContext) throws InvoiceApiException {
    if (events.isEmpty()) {
        return;
    }
    // Pretty-print the generated invoice items from the junction events
    final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger = new InvoiceItemGeneratorLogger(invoiceId, accountId, "recurring", log);
    final Iterator<BillingEvent> eventIt = events.iterator();
    BillingEvent nextEvent = eventIt.next();
    while (eventIt.hasNext()) {
        final BillingEvent thisEvent = nextEvent;
        nextEvent = eventIt.next();
        if (!events.getSubscriptionIdsWithAutoInvoiceOff().contains(thisEvent.getSubscription().getId())) {
            // don't consider events for subscriptions that have auto_invoice_off
            final BillingEvent adjustedNextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
            final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency, invoiceItemGeneratorLogger, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
            proposedItems.addAll(newProposedItems);
        }
    }
    final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, nextEvent, null, targetDate, currency, invoiceItemGeneratorLogger, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
    proposedItems.addAll(newProposedItems);
    invoiceItemGeneratorLogger.logItems();
}
Also used : FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) BillingEvent(org.killbill.billing.junction.BillingEvent)

Example 60 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem in project killbill by killbill.

the class FixedAndRecurringInvoiceItemGenerator method updatePerSubscriptionNextNotificationDate.

private void updatePerSubscriptionNextNotificationDate(final UUID subscriptionId, final LocalDate nextBillingCycleDate, final List<InvoiceItem> newProposedItems, final BillingMode billingMode, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates) {
    LocalDate nextNotificationDate = null;
    switch(billingMode) {
        case IN_ADVANCE:
            for (final InvoiceItem item : newProposedItems) {
                if ((item.getEndDate() != null) && (item.getAmount() == null || item.getAmount().compareTo(BigDecimal.ZERO) >= 0)) {
                    if (nextNotificationDate == null) {
                        nextNotificationDate = item.getEndDate();
                    } else {
                        nextNotificationDate = nextNotificationDate.compareTo(item.getEndDate()) > 0 ? nextNotificationDate : item.getEndDate();
                    }
                }
            }
            break;
        case IN_ARREAR:
            nextNotificationDate = nextBillingCycleDate;
            break;
        default:
            throw new IllegalStateException("Unrecognized billing mode " + billingMode);
    }
    if (nextNotificationDate != null) {
        SubscriptionFutureNotificationDates subscriptionFutureNotificationDates = perSubscriptionFutureNotificationDates.get(subscriptionId);
        if (subscriptionFutureNotificationDates == null) {
            subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates(billingMode);
            perSubscriptionFutureNotificationDates.put(subscriptionId, subscriptionFutureNotificationDates);
        }
        subscriptionFutureNotificationDates.updateNextRecurringDateIfRequired(nextNotificationDate);
    }
}
Also used : SubscriptionFutureNotificationDates(org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) LocalDate(org.joda.time.LocalDate)

Aggregations

InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)168 LocalDate (org.joda.time.LocalDate)118 Test (org.testng.annotations.Test)109 BigDecimal (java.math.BigDecimal)103 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)97 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)92 ItemAdjInvoiceItem (org.killbill.billing.invoice.model.ItemAdjInvoiceItem)79 RepairAdjInvoiceItem (org.killbill.billing.invoice.model.RepairAdjInvoiceItem)76 UUID (java.util.UUID)68 Invoice (org.killbill.billing.invoice.api.Invoice)57 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)36 ExternalChargeInvoiceItem (org.killbill.billing.invoice.model.ExternalChargeInvoiceItem)32 BillingEvent (org.killbill.billing.junction.BillingEvent)27 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)25 ArrayList (java.util.ArrayList)23 DateTime (org.joda.time.DateTime)23 MockPlan (org.killbill.billing.catalog.MockPlan)23 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)23 Plan (org.killbill.billing.catalog.api.Plan)22 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)21