Search in sources :

Example 81 with InvoiceItem

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

the class InvoiceResource method adjustInvoiceItem.

@TimedResource
@POST
@Path("/{invoiceId:" + UUID_PATTERN + "}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Adjust an invoice item")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"), @ApiResponse(code = 404, message = "Invoice not found") })
public Response adjustInvoiceItem(final InvoiceItemJson json, @PathParam("invoiceId") final String invoiceId, @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request, @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
    verifyNonNullOrEmpty(json, "InvoiceItemJson body should be specified");
    verifyNonNullOrEmpty(json.getAccountId(), "InvoiceItemJson accountId needs to be set", json.getInvoiceItemId(), "InvoiceItemJson invoiceItemId needs to be set");
    final CallContext callContext = context.createContext(createdBy, reason, comment, request);
    final UUID accountId = UUID.fromString(json.getAccountId());
    final LocalDate requestedDate = toLocalDateDefaultToday(accountId, requestedDateTimeString, callContext);
    final InvoiceItem adjustmentItem;
    if (json.getAmount() == null) {
        adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId, UUID.fromString(invoiceId), UUID.fromString(json.getInvoiceItemId()), requestedDate, json.getDescription(), callContext);
    } else {
        adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId, UUID.fromString(invoiceId), UUID.fromString(json.getInvoiceItemId()), requestedDate, json.getAmount(), Currency.valueOf(json.getCurrency()), json.getDescription(), callContext);
    }
    return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId(), request);
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) UUID(java.util.UUID) CallContext(org.killbill.billing.util.callcontext.CallContext) LocalDate(org.joda.time.LocalDate) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 82 with InvoiceItem

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

the class InvoiceDispatcher method processAccountWithLockAndInputTargetDate.

private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate, final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
    try {
        final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
        final List<Invoice> invoices = billingEvents.isAccountAutoInvoiceOff() ? ImmutableList.<Invoice>of() : ImmutableList.<Invoice>copyOf(Collections2.transform(invoiceDao.getInvoicesByAccount(context), new Function<InvoiceModelDao, Invoice>() {

            @Override
            public Invoice apply(final InvoiceModelDao input) {
                return new DefaultInvoice(input);
            }
        }));
        final Currency targetCurrency = account.getCurrency();
        final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, billingEvents, invoices, targetDate, targetCurrency, context);
        final DefaultInvoice invoice = invoiceWithMetadata.getInvoice();
        // Compute future notifications
        final FutureAccountNotifications futureAccountNotifications = createNextFutureNotificationDate(invoiceWithMetadata, context);
        //
        if (invoice == null) {
            if (isDryRun) {
                log.info("Generated null dryRun invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
            } else {
                log.info("Generated null invoice for accountId='{}', targetDate='{}'", accountId, targetDate);
                final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
                commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
                postEvent(event);
            }
            return null;
        }
        // Generate missing credit (> 0 for generation and < 0 for use) prior we call the plugin
        final InvoiceItem cbaItemPreInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
        DefaultInvoice tmpInvoiceForInvoicePlugins = invoice;
        if (cbaItemPreInvoicePlugins != null) {
            tmpInvoiceForInvoicePlugins = (DefaultInvoice) tmpInvoiceForInvoicePlugins.clone();
            tmpInvoiceForInvoicePlugins.addInvoiceItem(cbaItemPreInvoicePlugins);
        }
        //
        // Ask external invoice plugins if additional items (tax, etc) shall be added to the invoice
        //
        final CallContext callContext = buildCallContext(context);
        final List<InvoiceItem> additionalInvoiceItemsFromPlugins = invoicePluginDispatcher.getAdditionalInvoiceItems(tmpInvoiceForInvoicePlugins, isDryRun, callContext);
        if (additionalInvoiceItemsFromPlugins.isEmpty()) {
            // PERF: avoid re-computing the CBA if no change was made
            if (cbaItemPreInvoicePlugins != null) {
                invoice.addInvoiceItem(cbaItemPreInvoicePlugins);
            }
        } else {
            invoice.addInvoiceItems(additionalInvoiceItemsFromPlugins);
            // Use credit after we call the plugin (https://github.com/killbill/killbill/issues/637)
            final InvoiceItem cbaItemPostInvoicePlugins = computeCBAOnExistingInvoice(invoice, context);
            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, targetDate, adjustedUniqueOtherInvoiceId, isRealInvoiceWithItems);
            // Transformation to Invoice -> InvoiceModelDao
            final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
            final List<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
            invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
            // Commit invoice on disk
            final boolean isThereAnyItemsLeft = commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, context);
            final boolean isRealInvoiceWithNonEmptyItems = isThereAnyItemsLeft ? isRealInvoiceWithItems : false;
            setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
            if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
                notifyAccountIfEnabled(account, invoice, isRealInvoiceWithNonEmptyItems, context);
            }
        }
        return invoice;
    } catch (final AccountApiException e) {
        log.error("Failed handling SubscriptionBase change.", e);
        return null;
    } catch (final SubscriptionBaseApiException e) {
        log.error("Failed handling SubscriptionBase change.", e);
        return null;
    }
}
Also used : ImmutableAccountData(org.killbill.billing.account.api.ImmutableAccountData) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) Invoice(org.killbill.billing.invoice.api.Invoice) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) BusInternalEvent(org.killbill.billing.events.BusInternalEvent) InvoiceWithMetadata(org.killbill.billing.invoice.generator.InvoiceWithMetadata) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) DefaultNullInvoiceEvent(org.killbill.billing.invoice.api.user.DefaultNullInvoiceEvent) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) Currency(org.killbill.billing.catalog.api.Currency) AccountApiException(org.killbill.billing.account.api.AccountApiException) UUID(java.util.UUID) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 83 with InvoiceItem

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

the class InvoiceDispatcher method logInvoiceWithItems.

private void logInvoiceWithItems(final ImmutableAccountData account, final Invoice invoice, final LocalDate targetDate, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithItems) {
    final StringBuilder tmp = new StringBuilder();
    if (isRealInvoiceWithItems) {
        tmp.append(String.format("Generated invoiceId='%s', numberOfItems='%d', accountId='%s', targetDate='%s':", invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate));
    } else {
        final String adjustedInvoices = JOINER_COMMA.join(adjustedUniqueOtherInvoiceId.toArray(new UUID[adjustedUniqueOtherInvoiceId.size()]));
        tmp.append(String.format("Adjusting existing invoiceId='%s', numberOfItems='%d', accountId='%s', targetDate='%s':\n", adjustedInvoices, invoice.getNumberOfItems(), account.getId(), targetDate));
    }
    for (final InvoiceItem item : invoice.getInvoiceItems()) {
        tmp.append(String.format("\n\t item = %s", item));
    }
    log.info(tmp.toString());
}
Also used : RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) UUID(java.util.UUID)

Example 84 with InvoiceItem

use of org.killbill.billing.invoice.api.InvoiceItem 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);
    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 (InvoiceItemModelDao item : draftParentInvoice.getInvoiceItems()) {
            if ((item.getChildAccountId() != null) && item.getChildAccountId().equals(childInvoice.getAccountId())) {
                // update child item amount for existing parent invoice item
                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);
        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, 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), 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) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) 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 85 with InvoiceItem

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

the class InvoiceDispatcher method computeCBAOnExistingInvoice.

private InvoiceItem computeCBAOnExistingInvoice(final Invoice invoice, final InternalCallContext context) throws InvoiceApiException {
    // Transformation to Invoice -> InvoiceModelDao
    final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
    final List<InvoiceItemModelDao> invoiceItemModelDaos = ImmutableList.copyOf(Collections2.transform(invoice.getInvoiceItems(), new Function<InvoiceItem, InvoiceItemModelDao>() {

        @Override
        public InvoiceItemModelDao apply(final InvoiceItem input) {
            return new InvoiceItemModelDao(input);
        }
    }));
    invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
    final InvoiceItemModelDao cbaItem = invoiceDao.doCBAComplexity(invoiceModelDao, context);
    return cbaItem != null ? InvoiceItemFactory.fromModelDao(cbaItem) : null;
}
Also used : Function(com.google.common.base.Function) RecurringInvoiceItem(org.killbill.billing.invoice.model.RecurringInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ItemAdjInvoiceItem(org.killbill.billing.invoice.model.ItemAdjInvoiceItem) FixedPriceInvoiceItem(org.killbill.billing.invoice.model.FixedPriceInvoiceItem) ParentInvoiceItem(org.killbill.billing.invoice.model.ParentInvoiceItem) InvoiceItemModelDao(org.killbill.billing.invoice.dao.InvoiceItemModelDao) InvoiceModelDao(org.killbill.billing.invoice.dao.InvoiceModelDao)

Aggregations

InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)168 LocalDate (org.joda.time.LocalDate)118 Test (org.testng.annotations.Test)109 BigDecimal (java.math.BigDecimal)103 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)97 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)92 ItemAdjInvoiceItem (org.killbill.billing.invoice.model.ItemAdjInvoiceItem)79 RepairAdjInvoiceItem (org.killbill.billing.invoice.model.RepairAdjInvoiceItem)76 UUID (java.util.UUID)68 Invoice (org.killbill.billing.invoice.api.Invoice)57 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)36 ExternalChargeInvoiceItem (org.killbill.billing.invoice.model.ExternalChargeInvoiceItem)32 BillingEvent (org.killbill.billing.junction.BillingEvent)27 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)25 ArrayList (java.util.ArrayList)23 DateTime (org.joda.time.DateTime)23 MockPlan (org.killbill.billing.catalog.MockPlan)23 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)23 Plan (org.killbill.billing.catalog.api.Plan)22 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)21