Search in sources :

Example 21 with DefaultInvoice

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

the class TestInvoiceWithMetadata method testWith$0RecurringItem.

@Test(groups = "fast")
public void testWith$0RecurringItem() {
    final LocalDate invoiceDate = new LocalDate(2016, 11, 15);
    final DefaultInvoice originalInvoice = new DefaultInvoice(account.getId(), invoiceDate, account.getCurrency());
    final Plan plan = new MockPlan("my-plan");
    final MockInternationalPrice price = new MockInternationalPrice(new DefaultPrice(BigDecimal.TEN, account.getCurrency()));
    final PlanPhase planPhase = new MockPlanPhase(price, null, BillingPeriod.MONTHLY, PhaseType.EVERGREEN);
    final BillingEvent event = invoiceUtil.createMockBillingEvent(account, subscription, invoiceDate.toDateTimeAtStartOfDay(), plan, planPhase, null, BigDecimal.ZERO, account.getCurrency(), planPhase.getRecurring().getBillingPeriod(), 1, BillingMode.IN_ADVANCE, "Billing Event Desc", 1L, SubscriptionBaseTransitionType.CREATE);
    final InvoiceItem invoiceItem = new RecurringInvoiceItem(UUID.randomUUID(), invoiceDate.toDateTimeAtStartOfDay(), originalInvoice.getId(), account.getId(), subscription.getBundleId(), subscription.getId(), null, event.getPlan().getName(), event.getPlanPhase().getName(), null, invoiceDate, invoiceDate.plusMonths(1), BigDecimal.ZERO, BigDecimal.ZERO, account.getCurrency());
    originalInvoice.addInvoiceItem(invoiceItem);
    final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDates = new HashMap<UUID, SubscriptionFutureNotificationDates>();
    final SubscriptionFutureNotificationDates subscriptionFutureNotificationDates = new SubscriptionFutureNotificationDates(BillingMode.IN_ADVANCE);
    subscriptionFutureNotificationDates.updateNextRecurringDateIfRequired(invoiceDate.plusMonths(1));
    perSubscriptionFutureNotificationDates.put(subscription.getId(), subscriptionFutureNotificationDates);
    final InvoiceWithMetadata invoiceWithMetadata = new InvoiceWithMetadata(originalInvoice, ImmutableSet.of(), perSubscriptionFutureNotificationDates, false, internalCallContext);
    // We generate an invoice with one item, invoicing for $0
    final Invoice resultingInvoice = invoiceWithMetadata.getInvoice();
    Assert.assertNotNull(resultingInvoice);
    Assert.assertEquals(resultingInvoice.getInvoiceItems().size(), 1);
    Assert.assertEquals(resultingInvoice.getInvoiceItems().get(0).getAmount().compareTo(BigDecimal.ZERO), 0);
    final Map<UUID, InvoiceWithMetadata.SubscriptionFutureNotificationDates> dateMap = invoiceWithMetadata.getPerSubscriptionFutureNotificationDates();
    final InvoiceWithMetadata.SubscriptionFutureNotificationDates futureNotificationDates = dateMap.get(subscription.getId());
    // We verify that we generated the future notification for a month ahead
    Assert.assertNotNull(futureNotificationDates.getNextRecurringDate());
    Assert.assertEquals(futureNotificationDates.getNextRecurringDate().compareTo(invoiceDate.plusMonths(1)), 0);
}
Also used : SubscriptionFutureNotificationDates(org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) Invoice(org.killbill.billing.invoice.api.Invoice) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) HashMap(java.util.HashMap) MockPlan(org.killbill.billing.catalog.MockPlan) Plan(org.killbill.billing.catalog.api.Plan) LocalDate(org.joda.time.LocalDate) MockInternationalPrice(org.killbill.billing.catalog.MockInternationalPrice) SubscriptionFutureNotificationDates(org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates) MockPlan(org.killbill.billing.catalog.MockPlan) MockPlanPhase(org.killbill.billing.catalog.MockPlanPhase) PlanPhase(org.killbill.billing.catalog.api.PlanPhase) MockPlanPhase(org.killbill.billing.catalog.MockPlanPhase) BillingEvent(org.killbill.billing.junction.BillingEvent) DefaultPrice(org.killbill.billing.catalog.DefaultPrice) UUID(java.util.UUID) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Test(org.testng.annotations.Test)

Example 22 with DefaultInvoice

use of org.killbill.billing.invoice.model.DefaultInvoice 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)

Example 23 with DefaultInvoice

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

the class InvoiceDispatcher method processParentInvoiceForInvoiceGenerationWithLock.

private void processParentInvoiceForInvoiceGenerationWithLock(final Account childAccount, final UUID childInvoiceId, final InternalCallContext context) throws InvoiceApiException {
    log.info("Processing parent invoice for parentAccountId='{}', childInvoiceId='{}'", childAccount.getParentAccountId(), childInvoiceId);
    final InvoiceModelDao childInvoiceModelDao = invoiceDao.getById(childInvoiceId, context);
    final Invoice childInvoice = new DefaultInvoice(childInvoiceModelDao);
    final Long parentAccountRecordId = internalCallContextFactory.getRecordIdFromObject(childAccount.getParentAccountId(), ObjectType.ACCOUNT, buildTenantContext(context));
    final InternalCallContext parentContext = internalCallContextFactory.createInternalCallContext(parentAccountRecordId, context);
    final BigDecimal childInvoiceAmount = InvoiceCalculatorUtils.computeChildInvoiceAmount(childInvoice.getCurrency(), childInvoice.getInvoiceItems());
    InvoiceModelDao draftParentInvoice = invoiceDao.getParentDraftInvoice(childAccount.getParentAccountId(), parentContext);
    final String description = childAccount.getExternalKey().concat(" summary");
    if (draftParentInvoice != null) {
        for (final InvoiceItemModelDao item : draftParentInvoice.getInvoiceItems()) {
            if ((item.getChildAccountId() != null) && item.getChildAccountId().equals(childInvoice.getAccountId())) {
                // update child item amount for existing parent invoice item
                final BigDecimal newChildInvoiceAmount = childInvoiceAmount.add(item.getAmount());
                log.info("Updating existing itemId='{}', oldAmount='{}', newAmount='{}' on existing DRAFT invoiceId='{}'", item.getId(), item.getAmount(), newChildInvoiceAmount, draftParentInvoice.getId());
                invoiceDao.updateInvoiceItemAmount(item.getId(), newChildInvoiceAmount, parentContext);
                return;
            }
        }
        // new item when the parent invoices does not have this child item yet
        final ParentInvoiceItem newParentInvoiceItem = new ParentInvoiceItem(UUID.randomUUID(), context.getCreatedDate(), draftParentInvoice.getId(), childAccount.getParentAccountId(), childAccount.getId(), childInvoiceAmount, childAccount.getCurrency(), description);
        final InvoiceItemModelDao parentInvoiceItem = new InvoiceItemModelDao(newParentInvoiceItem);
        draftParentInvoice.addInvoiceItem(parentInvoiceItem);
        final List<InvoiceModelDao> invoices = new ArrayList<InvoiceModelDao>();
        invoices.add(draftParentInvoice);
        log.info("Adding new itemId='{}', amount='{}' on existing DRAFT invoiceId='{}'", parentInvoiceItem.getId(), childInvoiceAmount, draftParentInvoice.getId());
        invoiceDao.createInvoices(invoices, null, ImmutableSet.of(), parentContext);
    } else {
        if (shouldIgnoreChildInvoice(childInvoice, childInvoiceAmount)) {
            return;
        }
        final LocalDate invoiceDate = context.toLocalDate(context.getCreatedDate());
        draftParentInvoice = new InvoiceModelDao(childAccount.getParentAccountId(), invoiceDate, childAccount.getCurrency(), InvoiceStatus.DRAFT, true);
        final InvoiceItem parentInvoiceItem = new ParentInvoiceItem(UUID.randomUUID(), context.getCreatedDate(), draftParentInvoice.getId(), childAccount.getParentAccountId(), childAccount.getId(), childInvoiceAmount, childAccount.getCurrency(), description);
        draftParentInvoice.addInvoiceItem(new InvoiceItemModelDao(parentInvoiceItem));
        log.info("Adding new itemId='{}', amount='{}' on new DRAFT invoiceId='{}'", parentInvoiceItem.getId(), childInvoiceAmount, draftParentInvoice.getId());
        invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(draftParentInvoice), null, ImmutableSet.of(), parentContext);
    }
    // save parent child invoice relation
    final InvoiceParentChildModelDao invoiceRelation = new InvoiceParentChildModelDao(draftParentInvoice.getId(), childInvoiceId, childAccount.getId());
    invoiceDao.createParentChildInvoiceRelation(invoiceRelation, parentContext);
}
Also used : DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Invoice(org.killbill.billing.invoice.api.Invoice) 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) ArrayList(java.util.ArrayList) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) LocalDate(org.joda.time.LocalDate) BigDecimal(java.math.BigDecimal) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) InvoiceParentChildModelDao(org.killbill.billing.invoice.dao.InvoiceParentChildModelDao) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice)

Example 24 with DefaultInvoice

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

the class InvoicePluginDispatcher method onCompletionCall.

private void onCompletionCall(final boolean isSuccess, final LocalDate targetDate, @Nullable final DefaultInvoice originalInvoice, final List<Invoice> existingInvoices, final boolean isDryRun, final boolean isRescheduled, final CallContext callContext, // The pluginProperties list passed to plugins is mutable by the plugins
@SuppressWarnings("TypeMayBeWeakened") final LinkedList<PluginProperty> properties, final InternalTenantContext internalTenantContext) {
    final Collection<InvoicePluginApi> invoicePlugins = getInvoicePlugins(internalTenantContext).values();
    if (invoicePlugins.isEmpty()) {
        return;
    }
    // We clone the original invoice so plugins don't remove/add items
    final Invoice clonedInvoice = originalInvoice == null ? null : (Invoice) originalInvoice.clone();
    final InvoiceContext invoiceContext = new DefaultInvoiceContext(targetDate, clonedInvoice, existingInvoices, isDryRun, isRescheduled, callContext);
    for (final InvoicePluginApi invoicePlugin : invoicePlugins) {
        if (isSuccess) {
            invoicePlugin.onSuccessCall(invoiceContext, properties);
        } else {
            invoicePlugin.onFailureCall(invoiceContext, properties);
        }
    }
}
Also used : InvoicePluginApi(org.killbill.billing.invoice.plugin.api.InvoicePluginApi) InvoiceContext(org.killbill.billing.invoice.plugin.api.InvoiceContext) DefaultInvoiceContext(org.killbill.billing.invoice.api.DefaultInvoiceContext) Invoice(org.killbill.billing.invoice.api.Invoice) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) DefaultInvoiceContext(org.killbill.billing.invoice.api.DefaultInvoiceContext)

Example 25 with DefaultInvoice

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

the class InvoiceApiHelper method dispatchToInvoicePluginsAndInsertItems.

@SuppressFBWarnings("NP_ALWAYS_NULL_EXCEPTION")
public List<InvoiceItem> dispatchToInvoicePluginsAndInsertItems(final UUID accountId, final boolean isDryRun, final WithAccountLock withAccountLock, final LinkedList<PluginProperty> properties, final CallContext contextMaybeWithoutAccountId) throws InvoiceApiException {
    // Invoked by User API call
    final LocalDate targetDate = null;
    final List<Invoice> existingInvoices = null;
    final boolean isRescheduled = false;
    final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, contextMaybeWithoutAccountId);
    final CallContext context = internalCallContextFactory.createCallContext(internalCallContext);
    final DateTime rescheduleDate = invoicePluginDispatcher.priorCall(targetDate, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
    if (rescheduleDate != null) {
        throw new InvoiceApiException(ErrorCode.INVOICE_PLUGIN_API_ABORTED, "delayed scheduling is unsupported for API calls");
    }
    boolean success = false;
    GlobalLock lock = null;
    Iterable<DefaultInvoice> invoicesForPlugins = null;
    try {
        lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries());
        invoicesForPlugins = withAccountLock.prepareInvoices();
        final List<InvoiceModelDao> invoiceModelDaos = new LinkedList<InvoiceModelDao>();
        for (final DefaultInvoice invoiceForPlugin : invoicesForPlugins) {
            // Call plugin(s)
            invoicePluginDispatcher.updateOriginalInvoiceWithPluginInvoiceItems(invoiceForPlugin, isDryRun, context, properties, internalCallContext);
            // Transformation to InvoiceModelDao
            final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoiceForPlugin);
            final List<InvoiceItem> invoiceItems = invoiceForPlugin.getInvoiceItems();
            final List<InvoiceItemModelDao> invoiceItemModelDaos = toInvoiceItemModelDao(invoiceItems);
            invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
            // Keep track of modified invoices
            invoiceModelDaos.add(invoiceModelDao);
        }
        final List<InvoiceItemModelDao> createdInvoiceItems = dao.createInvoices(invoiceModelDaos, null, ImmutableSet.of(), internalCallContext);
        success = true;
        return fromInvoiceItemModelDao(createdInvoiceItems);
    } catch (final LockFailedException e) {
        throw new InvoiceApiException(e, ErrorCode.UNEXPECTED_ERROR, "Failed to process invoice items: failed to acquire lock");
    } finally {
        if (lock != null) {
            lock.release();
        }
        if (success) {
            for (final Invoice invoiceForPlugin : invoicesForPlugins) {
                final DefaultInvoice refreshedInvoice = new DefaultInvoice(dao.getById(invoiceForPlugin.getId(), internalCallContext));
                invoicePluginDispatcher.onSuccessCall(targetDate, refreshedInvoice, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
            }
        } else {
            invoicePluginDispatcher.onFailureCall(targetDate, null, existingInvoices, isDryRun, isRescheduled, context, properties, internalCallContext);
        }
    }
}
Also used : DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) LockFailedException(org.killbill.commons.locker.LockFailedException) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) LocalDate(org.joda.time.LocalDate) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) DateTime(org.joda.time.DateTime) LinkedList(java.util.LinkedList) GlobalLock(org.killbill.commons.locker.GlobalLock) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Aggregations

DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)92 Invoice (org.killbill.billing.invoice.api.Invoice)81 LocalDate (org.joda.time.LocalDate)64 Test (org.testng.annotations.Test)63 UUID (java.util.UUID)51 BigDecimal (java.math.BigDecimal)46 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)46 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)38 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)37 RepairAdjInvoiceItem (org.killbill.billing.invoice.model.RepairAdjInvoiceItem)28 LinkedList (java.util.LinkedList)25 HashMap (java.util.HashMap)24 ItemAdjInvoiceItem (org.killbill.billing.invoice.model.ItemAdjInvoiceItem)24 MockBillingEventSet (org.killbill.billing.invoice.MockBillingEventSet)20 AccountInvoices (org.killbill.billing.invoice.optimizer.InvoiceOptimizerBase.AccountInvoices)20 BillingEventSet (org.killbill.billing.junction.BillingEventSet)20 MockPlan (org.killbill.billing.catalog.MockPlan)18 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)18 BillingEvent (org.killbill.billing.junction.BillingEvent)18 Plan (org.killbill.billing.catalog.api.Plan)17