public List<InvoiceItem> dispatchToInvoicePluginsAndInsertItems( final UUID accountId, final boolean isDryRun, final WithAccountLock withAccountLock, final CallContext context) throws InvoiceApiException { GlobalLock lock = null; try { lock = locker.lockWithNumberOfTries( LockerType.ACCNT_INV_PAY.toString(), accountId.toString(), invoiceConfig.getMaxGlobalLockRetries()); final Iterable<Invoice> invoicesForPlugins = withAccountLock.prepareInvoices(); final List<InvoiceModelDao> invoiceModelDaos = new LinkedList<InvoiceModelDao>(); for (final Invoice invoiceForPlugin : invoicesForPlugins) { // Call plugin final List<InvoiceItem> additionalInvoiceItems = invoicePluginDispatcher.getAdditionalInvoiceItems(invoiceForPlugin, isDryRun, context); invoiceForPlugin.addInvoiceItems(additionalInvoiceItems); // Transformation to InvoiceModelDao final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoiceForPlugin); final List<InvoiceItem> invoiceItems = invoiceForPlugin.getInvoiceItems(); final List<InvoiceItemModelDao> invoiceItemModelDaos = toInvoiceItemModelDao(invoiceItems); invoiceModelDao.addInvoiceItems(invoiceItemModelDaos); // Keep track of modified invoices invoiceModelDaos.add(invoiceModelDao); } final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(accountId, context); final List<InvoiceItemModelDao> createdInvoiceItems = dao.createInvoices(invoiceModelDaos, internalCallContext); return fromInvoiceItemModelDao(createdInvoiceItems); } catch (final LockFailedException e) { log.error( String.format("Failed to process invoice items for account %s", accountId.toString()), e); return ImmutableList.<InvoiceItem>of(); } finally { if (lock != null) { lock.release(); } } }
public RawUsageOptimizerResult getConsumableInArrearUsage( final LocalDate firstEventStartDate, final LocalDate targetDate, final Iterable<InvoiceItem> existingUsageItems, final Map<String, Usage> knownUsage, final InternalCallContext internalCallContext) { final LocalDate targetStartDate = config.getMaxRawUsagePreviousPeriod() > 0 ? getOptimizedRawUsageStartDate( firstEventStartDate, targetDate, existingUsageItems, knownUsage) : firstEventStartDate; log.info( "RawUsageOptimizer [accountRecordId = {}]: rawUsageStartDate = {}, (proposed) firstEventStartDate = {}", new Object[] { internalCallContext.getAccountRecordId(), targetStartDate, firstEventStartDate }); final List<RawUsage> rawUsageData = usageApi.getRawUsageForAccount(targetStartDate, targetDate, internalCallContext); return new RawUsageOptimizerResult(firstEventStartDate, targetStartDate, rawUsageData); }
@VisibleForTesting LocalDate getOptimizedRawUsageStartDate( final LocalDate firstEventStartDate, final LocalDate targetDate, final Iterable<InvoiceItem> existingUsageItems, final Map<String, Usage> knownUsage) { 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 // final LocalDate[] perBillingPeriodMostRecentConsumableInArrearItemEndDate = new LocalDate[BillingPeriod.values().length - 1]; // Exclude the NO_BILLING_PERIOD int idx = 0; for (BillingPeriod bp : BillingPeriod.values()) { if (bp != BillingPeriod.NO_BILLING_PERIOD) { final LocalDate makerDateThanCannotBeChosenAsTheMinOfAllDates = targetDate.plusMonths(config.getMaxRawUsagePreviousPeriod() * bp.getNumberOfMonths()); 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 (BillingPeriod bp : BillingPeriod.values()) { if (bp != BillingPeriod.NO_BILLING_PERIOD) { final LocalDate tmp = perBillingPeriodMostRecentConsumableInArrearItemEndDate[idx]; final LocalDate targetBillingPeriodDate = tmp != null ? tmp.minusMonths(config.getMaxRawUsagePreviousPeriod() * bp.getNumberOfMonths()) : null; if (targetStartDate == null || (targetBillingPeriodDate != null && targetBillingPeriodDate.compareTo(targetStartDate) < 0)) { targetStartDate = targetBillingPeriodDate; } idx++; } } final LocalDate result = targetStartDate.compareTo(firstEventStartDate) > 0 ? targetStartDate : firstEventStartDate; return result; }