Search in sources :

Example 1 with TagApiException

use of org.killbill.billing.util.api.TagApiException 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;
    }
}
Also used : InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Invoice(org.killbill.billing.invoice.api.Invoice) TagApiException(org.killbill.billing.util.api.TagApiException) BillingEventSet(org.killbill.billing.junction.BillingEventSet) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) AccountApiException(org.killbill.billing.account.api.AccountApiException) UUID(java.util.UUID) LocalDate(org.joda.time.LocalDate) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 2 with TagApiException

use of org.killbill.billing.util.api.TagApiException in project killbill by killbill.

the class TestDefaultTagDao method testCatchEventsOnCreateAndDelete.

@Test(groups = "slow")
public void testCatchEventsOnCreateAndDelete() throws Exception {
    final String definitionName = UUID.randomUUID().toString().substring(0, 5);
    final String description = UUID.randomUUID().toString().substring(0, 5);
    final UUID objectId = UUID.randomUUID();
    final ObjectType objectType = ObjectType.INVOICE_ITEM;
    // Create a tag definition
    eventsListener.pushExpectedEvent(NextEvent.TAG_DEFINITION);
    final TagDefinitionModelDao createdTagDefinition = tagDefinitionDao.create(definitionName, description, ObjectType.ACCOUNT.name(), internalCallContext);
    Assert.assertEquals(createdTagDefinition.getName(), definitionName);
    Assert.assertEquals(createdTagDefinition.getDescription(), description);
    assertListenerStatus();
    final List<AuditLog> auditLogs1 = auditDao.getAuditLogsForId(TableName.TAG_DEFINITIONS, createdTagDefinition.getId(), AuditLevel.FULL, internalCallContext);
    Assert.assertEquals(auditLogs1.size(), 1);
    Assert.assertEquals(auditLogs1.get(0).getChangeType(), ChangeType.INSERT);
    // Make sure we can create a tag
    eventsListener.pushExpectedEvent(NextEvent.TAG);
    final Tag tag = new DescriptiveTag(createdTagDefinition.getId(), objectType, objectId, internalCallContext.getCreatedDate());
    tagDao.create(new TagModelDao(tag), internalCallContext);
    assertListenerStatus();
    final List<AuditLog> auditLogs2 = auditDao.getAuditLogsForId(TableName.TAG, tag.getId(), AuditLevel.FULL, internalCallContext);
    Assert.assertEquals(auditLogs2.size(), 1);
    Assert.assertEquals(auditLogs2.get(0).getChangeType(), ChangeType.INSERT);
    // Make sure we can retrieve it via the DAO
    final List<TagModelDao> foundTags = tagDao.getTagsForObject(objectId, objectType, false, internalCallContext);
    Assert.assertEquals(foundTags.size(), 1);
    Assert.assertEquals(foundTags.get(0).getTagDefinitionId(), createdTagDefinition.getId());
    final List<TagModelDao> foundTagsForAccount = tagDao.getTagsForAccount(false, internalCallContext);
    Assert.assertEquals(foundTagsForAccount.size(), 1);
    Assert.assertEquals(foundTagsForAccount.get(0).getTagDefinitionId(), createdTagDefinition.getId());
    // Delete the tag
    eventsListener.pushExpectedEvent(NextEvent.TAG);
    tagDao.deleteTag(objectId, objectType, createdTagDefinition.getId(), internalCallContext);
    assertListenerStatus();
    final List<AuditLog> auditLogs3 = auditDao.getAuditLogsForId(TableName.TAG, tag.getId(), AuditLevel.FULL, internalCallContext);
    Assert.assertEquals(auditLogs3.size(), 2);
    Assert.assertEquals(auditLogs3.get(0).getChangeType(), ChangeType.INSERT);
    Assert.assertEquals(auditLogs3.get(1).getChangeType(), ChangeType.DELETE);
    // Make sure the tag is deleted
    Assert.assertEquals(tagDao.getTagsForObject(objectId, objectType, false, internalCallContext).size(), 0);
    Assert.assertEquals(tagDao.getTagsForAccount(false, internalCallContext).size(), 0);
    Assert.assertEquals(tagDao.getTagsForObject(objectId, objectType, true, internalCallContext).size(), 1);
    Assert.assertEquals(tagDao.getTagsForAccount(true, internalCallContext).size(), 1);
    // Delete tag again, check correct error
    try {
        tagDao.deleteTag(objectId, objectType, createdTagDefinition.getId(), internalCallContext);
        Assert.fail("Deleting same tag again should fail");
    } catch (final TagApiException e) {
        Assert.assertEquals(e.getCode(), ErrorCode.TAG_DOES_NOT_EXIST.getCode());
    }
}
Also used : ObjectType(org.killbill.billing.ObjectType) TagApiException(org.killbill.billing.util.api.TagApiException) DescriptiveTag(org.killbill.billing.util.tag.DescriptiveTag) Tag(org.killbill.billing.util.tag.Tag) UUID(java.util.UUID) AuditLog(org.killbill.billing.util.audit.AuditLog) DescriptiveTag(org.killbill.billing.util.tag.DescriptiveTag) Test(org.testng.annotations.Test)

Example 3 with TagApiException

use of org.killbill.billing.util.api.TagApiException in project killbill by killbill.

the class TestDefaultTagDao method testInsertMultipleTags.

@Test(groups = "slow")
public void testInsertMultipleTags() throws TagApiException {
    final UUID objectId = UUID.randomUUID();
    final ObjectType objectType = ObjectType.ACCOUNT;
    eventsListener.pushExpectedEvent(NextEvent.TAG);
    final Tag tag = new DescriptiveTag(ControlTagType.AUTO_INVOICING_OFF.getId(), objectType, objectId, internalCallContext.getCreatedDate());
    tagDao.create(new TagModelDao(tag), internalCallContext);
    assertListenerStatus();
    try {
        final Tag tag2 = new DescriptiveTag(ControlTagType.AUTO_INVOICING_OFF.getId(), objectType, objectId, internalCallContext.getCreatedDate());
        tagDao.create(new TagModelDao(tag2), internalCallContext);
        Assert.fail("Should not be able to create twice the same tag");
        assertListenerStatus();
    } catch (final TagApiException e) {
        Assert.assertEquals(ErrorCode.TAG_ALREADY_EXISTS.getCode(), e.getCode());
    }
}
Also used : ObjectType(org.killbill.billing.ObjectType) TagApiException(org.killbill.billing.util.api.TagApiException) DescriptiveTag(org.killbill.billing.util.tag.DescriptiveTag) Tag(org.killbill.billing.util.tag.Tag) UUID(java.util.UUID) DescriptiveTag(org.killbill.billing.util.tag.DescriptiveTag) Test(org.testng.annotations.Test)

Example 4 with TagApiException

use of org.killbill.billing.util.api.TagApiException 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)

Example 5 with TagApiException

use of org.killbill.billing.util.api.TagApiException in project killbill by killbill.

the class InvoiceDispatcher method processAccount.

public Invoice processAccount(final boolean isApiCall, final UUID accountId, @Nullable final LocalDate targetDate, @Nullable final DryRunArguments dryRunArguments, final boolean isRescheduled, final InternalCallContext context) throws InvoiceApiException {
    boolean parkedAccount = false;
    try {
        parkedAccount = parkedAccountsManager.isParked(context);
        if (parkedAccount && !isApiCall) {
            log.warn("Ignoring invoice generation process for accountId='{}', targetDate='{}', account is parked", accountId.toString(), targetDate);
            return null;
        }
    } catch (final TagApiException e) {
        log.warn("Unable to determine parking state for accountId='{}'", accountId);
    }
    if (!isApiCall && !locker.isFree(LockerType.ACCNT_INV_PAY.toString(), accountId.toString())) {
        if (invoiceOptimizer.rescheduleProcessAccount(accountId, context)) {
            return null;
        }
    }
    GlobalLock lock = null;
    try {
        // Grab lock unless we do a dry-run
        final boolean isDryRun = dryRunArguments != null;
        lock = !isDryRun ? locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries()) : null;
        return processAccountInternal(isApiCall, parkedAccount, accountId, targetDate, dryRunArguments, isRescheduled, context);
    } catch (final LockFailedException e) {
        if (isApiCall) {
            throw new InvoiceApiException(e, ErrorCode.UNEXPECTED_ERROR, "Failed to generate invoice: failed to acquire lock");
        }
        if (!invoiceOptimizer.rescheduleProcessAccount(accountId, context)) {
            log.warn("Failed to process invoice for accountId='{}', targetDate='{}'", accountId.toString(), targetDate, e);
        }
    } finally {
        if (lock != null) {
            lock.release();
        }
    }
    return null;
}
Also used : GlobalLock(org.killbill.commons.locker.GlobalLock) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) LockFailedException(org.killbill.commons.locker.LockFailedException) TagApiException(org.killbill.billing.util.api.TagApiException)

Aggregations

TagApiException (org.killbill.billing.util.api.TagApiException)8 UUID (java.util.UUID)6 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)3 ApiOperation (io.swagger.annotations.ApiOperation)2 ApiResponses (io.swagger.annotations.ApiResponses)2 Consumes (javax.ws.rs.Consumes)2 DELETE (javax.ws.rs.DELETE)2 Path (javax.ws.rs.Path)2 Produces (javax.ws.rs.Produces)2 LocalDate (org.joda.time.LocalDate)2 ObjectType (org.killbill.billing.ObjectType)2 Account (org.killbill.billing.account.api.Account)2 AccountApiException (org.killbill.billing.account.api.AccountApiException)2 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)2 Invoice (org.killbill.billing.invoice.api.Invoice)2 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)2 BillingEventSet (org.killbill.billing.junction.BillingEventSet)2 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)2 CallContext (org.killbill.billing.util.callcontext.CallContext)2 DescriptiveTag (org.killbill.billing.util.tag.DescriptiveTag)2