killbill-aplcache

Merge branch 'work-for-release-0.17.x' of github.com:killbill/killbill

7/8/2016 4:11:00 PM

Details

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
index 1370254..55106c2 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/FixedAndRecurringInvoiceItemGenerator.java
@@ -48,12 +48,10 @@ import org.killbill.billing.invoice.tree.AccountItemTree;
 import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.util.currency.KillBillMoney;
-import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.inject.Inject;
 
 import static org.killbill.billing.invoice.generator.InvoiceDateUtils.calculateNumberOfWholeBillingPeriods;
 import static org.killbill.billing.invoice.generator.InvoiceDateUtils.calculateProRationAfterLastBillingCycleDate;
@@ -63,16 +61,9 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
 
     private static final Logger log = LoggerFactory.getLogger(FixedAndRecurringInvoiceItemGenerator.class);
 
-    private final Clock clock;
-
-    @Inject
-    public FixedAndRecurringInvoiceItemGenerator(final Clock clock) {
-        this.clock = clock;
-    }
-
     public List<InvoiceItem> generateItems(final ImmutableAccountData account, final UUID invoiceId, final BillingEventSet eventSet,
                                            @Nullable final List<Invoice> existingInvoices, final LocalDate targetDate,
-                                           final Currency targetCurrency, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
+                                           final Currency targetCurrency, final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                            final InternalCallContext internalCallContext) throws InvoiceApiException {
         final AccountItemTree accountItemTree = new AccountItemTree(account.getId(), invoiceId);
         if (existingInvoices != null) {
@@ -100,16 +91,12 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
                                                final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                                @Nullable final List<Invoice> existingInvoices,
                                                final InternalCallContext internalCallContext) throws InvoiceApiException {
-        if (events.size() == 0) {
+        if (events.isEmpty()) {
             return;
         }
 
         // Pretty-print the generated invoice items from the junction events
-        final StringBuilder logStringBuilder = new StringBuilder("Proposed Invoice items for invoiceId='")
-                .append(invoiceId)
-                .append("', accountId='")
-                .append(accountId)
-                .append("'");
+        final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger = new InvoiceItemGeneratorLogger(invoiceId, accountId, "recurring", log);
 
         final Iterator<BillingEvent> eventIt = events.iterator();
         BillingEvent nextEvent = eventIt.next();
@@ -119,29 +106,34 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
             if (!events.getSubscriptionIdsWithAutoInvoiceOff().
                     contains(thisEvent.getSubscription().getId())) { // don't consider events for subscriptions that have auto_invoice_off
                 final BillingEvent adjustedNextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
-                final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency, logStringBuilder, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
+                final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, currency, invoiceItemGeneratorLogger, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
                 proposedItems.addAll(newProposedItems);
             }
         }
-        final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, nextEvent, null, targetDate, currency, logStringBuilder, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
+        final List<InvoiceItem> newProposedItems = processRecurringEvent(invoiceId, accountId, nextEvent, null, targetDate, currency, invoiceItemGeneratorLogger, events.getRecurringBillingMode(), perSubscriptionFutureNotificationDate, internalCallContext);
 
         proposedItems.addAll(newProposedItems);
 
-        log.info(logStringBuilder.toString());
-
-        return;
+        invoiceItemGeneratorLogger.logItems();
     }
 
     @VisibleForTesting
     void processFixedBillingEvents(final UUID invoiceId, final UUID accountId, final BillingEventSet events, final LocalDate targetDate,
                                    final Currency currency, final List<InvoiceItem> proposedItems, final InternalCallContext internalCallContext) throws InvoiceApiException {
+        if (events.isEmpty()) {
+            return;
+        }
+
         InvoiceItem prevItem = null;
 
+        // Pretty-print the generated invoice items from the junction events
+        final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger = new InvoiceItemGeneratorLogger(invoiceId, accountId, "fixed", log);
+
         final Iterator<BillingEvent> eventIt = events.iterator();
         while (eventIt.hasNext()) {
             final BillingEvent thisEvent = eventIt.next();
 
-            final InvoiceItem currentFixedPriceItem = generateFixedPriceItem(invoiceId, accountId, thisEvent, targetDate, currency, internalCallContext);
+            final InvoiceItem currentFixedPriceItem = generateFixedPriceItem(invoiceId, accountId, thisEvent, targetDate, currency, invoiceItemGeneratorLogger, internalCallContext);
             if (!isSameDayAndSameSubscription(prevItem, thisEvent, internalCallContext) && prevItem != null) {
                 proposedItems.add(prevItem);
             }
@@ -151,6 +143,8 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
         if (prevItem != null) {
             proposedItems.add(prevItem);
         }
+
+        invoiceItemGeneratorLogger.logItems();
     }
 
     @VisibleForTesting
@@ -168,12 +162,11 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
     // Turn a set of events into a list of invoice items. Note that the dates on the invoice items will be rounded (granularity of a day)
     private List<InvoiceItem> processRecurringEvent(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
                                                     final LocalDate targetDate, final Currency currency,
-                                                    final StringBuilder logStringBuilder, final BillingMode billingMode,
+                                                    final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger, final BillingMode billingMode,
                                                     final Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                                     final InternalCallContext internalCallContext) throws InvoiceApiException {
 
         try {
-
             final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
 
             // For FIXEDTERM phases we need to stop when the specified duration has been reached
@@ -194,7 +187,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
                     final RecurringInvoiceItemDataWithNextBillingCycleDate itemDataWithNextBillingCycleDate;
                     try {
                         itemDataWithNextBillingCycleDate = generateInvoiceItemData(startDate, endDate, targetDate, billCycleDayLocal, billingPeriod, billingMode);
-                    } catch (InvalidDateSequenceException e) {
+                    } catch (final InvalidDateSequenceException e) {
                         throw new InvoiceApiException(ErrorCode.INVOICE_INVALID_DATE_SEQUENCE, startDate, endDate, targetDate);
                     }
                     for (final RecurringInvoiceItemData itemDatum : itemDataWithNextBillingCycleDate.getItemData()) {
@@ -224,14 +217,9 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
             }
 
             // For debugging purposes
-            logStringBuilder.append("\n")
-                            .append(thisEvent);
-            for (final InvoiceItem item : items) {
-                logStringBuilder.append("\n\t")
-                                .append(item);
-            }
-            return items;
+            invoiceItemGeneratorLogger.append(thisEvent, items);
 
+            return items;
         } catch (final CatalogApiException e) {
             throw new InvoiceApiException(e);
         }
@@ -334,7 +322,7 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
 
         for (int i = 0; i < numberOfWholeBillingPeriods; i++) {
             final LocalDate servicePeriodStartDate;
-            if (results.size() > 0) {
+            if (!results.isEmpty()) {
                 // Make sure the periods align, especially with the pro-ration calculations above
                 servicePeriodStartDate = results.get(results.size() - 1).getEndDate();
             } else if (i == 0) {
@@ -365,7 +353,8 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
     }
 
     private InvoiceItem generateFixedPriceItem(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent,
-                                               final LocalDate targetDate, final Currency currency, final InternalCallContext internalCallContext) throws InvoiceApiException {
+                                               final LocalDate targetDate, final Currency currency,
+                                               final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger, final InternalCallContext internalCallContext) throws InvoiceApiException {
         final LocalDate roundedStartDate = internalCallContext.toLocalDate(thisEvent.getEffectiveDate());
         if (roundedStartDate.isAfter(targetDate)) {
             return null;
@@ -373,10 +362,15 @@ public class FixedAndRecurringInvoiceItemGenerator extends InvoiceItemGenerator 
             final BigDecimal fixedPrice = thisEvent.getFixedPrice();
 
             if (fixedPrice != null) {
-                return new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(),
-                                                 thisEvent.getSubscription().getId(),
-                                                 thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
-                                                 roundedStartDate, fixedPrice, currency);
+                final FixedPriceInvoiceItem fixedPriceInvoiceItem = new FixedPriceInvoiceItem(invoiceId, accountId, thisEvent.getSubscription().getBundleId(),
+                                                                                              thisEvent.getSubscription().getId(),
+                                                                                              thisEvent.getPlan().getName(), thisEvent.getPlanPhase().getName(),
+                                                                                              roundedStartDate, fixedPrice, currency);
+
+                // For debugging purposes
+                invoiceItemGeneratorLogger.append(thisEvent, fixedPriceInvoiceItem);
+
+                return fixedPriceInvoiceItem;
             } else {
                 return null;
             }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
index d9b3090..eb2ce88 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/InvoiceItemGenerator.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -17,6 +17,7 @@
 
 package org.killbill.billing.invoice.generator;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -32,6 +33,7 @@ import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates;
 import org.killbill.billing.junction.BillingEventSet;
+import org.slf4j.Logger;
 
 public abstract class InvoiceItemGenerator {
 
@@ -40,4 +42,60 @@ public abstract class InvoiceItemGenerator {
                                                     final Currency targetCurrency, Map<UUID, SubscriptionFutureNotificationDates> perSubscriptionFutureNotificationDate,
                                                     final InternalCallContext context) throws InvoiceApiException;
 
+    public static class InvoiceItemGeneratorLogger {
+
+        private final UUID invoiceId;
+        private final UUID accountId;
+        private final String type;
+        private final Logger delegate;
+
+        private StringBuilder logStringBuilder = null;
+
+        public InvoiceItemGeneratorLogger(final UUID invoiceId, final UUID accountId, final String type, final Logger delegate) {
+            this.invoiceId = invoiceId;
+            this.accountId = accountId;
+            this.type = type;
+            this.delegate = delegate;
+        }
+
+        public void append(final Object event, final Collection<InvoiceItem> items) {
+            if (items.isEmpty()) {
+                return;
+            }
+            append(event, items.toArray(new InvoiceItem[items.size()]));
+        }
+
+        public void append(final Object event, final InvoiceItem... items) {
+            if (items.length == 0) {
+                return;
+            }
+
+            getLogStringBuilder().append("\n")
+                                 .append(event);
+
+            for (final InvoiceItem item : items) {
+                getLogStringBuilder().append("\n\t")
+                                     .append(item);
+            }
+        }
+
+        public void logItems() {
+            if (logStringBuilder != null) {
+                delegate.info(getLogStringBuilder().toString());
+            }
+        }
+
+        private StringBuilder getLogStringBuilder() {
+            if (logStringBuilder == null) {
+                logStringBuilder = new StringBuilder("Proposed ").append(type)
+                                                                 .append(" items for invoiceId='")
+                                                                 .append(invoiceId)
+                                                                 .append("', accountId='")
+                                                                 .append(accountId)
+                                                                 .append("'");
+            }
+
+            return logStringBuilder;
+        }
+    }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
index d94b8f9..850b8a6 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/UsageInvoiceItemGenerator.java
@@ -79,6 +79,8 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
                                            final InternalCallContext internalCallContext) throws InvoiceApiException {
         final Map<UUID, List<InvoiceItem>> perSubscriptionConsumableInArrearUsageItems = extractPerSubscriptionExistingConsumableInArrearUsageItems(eventSet.getUsages(), existingInvoices);
         try {
+            // Pretty-print the generated invoice items from the junction events
+            final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger = new InvoiceItemGeneratorLogger(invoiceId, account.getId(), "usage", log);
 
             final LocalDate minBillingEventDate = getMinBillingEventDate(eventSet, internalCallContext);
 
@@ -118,7 +120,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
                     final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(account.getId(), invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate(), internalCallContext);
                     final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
 
-                    final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
+                    final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of(), invoiceItemGeneratorLogger);
                     final List<InvoiceItem> newInArrearUsageItems = subscriptionResult.getInvoiceItems();
                     items.addAll(newInArrearUsageItems);
                     updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, subscriptionResult.getPerUsageNotificationDates(), BillingMode.IN_ARREAR, perSubscriptionFutureNotificationDates);
@@ -131,23 +133,23 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
                 final SubscriptionConsumableInArrear subscriptionConsumableInArrear = new SubscriptionConsumableInArrear(account.getId(), invoiceId, curEvents, rawUsageOptimizerResult.getRawUsage(), targetDate, rawUsageOptimizerResult.getRawUsageStartDate(), internalCallContext);
                 final List<InvoiceItem> consumableInUsageArrearItems = perSubscriptionConsumableInArrearUsageItems.get(curSubscriptionId);
 
-                final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of());
+                final SubscriptionConsumableInArrearItemsAndNextNotificationDate subscriptionResult = subscriptionConsumableInArrear.computeMissingUsageInvoiceItems(consumableInUsageArrearItems != null ? consumableInUsageArrearItems : ImmutableList.<InvoiceItem>of(), invoiceItemGeneratorLogger);
                 final List<InvoiceItem> newInArrearUsageItems = subscriptionResult.getInvoiceItems();
                 items.addAll(newInArrearUsageItems);
                 updatePerSubscriptionNextNotificationUsageDate(curSubscriptionId, subscriptionResult.getPerUsageNotificationDates(), BillingMode.IN_ARREAR, perSubscriptionFutureNotificationDates);
             }
-            return items;
 
-        } catch (CatalogApiException e) {
+            invoiceItemGeneratorLogger.logItems();
+
+            return items;
+        } catch (final CatalogApiException e) {
             throw new InvoiceApiException(e);
         }
     }
 
     private LocalDate getMinBillingEventDate(final BillingEventSet eventSet, final InternalCallContext internalCallContext) {
         DateTime minDate = null;
-        final Iterator<BillingEvent> events = eventSet.iterator();
-        while (events.hasNext()) {
-            final BillingEvent cur = events.next();
+        for (final BillingEvent cur : eventSet) {
             if (minDate == null || minDate.compareTo(cur.getEffectiveDate()) > 0) {
                 minDate = cur.getEffectiveDate();
             }
@@ -171,7 +173,6 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
     }
 
     private Map<UUID, List<InvoiceItem>> extractPerSubscriptionExistingConsumableInArrearUsageItems(final Map<String, Usage> knownUsage, @Nullable final List<Invoice> existingInvoices) {
-
         if (existingInvoices == null || existingInvoices.isEmpty()) {
             return ImmutableMap.of();
         }
@@ -194,7 +195,7 @@ public class UsageInvoiceItemGenerator extends InvoiceItemGenerator {
             }
         }));
 
-        for (InvoiceItem cur : usageConsumableInArrearItems) {
+        for (final InvoiceItem cur : usageConsumableInArrearItems) {
             List<InvoiceItem> perSubscriptionUsageItems = result.get(cur.getSubscriptionId());
             if (perSubscriptionUsageItems == null) {
                 perSubscriptionUsageItems = new LinkedList<InvoiceItem>();
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index 97cb002..dff9142 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -460,14 +460,14 @@ public class InvoiceDispatcher {
     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':\n", invoice.getId(), invoice.getNumberOfItems(), account.getId(), targetDate));
+            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("\t item = %s\n", item));
+            tmp.append(String.format("\n\t item = %s", item));
         }
         log.info(tmp.toString());
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
index 3e9c5e8..65f5449 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/ContiguousIntervalConsumableInArrear.java
@@ -105,7 +105,6 @@ public class ContiguousIntervalConsumableInArrear {
      *
      * @param closedInterval whether there was a last billing event referencing the usage section or whether this is ongoing and
      *                       then targetDate will define the endDate.
-     * @return
      */
     public ContiguousIntervalConsumableInArrear build(final boolean closedInterval) {
 
@@ -143,30 +142,10 @@ public class ContiguousIntervalConsumableInArrear {
         return this;
     }
 
-    public class ConsumableInArrearItemsAndNextNotificationDate {
-        private final List<InvoiceItem> invoiceItems;
-        private final LocalDate nextNotificationDate;
-
-        public ConsumableInArrearItemsAndNextNotificationDate(final List<InvoiceItem> invoiceItems, final LocalDate nextNotificationDate) {
-            this.invoiceItems = invoiceItems;
-            this.nextNotificationDate = nextNotificationDate;
-        }
-
-        public List<InvoiceItem> getInvoiceItems() {
-            return invoiceItems;
-        }
-
-        public LocalDate getNextNotificationDate() {
-            return nextNotificationDate;
-        }
-    }
-
-
     /**
      * Compute the missing usage invoice items based on what should be billed and what has been billed ($ amount comparison).
      *
      * @param existingUsage existing on disk usage items for the subscription
-     * @return
      * @throws CatalogApiException
      */
     public ConsumableInArrearItemsAndNextNotificationDate computeMissingItemsAndNextNotificationDate(final List<InvoiceItem> existingUsage) throws CatalogApiException {
@@ -183,10 +162,10 @@ public class ContiguousIntervalConsumableInArrear {
         // We start by generating 'marker' USAGE items with $0 that will allow to correctly insert the next notification for when there is no USAGE to bill.
         // Those will be removed by the invoicing code later so as to not end up with superfluous $0 items
         LocalDate prevDate = null;
-        for (LocalDate curDate : transitionTimes) {
+        for (final LocalDate curDate : transitionTimes) {
             if (prevDate != null) {
-                InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
-                                                        getPhaseName(), usage.getName(), prevDate, curDate, BigDecimal.ZERO, getCurrency());
+                final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
+                                                              getPhaseName(), usage.getName(), prevDate, curDate, BigDecimal.ZERO, getCurrency());
                 result.add(item);
             }
             prevDate = curDate;
@@ -213,8 +192,8 @@ public class ContiguousIntervalConsumableInArrear {
             if (!billedItems.iterator().hasNext() || billedUsage.compareTo(toBeBilledUsage) < 0) {
                 final BigDecimal amountToBill = toBeBilledUsage.subtract(billedUsage);
                 if (amountToBill.compareTo(BigDecimal.ZERO) > 0) {
-                    InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
-                                                            getPhaseName(), usage.getName(), ru.getStart(), ru.getEnd(), amountToBill, getCurrency());
+                    final InvoiceItem item = new UsageInvoiceItem(invoiceId, accountId, getBundleId(), getSubscriptionId(), getPlanName(),
+                                                                  getPhaseName(), usage.getName(), ru.getStart(), ru.getEnd(), amountToBill, getCurrency());
                     result.add(item);
                 }
             }
@@ -246,10 +225,8 @@ public class ContiguousIntervalConsumableInArrear {
         return result;
     }
 
-
     @VisibleForTesting
     List<RolledUpUsage> getRolledUpUsage() {
-
         final Iterator<RawUsage> rawUsageIterator = rawSubscriptionUsage.iterator();
         if (!rawUsageIterator.hasNext()) {
             return ImmutableList.of();
@@ -281,7 +258,7 @@ public class ContiguousIntervalConsumableInArrear {
         // matching RolledUpUsage for that interval, and we'll detect that in the 'computeMissingItems' logic
         //
         LocalDate prevDate = null;
-        for (LocalDate curDate : transitionTimes) {
+        for (final LocalDate curDate : transitionTimes) {
 
             if (prevDate != null) {
 
@@ -291,8 +268,8 @@ public class ContiguousIntervalConsumableInArrear {
                 // Start consuming prevRawUsage element if it exists and falls into the range
                 if (prevRawUsage != null) {
                     if (prevRawUsage.getDate().compareTo(prevDate) >= 0 && prevRawUsage.getDate().compareTo(curDate) < 0) {
-                        Long currentAmount = perRangeUnitToAmount.get(prevRawUsage.getUnitType());
-                        Long updatedAmount = (currentAmount != null) ? currentAmount + prevRawUsage.getAmount() : prevRawUsage.getAmount();
+                        final Long currentAmount = perRangeUnitToAmount.get(prevRawUsage.getUnitType());
+                        final Long updatedAmount = (currentAmount != null) ? currentAmount + prevRawUsage.getAmount() : prevRawUsage.getAmount();
                         perRangeUnitToAmount.put(prevRawUsage.getUnitType(), updatedAmount);
                         prevRawUsage = null;
                     }
@@ -312,8 +289,8 @@ public class ContiguousIntervalConsumableInArrear {
                             break;
                         }
 
-                        Long currentAmount = perRangeUnitToAmount.get(curRawUsage.getUnitType());
-                        Long updatedAmount = (currentAmount != null) ? currentAmount + curRawUsage.getAmount() : curRawUsage.getAmount();
+                        final Long currentAmount = perRangeUnitToAmount.get(curRawUsage.getUnitType());
+                        final Long updatedAmount = (currentAmount != null) ? currentAmount + curRawUsage.getAmount() : curRawUsage.getAmount();
                         perRangeUnitToAmount.put(curRawUsage.getUnitType(), updatedAmount);
                     }
                 }
@@ -346,7 +323,7 @@ public class ContiguousIntervalConsumableInArrear {
         BigDecimal result = BigDecimal.ZERO;
         final List<TieredBlock> tieredBlocks = getConsumableInArrearTieredBlocks(usage, unitType);
         int remainingUnits = nbUnits.intValue();
-        for (TieredBlock tieredBlock : tieredBlocks) {
+        for (final TieredBlock tieredBlock : tieredBlocks) {
 
             final int blockTierSize = tieredBlock.getSize().intValue();
             final int tmp = remainingUnits / blockTierSize + (remainingUnits % blockTierSize == 0 ? 0 : 1);
@@ -372,7 +349,7 @@ public class ContiguousIntervalConsumableInArrear {
 
         Preconditions.checkState(isBuilt.get());
         BigDecimal billedAmount = BigDecimal.ZERO;
-        for (InvoiceItem ii : filteredUsageForInterval) {
+        for (final InvoiceItem ii : filteredUsageForInterval) {
             billedAmount = billedAmount.add(ii.getAmount());
         }
         // Return the billed $ amount (not the # of units)
@@ -415,7 +392,6 @@ public class ContiguousIntervalConsumableInArrear {
         return billingEvents.get(0).getBillCycleDayLocal();
     }
 
-
     public UUID getBundleId() {
         return billingEvents.get(0).getSubscription().getBundleId();
     }
@@ -437,8 +413,33 @@ public class ContiguousIntervalConsumableInArrear {
         return billingEvents.get(0).getCurrency();
     }
 
-    public DateTimeZone getAccountTimeZone() {
-        return billingEvents.get(0).getTimeZone();
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("ContiguousIntervalConsumableInArrear{");
+        sb.append("transitionTimes=").append(transitionTimes);
+        sb.append(", billingEvents=").append(billingEvents);
+        sb.append(", rawSubscriptionUsage=").append(rawSubscriptionUsage);
+        sb.append(", rawUsageStartDate=").append(rawUsageStartDate);
+        sb.append('}');
+        return sb.toString();
     }
 
+    public class ConsumableInArrearItemsAndNextNotificationDate {
+
+        private final List<InvoiceItem> invoiceItems;
+        private final LocalDate nextNotificationDate;
+
+        public ConsumableInArrearItemsAndNextNotificationDate(final List<InvoiceItem> invoiceItems, final LocalDate nextNotificationDate) {
+            this.invoiceItems = invoiceItems;
+            this.nextNotificationDate = nextNotificationDate;
+        }
+
+        public List<InvoiceItem> getInvoiceItems() {
+            return invoiceItems;
+        }
+
+        public LocalDate getNextNotificationDate() {
+            return nextNotificationDate;
+        }
+    }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/RawUsageOptimizer.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/RawUsageOptimizer.java
index 854a91f..1d3efeb 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/RawUsageOptimizer.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/RawUsageOptimizer.java
@@ -68,15 +68,14 @@ public class RawUsageOptimizer {
 
     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(internalCallContext) > 0 ? getOptimizedRawUsageStartDate(firstEventStartDate, targetDate, existingUsageItems, knownUsage, internalCallContext) : firstEventStartDate;
-        log.info("ConsumableInArrear accountRecordId='{}', rawUsageStartDate='{}', firstEventStartDate='{}'",
-                 internalCallContext.getAccountRecordId(), targetStartDate, firstEventStartDate);
+        log.debug("ConsumableInArrear accountRecordId='{}', rawUsageStartDate='{}', firstEventStartDate='{}'",
+                  internalCallContext.getAccountRecordId(), targetStartDate, firstEventStartDate);
         final List<RawUsage> rawUsageData = usageApi.getRawUsageForAccount(targetStartDate, targetDate, internalCallContext);
-        return new RawUsageOptimizerResult(firstEventStartDate, targetStartDate, rawUsageData);
+        return new RawUsageOptimizerResult(targetStartDate, rawUsageData);
     }
 
     @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;
 
@@ -99,7 +98,7 @@ public class RawUsageOptimizer {
         //
         final LocalDate[] perBillingPeriodMostRecentConsumableInArrearItemEndDate = new LocalDate[BillingPeriod.values().length - 1]; // Exclude the NO_BILLING_PERIOD
         int idx = 0;
-        for (BillingPeriod bp : BillingPeriod.values()) {
+        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;
@@ -124,7 +123,7 @@ public class RawUsageOptimizer {
         // Extract the min from all the dates
         LocalDate targetStartDate = null;
         idx = 0;
-        for (BillingPeriod bp : BillingPeriod.values()) {
+        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;
@@ -152,20 +151,14 @@ public class RawUsageOptimizer {
 
     public static class RawUsageOptimizerResult {
 
-        private final LocalDate firstEventStartDate;
         private final LocalDate rawUsageStartDate;
         private final List<RawUsage> rawUsage;
 
-        public RawUsageOptimizerResult(final LocalDate firstEventStartDate, final LocalDate rawUsageStartDate, final List<RawUsage> rawUsage) {
-            this.firstEventStartDate = firstEventStartDate;
+        public RawUsageOptimizerResult(final LocalDate rawUsageStartDate, final List<RawUsage> rawUsage) {
             this.rawUsageStartDate = rawUsageStartDate;
             this.rawUsage = rawUsage;
         }
 
-        public LocalDate getFirstEventStartDate() {
-            return firstEventStartDate;
-        }
-
         public LocalDate getRawUsageStartDate() {
             return rawUsageStartDate;
         }
@@ -174,5 +167,4 @@ public class RawUsageOptimizer {
             return rawUsage;
         }
     }
-
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
index 28b6aca..2f93a43 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/usage/SubscriptionConsumableInArrear.java
@@ -34,6 +34,7 @@ import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Usage;
 import org.killbill.billing.catalog.api.UsageType;
 import org.killbill.billing.invoice.api.InvoiceItem;
+import org.killbill.billing.invoice.generator.InvoiceItemGenerator.InvoiceItemGeneratorLogger;
 import org.killbill.billing.invoice.usage.ContiguousIntervalConsumableInArrear.ConsumableInArrearItemsAndNextNotificationDate;
 import org.killbill.billing.junction.BillingEvent;
 import org.killbill.billing.usage.RawUsage;
@@ -101,36 +102,35 @@ public class SubscriptionConsumableInArrear {
         }));
     }
 
-
     /**
      * Based on billing events, (@code existingUsage} and targetDate, figure out what remains to be billed.
      *
      * @param existingUsage the existing on disk usage items.
-     * @return
      * @throws CatalogApiException
      */
-    public SubscriptionConsumableInArrearItemsAndNextNotificationDate computeMissingUsageInvoiceItems(final List<InvoiceItem> existingUsage) throws CatalogApiException {
-
+    public SubscriptionConsumableInArrearItemsAndNextNotificationDate computeMissingUsageInvoiceItems(final List<InvoiceItem> existingUsage, final InvoiceItemGeneratorLogger invoiceItemGeneratorLogger) throws CatalogApiException {
         final SubscriptionConsumableInArrearItemsAndNextNotificationDate result = new SubscriptionConsumableInArrearItemsAndNextNotificationDate();
         final List<ContiguousIntervalConsumableInArrear> billingEventTransitionTimePeriods = computeInArrearUsageInterval();
-        for (ContiguousIntervalConsumableInArrear usageInterval : billingEventTransitionTimePeriods) {
-            result.addConsumableInArrearItemsAndNextNotificationDate(usageInterval.getUsage().getName(), usageInterval.computeMissingItemsAndNextNotificationDate(existingUsage));
+        for (final ContiguousIntervalConsumableInArrear usageInterval : billingEventTransitionTimePeriods) {
+            final ConsumableInArrearItemsAndNextNotificationDate newItemsAndDate = usageInterval.computeMissingItemsAndNextNotificationDate(existingUsage);
+
+            // For debugging purposes
+            invoiceItemGeneratorLogger.append(usageInterval, newItemsAndDate.getInvoiceItems());
+
+            result.addConsumableInArrearItemsAndNextNotificationDate(usageInterval.getUsage().getName(), newItemsAndDate);
         }
         return result;
     }
 
-
-
     @VisibleForTesting
     List<ContiguousIntervalConsumableInArrear> computeInArrearUsageInterval() {
-
         final List<ContiguousIntervalConsumableInArrear> usageIntervals = Lists.newLinkedList();
 
         final Map<String, ContiguousIntervalConsumableInArrear> inFlightInArrearUsageIntervals = new HashMap<String, ContiguousIntervalConsumableInArrear>();
 
         final Set<String> allSeenUsage = new HashSet<String>();
 
-        for (BillingEvent event : subscriptionBillingEvents) {
+        for (final BillingEvent event : subscriptionBillingEvents) {
 
             // Extract all in arrear /consumable usage section for that billing event.
             final List<Usage> usages = findConsumableInArrearUsages(event);
@@ -144,7 +144,7 @@ public class SubscriptionConsumableInArrear {
             // All inflight usage interval are candidates to be closed unless we see that current billing event referencing the same usage section.
             final Set<String> toBeClosed = new HashSet<String>(allSeenUsage);
 
-            for (Usage usage : usages) {
+            for (final Usage usage : usages) {
 
                 // Add inflight usage interval if non existent
                 ContiguousIntervalConsumableInArrear existingInterval = inFlightInArrearUsageIntervals.get(usage.getName());
@@ -159,7 +159,7 @@ public class SubscriptionConsumableInArrear {
             }
 
             // Build the usage interval that are no longer referenced
-            for (String usageName : toBeClosed) {
+            for (final String usageName : toBeClosed) {
                 final ContiguousIntervalConsumableInArrear interval = inFlightInArrearUsageIntervals.remove(usageName);
                 if (interval != null) {
                     interval.addBillingEvent(event);
@@ -167,20 +167,20 @@ public class SubscriptionConsumableInArrear {
                 }
             }
         }
-        for (String usageName : inFlightInArrearUsageIntervals.keySet()) {
+        for (final String usageName : inFlightInArrearUsageIntervals.keySet()) {
             usageIntervals.add(inFlightInArrearUsageIntervals.get(usageName).build(false));
         }
         inFlightInArrearUsageIntervals.clear();
         return usageIntervals;
     }
 
-    List<Usage> findConsumableInArrearUsages(final BillingEvent event) {
-        if (event.getUsages().size() == 0) {
+    private List<Usage> findConsumableInArrearUsages(final BillingEvent event) {
+        if (event.getUsages().isEmpty()) {
             return Collections.emptyList();
         }
 
         final List<Usage> result = Lists.newArrayList();
-        for (Usage usage : event.getUsages()) {
+        for (final Usage usage : event.getUsages()) {
             if (usage.getUsageType() != UsageType.CONSUMABLE ||
                 usage.getBillingMode() != BillingMode.IN_ARREAR) {
                 continue;
@@ -191,6 +191,7 @@ public class SubscriptionConsumableInArrear {
     }
 
     public class SubscriptionConsumableInArrearItemsAndNextNotificationDate {
+
         private List<InvoiceItem> invoiceItems;
         private Map<String, LocalDate> perUsageNotificationDates;
 
@@ -224,5 +225,4 @@ public class SubscriptionConsumableInArrear {
             return perUsageNotificationDates != null ? perUsageNotificationDates : ImmutableMap.<String, LocalDate>of();
         }
     }
-
 }
diff --git a/usage/src/main/java/org/killbill/billing/usage/api/svcs/DefaultRawUsage.java b/usage/src/main/java/org/killbill/billing/usage/api/svcs/DefaultRawUsage.java
index 7ce8718..f7a50f0 100644
--- a/usage/src/main/java/org/killbill/billing/usage/api/svcs/DefaultRawUsage.java
+++ b/usage/src/main/java/org/killbill/billing/usage/api/svcs/DefaultRawUsage.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -55,4 +55,15 @@ public class DefaultRawUsage implements RawUsage {
     public Long getAmount() {
         return amount;
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("DefaultRawUsage{");
+        sb.append("subscriptionId=").append(subscriptionId);
+        sb.append(", recordDate=").append(recordDate);
+        sb.append(", unitType='").append(unitType).append('\'');
+        sb.append(", amount=").append(amount);
+        sb.append('}');
+        return sb.toString();
+    }
 }