Search in sources :

Example 1 with ExternalChargeInvoiceItem

use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem 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);
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) UUID(java.util.UUID) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 2 with ExternalChargeInvoiceItem

use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.

the class TestIntegrationInvoice method testExternalChargeInTheFuture.

@Test(groups = "slow")
public void testExternalChargeInTheFuture() throws Exception {
    final int billingDay = 1;
    final DateTime initialCreationDate = new DateTime(2019, 1, 1, 0, 0, 0, 0, testTimeZone);
    // set clock to the initial start date
    clock.setTime(initialCreationDate);
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
    // Create external charge with an effective date a year from now
    final LocalDate chargeEffectiveDate = clock.getToday(account.getTimeZone()).plusYears(1);
    final List<InvoiceItem> invoiceItemList = new ArrayList<InvoiceItem>();
    ExternalChargeInvoiceItem item = new ExternalChargeInvoiceItem(null, account.getId(), null, "", chargeEffectiveDate, chargeEffectiveDate, BigDecimal.TEN, account.getCurrency(), null);
    invoiceItemList.add(item);
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    final List<InvoiceItem> chargeItems = invoiceUserApi.insertExternalCharges(account.getId(), chargeEffectiveDate, invoiceItemList, true, null, callContext);
    assertListenerStatus();
    final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
    expectedInvoices.add(new ExpectedInvoiceItemCheck(chargeEffectiveDate, chargeEffectiveDate, InvoiceItemType.EXTERNAL_CHARGE, BigDecimal.TEN));
    List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    invoiceChecker.checkInvoice(invoices.get(0).getId(), callContext, expectedInvoices);
    expectedInvoices.clear();
    DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    DefaultSubscriptionBase subscription = subscriptionDataFromSubscription(baseEntitlement.getSubscriptionBase());
    expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2019, 1, 1), new LocalDate(2019, 2, 1), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addDays(30);
    assertListenerStatus();
}
Also used : Account(org.killbill.billing.account.api.Account) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) Invoice(org.killbill.billing.invoice.api.Invoice) ArrayList(java.util.ArrayList) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) LocalDate(org.joda.time.LocalDate) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) Test(org.testng.annotations.Test)

Example 3 with ExternalChargeInvoiceItem

use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.

the class DefaultInvoiceUserApi method insertItems.

private List<InvoiceItem> insertItems(final UUID accountId, final LocalDate effectiveDate, final InvoiceItemType itemType, final Iterable<InvoiceItem> inputItems, final boolean autoCommit, final LinkedList<PluginProperty> properties, final CallContext context) throws InvoiceApiException {
    final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, context);
    ImmutableAccountData accountData;
    try {
        accountData = accountUserApi.getImmutableAccountDataById(accountId, internalTenantContext);
    } catch (AccountApiException e) {
        throw new InvoiceApiException(e);
    }
    final Currency accountCurrency = accountData.getCurrency();
    final WithAccountLock withAccountLock = new WithAccountLock() {

        @Override
        public Iterable<DefaultInvoice> prepareInvoices() throws InvoiceApiException {
            final LocalDate invoiceDate = internalTenantContext.toLocalDate(context.getCreatedDate());
            final Map<UUID, DefaultInvoice> newAndExistingInvoices = new HashMap<UUID, DefaultInvoice>();
            UUID newInvoiceId = null;
            for (final InvoiceItem inputItem : inputItems) {
                if (inputItem.getAmount() == null || inputItem.getAmount().compareTo(BigDecimal.ZERO) < 0) {
                    if (itemType == InvoiceItemType.EXTERNAL_CHARGE) {
                        throw new InvoiceApiException(ErrorCode.EXTERNAL_CHARGE_AMOUNT_INVALID, inputItem.getAmount());
                    } else if (itemType == InvoiceItemType.CREDIT_ADJ) {
                        throw new InvoiceApiException(ErrorCode.CREDIT_AMOUNT_INVALID, inputItem.getAmount());
                    }
                }
                if (inputItem.getCurrency() != null && !inputItem.getCurrency().equals(accountCurrency)) {
                    throw new InvoiceApiException(ErrorCode.CURRENCY_INVALID, inputItem.getCurrency(), accountCurrency);
                }
                final UUID invoiceIdForItem = inputItem.getInvoiceId();
                final Invoice curInvoiceForItem;
                if (invoiceIdForItem == null) {
                    final Currency currency = inputItem.getCurrency();
                    final InvoiceStatus status = autoCommit ? InvoiceStatus.COMMITTED : InvoiceStatus.DRAFT;
                    if (newInvoiceId == null) {
                        final DefaultInvoice newInvoiceForItems = new DefaultInvoice(accountId, invoiceDate, effectiveDate, currency, status);
                        newInvoiceId = newInvoiceForItems.getId();
                        newAndExistingInvoices.put(newInvoiceId, newInvoiceForItems);
                    }
                    curInvoiceForItem = newAndExistingInvoices.get(newInvoiceId);
                } else {
                    if (newAndExistingInvoices.get(invoiceIdForItem) == null) {
                        final DefaultInvoice existingInvoiceForExternalCharge = getInvoiceInternal(invoiceIdForItem, context);
                        switch(existingInvoiceForExternalCharge.getStatus()) {
                            case COMMITTED:
                                throw new InvoiceApiException(ErrorCode.INVOICE_ALREADY_COMMITTED, existingInvoiceForExternalCharge.getId());
                            case VOID:
                                // TODO Add missing error https://github.com/killbill/killbill/issues/1501
                                throw new IllegalStateException(String.format("Cannot add credit or external charge for invoice id %s because it is in \" + InvoiceStatus.VOID + \" status\"", existingInvoiceForExternalCharge.getId()));
                            case DRAFT:
                            default:
                                break;
                        }
                        newAndExistingInvoices.put(invoiceIdForItem, existingInvoiceForExternalCharge);
                    }
                    curInvoiceForItem = newAndExistingInvoices.get(invoiceIdForItem);
                }
                final InvoiceItem newInvoiceItem;
                switch(itemType) {
                    case EXTERNAL_CHARGE:
                        newInvoiceItem = new ExternalChargeInvoiceItem(UUIDs.randomUUID(), context.getCreatedDate(), curInvoiceForItem.getId(), accountId, inputItem.getBundleId(), inputItem.getSubscriptionId(), inputItem.getProductName(), inputItem.getPlanName(), inputItem.getPhaseName(), inputItem.getPrettyProductName(), inputItem.getPrettyPlanName(), inputItem.getPrettyPhaseName(), inputItem.getDescription(), MoreObjects.firstNonNull(inputItem.getStartDate(), effectiveDate), inputItem.getEndDate(), inputItem.getAmount(), inputItem.getRate(), accountCurrency, inputItem.getLinkedItemId(), inputItem.getQuantity(), inputItem.getItemDetails());
                        break;
                    case CREDIT_ADJ:
                        newInvoiceItem = new CreditAdjInvoiceItem(UUIDs.randomUUID(), context.getCreatedDate(), curInvoiceForItem.getId(), accountId, effectiveDate, inputItem.getDescription(), // Note! The amount is negated here!
                        inputItem.getAmount().negate(), inputItem.getRate(), inputItem.getCurrency(), inputItem.getQuantity(), inputItem.getItemDetails());
                        break;
                    case TAX:
                        newInvoiceItem = new TaxInvoiceItem(UUIDs.randomUUID(), curInvoiceForItem.getId(), accountId, inputItem.getBundleId(), inputItem.getDescription(), MoreObjects.firstNonNull(inputItem.getStartDate(), effectiveDate), inputItem.getAmount(), accountCurrency);
                        break;
                    default:
                        throw new IllegalStateException(String.format("Unsupported to add item of type '%s'", itemType));
                }
                curInvoiceForItem.addInvoiceItem(newInvoiceItem);
            }
            return newAndExistingInvoices.values();
        }
    };
    return invoiceApiHelper.dispatchToInvoicePluginsAndInsertItems(accountId, false, withAccountLock, properties, context);
}
Also used : ImmutableAccountData(org.killbill.billing.account.api.ImmutableAccountData) TaxInvoiceItem(org.killbill.billing.invoice.model.TaxInvoiceItem) TaxInvoiceItem(org.killbill.billing.invoice.model.TaxInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) Invoice(org.killbill.billing.invoice.api.Invoice) HtmlInvoice(org.killbill.billing.invoice.template.HtmlInvoice) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) HashMap(java.util.HashMap) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) WithAccountLock(org.killbill.billing.invoice.api.WithAccountLock) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) LocalDate(org.joda.time.LocalDate) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) Currency(org.killbill.billing.catalog.api.Currency) AccountApiException(org.killbill.billing.account.api.AccountApiException) UUID(java.util.UUID) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) InvoiceStatus(org.killbill.billing.invoice.api.InvoiceStatus)

Example 4 with ExternalChargeInvoiceItem

use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.

the class TestWithInvoicePlugin method testBasicAdditionalExternalChargeItem.

@Test(groups = "slow")
public void testBasicAdditionalExternalChargeItem() throws Exception {
    // We take april as it has 30 days (easier to play with BCD)
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDay(new LocalDate(2012, 4, 1));
    final AccountData accountData = getAccountData(1);
    final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
    accountChecker.checkAccount(account.getId(), accountData, callContext);
    final UUID pluginInvoiceItemId = UUID.randomUUID();
    final UUID pluginLinkedItemId = UUID.randomUUID();
    testInvoicePluginApi.additionalInvoiceItem = new ExternalChargeInvoiceItem(pluginInvoiceItemId, clock.getUTCNow(), null, account.getId(), null, null, null, null, null, null, null, null, "My charge", clock.getUTCToday(), null, BigDecimal.TEN, null, Currency.USD, pluginLinkedItemId, null);
    Assert.assertEquals(testInvoicePluginApi.invocationCount, 0);
    // Create original subscription (Trial PHASE) -> $0 invoice but plugin added one item
    final DefaultEntitlement bpSubscription = createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
    invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")), new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.EXTERNAL_CHARGE, BigDecimal.TEN));
    subscriptionChecker.checkSubscriptionCreated(bpSubscription.getId(), internalCallContext);
    Assert.assertEquals(testInvoicePluginApi.invocationCount, 1);
    final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 1);
    final List<InvoiceItem> invoiceItems = invoices.get(0).getInvoiceItems();
    final InvoiceItem externalCharge = Iterables.tryFind(invoiceItems, new Predicate<InvoiceItem>() {

        @Override
        public boolean apply(final InvoiceItem input) {
            return input.getInvoiceItemType() == InvoiceItemType.EXTERNAL_CHARGE;
        }
    }).orNull();
    assertNotNull(externalCharge);
    // verify the ID is the one passed by the plugin #818
    assertEquals(externalCharge.getId(), pluginInvoiceItemId);
    // verify the ID is the one passed by the plugin #887
    assertEquals(externalCharge.getLinkedItemId(), pluginLinkedItemId);
    // On next invoice we will update the amount and the description of the previously inserted EXTERNAL_CHARGE item
    testInvoicePluginApi.additionalInvoiceItem = new ExternalChargeInvoiceItem(pluginInvoiceItemId, clock.getUTCNow(), invoices.get(0).getId(), account.getId(), null, null, null, null, null, null, null, null, "Update Description", clock.getUTCToday(), null, BigDecimal.ONE, null, Currency.USD, pluginLinkedItemId, null);
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
    clock.addDays(30);
    assertListenerStatus();
    invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), new LocalDate(2012, 6, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
    final List<Invoice> invoices2 = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    final List<InvoiceItem> invoiceItems2 = invoices2.get(0).getInvoiceItems();
    final InvoiceItem externalCharge2 = Iterables.tryFind(invoiceItems2, new Predicate<InvoiceItem>() {

        @Override
        public boolean apply(final InvoiceItem input) {
            return input.getInvoiceItemType() == InvoiceItemType.EXTERNAL_CHARGE;
        }
    }).orNull();
    assertNotNull(externalCharge2);
    assertEquals(externalCharge2.getAmount().compareTo(BigDecimal.ONE), 0);
}
Also used : Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) TaxInvoiceItem(org.killbill.billing.invoice.model.TaxInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) LocalDate(org.joda.time.LocalDate) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) BigDecimal(java.math.BigDecimal) Predicate(com.google.common.base.Predicate) AccountData(org.killbill.billing.account.api.AccountData) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Example 5 with ExternalChargeInvoiceItem

use of org.killbill.billing.invoice.model.ExternalChargeInvoiceItem in project killbill by killbill.

the class TestOverdueIntegration method testShouldNotBeInOverdueAfterDraftExternalCharge.

@Test(groups = "slow", description = "Test overdue for draft external charge", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testShouldNotBeInOverdueAfterDraftExternalCharge() throws Exception {
    // 2012-05-01T00:03:42.000Z
    clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
    setupAccount();
    // Create a subscription without failing payments
    final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
    bundle = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
    invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
    invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
    // 2012-05-06 => Create an external charge on a new invoice
    addDaysAndCheckForCompletion(5);
    final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(null, account.getId(), bundle.getId(), "For overdue", new LocalDate(2012, 5, 6), new LocalDate(2012, 6, 6), BigDecimal.TEN, Currency.USD, null);
    invoiceUserApi.insertExternalCharges(account.getId(), clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), false, null, callContext).get(0);
    assertListenerStatus();
    invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 6), new LocalDate(2012, 6, 6), InvoiceItemType.EXTERNAL_CHARGE, BigDecimal.TEN));
    // 2012-05-31 => DAY 30 have to get out of trial before first payment
    addDaysAndCheckForCompletion(25, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
    invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
    // Should still be in clear state - the invoice for the bundle has been paid, but not the invoice with the external charge (because it is in draft mode)
    // We refresh overdue just to be safe, see below
    checkODState(OverdueWrapper.CLEAR_STATE_NAME);
    // 2012-06-06 => Past 30 days since the external charge
    addDaysAndCheckForCompletion(6);
    // We should still be clear
    checkODState(OverdueWrapper.CLEAR_STATE_NAME);
    Assert.assertEquals(invoiceUserApi.getUnpaidInvoicesByAccountId(account.getId(), null, clock.getUTCToday(), callContext).size(), 0);
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Aggregations

ExternalChargeInvoiceItem (org.killbill.billing.invoice.model.ExternalChargeInvoiceItem)31 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)27 Test (org.testng.annotations.Test)26 BigDecimal (java.math.BigDecimal)24 UUID (java.util.UUID)24 Invoice (org.killbill.billing.invoice.api.Invoice)19 CreditAdjInvoiceItem (org.killbill.billing.invoice.model.CreditAdjInvoiceItem)19 TaxInvoiceItem (org.killbill.billing.invoice.model.TaxInvoiceItem)16 Account (org.killbill.billing.account.api.Account)15 LocalDate (org.joda.time.LocalDate)12 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)7 DefaultEntitlement (org.killbill.billing.entitlement.api.DefaultEntitlement)6 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)6 DateTime (org.joda.time.DateTime)5 ExpectedInvoiceItemCheck (org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck)5 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)4 HashMap (java.util.HashMap)3 AccountData (org.killbill.billing.account.api.AccountData)3 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)3 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)3