use of org.killbill.billing.subscription.api.user.SubscriptionBaseApiException in project killbill by killbill.
the class InvoiceDispatcher method processAccountWithLock.
private Invoice processAccountWithLock(final boolean parkedAccount, final UUID accountId, @Nullable final LocalDate inputTargetDateMaybeNull, @Nullable final DryRunArguments dryRunArguments, 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 dryRun mode to have the system compute it
if (inputTargetDate == null && !upcomingInvoiceDryRun) {
inputTargetDate = clock.getUTCToday();
}
Preconditions.checkArgument(inputTargetDate != null || upcomingInvoiceDryRun, "inputTargetDate is required in non dryRun mode");
try {
// Make sure to first set the BCD if needed then get the account object (to have the BCD set)
final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, dryRunArguments, context);
if (billingEvents.isEmpty()) {
return null;
}
final Iterable<UUID> filteredSubscriptionIdsForDryRun = getFilteredSubscriptionIdsForDryRun(dryRunArguments, billingEvents);
final List<LocalDate> candidateTargetDates = (inputTargetDate != null) ? ImmutableList.<LocalDate>of(inputTargetDate) : getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
for (final LocalDate curTargetDate : candidateTargetDates) {
final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDate, billingEvents, isDryRun, context);
if (invoice != null) {
filterInvoiceItemsForDryRun(filteredSubscriptionIdsForDryRun, invoice);
if (!isDryRun && 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);
}
}
return invoice;
}
}
return null;
} 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.UNEXPECTED_ERROR.getCode() && !isDryRun) {
log.warn("Illegal invoicing state detected for accountId='{}', dryRunArguments='{}', parking account", accountId, dryRunArguments, e);
parkAccount(accountId, context);
}
throw e;
}
}
use of org.killbill.billing.subscription.api.user.SubscriptionBaseApiException 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");
}
}
use of org.killbill.billing.subscription.api.user.SubscriptionBaseApiException in project killbill by killbill.
the class InvoiceDispatcher method processSubscriptionStartRequestedDateWithLock.
private void processSubscriptionStartRequestedDateWithLock(final UUID accountId, final RequestedSubscriptionInternalEvent transition, final InternalCallContext context) {
try {
// TODO
// Can we use cutoffDt ?
// Do we even need the billing events ?
final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, null, null, context);
if (billingEvents.isEmpty()) {
return;
}
final FutureAccountNotificationsBuilder notificationsBuilder = new FutureAccountNotificationsBuilder();
populateNextFutureDryRunNotificationDate(billingEvents, notificationsBuilder, context);
final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
setFutureNotifications(account, notificationsBuilder.build(), context);
} catch (final SubscriptionBaseApiException e) {
log.warn("Failed handling SubscriptionBase change.", new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, transition.getSubscriptionId().toString()));
} catch (final AccountApiException e) {
log.warn("Failed to retrieve BillingEvents for accountId='{}'", accountId, e);
} catch (final CatalogApiException e) {
log.warn("Failed to retrieve BillingEvents for accountId='{}'", accountId, e);
}
}
use of org.killbill.billing.subscription.api.user.SubscriptionBaseApiException in project killbill by killbill.
the class EventsStreamBuilder method buildForBundle.
public List<EventsStream> buildForBundle(final UUID bundleId, final InternalTenantContext internalTenantContext) throws EntitlementApiException {
final SubscriptionBaseBundle bundle;
final List<SubscriptionBase> subscriptionsForBundle;
try {
bundle = subscriptionInternalApi.getBundleFromId(bundleId, internalTenantContext);
subscriptionsForBundle = subscriptionInternalApi.getSubscriptionsForBundle(bundleId, null, internalTenantContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
final List<EventsStream> eventsStreams = new LinkedList<EventsStream>();
for (final SubscriptionBase subscription : subscriptionsForBundle) {
eventsStreams.add(buildForEntitlement(bundle, subscription, subscriptionsForBundle, internalTenantContext));
}
return eventsStreams;
}
use of org.killbill.billing.subscription.api.user.SubscriptionBaseApiException in project killbill by killbill.
the class EventsStreamBuilder method buildForBaseSubscription.
public EventsStream buildForBaseSubscription(final UUID bundleId, final TenantContext tenantContext) throws EntitlementApiException {
final SubscriptionBase baseSubscription;
try {
final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(bundleId, ObjectType.BUNDLE, tenantContext);
baseSubscription = subscriptionInternalApi.getBaseSubscription(bundleId, internalTenantContext);
} catch (final SubscriptionBaseApiException e) {
throw new EntitlementApiException(e);
}
return buildForEntitlement(baseSubscription.getId(), tenantContext);
}
Aggregations