Search in sources :

Example 1 with InvoiceItemModelDao

use of org.killbill.billing.invoice.dao.InvoiceItemModelDao in project killbill by killbill.

the class InvoiceDispatcher method processAccountWithLockAndInputTargetDate.

private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate, final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
    try {
        final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
        final List<Invoice> invoices = billingEvents.isAccountAutoInvoiceOff() ? ImmutableList.<Invoice>of() : ImmutableList.<Invoice>copyOf(Collections2.transform(invoiceDao.getInvoicesByAccount(context), new Function<InvoiceModelDao, Invoice>() {

            @Override
            public Invoice apply(final InvoiceModelDao input) {
                return new DefaultInvoice(input);
            }
        }));
        final Currency targetCurrency = account.getCurrency();
        final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, billingEvents, invoices, targetDate, targetCurrency, context);
        final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
        // Compute future notifications
        final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, context);
        //
        if (invoice == null) {
            if (isDryRun) {
                log.info("Generated null dryRun invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
            } else {
                log.info("Generated null invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
                final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
                commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
                postEvent(event);
            }
            return null;
        }
        // Generate missing credit (> 0 for generation and < 0 for use) prior we call the plugin
        final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
        DefaultInvoice tmpInvoiceForInvoicePlugins = invoice;
        if (cbaItemPreInvoicePlugins != null) {
            tmpInvoiceForInvoicePlugins = (DefaultInvoice) tmpInvoiceForInvoicePlugins.clone();
            tmpInvoiceForInvoicePlugins.addInvoiceItem(cbaItemPreInvoicePlugins);
        }
        //
        // Ask external invoice plugins if additional items (tax, etc) shall be added to the invoice
        //
        final CallContext callContext = buildCallContext(context);
        final List<InvoiceItem> additionalInvoiceItemsFromPlugins = invoicePluginDispatcher.getAdditionalInvoiceItems(tmpInvoiceForInvoicePlugins, isDryRun, callContext);
        if (additionalInvoiceItemsFromPlugins.isEmpty()) {
            // PERF: avoid re-computing the CBA if no change was made
            if (cbaItemPreInvoicePlugins != null) {
                invoice.addInvoiceItem(cbaItemPreInvoicePlugins);
            }
        } else {
            invoice.addInvoiceItems(additionalInvoiceItemsFromPlugins);
            // Use credit after we call the plugin (https://github.com/killbill/killbill/issues/637)
            final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
            if (cbaItemPostInvoicePlugins != null) {
                invoice.addInvoiceItem(cbaItemPostInvoicePlugins);
            }
        }
        if (!isDryRun) {
            // Compute whether this is a new invoice object (or just some adjustments on an existing invoice), and extract invoiceIds for later use
            final Set<UUID> uniqueInvoiceIds = getUniqueInvoiceIds(invoice);
            final boolean isRealInvoiceWithItems = uniqueInvoiceIds.remove(invoice.getId());
            final Set<UUID> adjustedUniqueOtherInvoiceId = uniqueInvoiceIds;
            logInvoiceWithItems(account, invoice, targetDate, adjustedUniqueOtherInvoiceId, isRealInvoiceWithItems);
            // Transformation to Invoice -> InvoiceModelDao
            final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
            final List<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
            invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
            // Commit invoice on disk
            final boolean isThereAnyItemsLeft = commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, context);
            final boolean isRealInvoiceWithNonEmptyItems = isThereAnyItemsLeft ? isRealInvoiceWithItems : false;
            setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
            if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
                notifyAccountIfEnabled(account, invoice, isRealInvoiceWithNonEmptyItems, context);
            }
        }
        return invoice;
    } catch (final AccountApiException e) {
        log.error("Failed handling SubscriptionBase change.", e);
        return null;
    } catch (final SubscriptionBaseApiException e) {
        log.error("Failed handling SubscriptionBase change.", e);
        return null;
    }
}
Also used : ImmutableAccountData(org.killbill.billing.account.api.ImmutableAccountData) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Invoice(org.killbill.billing.invoice.api.Invoice) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) BusInternalEvent(org.killbill.billing.events.BusInternalEvent) InvoiceWithMetadata(org.killbill.billing.invoice.generator.InvoiceWithMetadata) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) DefaultNullInvoiceEvent(org.killbill.billing.invoice.api.user.DefaultNullInvoiceEvent) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) Currency(org.killbill.billing.catalog.api.Currency) AccountApiException(org.killbill.billing.account.api.AccountApiException) UUID(java.util.UUID) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 2 with InvoiceItemModelDao

use of org.killbill.billing.invoice.dao.InvoiceItemModelDao in project killbill by killbill.

the class TestIntegrationInvoiceWithRepairLogic method testWithWrongInitialItem.

// This is a beatrix level test matching ur invoice TestSubscriptionItemTree#testWithWrongInitialItem
@Test(groups = "slow")
public void testWithWrongInitialItem() throws Exception {
    final DateTime initialDate = new DateTime(2016, 9, 8, 0, 0, 0, 0, testTimeZone);
    final LocalDate correctStartDate = initialDate.toLocalDate();
    final LocalDate wrongStartDate = new LocalDate(2016, 9, 9);
    final LocalDate endDate = new LocalDate(2016, 10, 8);
    clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(8));
    assertNotNull(account);
    add_AUTO_INVOICING_OFF_Tag(account.getId(), ObjectType.ACCOUNT);
    add_AUTO_PAY_OFF_Tag(account.getId(), ObjectType.ACCOUNT);
    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial");
    busHandler.pushExpectedEvents(NextEvent.BLOCK, NextEvent.CREATE);
    final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec, null, null, null), null, correctStartDate, correctStartDate, false, false, ImmutableList.<PluginProperty>of(), callContext);
    final Entitlement bpEntitlement = entitlementApi.getEntitlementForId(entitlementId, callContext);
    assertListenerStatus();
    final InvoiceModelDao existingBadInvoice = new InvoiceModelDao(UUID.randomUUID(), clock.getUTCNow(), account.getId(), null, correctStartDate, correctStartDate, Currency.USD, false, InvoiceStatus.COMMITTED, false);
    final InvoiceItemModelDao wrongRecurring = new InvoiceItemModelDao(initialDate, InvoiceItemType.RECURRING, existingBadInvoice.getId(), existingBadInvoice.getAccountId(), bpEntitlement.getBundleId(), entitlementId, "", "Pistol", "pistol-monthly-notrial", "pistol-monthly-notrial-evergreen", null, null, new LocalDate(2016, 9, 9), new LocalDate(2016, 10, 8), new BigDecimal("19.29"), new BigDecimal("19.95"), account.getCurrency(), null);
    existingBadInvoice.addInvoiceItem(wrongRecurring);
    insertInvoiceItems(existingBadInvoice);
    existingBadInvoice.getInvoiceItems().clear();
    final InvoiceItemModelDao adj = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.ITEM_ADJ, existingBadInvoice.getId(), existingBadInvoice.getAccountId(), null, null, null, wrongRecurring.getProductName(), wrongRecurring.getPlanName(), wrongRecurring.getPhaseName(), wrongRecurring.getUsageName(), wrongRecurring.getCatalogEffectiveDate(), clock.getUTCToday(), clock.getUTCToday(), new BigDecimal("-19.29"), null, wrongRecurring.getCurrency(), wrongRecurring.getId());
    existingBadInvoice.addInvoiceItem(adj);
    busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.INVOICE_ADJUSTMENT);
    insertInvoiceItems(existingBadInvoice);
    assertListenerStatus();
    busHandler.pushExpectedEvents(NextEvent.INVOICE);
    remove_AUTO_INVOICING_OFF_Tag(account.getId(), ObjectType.ACCOUNT);
    assertListenerStatus();
    invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2016, 9, 8), new LocalDate(2016, 9, 9), InvoiceItemType.RECURRING, new BigDecimal("0.66")));
    checkNoMoreInvoiceToGenerate(account);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) Account(org.killbill.billing.account.api.Account) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) UUID(java.util.UUID) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) Entitlement(org.killbill.billing.entitlement.api.Entitlement) LocalDate(org.joda.time.LocalDate) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 3 with InvoiceItemModelDao

use of org.killbill.billing.invoice.dao.InvoiceItemModelDao in project killbill by killbill.

the class TestIntegrationInvoiceWithRepairLogic method testAdjustmentsToolarge.

@Test(groups = "slow")
public void testAdjustmentsToolarge() throws Exception {
    final LocalDate today = new LocalDate(2013, 7, 19);
    // Set clock to the initial start date - we implicitly assume here that the account timezone is UTC
    clock.setDeltaFromReality(today.toDateTimeAtCurrentTime(DateTimeZone.UTC).getMillis() - clock.getUTCNow().getMillis());
    final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
    final String productName = "Shotgun";
    final BillingPeriod term = BillingPeriod.ANNUAL;
    // 
    // 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);
    assertEquals(invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext).size(), 1);
    assertEquals(bpEntitlement.getSubscriptionBase().getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.ANNUAL);
    // Move out of trials for interesting invoices adjustments
    busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    clock.addDays(30);
    assertListenerStatus();
    List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), false, false, callContext);
    assertEquals(invoices.size(), 2);
    ImmutableList<ExpectedInvoiceItemCheck> toBeChecked = ImmutableList.<ExpectedInvoiceItemCheck>of(new ExpectedInvoiceItemCheck(new LocalDate(2013, 8, 18), new LocalDate(2014, 8, 18), InvoiceItemType.RECURRING, new BigDecimal("2399.95")));
    invoiceChecker.checkInvoice(invoices.get(1).getId(), callContext, toBeChecked);
    final InvoiceItem targetItem = invoices.get(1).getInvoiceItems().get(0);
    final InvoiceItemModelDao adj1 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.ITEM_ADJ, targetItem.getInvoiceId(), targetItem.getAccountId(), null, null, null, targetItem.getProductName(), targetItem.getPlanName(), targetItem.getPhaseName(), targetItem.getUsageName(), targetItem.getCatalogEffectiveDate(), clock.getUTCToday(), clock.getUTCToday(), new BigDecimal("-1000.00"), null, targetItem.getCurrency(), targetItem.getId());
    final InvoiceItemModelDao adj2 = new InvoiceItemModelDao(clock.getUTCNow(), InvoiceItemType.ITEM_ADJ, targetItem.getInvoiceId(), targetItem.getAccountId(), null, null, null, targetItem.getProductName(), targetItem.getPlanName(), targetItem.getPhaseName(), targetItem.getUsageName(), targetItem.getCatalogEffectiveDate(), clock.getUTCToday(), clock.getUTCToday(), new BigDecimal("-2000.00"), null, targetItem.getCurrency(), targetItem.getId());
    final InvoiceModelDao invoiceForAdj = new InvoiceModelDao(UUID.randomUUID(), clock.getUTCNow(), bpEntitlement.getAccountId(), null, clock.getUTCToday(), clock.getUTCToday(), Currency.USD, false, InvoiceStatus.COMMITTED, false);
    invoiceForAdj.addInvoiceItem(adj1);
    invoiceForAdj.addInvoiceItem(adj2);
    busHandler.pushExpectedEvents(NextEvent.INVOICE_ADJUSTMENT);
    insertInvoiceItems(invoiceForAdj);
    assertListenerStatus();
    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) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) LocalDate(org.joda.time.LocalDate) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) BigDecimal(java.math.BigDecimal) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) Test(org.testng.annotations.Test)

Example 4 with InvoiceItemModelDao

use of org.killbill.billing.invoice.dao.InvoiceItemModelDao in project killbill by killbill.

the class InvoiceDispatcher method computeCBAOnExistingInvoice.

private InvoiceItem computeCBAOnExistingInvoice(final Invoice invoice, final InternalCallContext context) throws InvoiceApiException {
    // Transformation to Invoice -> InvoiceModelDao
    final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
    final List<InvoiceItemModelDao> invoiceItemModelDaos = ImmutableList.copyOf(Collections2.transform(invoice.getInvoiceItems(), new Function<InvoiceItem, InvoiceItemModelDao>() {

        @Override
        public InvoiceItemModelDao apply(final InvoiceItem input) {
            return new InvoiceItemModelDao(input);
        }
    }));
    invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
    final InvoiceItemModelDao cbaItem = invoiceDao.doCBAComplexity(invoiceModelDao, context);
    return cbaItem != null ? InvoiceItemFactory.fromModelDao(cbaItem) : null;
}
Also used : Function(com.google.common.base.Function) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao)

Example 5 with InvoiceItemModelDao

use of org.killbill.billing.invoice.dao.InvoiceItemModelDao in project killbill by killbill.

the class InvoiceDispatcher method processAccountWithLockAndInputTargetDate.

private InvoiceWithFutureNotifications processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate originalTargetDate, final BillingEventSet billingEvents, final AccountInvoices accountInvoices, @Nullable final DryRunInfo dryRunInfo, final boolean isRescheduled, final LinkedList<PluginProperty> pluginProperties, final Map<InvoiceTiming, Long> invoiceTimings, final InternalCallContext internalCallContext) throws InvoiceApiException {
    final boolean isDryRun = dryRunInfo != null;
    final CallContext callContext = buildCallContext(internalCallContext);
    final ImmutableAccountData account;
    try {
        account = accountApi.getImmutableAccountDataById(accountId, internalCallContext);
    } catch (final AccountApiException e) {
        log.error("Unable to generate invoice for accountId='{}', a future notification has NOT been recorded", accountId, e);
        long startNano = System.nanoTime();
        invoicePluginDispatcher.onFailureCall(originalTargetDate, null, accountInvoices.getInvoices(), isDryRun, isRescheduled, callContext, pluginProperties, internalCallContext);
        invoiceTimings.put(InvoiceTiming.PLUGINS_COMPLETION_CALL, System.nanoTime() - startNano);
        return null;
    }
    long startNano = System.nanoTime();
    final DateTime rescheduleDate = invoicePluginDispatcher.priorCall(originalTargetDate, accountInvoices.getInvoices(), isDryRun, isRescheduled, callContext, pluginProperties, internalCallContext);
    invoiceTimings.put(InvoiceTiming.PLUGINS_PRIOR_CALL, System.nanoTime() - startNano);
    if (rescheduleDate != null) {
        if (isDryRun) {
            log.warn("Ignoring rescheduleDate='{}', delayed scheduling is unsupported in dry-run", rescheduleDate);
        } else {
            final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(rescheduleDate, billingEvents, internalCallContext);
            setFutureNotifications(account, futureAccountNotifications, internalCallContext);
        }
        return null;
    }
    startNano = System.nanoTime();
    final InvoiceWithMetadata invoiceWithMetadata = generateKillBillInvoice(account, originalTargetDate, billingEvents, accountInvoices, dryRunInfo, internalCallContext);
    invoiceTimings.put(InvoiceTiming.INVOICE_GENERATION, System.nanoTime() - startNano);
    final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
    // Compute future notifications
    final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, billingEvents, internalCallContext);
    // If invoice comes back null, there is nothing new to generate, we can bail early
    if (invoice == null) {
        startNano = System.nanoTime();
        invoicePluginDispatcher.onSuccessCall(originalTargetDate, null, accountInvoices.getInvoices(), isDryRun, isRescheduled, callContext, pluginProperties, internalCallContext);
        invoiceTimings.put(InvoiceTiming.PLUGINS_COMPLETION_CALL, System.nanoTime() - startNano);
        if (isDryRun) {
            log.info("Generated null dryRun invoice for accountId='{}', targetDate='{}'", accountId, originalTargetDate);
        } else {
            log.info("Generated null invoice for accountId='{}', targetDate='{}'", accountId, originalTargetDate);
            final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(), internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId(), internalCallContext.getUserToken());
            // Although we have a null invoice, it could be as a result of removing $0 USAGE (config#isUsageZeroAmountDisabled)
            // and so we may still need to set the CTD for such subscriptions.
            startNano = System.nanoTime();
            setChargedThroughDatesNoExceptions(invoiceWithMetadata.getChargeThroughDates(), internalCallContext);
            invoiceTimings.put(InvoiceTiming.SET_CHARGE_THROUGH_DT, System.nanoTime() - startNano);
            setFutureNotifications(account, futureAccountNotifications, internalCallContext);
            postEvent(event);
        }
        return null;
    }
    final LocalDate actualTargetDate = invoice.getTargetDate();
    boolean success = false;
    try {
        // Generate missing credit (> 0 for generation and < 0 for use) prior we call the plugin(s)
        final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, internalCallContext);
        if (cbaItemPreInvoicePlugins != null) {
            invoice.addInvoiceItem(cbaItemPreInvoicePlugins);
        }
        // 
        // Ask external invoice plugins if additional items (tax, etc) shall be added to the invoice
        // 
        startNano = System.nanoTime();
        final boolean invoiceUpdated = invoicePluginDispatcher.updateOriginalInvoiceWithPluginInvoiceItems(invoice, isDryRun, callContext, pluginProperties, internalCallContext);
        invoiceTimings.put(InvoiceTiming.PLUGINS_ADDITIONAL_ITEMS, System.nanoTime() - startNano);
        if (invoiceUpdated) {
            // Remove the temporary CBA item as we need to re-compute CBA
            if (cbaItemPreInvoicePlugins != null) {
                invoice.removeInvoiceItem(cbaItemPreInvoicePlugins);
            }
            // Use credit after we call the plugin (https://github.com/killbill/killbill/issues/637)
            final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, internalCallContext);
            if (cbaItemPostInvoicePlugins != null) {
                invoice.addInvoiceItem(cbaItemPostInvoicePlugins);
            }
        }
        if (!isDryRun) {
            // Compute whether this is a new invoice object (or just some adjustments on an existing invoice), and extract invoiceIds for later use
            final Set<UUID> uniqueInvoiceIds = getUniqueInvoiceIds(invoice);
            final boolean isRealInvoiceWithItems = uniqueInvoiceIds.remove(invoice.getId());
            final Set<UUID> adjustedUniqueOtherInvoiceId = uniqueInvoiceIds;
            logInvoiceWithItems(account, invoice, actualTargetDate, adjustedUniqueOtherInvoiceId, isRealInvoiceWithItems);
            // Transformation to Invoice -> InvoiceModelDao
            final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
            final List<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
            invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
            final Set<InvoiceTrackingModelDao> trackingIds = new HashSet<>();
            for (final TrackingRecordId cur : invoiceWithMetadata.getTrackingIds()) {
                trackingIds.add(new InvoiceTrackingModelDao(cur.getTrackingId(), cur.getInvoiceId(), cur.getSubscriptionId(), cur.getUnitType(), cur.getRecordDate()));
            }
            // Commit invoice on disk
            final ExistingInvoiceMetadata existingInvoiceMetadata = new ExistingInvoiceMetadata(accountInvoices.getInvoices());
            startNano = System.nanoTime();
            commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, billingEvents, trackingIds, futureAccountNotifications, existingInvoiceMetadata, internalCallContext);
            invoiceTimings.put(InvoiceTiming.COMMIT_INVOICE, System.nanoTime() - startNano);
            startNano = System.nanoTime();
            setChargedThroughDatesNoExceptions(invoiceWithMetadata.getChargeThroughDates(), internalCallContext);
            invoiceTimings.put(InvoiceTiming.SET_CHARGE_THROUGH_DT, System.nanoTime() - startNano);
            success = true;
        }
    } finally {
        // Make sure we always set future notifications in case of errors
        if (!isDryRun && !success) {
            setFutureNotifications(account, futureAccountNotifications, internalCallContext);
        }
        if (isDryRun || success) {
            final DefaultInvoice refreshedInvoice = isDryRun ? invoice : new DefaultInvoice(invoiceDao.getById(invoice.getId(), internalCallContext));
            startNano = System.nanoTime();
            invoicePluginDispatcher.onSuccessCall(actualTargetDate, refreshedInvoice, accountInvoices.getInvoices(), isDryRun, isRescheduled, callContext, pluginProperties, internalCallContext);
            invoiceTimings.put(InvoiceTiming.PLUGINS_COMPLETION_CALL, System.nanoTime() - startNano);
        } else {
            startNano = System.nanoTime();
            invoicePluginDispatcher.onFailureCall(actualTargetDate, invoice, accountInvoices.getInvoices(), isDryRun, isRescheduled, callContext, pluginProperties, internalCallContext);
            invoiceTimings.put(InvoiceTiming.PLUGINS_COMPLETION_CALL, System.nanoTime() - startNano);
        }
    }
    return new InvoiceWithFutureNotifications(invoice, futureAccountNotifications);
}
Also used : ImmutableAccountData(org.killbill.billing.account.api.ImmutableAccountData) TrackingRecordId(org.killbill.billing.invoice.generator.InvoiceWithMetadata.TrackingRecordId) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) BusInternalEvent(org.killbill.billing.events.BusInternalEvent) ExistingInvoiceMetadata(org.killbill.billing.invoice.dao.ExistingInvoiceMetadata) InvoiceWithMetadata(org.killbill.billing.invoice.generator.InvoiceWithMetadata) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) DefaultNullInvoiceEvent(org.killbill.billing.invoice.api.user.DefaultNullInvoiceEvent) InvoiceTrackingModelDao(org.killbill.billing.invoice.dao.InvoiceTrackingModelDao) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) AccountApiException(org.killbill.billing.account.api.AccountApiException) UUID(java.util.UUID) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) HashSet(java.util.HashSet)

Aggregations

InvoiceItemModelDao (org.killbill.billing.invoice.dao.InvoiceItemModelDao)25 InvoiceModelDao (org.killbill.billing.invoice.dao.InvoiceModelDao)23 LocalDate (org.joda.time.LocalDate)18 BigDecimal (java.math.BigDecimal)17 Invoice (org.killbill.billing.invoice.api.Invoice)13 Test (org.testng.annotations.Test)13 Account (org.killbill.billing.account.api.Account)12 UUID (java.util.UUID)10 ExpectedInvoiceItemCheck (org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck)10 DefaultEntitlement (org.killbill.billing.entitlement.api.DefaultEntitlement)10 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)10 DateTime (org.joda.time.DateTime)9 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)7 ItemAdjInvoiceItem (org.killbill.billing.invoice.model.ItemAdjInvoiceItem)6 PlanPhaseSpecifier (org.killbill.billing.catalog.api.PlanPhaseSpecifier)5 DefaultEntitlementSpecifier (org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier)5 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)5 Function (com.google.common.base.Function)4 AccountApiException (org.killbill.billing.account.api.AccountApiException)4 BillingPeriod (org.killbill.billing.catalog.api.BillingPeriod)4