Search in sources :

Example 96 with InvoiceItem

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

the class SubscriptionItemTree method checkItemsListState.

// Verify there is no double billing, and no double repair (credits)
private void checkItemsListState(final List<InvoiceItem> orderedList) {
    LocalDate prevRecurringEndDate = null;
    LocalDate prevRepairEndDate = null;
    for (InvoiceItem cur : orderedList) {
        switch(cur.getInvoiceItemType()) {
            case FIXED:
                break;
            case RECURRING:
                if (prevRecurringEndDate != null) {
                    Preconditions.checkState(prevRecurringEndDate.compareTo(cur.getStartDate()) <= 0);
                }
                prevRecurringEndDate = cur.getEndDate();
                break;
            case REPAIR_ADJ:
                if (prevRepairEndDate != null) {
                    Preconditions.checkState(prevRepairEndDate.compareTo(cur.getStartDate()) <= 0);
                }
                prevRepairEndDate = cur.getEndDate();
                break;
            default:
                Preconditions.checkState(false, "Unexpected item type " + cur.getInvoiceItemType());
        }
    }
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) LocalDate(org.joda.time.LocalDate)

Example 97 with InvoiceItem

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

the class SubscriptionItemTree method build.

/**
     * Build the tree and process adjustments
     */
public void build() {
    Preconditions.checkState(!isBuilt);
    for (final InvoiceItem item : pendingItemAdj) {
        final Item fullyAdjustedItem = root.addAdjustment(item, targetInvoiceId);
        if (fullyAdjustedItem != null) {
            existingFullyAdjustedItems.add(fullyAdjustedItem);
        }
    }
    pendingItemAdj.clear();
    root.buildForExistingItems(items, targetInvoiceId);
    isBuilt = true;
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem)

Example 98 with InvoiceItem

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

the class RawUsageOptimizer method getOptimizedRawUsageStartDate.

@VisibleForTesting
LocalDate getOptimizedRawUsageStartDate(final LocalDate firstEventStartDate, final LocalDate targetDate, final Iterable<InvoiceItem> existingUsageItems, final Map<String, Usage> knownUsage, final InternalCallContext internalCallContext) {
    if (!existingUsageItems.iterator().hasNext()) {
        return firstEventStartDate;
    }
    // Extract all usage billing period known in that catalog
    final Set<BillingPeriod> knownUsageBillingPeriod = ImmutableSet.copyOf(Iterables.transform(knownUsage.values(), new Function<Usage, BillingPeriod>() {

        @Nullable
        @Override
        public BillingPeriod apply(final Usage input) {
            return input.getBillingPeriod();
        }
    }));
    // Make sure all usage items are sorted by endDate
    final List<InvoiceItem> sortedUsageItems = USAGE_ITEM_ORDERING.sortedCopy(existingUsageItems);
    // Compute an array with one date per BillingPeriod:
    // If BillingPeriod is never defined in the catalog (no need to look for items), we initialize its value
    // such that it cannot be chosen
    //
    // Exclude the NO_BILLING_PERIOD
    final LocalDate[] perBillingPeriodMostRecentConsumableInArrearItemEndDate = new LocalDate[BillingPeriod.values().length - 1];
    int idx = 0;
    for (final BillingPeriod bp : BillingPeriod.values()) {
        if (bp != BillingPeriod.NO_BILLING_PERIOD) {
            final LocalDate makerDateThanCannotBeChosenAsTheMinOfAllDates = InvoiceDateUtils.advanceByNPeriods(targetDate, bp, config.getMaxRawUsagePreviousPeriod(internalCallContext));
            perBillingPeriodMostRecentConsumableInArrearItemEndDate[idx++] = (knownUsageBillingPeriod.contains(bp)) ? null : makerDateThanCannotBeChosenAsTheMinOfAllDates;
        }
    }
    final ListIterator<InvoiceItem> iterator = sortedUsageItems.listIterator(sortedUsageItems.size());
    while (iterator.hasPrevious()) {
        final InvoiceItem previous = iterator.previous();
        Preconditions.checkState(previous instanceof UsageInvoiceItem);
        final UsageInvoiceItem item = (UsageInvoiceItem) previous;
        final Usage usage = knownUsage.get(item.getUsageName());
        if (perBillingPeriodMostRecentConsumableInArrearItemEndDate[usage.getBillingPeriod().ordinal()] == null) {
            perBillingPeriodMostRecentConsumableInArrearItemEndDate[usage.getBillingPeriod().ordinal()] = item.getEndDate();
            if (!containsNullEntries(perBillingPeriodMostRecentConsumableInArrearItemEndDate)) {
                break;
            }
        }
    }
    // Extract the min from all the dates
    LocalDate targetStartDate = null;
    idx = 0;
    for (final BillingPeriod bp : BillingPeriod.values()) {
        if (bp != BillingPeriod.NO_BILLING_PERIOD) {
            final LocalDate tmp = perBillingPeriodMostRecentConsumableInArrearItemEndDate[idx];
            final LocalDate targetBillingPeriodDate = tmp != null ? InvoiceDateUtils.recedeByNPeriods(tmp, bp, config.getMaxRawUsagePreviousPeriod(internalCallContext)) : null;
            if (targetStartDate == null || (targetBillingPeriodDate != null && targetBillingPeriodDate.compareTo(targetStartDate) < 0)) {
                targetStartDate = targetBillingPeriodDate;
            }
            idx++;
        }
    }
    final LocalDate result = targetStartDate.compareTo(firstEventStartDate) > 0 ? targetStartDate : firstEventStartDate;
    return result;
}
Also used : Function(com.google.common.base.Function) Usage(org.killbill.billing.catalog.api.Usage) RawUsage(org.killbill.billing.usage.RawUsage) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) UsageInvoiceItem(org.killbill.billing.invoice.model.UsageInvoiceItem) LocalDate(org.joda.time.LocalDate) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 99 with InvoiceItem

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

the class DefaultInvoiceUserApi method insertInvoiceItemAdjustment.

@Override
public InvoiceItem insertInvoiceItemAdjustment(final UUID accountId, final UUID invoiceId, final UUID invoiceItemId, final LocalDate effectiveDate, @Nullable final BigDecimal amount, @Nullable final Currency currency, final String description, final CallContext context) throws InvoiceApiException {
    if (amount != null && amount.compareTo(BigDecimal.ZERO) <= 0) {
        throw new InvoiceApiException(ErrorCode.INVOICE_ITEM_ADJUSTMENT_AMOUNT_SHOULD_BE_POSITIVE, amount);
    }
    final WithAccountLock withAccountLock = new WithAccountLock() {

        @Override
        public Iterable<Invoice> prepareInvoices() throws InvoiceApiException {
            final Invoice invoice = getInvoiceAndCheckCurrency(invoiceId, currency, context);
            final InvoiceItem adjustmentItem = invoiceApiHelper.createAdjustmentItem(invoice, invoiceItemId, amount, currency, effectiveDate, description, internalCallContextFactory.createInternalCallContext(accountId, context));
            invoice.addInvoiceItem(adjustmentItem);
            return ImmutableList.<Invoice>of(invoice);
        }
    };
    final Collection<InvoiceItem> adjustmentInvoiceItems = Collections2.<InvoiceItem>filter(invoiceApiHelper.dispatchToInvoicePluginsAndInsertItems(accountId, false, withAccountLock, context), new Predicate<InvoiceItem>() {

        @Override
        public boolean apply(final InvoiceItem invoiceItem) {
            return InvoiceItemType.ITEM_ADJ.equals(invoiceItem.getInvoiceItemType());
        }
    });
    Preconditions.checkState(adjustmentInvoiceItems.size() == 1, "Should have created a single adjustment item: " + adjustmentInvoiceItems);
    return adjustmentInvoiceItems.iterator().next();
}
Also used : InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) Invoice(org.killbill.billing.invoice.api.Invoice) HtmlInvoice(org.killbill.billing.invoice.template.HtmlInvoice) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) WithAccountLock(org.killbill.billing.invoice.api.WithAccountLock)

Example 100 with InvoiceItem

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

the class DefaultInvoiceUserApi method insertExternalCharges.

@Override
public List<InvoiceItem> insertExternalCharges(final UUID accountId, final LocalDate effectiveDate, final Iterable<InvoiceItem> charges, final boolean autoCommit, final CallContext context) throws InvoiceApiException {
    for (final InvoiceItem charge : charges) {
        if (charge.getAmount() == null || charge.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new InvoiceApiException(ErrorCode.EXTERNAL_CHARGE_AMOUNT_INVALID, charge.getAmount());
        }
    }
    final WithAccountLock withAccountLock = new WithAccountLock() {

        @Override
        public Iterable<Invoice> prepareInvoices() throws InvoiceApiException {
            final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, context);
            final LocalDate invoiceDate = internalTenantContext.toLocalDate(context.getCreatedDate());
            // Group all new external charges on the same invoice (per currency)
            final Map<Currency, Invoice> newInvoicesForExternalCharges = new HashMap<Currency, Invoice>();
            final Map<UUID, Invoice> existingInvoicesForExternalCharges = new HashMap<UUID, Invoice>();
            for (final InvoiceItem charge : charges) {
                final Invoice invoiceForExternalCharge;
                final UUID invoiceIdForExternalCharge = charge.getInvoiceId();
                // Create an invoice for that external charge if it doesn't exist
                if (invoiceIdForExternalCharge == null) {
                    final Currency currency = charge.getCurrency();
                    if (newInvoicesForExternalCharges.get(currency) == null) {
                        final InvoiceStatus status = autoCommit ? InvoiceStatus.COMMITTED : InvoiceStatus.DRAFT;
                        final Invoice newInvoiceForExternalCharge = new DefaultInvoice(accountId, invoiceDate, effectiveDate, currency, status);
                        newInvoicesForExternalCharges.put(currency, newInvoiceForExternalCharge);
                    }
                    invoiceForExternalCharge = newInvoicesForExternalCharges.get(currency);
                } else {
                    if (existingInvoicesForExternalCharges.get(invoiceIdForExternalCharge) == null) {
                        final Invoice existingInvoiceForExternalCharge = getInvoice(invoiceIdForExternalCharge, context);
                        existingInvoicesForExternalCharges.put(invoiceIdForExternalCharge, existingInvoiceForExternalCharge);
                    }
                    invoiceForExternalCharge = existingInvoicesForExternalCharges.get(invoiceIdForExternalCharge);
                }
                final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(UUIDs.randomUUID(), context.getCreatedDate(), invoiceForExternalCharge.getId(), accountId, charge.getBundleId(), charge.getDescription(), effectiveDate, charge.getAmount(), charge.getCurrency());
                invoiceForExternalCharge.addInvoiceItem(externalCharge);
            }
            return Iterables.<Invoice>concat(newInvoicesForExternalCharges.values(), existingInvoicesForExternalCharges.values());
        }
    };
    return invoiceApiHelper.dispatchToInvoicePluginsAndInsertItems(accountId, false, withAccountLock, context);
}
Also used : InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CreditAdjInvoiceItem(org.killbill.billing.invoice.model.CreditAdjInvoiceItem) Invoice(org.killbill.billing.invoice.api.Invoice) HtmlInvoice(org.killbill.billing.invoice.template.HtmlInvoice) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice) HashMap(java.util.HashMap) WithAccountLock(org.killbill.billing.invoice.api.WithAccountLock) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) LocalDate(org.joda.time.LocalDate) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) Currency(org.killbill.billing.catalog.api.Currency) UUID(java.util.UUID) InvoiceStatus(org.killbill.billing.invoice.api.InvoiceStatus) DefaultInvoice(org.killbill.billing.invoice.model.DefaultInvoice)

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