Search in sources :

Example 1 with DryRunInfo

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

the class InvoiceDispatcher method processAccountInternal.

private Invoice processAccountInternal(final boolean isApiCall, final boolean parkedAccount, final UUID accountId, @Nullable final LocalDate inputTargetDateMaybeNull, @Nullable final DryRunArguments dryRunArguments, final boolean isRescheduled, final InternalCallContext context) throws InvoiceApiException {
    final boolean isDryRun = dryRunArguments != null;
    final boolean upcomingInvoiceDryRun = isDryRun && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType());
    LocalDate inputTargetDate = inputTargetDateMaybeNull;
    // A null inputTargetDate is only allowed in UPCOMING_INVOICE dryRun mode to have the system compute it
    if (inputTargetDate == null && !upcomingInvoiceDryRun) {
        inputTargetDate = context.toLocalDate(clock.getUTCNow());
    }
    Preconditions.checkArgument(inputTargetDate != null || upcomingInvoiceDryRun, "inputTargetDate is required in non dryRun mode");
    // Passed through invoice code to be propagated to usage module/plugins
    final LocalDate dryRunInfoDate = isDryRun && dryRunArguments.getDryRunType() == DryRunType.SUBSCRIPTION_ACTION ? dryRunArguments.getEffectiveDate() : inputTargetDate;
    final DryRunInfo dryRunInfo = isDryRun ? new DryRunInfo(dryRunArguments.getDryRunType(), dryRunInfoDate) : null;
    final Map<InvoiceTiming, Long> invoiceTimings = new HashMap<>();
    try {
        long startNano = System.nanoTime();
        final AccountInvoices accountInvoices = invoiceOptimizer.getInvoices(context);
        invoiceTimings.put(InvoiceTiming.FETCH_INVOICES, System.nanoTime() - startNano);
        // Make sure to first set the BCD if needed then get the account object (to have the BCD set)
        startNano = System.nanoTime();
        final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, dryRunArguments, accountInvoices.getBillingEventCutoffDate(), context);
        invoiceTimings.put(InvoiceTiming.BILLING_EVENTS, System.nanoTime() - startNano);
        if (!isApiCall && billingEvents.isAccountAutoInvoiceOff()) {
            return null;
        }
        final Invoice invoice;
        if (!isDryRun) {
            final InvoiceWithFutureNotifications invoiceWithFutureNotifications = processAccountWithLockAndInputTargetDate(accountId, inputTargetDate, billingEvents, accountInvoices, dryRunInfo, isRescheduled, Lists.newLinkedList(), invoiceTimings, context);
            invoice = invoiceWithFutureNotifications != null ? invoiceWithFutureNotifications.getInvoice() : null;
            if (parkedAccount) {
                try {
                    log.info("Illegal invoicing state fixed for accountId='{}', unparking account", accountId);
                    parkedAccountsManager.unparkAccount(accountId, context);
                } catch (final TagApiException ignored) {
                    log.warn("Unable to unpark account", ignored);
                }
            }
        } else /* Dry run use cases */
        {
            final NotificationQueue notificationQueue = notificationQueueService.getNotificationQueue(KILLBILL_SERVICES.INVOICE_SERVICE.getServiceName(), DefaultNextBillingDateNotifier.NEXT_BILLING_DATE_NOTIFIER_QUEUE);
            final Iterable<NotificationEventWithMetadata<NextBillingDateNotificationKey>> futureNotificationsIterable = notificationQueue.getFutureNotificationForSearchKeys(context.getAccountRecordId(), context.getTenantRecordId());
            // Copy the results as retrieving the iterator will issue a query each time. This also makes sure the underlying JDBC connection is closed.
            final List<NotificationEventWithMetadata<NextBillingDateNotificationKey>> futureNotifications = ImmutableList.<NotificationEventWithMetadata<NextBillingDateNotificationKey>>copyOf(futureNotificationsIterable);
            final Map<UUID, DateTime> nextScheduledSubscriptionsEventMap = getNextTransitionsForSubscriptions(billingEvents);
            // List of all existing invoice notifications
            final Set<LocalDate> allCandidateTargetDates = getUpcomingInvoiceCandidateDates(futureNotifications, nextScheduledSubscriptionsEventMap, ImmutableList.<UUID>of(), context);
            if (dryRunArguments.getDryRunType() == DryRunType.UPCOMING_INVOICE) {
                final Iterable<UUID> filteredSubscriptionIdsForDryRun = getFilteredSubscriptionIdsFor_UPCOMING_INVOICE_DryRun(dryRunArguments, billingEvents);
                // List of existing invoice notifications associated to the filter set of subscriptionIds
                final Set<LocalDate> filteredCandidateTargetDates = Iterables.isEmpty(filteredSubscriptionIdsForDryRun) ? allCandidateTargetDates : getUpcomingInvoiceCandidateDates(futureNotifications, nextScheduledSubscriptionsEventMap, filteredSubscriptionIdsForDryRun, context);
                if (Iterables.isEmpty(filteredSubscriptionIdsForDryRun)) {
                    invoice = processDryRun_UPCOMING_INVOICE_Invoice(accountId, allCandidateTargetDates, billingEvents, accountInvoices, dryRunInfo, invoiceTimings, context);
                } else {
                    invoice = processDryRun_UPCOMING_INVOICE_FILTERING_Invoice(accountId, filteredCandidateTargetDates, allCandidateTargetDates, billingEvents, accountInvoices, dryRunInfo, invoiceTimings, context);
                }
            } else /* DryRunType.TARGET_DATE, SUBSCRIPTION_ACTION */
            {
                invoice = processDryRun_TARGET_DATE_Invoice(accountId, inputTargetDate, allCandidateTargetDates, billingEvents, accountInvoices, dryRunInfo, invoiceTimings, context);
            }
        }
        printInvoiceTiming(invoiceTimings);
        return invoice;
    } catch (final CatalogApiException e) {
        log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
        return null;
    } catch (final AccountApiException e) {
        log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
        return null;
    } catch (final SubscriptionBaseApiException e) {
        log.warn("Failed to retrieve BillingEvents for accountId='{}', dryRunArguments='{}'", accountId, dryRunArguments, e);
        return null;
    } catch (final InvoiceApiException e) {
        if (e.getCode() == ErrorCode.INVOICE_PLUGIN_API_ABORTED.getCode()) {
            return null;
        }
        if (e.getCode() == ErrorCode.UNEXPECTED_ERROR.getCode() && !isDryRun) {
            log.warn("Illegal invoicing state detected for accountId='{}', dryRunArguments='{}', parking account", accountId, dryRunArguments, e);
            parkAccount(accountId, context);
        }
        throw e;
    } catch (final NoSuchNotificationQueue e) {
        throw new InvoiceApiException(ErrorCode.UNEXPECTED_ERROR, "Failed to retrieve future notifications from notificationQ");
    }
}
Also used : AccountInvoices(org.killbill.billing.invoice.optimizer.InvoiceOptimizerBase.AccountInvoices) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Invoice(org.killbill.billing.invoice.api.Invoice) HashMap(java.util.HashMap) NotificationQueue(org.killbill.notificationq.api.NotificationQueue) NoSuchNotificationQueue(org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue) LocalDate(org.joda.time.LocalDate) DryRunInfo(org.killbill.billing.invoice.api.DryRunInfo) DateTime(org.joda.time.DateTime) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) AccountApiException(org.killbill.billing.account.api.AccountApiException) NotificationEventWithMetadata(org.killbill.notificationq.api.NotificationEventWithMetadata) UUID(java.util.UUID) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) NoSuchNotificationQueue(org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue) TagApiException(org.killbill.billing.util.api.TagApiException) BillingEventSet(org.killbill.billing.junction.BillingEventSet) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException)

Aggregations

HashMap (java.util.HashMap)1 UUID (java.util.UUID)1 DateTime (org.joda.time.DateTime)1 LocalDate (org.joda.time.LocalDate)1 AccountApiException (org.killbill.billing.account.api.AccountApiException)1 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)1 DryRunInfo (org.killbill.billing.invoice.api.DryRunInfo)1 Invoice (org.killbill.billing.invoice.api.Invoice)1 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)1 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)1 AccountInvoices (org.killbill.billing.invoice.optimizer.InvoiceOptimizerBase.AccountInvoices)1 BillingEventSet (org.killbill.billing.junction.BillingEventSet)1 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)1 TagApiException (org.killbill.billing.util.api.TagApiException)1 NotificationEventWithMetadata (org.killbill.notificationq.api.NotificationEventWithMetadata)1 NotificationQueue (org.killbill.notificationq.api.NotificationQueue)1 NoSuchNotificationQueue (org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue)1