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");
}
}
Aggregations