killbill-aplcache

Merge remote-tracking branch 'origin/hierarchical-accounts'

7/11/2016 4:23:12 PM

Changes

pom.xml 2(+1 -1)

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index a01413c..ebf1e53 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -610,8 +610,8 @@ public class TestOverdueIntegration extends TestOverdueBase {
         // Should still be in clear state
         checkODState(OverdueWrapper.CLEAR_STATE_NAME);
 
-        // 2012-07-05 => DAY 65 - 35 days after invoice
-        addDaysAndCheckForCompletion(20, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT_ERROR);
+        // 2012-06-30 => DAY 65 - 30 days after invoice
+        addDaysAndCheckForCompletion(15, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT_ERROR);
 
         invoiceChecker.checkInvoice(account.getId(), 3, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 6, 30), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
         invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 7, 31), callContext);
@@ -627,14 +627,14 @@ public class TestOverdueIntegration extends TestOverdueBase {
         checkODState("OD1");
         checkChangePlanWithOverdueState(baseEntitlement, true, true);
 
-        // 2012-07-15 => DAY 75 - 45 days after invoice
+        // 2012-07-10 => DAY 75 - 40 days after invoice
         addDaysAndCheckForCompletion(8, NextEvent.BLOCK, NextEvent.TAG);
 
         // Should now be in OD2
         checkODState("OD2");
         checkChangePlanWithOverdueState(baseEntitlement, true, true);
 
-        // 2012-07-25 => DAY 85 - 55 days after invoice
+        // 2012-07-20 => DAY 85 - 50 days after invoice
         addDaysAndCheckForCompletion(10, NextEvent.BLOCK);
 
         // Should now be in OD3
@@ -652,26 +652,26 @@ public class TestOverdueIntegration extends TestOverdueBase {
 
         invoiceChecker.checkInvoice(account.getId(), 4, callContext,
                                     // Item for the blocked period
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 15), new LocalDate(2012, 7, 25), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-80.63")),
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 25), new LocalDate(2012, 7, 25), InvoiceItemType.CBA_ADJ, new BigDecimal("80.63")));
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 10), new LocalDate(2012, 7, 20), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-80.63")),
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 20), new LocalDate(2012, 7, 20), InvoiceItemType.CBA_ADJ, new BigDecimal("80.63")));
 
         invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 7, 31), callContext);
 
-        checkChangePlanWithOverdueState(baseEntitlement, false, false);
+        checkChangePlanWithOverdueState(baseEntitlement, false, true);
 
         invoiceChecker.checkInvoice(account.getId(), 4, callContext,
                                     // Item for the blocked period
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 15), new LocalDate(2012, 7, 25), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-80.63")),
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 25), new LocalDate(2012, 7, 25), InvoiceItemType.CBA_ADJ, new BigDecimal("80.63")));
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 10), new LocalDate(2012, 7, 20), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-80.63")),
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 20), new LocalDate(2012, 7, 20), InvoiceItemType.CBA_ADJ, new BigDecimal("80.63")));
 
         invoiceChecker.checkInvoice(account.getId(), 5, callContext,
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 25), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("116.12")),
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 25), new LocalDate(2012, 7, 31), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-48.38")),
-                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 25), new LocalDate(2012, 7, 25), InvoiceItemType.CBA_ADJ, new BigDecimal("-67.74")));
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 20), new LocalDate(2012, 7, 31), InvoiceItemType.RECURRING, new BigDecimal("212.89")),
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 20), new LocalDate(2012, 7, 31), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-88.69")),
+                                    new ExpectedInvoiceItemCheck(new LocalDate(2012, 7, 20), new LocalDate(2012, 7, 20), InvoiceItemType.CBA_ADJ, new BigDecimal("-80.63")));
 
         invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 7, 31), callContext);
 
-        assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(new BigDecimal("-12.89")), 0);
+        assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(BigDecimal.ZERO), 0);
     }
 
     @Test(groups = "slow", description = "Test overdue for draft external charge")
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index 3c3473a..a5e1c5c 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -88,7 +88,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
                 if (compared2 != 0) {
                     return compared2;
                 } else {
-                    // Default, stable, ordering
+                    // Default stable ordering (in the sense that doing twice the same call will lead to same result)
                     return o1.getId().compareTo(o2.getId());
                 }
             }
@@ -203,8 +203,8 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
             final SubscriptionBundle bundle = getSubscriptionBundle(cur.getId(), context);
             result.add(bundle);
         }
-
-        return result;
+        // Sorting by createdDate will likely place the active bundle last, but this is the same ordering we already use for getSubscriptionBundlesForAccount
+        return Ordering.from(SUBSCRIPTION_BUNDLE_COMPARATOR).sortedCopy(result);
     }
 
     @Override
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/notification/DefaultNextBillingDateNotifier.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
index 3131548..644cec3 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/DefaultNextBillingDateNotifier.java
@@ -44,7 +44,6 @@ public class DefaultNextBillingDateNotifier implements NextBillingDateNotifier {
     public static final String NEXT_BILLING_DATE_NOTIFIER_QUEUE = "next-billing-date-queue";
 
     private final NotificationQueueService notificationQueueService;
-    private final InvoiceConfig config;
     private final SubscriptionBaseInternalApi subscriptionApi;
     private final InvoiceListener listener;
     private final InternalCallContextFactory callContextFactory;
@@ -53,12 +52,10 @@ public class DefaultNextBillingDateNotifier implements NextBillingDateNotifier {
 
     @Inject
     public DefaultNextBillingDateNotifier(final NotificationQueueService notificationQueueService,
-                                          final InvoiceConfig config,
                                           final SubscriptionBaseInternalApi subscriptionApi,
                                           final InvoiceListener listener,
                                           final InternalCallContextFactory callContextFactory) {
         this.notificationQueueService = notificationQueueService;
-        this.config = config;
         this.subscriptionApi = subscriptionApi;
         this.listener = listener;
         this.callContextFactory = callContextFactory;
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/notification/ParentInvoiceCommitmentNotifier.java b/invoice/src/main/java/org/killbill/billing/invoice/notification/ParentInvoiceCommitmentNotifier.java
index 9760f46..a59e51b 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/notification/ParentInvoiceCommitmentNotifier.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/notification/ParentInvoiceCommitmentNotifier.java
@@ -42,21 +42,15 @@ public class ParentInvoiceCommitmentNotifier implements NextBillingDateNotifier 
     public static final String PARENT_INVOICE_COMMITMENT_NOTIFIER_QUEUE = "parent-invoice-commitment-queue";
 
     private final NotificationQueueService notificationQueueService;
-    private final InvoiceConfig config;
     private final InvoiceListener listener;
-    private final InternalCallContextFactory callContextFactory;
 
     private NotificationQueue commitInvoiceQueue;
 
     @Inject
     public ParentInvoiceCommitmentNotifier(final NotificationQueueService notificationQueueService,
-                                           final InvoiceConfig config,
-                                           final InvoiceListener listener,
-                                           final InternalCallContextFactory callContextFactory) {
+                                           final InvoiceListener listener) {
         this.notificationQueueService = notificationQueueService;
-        this.config = config;
         this.listener = listener;
-        this.callContextFactory = callContextFactory;
     }
 
     @Override
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/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 3508ed9..2b2c0a4 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -1118,7 +1118,7 @@ public class AccountResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Account not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final String accountIdString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
         final UUID accountId = UUID.fromString(accountIdString);
         return super.getTags(accountId, accountId, auditMode, includedDeleted, context.createContext(request));
@@ -1134,7 +1134,7 @@ public class AccountResource extends JaxRsResourceBase {
     public Response getAllTags(@PathParam(ID_PARAM_NAME) final String accountIdString,
                                @QueryParam(QUERY_OBJECT_TYPE) final ObjectType objectType,
                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                               @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                               @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
         final UUID accountId = UUID.fromString(accountIdString);
         final TenantContext tenantContext = context.createContext(request);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
index f32c0f3..daffae5 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/BundleResource.java
@@ -17,6 +17,7 @@
 package org.killbill.billing.jaxrs.resources;
 
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -74,6 +75,7 @@ import org.killbill.clock.Clock;
 import org.killbill.commons.metrics.TimedResource;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
 import com.wordnik.swagger.annotations.Api;
@@ -132,14 +134,26 @@ public class BundleResource extends JaxRsResourceBase {
     @ApiOperation(value = "Retrieve a bundle by external key", response = BundleJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Bundle not found")})
     public Response getBundleByKey(@QueryParam(QUERY_EXTERNAL_KEY) final String externalKey,
+                                   @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                                    @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException, AccountApiException, CatalogApiException {
 
         final TenantContext tenantContext = this.context.createContext(request);
 
-        final SubscriptionBundle bundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey(externalKey, tenantContext);
-        final Account account = accountUserApi.getAccountById(bundle.getAccountId(), tenantContext);
-        final BundleJson json = new BundleJson(bundle, account.getCurrency(), null);
-        return Response.status(Status.OK).entity(json).build();
+        final List<SubscriptionBundle> bundles;
+        if (includedDeleted) {
+            bundles = subscriptionApi.getSubscriptionBundlesForExternalKey(externalKey, tenantContext);
+        } else {
+            final SubscriptionBundle activeBundle = subscriptionApi.getActiveSubscriptionBundleForExternalKey(externalKey, tenantContext);
+            bundles = ImmutableList.of(activeBundle);
+        }
+
+        final List<BundleJson> result = new ArrayList<BundleJson>(bundles.size());
+        for (final SubscriptionBundle bundle : bundles) {
+            final Account account = accountUserApi.getAccountById(bundle.getAccountId(), tenantContext);
+            final BundleJson json = new BundleJson(bundle, account.getCurrency(), null);
+            result.add(json);
+        }
+        return Response.status(Status.OK).entity(result).build();
     }
 
     @TimedResource
@@ -333,7 +347,7 @@ public class BundleResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Bundle not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final String bundleIdString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
         final UUID bundleId = UUID.fromString(bundleIdString);
         final TenantContext tenantContext = context.createContext(request);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
index 74e1588..377dd1c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoicePaymentResource.java
@@ -294,7 +294,7 @@ public class InvoicePaymentResource extends JaxRsResourceBase {
     public Response getTags(@PathParam(ID_PARAM_NAME) final String paymentIdString,
                             @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, PaymentApiException {
         final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
         final UUID paymentId = UUID.fromString(paymentIdString);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 9d6b982..6811d99 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -925,7 +925,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Invoice not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final String invoiceIdString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, InvoiceApiException {
         final UUID invoiceId = UUID.fromString(invoiceIdString);
         final TenantContext tenantContext = context.createContext(request);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index d66420d..db3dc47 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -104,7 +104,6 @@ public interface JaxrsResource {
 
 
     public static final String QUERY_TAGS = "tagList";
-    public static final String QUERY_TAGS_INCLUDED_DELETED = "includedDeleted";
     public static final String QUERY_CUSTOM_FIELDS = "customFieldList";
 
     public static final String QUERY_OBJECT_TYPE = "objectType";
@@ -263,4 +262,7 @@ public interface JaxrsResource {
     public static final String BCD = "bcd";
     public static final String TRANSFER_CREDIT = "transferCredit";
 
+    public static final String QUERY_INCLUDED_DELETED = "includedDeleted";
+
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
index e770d05..5fb1531 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/SubscriptionResource.java
@@ -718,7 +718,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
                            @ApiResponse(code = 404, message = "Subscription not found")})
     public Response getTags(@PathParam(ID_PARAM_NAME) final String subscriptionIdString,
                             @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
-                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
+                            @QueryParam(QUERY_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, SubscriptionApiException {
         final UUID subscriptionId = UUID.fromString(subscriptionIdString);
         final TenantContext tenantContext = context.createContext(request);
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
index 37989fa..f78edf5 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -98,9 +98,9 @@ public class BlockingCalculator {
      *
      * @param billingEvents the original list of billing events to update (without overdue events)
      */
-    public void insertBlockingEvents(final SortedSet<BillingEvent> billingEvents, final Set<UUID> skippedSubscriptions, final InternalTenantContext context) throws CatalogApiException {
+    public boolean insertBlockingEvents(final SortedSet<BillingEvent> billingEvents, final Set<UUID> skippedSubscriptions, final InternalTenantContext context) throws CatalogApiException {
         if (billingEvents.size() <= 0) {
-            return;
+            return false;
         }
 
         final Hashtable<UUID, List<SubscriptionBase>> bundleMap = createBundleSubscriptionMap(billingEvents);
@@ -146,6 +146,8 @@ public class BlockingCalculator {
         for (final BillingEvent eventToRemove : billingEventsToRemove) {
             billingEvents.remove(eventToRemove);
         }
+
+        return !(billingEventsToAdd.isEmpty() && billingEventsToRemove.isEmpty());
     }
 
     final List<BlockingState> getAggregateBlockingEventsPerSubscription(final Iterable<BlockingState> subscriptionBlockingEvents, final Iterable<BlockingState> bundleBlockingEvents, final Iterable<BlockingState> accountBlockingEvents) {
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 70cf640..e556f31 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -70,66 +70,65 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultInternalBillingApi.class);
     private final AccountInternalApi accountApi;
-    private final BillCycleDayCalculator bcdCalculator;
     private final SubscriptionBaseInternalApi subscriptionApi;
     private final CatalogService catalogService;
     private final BlockingCalculator blockCalculator;
     private final TagInternalApi tagApi;
-    private final Clock clock;
 
     @Inject
     public DefaultInternalBillingApi(final AccountInternalApi accountApi,
-                                     final BillCycleDayCalculator bcdCalculator,
                                      final SubscriptionBaseInternalApi subscriptionApi,
                                      final BlockingCalculator blockCalculator,
                                      final CatalogService catalogService,
-                                     final TagInternalApi tagApi,
-                                     final Clock clock) {
+                                     final TagInternalApi tagApi) {
         this.accountApi = accountApi;
-        this.bcdCalculator = bcdCalculator;
         this.subscriptionApi = subscriptionApi;
         this.catalogService = catalogService;
         this.blockCalculator = blockCalculator;
         this.tagApi = tagApi;
-        this.clock = clock;
     }
 
     @Override
     public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final DryRunArguments dryRunArguments, final InternalCallContext context) throws CatalogApiException, AccountApiException {
-        final List<SubscriptionBaseBundle> bundles = subscriptionApi.getBundlesForAccount(accountId, context);
         final StaticCatalog currentCatalog = catalogService.getCurrentCatalog(context);
 
-        final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
-        final DefaultBillingEventSet result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode());
+        // Check to see if billing is off for the account
+        final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
+        final boolean found_AUTO_INVOICING_OFF = is_AUTO_INVOICING_OFF(accountTags);
+        if (found_AUTO_INVOICING_OFF) {
+            return new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode()); // billing is off, we are done
+        }
 
+        final List<SubscriptionBaseBundle> bundles = subscriptionApi.getBundlesForAccount(accountId, context);
 
+        final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
+        final DefaultBillingEventSet result = new DefaultBillingEventSet(false, currentCatalog.getRecurringBillingMode());
 
         final Set<UUID> skippedSubscriptions = new HashSet<UUID>();
         try {
-            // Check to see if billing is off for the account
-            final List<Tag> accountTags = tagApi.getTags(accountId, ObjectType.ACCOUNT, context);
-            final boolean found_AUTO_INVOICING_OFF = is_AUTO_INVOICING_OFF(accountTags);
-            if (found_AUTO_INVOICING_OFF) {
-                return new DefaultBillingEventSet(true, currentCatalog.getRecurringBillingMode()); // billing is off, we are done
-            }
-
             addBillingEventsForBundles(bundles, account, dryRunArguments, context, result, skippedSubscriptions);
-        } catch (SubscriptionBaseApiException e) {
+        } catch (final SubscriptionBaseApiException e) {
             log.warn("Failed while getting BillingEvent", e);
         }
 
+        if (result.isEmpty()) {
+            log.info("No billing event for accountId='{}'", accountId);
+            return result;
+        }
+
         // Pretty-print the events, before and after the blocking calculator does its magic
         final StringBuilder logStringBuilder = new StringBuilder("Computed billing events for accountId='").append(accountId).append("'");
-        eventsToString(logStringBuilder, result, "\nBilling Events Raw");
-        blockCalculator.insertBlockingEvents(result, skippedSubscriptions, context);
-        eventsToString(logStringBuilder, result, "\nBilling Events After Blocking");
+        eventsToString(logStringBuilder, result);
+        if (blockCalculator.insertBlockingEvents(result, skippedSubscriptions, context)) {
+            logStringBuilder.append("\nBilling Events After Blocking");
+            eventsToString(logStringBuilder, result);
+        }
         log.info(logStringBuilder.toString());
 
         return result;
     }
 
-    private void eventsToString(final StringBuilder stringBuilder, final SortedSet<BillingEvent> events, final String title) {
-        stringBuilder.append(title);
+    private void eventsToString(final StringBuilder stringBuilder, final SortedSet<BillingEvent> events) {
         for (final BillingEvent event : events) {
             stringBuilder.append("\n").append(event.toString());
         }
@@ -185,8 +184,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
         // If dryRun is specified, we don't want to to update the account BCD value, so we initialize the flag updatedAccountBCD to true
         boolean updatedAccountBCD = dryRunMode;
 
-
-        int currentAccountBCD = accountApi.getBCD(account.getId(), context);
+        final int currentAccountBCD = accountApi.getBCD(account.getId(), context);
         for (final SubscriptionBase subscription : subscriptions) {
 
             // The subscription did not even start, so there is nothing to do yet, we can skip and avoid some NPE down the line when calculating the BCD
@@ -218,6 +216,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                                      calculateBcdForTransition(catalog, baseSubscription, subscription, account, currentAccountBCD, transition);
 
                 if (currentAccountBCD == 0 && !updatedAccountBCD) {
+                    log.info("Setting account BCD='{}', accountId='{}'", bcdLocal, account.getId());
                     accountApi.updateBCD(account.getExternalKey(), bcdLocal, context);
                     updatedAccountBCD = true;
                 }
@@ -231,7 +230,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
     private int calculateBcdForTransition(final Catalog catalog, final SubscriptionBase baseSubscription, final SubscriptionBase subscription, final ImmutableAccountData account, final int accountBillCycleDayLocal, final EffectiveSubscriptionInternalEvent transition)
             throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(catalog, transition), transition.getEffectiveTransitionTime());
-        return bcdCalculator.calculateBcdForAlignment(subscription, baseSubscription, alignment, account.getTimeZone(), accountBillCycleDayLocal);
+        return BillCycleDayCalculator.calculateBcdForAlignment(subscription, baseSubscription, alignment, account.getTimeZone(), accountBillCycleDayLocal);
     }
 
     private PlanPhaseSpecifier getPlanPhaseSpecifierFromTransition(final Catalog catalog, final EffectiveSubscriptionInternalEvent transition) throws CatalogApiException {
@@ -255,7 +254,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                                phase.getPhaseType());
     }
 
-    private final boolean is_AUTO_INVOICING_OFF(final List<Tag> tags) {
+    private boolean is_AUTO_INVOICING_OFF(final List<Tag> tags) {
         return ControlTagType.isAutoInvoicingOff(Collections2.transform(tags, new Function<Tag, UUID>() {
             @Nullable
             @Override
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
index 22d0865..cf2ea4f 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/applicator/OverdueStateApplicator.java
@@ -86,7 +86,6 @@ public class OverdueStateApplicator {
     private static final Logger log = LoggerFactory.getLogger(OverdueStateApplicator.class);
 
     private final BlockingInternalApi blockingApi;
-    private final Clock clock;
     private final OverduePoster checkPoster;
     private final PersistentBus bus;
     private final AccountInternalApi accountApi;
@@ -102,7 +101,6 @@ public class OverdueStateApplicator {
                                   final AccountInternalApi accountApi,
                                   final EntitlementApi entitlementApi,
                                   final EntitlementInternalApi entitlementInternalApi,
-                                  final Clock clock,
                                   @Named(DefaultOverdueModule.OVERDUE_NOTIFIER_CHECK_NAMED) final OverduePoster checkPoster,
                                   final OverdueEmailGenerator overdueEmailGenerator,
                                   final EmailConfig config,
@@ -114,7 +112,6 @@ public class OverdueStateApplicator {
         this.accountApi = accountApi;
         this.entitlementApi = entitlementApi;
         this.entitlementInternalApi = entitlementInternalApi;
-        this.clock = clock;
         this.checkPoster = checkPoster;
         this.overdueEmailGenerator = overdueEmailGenerator;
         this.tagApi = tagApi;
@@ -123,7 +120,7 @@ public class OverdueStateApplicator {
         this.bus = bus;
     }
 
-    public void apply(final OverdueStateSet overdueStateSet, final BillingState billingState,
+    public void apply(final DateTime effectiveDate, final OverdueStateSet overdueStateSet, final BillingState billingState,
                       final ImmutableAccountData account, final OverdueState previousOverdueState,
                       final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException, OverdueApiException {
         try {
@@ -132,7 +129,7 @@ public class OverdueStateApplicator {
                 return;
             }
 
-            log.debug("OverdueStateApplicator: time={}, previousState={}, nextState={}, billingState={}", clock.getUTCNow(), previousOverdueState, nextOverdueState, billingState);
+            log.debug("OverdueStateApplicator: time={}, previousState={}, nextState={}, billingState={}", effectiveDate, previousOverdueState, nextOverdueState, billingState);
 
             final OverdueState firstOverdueState = overdueStateSet.getFirstState();
             final boolean conditionForNextNotfication = !nextOverdueState.isClearState() ||
@@ -145,8 +142,8 @@ public class OverdueStateApplicator {
                 if (reevaluationInterval == null) {
                     log.debug("OverdueStateApplicator <notificationQ>: missing InitialReevaluationInterval from config, NOT inserting notification for account {}", account.getId());
                 } else {
-                    log.debug("OverdueStateApplicator <notificationQ>: inserting notification for account={}, time={}", account.getId(), clock.getUTCNow().plus(reevaluationInterval));
-                    createFutureNotification(account, clock.getUTCNow().plus(reevaluationInterval), context);
+                    log.debug("OverdueStateApplicator <notificationQ>: inserting notification for account={}, time={}", account.getId(), effectiveDate.plus(reevaluationInterval));
+                    createFutureNotification(account, effectiveDate.plus(reevaluationInterval), context);
                 }
             } else if (nextOverdueState.isClearState()) {
                 clearFutureNotification(account, context);
@@ -157,7 +154,7 @@ public class OverdueStateApplicator {
                 return;
             }
 
-            cancelSubscriptionsIfRequired(account, nextOverdueState, context);
+            cancelSubscriptionsIfRequired(effectiveDate, account, nextOverdueState, context);
 
             sendEmailIfRequired(account.getId(), billingState, nextOverdueState, context);
 
@@ -166,7 +163,7 @@ public class OverdueStateApplicator {
             // Make sure to store the new state last here: the entitlement DAO will send a BlockingTransitionInternalEvent
             // on the bus to which invoice will react. We need the latest state (including AUTO_INVOICE_OFF tag for example)
             // to be present in the database first.
-            storeNewState(account, nextOverdueState, context);
+            storeNewState(effectiveDate, account, nextOverdueState, context);
         } catch (final AccountApiException e) {
             throw new OverdueException(e);
         }
@@ -212,11 +209,11 @@ public class OverdueStateApplicator {
         }
     }
 
-    public void clear(final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException {
+    public void clear(final DateTime effectiveDate, final ImmutableAccountData account, final OverdueState previousOverdueState, final OverdueState clearState, final InternalCallContext context) throws OverdueException {
 
-        log.debug("OverdueStateApplicator:clear : time = " + clock.getUTCNow() + ", previousState = " + previousOverdueState.getName());
+        log.debug("OverdueStateApplicator:clear : time = " + effectiveDate + ", previousState = " + previousOverdueState.getName());
 
-        storeNewState(account, clearState, context);
+        storeNewState(effectiveDate, account, clearState, context);
 
         clearFutureNotification(account, context);
 
@@ -248,7 +245,7 @@ public class OverdueStateApplicator {
                                              context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
     }
 
-    protected void storeNewState(final ImmutableAccountData blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
+    protected void storeNewState(final DateTime effectiveDate, final ImmutableAccountData blockable, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
         try {
             blockingApi.setBlockingState(new DefaultBlockingState(blockable.getId(),
                                                                   BlockingStateType.ACCOUNT,
@@ -257,7 +254,7 @@ public class OverdueStateApplicator {
                                                                   blockChanges(nextOverdueState),
                                                                   blockEntitlement(nextOverdueState),
                                                                   blockBilling(nextOverdueState),
-                                                                  clock.getUTCNow()),
+                                                                  effectiveDate),
                                          context);
         } catch (final Exception e) {
             throw new OverdueException(e, ErrorCode.OVERDUE_CAT_ERROR_ENCOUNTERED, blockable.getId(), blockable.getClass().getName());
@@ -312,7 +309,7 @@ public class OverdueStateApplicator {
         checkPoster.clearOverdueCheckNotifications(account.getId(), OverdueCheckNotifier.OVERDUE_CHECK_NOTIFIER_QUEUE, OverdueCheckNotificationKey.class, context);
     }
 
-    private void cancelSubscriptionsIfRequired(final ImmutableAccountData account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
+    private void cancelSubscriptionsIfRequired(final DateTime effectiveDate, final ImmutableAccountData account, final OverdueState nextOverdueState, final InternalCallContext context) throws OverdueException {
         if (nextOverdueState.getOverdueCancellationPolicy() == OverdueCancellationPolicy.NONE) {
             return;
         }
@@ -334,7 +331,7 @@ public class OverdueStateApplicator {
             computeEntitlementsToCancel(account, toBeCancelled, callContext);
 
             try {
-                entitlementInternalApi.cancel(toBeCancelled, clock.getToday(account.getTimeZone()), actionPolicy, ImmutableList.<PluginProperty>of(), context);
+                entitlementInternalApi.cancel(toBeCancelled, context.toLocalDate(effectiveDate), actionPolicy, ImmutableList.<PluginProperty>of(), context);
             } catch (final EntitlementApiException e) {
                 throw new OverdueException(e);
             }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueDispatcher.java b/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueDispatcher.java
index c631b72..461539e 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueDispatcher.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/listener/OverdueDispatcher.java
@@ -18,6 +18,7 @@ package org.killbill.billing.overdue.listener;
 
 import java.util.UUID;
 
+import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,25 +39,25 @@ public class OverdueDispatcher {
         this.factory = factory;
     }
 
-    public void processOverdueForAccount(final UUID accountId, final InternalCallContext context) {
-        processOverdue(accountId, context);
+    public void processOverdueForAccount(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
+        processOverdue(accountId, effectiveDate, context);
     }
 
-    public void clearOverdueForAccount(final UUID accountId, final InternalCallContext context) {
-        clearOverdue(accountId, context);
+    public void clearOverdueForAccount(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
+        clearOverdue(accountId, effectiveDate, context);
     }
 
-    private void processOverdue(final UUID accountId, final InternalCallContext context) {
+    private void processOverdue(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
         try {
-            factory.createOverdueWrapperFor(accountId, context).refresh(context);
+            factory.createOverdueWrapperFor(accountId, context).refresh(effectiveDate, context);
         } catch (BillingExceptionBase e) {
             log.warn("Error processing Overdue for accountId='{}'", accountId, e);
         }
     }
 
-    private void clearOverdue(final UUID accountId, final InternalCallContext context) {
+    private void clearOverdue(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
         try {
-            factory.createOverdueWrapperFor(accountId, context).clear(context);
+            factory.createOverdueWrapperFor(accountId, context).clear(effectiveDate, context);
         } catch (BillingExceptionBase e) {
             log.warn("Error processing Overdue for accountId='{}'", accountId, e);
         }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusNotifier.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusNotifier.java
index be98671..4d90ec1 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusNotifier.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueAsyncBusNotifier.java
@@ -61,10 +61,10 @@ public class OverdueAsyncBusNotifier extends DefaultOverdueNotifierBase implemen
             final OverdueAsyncBusNotificationKey key = (OverdueAsyncBusNotificationKey) notificationKey;
             switch (key.getAction()) {
                 case CLEAR:
-                    dispatcher.clearOverdueForAccount(key.getUuidKey(), createCallContext(userToken, accountRecordId, tenantRecordId));
+                    dispatcher.clearOverdueForAccount(key.getUuidKey(), eventDate, createCallContext(userToken, accountRecordId, tenantRecordId));
                     break;
                 case REFRESH:
-                    dispatcher.processOverdueForAccount(key.getUuidKey(), createCallContext(userToken, accountRecordId, tenantRecordId));
+                    dispatcher.processOverdueForAccount(key.getUuidKey(), eventDate, createCallContext(userToken, accountRecordId, tenantRecordId));
                     break;
                 default:
                     throw new RuntimeException("Unexpected action " + key.getAction() + " for account " + key.getUuidKey());
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckNotifier.java b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckNotifier.java
index bd644dd..6fdb77d 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckNotifier.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/notification/OverdueCheckNotifier.java
@@ -59,7 +59,7 @@ public class OverdueCheckNotifier extends DefaultOverdueNotifierBase implements 
             }
 
             final OverdueCheckNotificationKey key = (OverdueCheckNotificationKey) notificationKey;
-            dispatcher.processOverdueForAccount(key.getUuidKey(), createCallContext(userToken, accountRecordId, tenantRecordId));
+            dispatcher.processOverdueForAccount(key.getUuidKey(), eventDate, createCallContext(userToken, accountRecordId, tenantRecordId));
         } catch (IllegalArgumentException e) {
             log.error("The key returned from the NextBillingNotificationQueue is not a valid UUID", e);
         }
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
index 46ed578..48ddfbb 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
@@ -20,6 +20,7 @@ package org.killbill.billing.overdue.wrapper;
 
 import java.util.List;
 
+import org.joda.time.DateTime;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.account.api.ImmutableAccountData;
@@ -85,7 +86,7 @@ public class OverdueWrapper {
         this.accountApi = accountApi;
     }
 
-    public OverdueState refresh(final InternalCallContext context) throws OverdueException, OverdueApiException {
+    public OverdueState refresh(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException {
         if (overdueStateSet.size() < 1) { // No configuration available
             return overdueStateSet.getClearState();
         }
@@ -94,7 +95,7 @@ public class OverdueWrapper {
         try {
             lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), overdueable.getId().toString(), MAX_LOCK_RETRIES);
 
-            return refreshWithLock(context);
+            return refreshWithLock(effectiveDate, context);
         } catch (final LockFailedException e) {
             log.warn("Failed to process overdue for accountId='{}'", overdueable.getId(), e);
         } finally {
@@ -105,14 +106,14 @@ public class OverdueWrapper {
         return null;
     }
 
-    private OverdueState refreshWithLock(final InternalCallContext context) throws OverdueException, OverdueApiException {
+    private OverdueState refreshWithLock(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException {
         final BillingState billingState = billingState(context);
         final BlockingState blockingStateForService = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context);
         final String previousOverdueStateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME;
         final OverdueState currentOverdueState = overdueStateSet.findState(previousOverdueStateName);
         final OverdueState nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getToday(billingState.getAccountTimeZone()));
 
-        overdueStateApplicator.apply(overdueStateSet, billingState, overdueable, currentOverdueState, nextOverdueState, context);
+        overdueStateApplicator.apply(effectiveDate, overdueStateSet, billingState, overdueable, currentOverdueState, nextOverdueState, context);
 
         try {
             final List<Account> childrenAccounts = accountApi.getChildrenAccounts(overdueable.getId(), context);
@@ -133,7 +134,7 @@ public class OverdueWrapper {
                                                                             billingState.getIdOfEarliestUnpaidInvoice(),
                                                                             billingState.getResponseForLastFailedPayment(),
                                                                             billingState.getTags());
-                    overdueStateApplicator.apply(overdueStateSet, childBillingState, accountData, currentOverdueState, nextOverdueState, accountContext);
+                    overdueStateApplicator.apply(effectiveDate, overdueStateSet, childBillingState, accountData, currentOverdueState, nextOverdueState, accountContext);
                 }
             }
 
@@ -144,12 +145,12 @@ public class OverdueWrapper {
         return nextOverdueState;
     }
 
-    public void clear(final InternalCallContext context) throws OverdueException, OverdueApiException {
+    public void clear(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException {
         GlobalLock lock = null;
         try {
             lock = locker.lockWithNumberOfTries(LockerType.ACCNT_INV_PAY.toString(), overdueable.getId().toString(), MAX_LOCK_RETRIES);
 
-            clearWithLock(context);
+            clearWithLock(effectiveDate, context);
         } catch (final LockFailedException e) {
             log.warn("Failed to clear overdue for accountId='{}'", overdueable.getId(), e);
         } finally {
@@ -159,13 +160,13 @@ public class OverdueWrapper {
         }
     }
 
-    private void clearWithLock(final InternalCallContext context) throws OverdueException, OverdueApiException {
+    private void clearWithLock(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException {
         final BlockingState blockingStateForService = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context);
         final String previousOverdueStateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME;
         final OverdueState previousOverdueState = overdueStateSet.findState(previousOverdueStateName);
-        overdueStateApplicator.clear(overdueable, previousOverdueState, overdueStateSet.getClearState(), context);
 
         // TODO maguero: should we do the same as "refreshWithLock"?
+        overdueStateApplicator.clear(effectiveDate, overdueable, previousOverdueState, overdueStateSet.getClearState(), context);
     }
 
     public BillingState billingState(final InternalTenantContext context) throws OverdueException {
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
index 2222377..42e70ce 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/applicator/TestOverdueStateApplicator.java
@@ -54,17 +54,17 @@ public class TestOverdueStateApplicator extends OverdueTestSuiteWithEmbeddedDB {
         OverdueState state;
 
         state = config.getOverdueStatesAccount().findState("OD1");
-        applicator.apply(overdueStateSet, null, account, clearState, state, internalCallContext);
+        applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext);
         testOverdueHelper.checkStateApplied(state);
         checkBussEvent("OD1");
 
         state = config.getOverdueStatesAccount().findState("OD2");
-        applicator.apply(overdueStateSet, null, account, clearState, state, internalCallContext);
+        applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext);
         testOverdueHelper.checkStateApplied(state);
         checkBussEvent("OD2");
 
         state = config.getOverdueStatesAccount().findState("OD3");
-        applicator.apply(overdueStateSet, null, account, clearState, state, internalCallContext);
+        applicator.apply(clock.getUTCNow(), overdueStateSet, null, account, clearState, state, internalCallContext);
         testOverdueHelper.checkStateApplied(state);
         checkBussEvent("OD3");
     }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
index b9da2b6..ee470c5 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/notification/TestOverdueCheckNotifier.java
@@ -53,7 +53,7 @@ public class TestOverdueCheckNotifier extends OverdueTestSuiteWithEmbeddedDB {
         }
 
         @Override
-        public void processOverdueForAccount(final UUID accountId, final InternalCallContext context) {
+        public void processOverdueForAccount(final UUID accountId, final DateTime effectiveDate, final InternalCallContext context) {
             eventCount++;
             latestAccountId = accountId;
         }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
index 2c22056..f495016 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/wrapper/TestOverdueWrapper.java
@@ -51,19 +51,19 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
         state = config.getOverdueStatesAccount().findState("OD1");
         account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(31));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
-        wrapper.refresh(internalCallContext);
+        wrapper.refresh(clock.getUTCNow(), internalCallContext);
         testOverdueHelper.checkStateApplied(state);
 
         state = config.getOverdueStatesAccount().findState("OD2");
         account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(41));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
-        wrapper.refresh(internalCallContext);
+        wrapper.refresh(clock.getUTCNow(), internalCallContext);
         testOverdueHelper.checkStateApplied(state);
 
         state = config.getOverdueStatesAccount().findState("OD3");
         account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(51));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
-        wrapper.refresh(internalCallContext);
+        wrapper.refresh(clock.getUTCNow(), internalCallContext);
         testOverdueHelper.checkStateApplied(state);
     }
 
@@ -79,7 +79,7 @@ public class TestOverdueWrapper extends OverdueTestSuiteWithEmbeddedDB {
         state = config.getOverdueStatesAccount().findState(OverdueWrapper.CLEAR_STATE_NAME);
         account = testOverdueHelper.createImmutableAccountData(clock.getUTCToday().minusDays(31));
         wrapper = overdueWrapperFactory.createOverdueWrapperFor(account, internalCallContext);
-        final OverdueState result = wrapper.refresh(internalCallContext);
+        final OverdueState result = wrapper.refresh(clock.getUTCNow(), internalCallContext);
 
         Assert.assertEquals(result.getName(), state.getName());
         Assert.assertEquals(result.isBlockChanges(), state.isBlockChanges());
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 5bfd18d..22f3a2a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -47,9 +47,10 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
-public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logEnterAPICall;
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logExitAPICall;
 
-    private static final Joiner JOINER = Joiner.on(",");
+public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
     private static final boolean SHOULD_LOCK_ACCOUNT = true;
     private static final boolean IS_API_PAYMENT = true;
@@ -84,7 +85,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createAuthorization(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
@@ -94,7 +95,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -130,7 +132,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createAuthorization(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
@@ -140,7 +142,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -168,7 +171,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createCapture(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentId, amount, currency, paymentTransactionExternalKey,
@@ -178,7 +181,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -210,7 +214,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createCapture(IS_API_PAYMENT, account, paymentId, amount, currency, paymentTransactionExternalKey,
@@ -220,7 +224,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -250,7 +255,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createPurchase(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
@@ -260,7 +265,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -303,7 +309,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         PaymentTransaction paymentTransaction = null;
 
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             payment = pluginControlPaymentProcessor.createPurchase(IS_API_PAYMENT, account, nonNulPaymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
                                                                                  properties, paymentControlPluginNames, callContext, internalCallContext);
@@ -312,7 +318,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -338,7 +345,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createVoid(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentId, paymentTransactionExternalKey,
@@ -348,7 +355,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -378,7 +386,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createVoid(IS_API_PAYMENT, account, paymentId, paymentTransactionExternalKey,
@@ -388,7 +396,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -416,7 +425,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createRefund(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentId, amount, currency, paymentTransactionExternalKey,
@@ -426,7 +435,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -460,7 +470,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createRefund(IS_API_PAYMENT, account, paymentId, amount, currency, paymentTransactionExternalKey,
@@ -470,7 +480,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -500,7 +511,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createCredit(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
@@ -510,7 +521,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -545,7 +557,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createCredit(IS_API_PAYMENT, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey,
@@ -555,7 +567,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -578,7 +591,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, null, paymentTransactionId, null, null, null, null, null, null);
+            logEnterAPICall(log, transactionType, account, null, null, paymentTransactionId, null, null, null, null, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.notifyPendingPaymentOfStateChanged(account, paymentTransactionId, isSuccess, callContext, internalCallContext);
@@ -592,7 +605,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                                                                                                 }).orNull();
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -622,7 +636,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createChargeback(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentId, paymentTransactionExternalKey, amount, currency, true,
@@ -632,7 +646,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -662,7 +677,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, amount, currency, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createChargeback(IS_API_PAYMENT, account, paymentId, paymentTransactionExternalKey, amount, currency,
@@ -672,7 +687,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -696,7 +712,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, null);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = paymentProcessor.createChargebackReversal(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentId, paymentTransactionExternalKey, null, null, true, callContext, internalCallContext);
@@ -705,7 +721,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -734,7 +751,7 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
         Payment payment = null;
         PaymentTransaction paymentTransaction = null;
         try {
-            logEnterAPICall(transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
+            logEnterAPICall(log, transactionType, account, null, paymentId, null, null, null, null, paymentTransactionExternalKey, null, paymentControlPluginNames);
 
             final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
             payment = pluginControlPaymentProcessor.createChargebackReversal(IS_API_PAYMENT, account, paymentId, paymentTransactionExternalKey, paymentControlPluginNames, callContext, internalCallContext);
@@ -750,7 +767,8 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
 
             return payment;
         } finally {
-            logExitAPICall(transactionType,
+            logExitAPICall(log,
+                           transactionType,
                            account,
                            payment != null ? payment.getPaymentMethodId() : null,
                            payment != null ? payment.getId() : null,
@@ -900,122 +918,4 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
                                                       });
         }
     }
-
-    private void logEnterAPICall(final String transactionType,
-                                   final Account account,
-                                   @Nullable final UUID paymentMethodId,
-                                   @Nullable final UUID paymentId,
-                                   @Nullable final UUID transactionId,
-                                   @Nullable final BigDecimal amount,
-                                   @Nullable final Currency currency,
-                                   @Nullable final String paymentExternalKey,
-                                   @Nullable final String paymentTransactionExternalKey,
-                                   @Nullable final TransactionStatus transactionStatus,
-                                   @Nullable final List<String> paymentControlPluginNames) {
-        logAPICallInternal("ENTERING ",
-                           transactionType,
-                           account,
-                           paymentMethodId,
-                           paymentId,
-                           transactionId,
-                           amount,
-                           currency,
-                           paymentExternalKey,
-                           paymentTransactionExternalKey,
-                           transactionStatus,
-                           paymentControlPluginNames);
-    }
-
-    private void logExitAPICall(final String transactionType,
-                                  final Account account,
-                                  @Nullable final UUID paymentMethodId,
-                                  @Nullable final UUID paymentId,
-                                  @Nullable final UUID transactionId,
-                                  @Nullable final BigDecimal amount,
-                                  @Nullable final Currency currency,
-                                  @Nullable final String paymentExternalKey,
-                                  @Nullable final String paymentTransactionExternalKey,
-                                  @Nullable final TransactionStatus transactionStatus,
-                                  @Nullable final List<String> paymentControlPluginNames) {
-        logAPICallInternal("EXITING ",
-                           transactionType,
-                           account,
-                           paymentMethodId,
-                           paymentId,
-                           transactionId,
-                           amount,
-                           currency,
-                           paymentExternalKey,
-                           paymentTransactionExternalKey,
-                           transactionStatus,
-                           paymentControlPluginNames);
-    }
-
-    private void logAPICallInternal(final String prefixMsg,
-                                    final String transactionType,
-                                    final Account account,
-                                    final UUID paymentMethodId,
-                                    @Nullable final UUID paymentId,
-                                    @Nullable final UUID transactionId,
-                                    @Nullable final BigDecimal amount,
-                                    @Nullable final Currency currency,
-                                    @Nullable final String paymentExternalKey,
-                                    @Nullable final String paymentTransactionExternalKey,
-                                    @Nullable final TransactionStatus transactionStatus,
-                                    @Nullable final List<String> paymentControlPluginNames) {
-        if (log.isInfoEnabled()) {
-            final StringBuilder logLine = new StringBuilder(prefixMsg);
-            logLine.append("PaymentApi: transactionType='")
-                   .append(transactionType)
-                   .append("', accountId='")
-                   .append(account.getId())
-                   .append("'");
-            if (paymentMethodId != null) {
-                logLine.append(", paymentMethodId='")
-                       .append(paymentMethodId)
-                       .append("'");
-            }
-            if (paymentExternalKey != null) {
-                logLine.append(", paymentExternalKey='")
-                       .append(paymentExternalKey)
-                       .append("'");
-            }
-            if (paymentTransactionExternalKey != null) {
-                logLine.append(", paymentTransactionExternalKey='")
-                       .append(paymentTransactionExternalKey)
-                       .append("'");
-            }
-            if (paymentId != null) {
-                logLine.append(", paymentId='")
-                       .append(paymentId)
-                       .append("'");
-            }
-            if (transactionId != null) {
-                logLine.append(", transactionId='")
-                       .append(transactionId)
-                       .append("'");
-            }
-            if (amount != null) {
-                logLine.append(", amount='")
-                       .append(amount)
-                       .append("'");
-            }
-            if (currency != null) {
-                logLine.append(", currency='")
-                       .append(currency)
-                       .append("'");
-            }
-            if (transactionStatus != null) {
-                logLine.append(", transactionStatus='")
-                       .append(transactionStatus)
-                       .append("'");
-            }
-            if (paymentControlPluginNames != null) {
-                logLine.append(", paymentControlPluginNames='")
-                       .append(JOINER.join(paymentControlPluginNames))
-                       .append("'");
-            }
-            log.info(logLine.toString());
-        }
-    }
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java b/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
index 145507a..fd9cebe 100644
--- a/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
+++ b/payment/src/main/java/org/killbill/billing/payment/bus/PaymentBusEventHandler.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * 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
@@ -20,6 +20,7 @@ package org.killbill.billing.payment.bus;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -30,8 +31,11 @@ import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.events.InvoiceCreationInternalEvent;
 import org.killbill.billing.events.PaymentInternalEvent;
+import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.PaymentTransaction;
 import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.PluginControlPaymentProcessor;
 import org.killbill.billing.payment.core.janitor.Janitor;
 import org.killbill.billing.payment.invoice.InvoicePaymentControlPluginApi;
@@ -44,10 +48,16 @@ import org.killbill.billing.util.config.definition.PaymentConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
 
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logEnterAPICall;
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logExitAPICall;
+
 public class PaymentBusEventHandler {
 
     private static final Logger log = LoggerFactory.getLogger(PaymentBusEventHandler.class);
@@ -82,22 +92,49 @@ public class PaymentBusEventHandler {
     public void processInvoiceEvent(final InvoiceCreationInternalEvent event) {
         log.info("Received invoice creation notification for accountId='{}', invoiceId='{}'", event.getAccountId(), event.getInvoiceId());
 
-        final Account account;
-        try {
-            final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
-            account = accountApi.getAccountById(event.getAccountId(), internalContext);
+        final Collection<PluginProperty> properties = new ArrayList<PluginProperty>();
+        final PluginProperty propertyInvoiceId = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, event.getInvoiceId().toString(), false);
+        properties.add(propertyInvoiceId);
+
+        final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
+        final CallContext callContext = internalCallContextFactory.createCallContext(internalContext);
 
-            final List<PluginProperty> properties = new ArrayList<PluginProperty>();
-            final PluginProperty prop1 = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, event.getInvoiceId().toString(), false);
-            properties.add(prop1);
+        final BigDecimal amountToBePaid = null; // We let the plugin compute how much should be paid
+        final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames(internalContext) != null ? new LinkedList<String>(paymentConfig.getPaymentControlPluginNames(internalContext)) : new LinkedList<String>();
+        paymentControlPluginNames.add(InvoicePaymentControlPluginApi.PLUGIN_NAME);
 
-            final CallContext callContext = internalCallContextFactory.createCallContext(internalContext);
+        final String paymentExternalKey = UUIDs.randomUUID().toString();
+        final String paymentTransactionExternalKey = UUIDs.randomUUID().toString();
+
+        final String transactionType = TransactionType.PURCHASE.name();
+        Account account = null;
+        Payment payment = null;
+        PaymentTransaction paymentTransaction = null;
+        try {
+            account = accountApi.getAccountById(event.getAccountId(), internalContext);
 
-            final BigDecimal amountToBePaid = null; // We let the plugin compute how much should be paid
-            final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames(internalContext) != null ? new LinkedList<String>(paymentConfig.getPaymentControlPluginNames(internalContext)) : new LinkedList<String>();
-            paymentControlPluginNames.add(InvoicePaymentControlPluginApi.PLUGIN_NAME);
-            pluginControlPaymentProcessor.createPurchase(false, account, account.getPaymentMethodId(), null, amountToBePaid, account.getCurrency(), UUIDs.randomUUID().toString(), UUIDs.randomUUID().toString(),
-                                                         properties, paymentControlPluginNames, callContext, internalContext);
+            logEnterAPICall(log,
+                            transactionType,
+                            account,
+                            account.getPaymentMethodId(),
+                            null,
+                            null,
+                            amountToBePaid,
+                            account.getCurrency(),
+                            paymentExternalKey,
+                            paymentTransactionExternalKey,
+                            null,
+                            paymentControlPluginNames);
+
+            payment = pluginControlPaymentProcessor.createPurchase(false, account, account.getPaymentMethodId(), null, amountToBePaid, account.getCurrency(), paymentExternalKey, paymentTransactionExternalKey, properties, paymentControlPluginNames, callContext, internalContext);
+
+            paymentTransaction = Iterables.<PaymentTransaction>find(Lists.<PaymentTransaction>reverse(payment.getTransactions()),
+                                                                    new Predicate<PaymentTransaction>() {
+                                                                        @Override
+                                                                        public boolean apply(final PaymentTransaction input) {
+                                                                            return paymentTransactionExternalKey.equals(input.getExternalKey());
+                                                                        }
+                                                                    });
         } catch (final AccountApiException e) {
             log.warn("Failed to process invoice payment", e);
         } catch (final PaymentApiException e) {
@@ -105,6 +142,19 @@ public class PaymentBusEventHandler {
             if (e.getCode() != ErrorCode.PAYMENT_PLUGIN_API_ABORTED.getCode()) {
                 log.warn("Failed to process invoice payment {}", e.toString());
             }
+        } finally {
+            logExitAPICall(log,
+                           transactionType,
+                           account,
+                           payment != null ? payment.getPaymentMethodId() : null,
+                           payment != null ? payment.getId() : null,
+                           paymentTransaction != null ? paymentTransaction.getId() : null,
+                           paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null,
+                           paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null,
+                           payment != null ? payment.getExternalKey() : null,
+                           paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
+                           paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
+                           paymentControlPluginNames);
         }
     }
 }
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
index cdb152d..30456c4 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/Janitor.java
@@ -108,25 +108,6 @@ public class Janitor {
 
     }
 
-    /*
-        public IncompletePaymentAttemptTask(final InternalCallContextFactory internalCallContextFactory,
-                                        final PaymentConfig paymentConfig,
-                                        final PaymentDao paymentDao,
-                                        final Clock clock,
-                                        final PaymentStateMachineHelper paymentStateMachineHelper,
-                                        final PaymentControlStateMachineHelper retrySMHelper,
-                                        final AccountInternalApi accountInternalApi,
-                                        final PluginControlPaymentAutomatonRunner pluginControlledPaymentAutomatonRunner,
-                                        final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry,
-                                        final GlobalLocker locker) {
-
-
-    public IncompletePaymentTransactionTask(final InternalCallContextFactory internalCallContextFactory, final PaymentConfig paymentConfig,
-                                            final PaymentDao paymentDao, final Clock clock,
-                                            final PaymentStateMachineHelper paymentStateMachineHelper, final PaymentControlStateMachineHelper retrySMHelper, final AccountInternalApi accountInternalApi,
-                                            final OSGIServiceRegistration<PaymentPluginApi> pluginRegistry, final GlobalLocker locker) {
-
-     */
 
     public void initialize() throws NotificationQueueAlreadyExists {
         janitorQueue = notificationQueueService.createNotificationQueue(DefaultPaymentService.SERVICE_NAME,
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
index 9ace343..b1dffa6 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PluginControlPaymentProcessor.java
@@ -36,6 +36,7 @@ import org.killbill.billing.invoice.api.InvoiceInternalApi;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.PaymentTransaction;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.core.sm.PaymentControlStateMachineHelper;
@@ -56,7 +57,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logEnterAPICall;
+import static org.killbill.billing.payment.logging.PaymentLoggingHelper.logExitAPICall;
 
 public class PluginControlPaymentProcessor extends ProcessorBase {
 
@@ -225,36 +232,60 @@ public class PluginControlPaymentProcessor extends ProcessorBase {
     }
 
     public void retryPaymentTransaction(final UUID attemptId, final List<String> paymentControlPluginNames, final InternalCallContext internalCallContext) {
-        try {
-            final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
-            final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
-            final UUID paymentId = payment != null ? payment.getId() : null;
+        final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
+        log.info("Retrying attemptId='{}', paymentExternalKey='{}', transactionExternalKey='{}'. paymentControlPluginNames='{}'",
+                 attemptId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), paymentControlPluginNames);
 
-            final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
-            final Account account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
-            final CallContext callContext = buildCallContext(internalCallContext);
+        final PaymentModelDao paymentModelDao = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
+        final UUID paymentId = paymentModelDao != null ? paymentModelDao.getId() : null;
 
+        final CallContext callContext = buildCallContext(internalCallContext);
+
+        final String transactionType = TransactionType.PURCHASE.name();
+        Account account = null;
+        Payment payment = null;
+        PaymentTransaction paymentTransaction = null;
+        try {
+            account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
             final State state = paymentControlStateMachineHelper.getState(attempt.getStateName());
+            final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
 
-            log.debug("Retrying attemptId={}, paymentExternalKey={}, transactionExternalKey={}. paymentControlPluginNames={}, now={}",
-                      attemptId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), paymentControlPluginNames, clock.getUTCNow());
+            logEnterAPICall(log,
+                            transactionType,
+                            account,
+                            attempt.getPaymentMethodId(),
+                            paymentId,
+                            null,
+                            attempt.getAmount(),
+                            attempt.getCurrency(),
+                            attempt.getPaymentExternalKey(),
+                            attempt.getTransactionExternalKey(),
+                            null,
+                            paymentControlPluginNames);
 
-            pluginControlledPaymentAutomatonRunner.run(state,
-                                                       false,
-                                                       attempt.getTransactionType(),
-                                                       ControlOperation.valueOf(attempt.getTransactionType().toString()),
-                                                       account,
-                                                       attempt.getPaymentMethodId(),
-                                                       paymentId,
-                                                       attempt.getPaymentExternalKey(),
-                                                       attempt.getTransactionExternalKey(),
-                                                       attempt.getAmount(),
-                                                       attempt.getCurrency(),
-                                                       pluginProperties,
-                                                       paymentControlPluginNames,
-                                                       callContext,
-                                                       internalCallContext);
+            payment = pluginControlledPaymentAutomatonRunner.run(state,
+                                                                 false,
+                                                                 attempt.getTransactionType(),
+                                                                 ControlOperation.valueOf(attempt.getTransactionType().toString()),
+                                                                 account,
+                                                                 attempt.getPaymentMethodId(),
+                                                                 paymentId,
+                                                                 attempt.getPaymentExternalKey(),
+                                                                 attempt.getTransactionExternalKey(),
+                                                                 attempt.getAmount(),
+                                                                 attempt.getCurrency(),
+                                                                 pluginProperties,
+                                                                 paymentControlPluginNames,
+                                                                 callContext,
+                                                                 internalCallContext);
 
+            paymentTransaction = Iterables.<PaymentTransaction>find(Lists.<PaymentTransaction>reverse(payment.getTransactions()),
+                                                                    new Predicate<PaymentTransaction>() {
+                                                                        @Override
+                                                                        public boolean apply(final PaymentTransaction input) {
+                                                                            return attempt.getTransactionExternalKey().equals(input.getExternalKey());
+                                                                        }
+                                                                    });
         } catch (final AccountApiException e) {
             log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
         } catch (final PaymentApiException e) {
@@ -263,6 +294,19 @@ public class PluginControlPaymentProcessor extends ProcessorBase {
             log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
         } catch (final MissingEntryException e) {
             log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
+        } finally {
+            logExitAPICall(log,
+                           transactionType,
+                           account,
+                           payment != null ? payment.getPaymentMethodId() : null,
+                           payment != null ? payment.getId() : null,
+                           paymentTransaction != null ? paymentTransaction.getId() : null,
+                           paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null,
+                           paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null,
+                           payment != null ? payment.getExternalKey() : null,
+                           paymentTransaction != null ? paymentTransaction.getExternalKey() : null,
+                           paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null,
+                           paymentControlPluginNames);
         }
     }
 
diff --git a/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java b/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java
new file mode 100644
index 0000000..c3ac9c2
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/logging/PaymentLoggingHelper.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 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
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.payment.logging;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.killbill.billing.account.api.Account;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.payment.api.TransactionStatus;
+import org.slf4j.Logger;
+
+import com.google.common.base.Joiner;
+
+public abstract class PaymentLoggingHelper {
+
+    private static final Joiner JOINER = Joiner.on(",");
+
+    public static void logEnterAPICall(final Logger log,
+                                       final String transactionType,
+                                       final Account account,
+                                       @Nullable final UUID paymentMethodId,
+                                       @Nullable final UUID paymentId,
+                                       @Nullable final UUID transactionId,
+                                       @Nullable final BigDecimal amount,
+                                       @Nullable final Currency currency,
+                                       @Nullable final String paymentExternalKey,
+                                       @Nullable final String paymentTransactionExternalKey,
+                                       @Nullable final TransactionStatus transactionStatus,
+                                       @Nullable final List<String> paymentControlPluginNames) {
+        logAPICallInternal(log,
+                           "ENTERING ",
+                           transactionType,
+                           account,
+                           paymentMethodId,
+                           paymentId,
+                           transactionId,
+                           amount,
+                           currency,
+                           paymentExternalKey,
+                           paymentTransactionExternalKey,
+                           transactionStatus,
+                           paymentControlPluginNames);
+    }
+
+    public static void logExitAPICall(final Logger log,
+                                      final String transactionType,
+                                      final Account account,
+                                      @Nullable final UUID paymentMethodId,
+                                      @Nullable final UUID paymentId,
+                                      @Nullable final UUID transactionId,
+                                      @Nullable final BigDecimal amount,
+                                      @Nullable final Currency currency,
+                                      @Nullable final String paymentExternalKey,
+                                      @Nullable final String paymentTransactionExternalKey,
+                                      @Nullable final TransactionStatus transactionStatus,
+                                      @Nullable final List<String> paymentControlPluginNames) {
+        logAPICallInternal(log,
+                           "EXITING ",
+                           transactionType,
+                           account,
+                           paymentMethodId,
+                           paymentId,
+                           transactionId,
+                           amount,
+                           currency,
+                           paymentExternalKey,
+                           paymentTransactionExternalKey,
+                           transactionStatus,
+                           paymentControlPluginNames);
+    }
+
+    public static void logAPICallInternal(final Logger log,
+                                          final String prefixMsg,
+                                          final String transactionType,
+                                          final Account account,
+                                          final UUID paymentMethodId,
+                                          @Nullable final UUID paymentId,
+                                          @Nullable final UUID transactionId,
+                                          @Nullable final BigDecimal amount,
+                                          @Nullable final Currency currency,
+                                          @Nullable final String paymentExternalKey,
+                                          @Nullable final String paymentTransactionExternalKey,
+                                          @Nullable final TransactionStatus transactionStatus,
+                                          @Nullable final List<String> paymentControlPluginNames) {
+        if (log.isInfoEnabled()) {
+            final StringBuilder logLine = new StringBuilder(prefixMsg);
+            logLine.append("PaymentApi: transactionType='")
+                   .append(transactionType)
+                   .append("', accountId='")
+                   .append(account.getId())
+                   .append("'");
+            if (paymentMethodId != null) {
+                logLine.append(", paymentMethodId='")
+                       .append(paymentMethodId)
+                       .append("'");
+            }
+            if (paymentExternalKey != null) {
+                logLine.append(", paymentExternalKey='")
+                       .append(paymentExternalKey)
+                       .append("'");
+            }
+            if (paymentTransactionExternalKey != null) {
+                logLine.append(", paymentTransactionExternalKey='")
+                       .append(paymentTransactionExternalKey)
+                       .append("'");
+            }
+            if (paymentId != null) {
+                logLine.append(", paymentId='")
+                       .append(paymentId)
+                       .append("'");
+            }
+            if (transactionId != null) {
+                logLine.append(", transactionId='")
+                       .append(transactionId)
+                       .append("'");
+            }
+            if (amount != null) {
+                logLine.append(", amount='")
+                       .append(amount)
+                       .append("'");
+            }
+            if (currency != null) {
+                logLine.append(", currency='")
+                       .append(currency)
+                       .append("'");
+            }
+            if (transactionStatus != null) {
+                logLine.append(", transactionStatus='")
+                       .append(transactionStatus)
+                       .append("'");
+            }
+            if (paymentControlPluginNames != null) {
+                logLine.append(", paymentControlPluginNames='")
+                       .append(JOINER.join(paymentControlPluginNames))
+                       .append("'");
+            }
+            log.info(logLine.toString());
+        }
+    }
+}
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
index 0c47d84..772235b 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
@@ -122,7 +122,8 @@ public class TestPaymentHelper {
 
         final InvoiceCreationInternalEvent event = new MockInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
                                                                                 invoice.getBalance(), invoice.getCurrency(),
-                                                                                invoice.getInvoiceDate(), 1L, 2L, null);
+                                                                                invoice.getInvoiceDate(), internalCallContext.getAccountRecordId(),
+                                                                                internalCallContext.getTenantRecordId(), null);
 
         eventBus.post(event);
         return invoice;

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index ca27368..d1cf442 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.109</version>
+        <version>0.111</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.17.1-SNAPSHOT</version>
diff --git a/profiles/killbill/src/main/resources/logback.xml b/profiles/killbill/src/main/resources/logback.xml
index f2cdef8..c2c710a 100644
--- a/profiles/killbill/src/main/resources/logback.xml
+++ b/profiles/killbill/src/main/resources/logback.xml
@@ -43,7 +43,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -64,7 +64,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -85,7 +85,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -106,7 +106,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -127,7 +127,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
@@ -148,7 +148,7 @@
                     </timeBasedFileNamingAndTriggeringPolicy>
                 </rollingPolicy>
                 <encoder>
-                    <pattern>%date [%thread] %maskedMsg%n</pattern>
+                    <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss,SSSZ", UTC} lvl='%level', log='%logger{0}', th='%thread', xff='%X{req.xForwardedFor}', rId='%X{req.requestId}', aRId='%X{kb.accountRecordId}', tRId='%X{kb.tenantRecordId}', %maskedMsg%n</pattern>
                 </encoder>
             </appender>
         </sift>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
index 33e7df6..a33bea7 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestBundle.java
@@ -78,9 +78,17 @@ public class TestBundle extends TestJaxrsBase {
     public void testBundleNonExistent() throws Exception {
         final Account accountJson = createAccount();
 
-        Assert.assertNull(killBillClient.getBundle(UUID.randomUUID()));
-        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), "98374982743892").isEmpty());
-        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId()).isEmpty());
+        // ID
+        Assert.assertNull(killBillClient.getBundle(UUID.randomUUID(), requestOptions));
+
+        // External Key
+        Assert.assertNull(killBillClient.getBundle(UUID.randomUUID().toString(), requestOptions));
+        Assert.assertTrue(killBillClient.getAllBundlesForExternalKey(UUID.randomUUID().toString(), requestOptions).isEmpty());
+
+        // Account Id
+        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), "98374982743892", requestOptions).isEmpty());
+        Assert.assertTrue(killBillClient.getAccountBundles(accountJson.getAccountId(), requestOptions).isEmpty());
+
     }
 
     @Test(groups = "slow", description = "Can handle non existent account")
@@ -102,7 +110,7 @@ public class TestBundle extends TestJaxrsBase {
         final Subscription entitlementJsonNoEvents = createEntitlement(accountJson.getAccountId(), bundleExternalKey, productName,
                                                                        ProductCategory.BASE, term, true);
 
-        final Bundle originalBundle = killBillClient.getBundle(bundleExternalKey);
+        final Bundle originalBundle = killBillClient.getBundle(bundleExternalKey, requestOptions);
         assertEquals(originalBundle.getAccountId(), accountJson.getAccountId());
         assertEquals(originalBundle.getExternalKey(), bundleExternalKey);
 
@@ -113,10 +121,18 @@ public class TestBundle extends TestJaxrsBase {
         bundle.setBundleId(entitlementJsonNoEvents.getBundleId());
         assertEquals(killBillClient.transferBundle(bundle, createdBy, reason, comment).getAccountId(), newAccount.getAccountId());
 
-        final Bundle newBundle = killBillClient.getBundle(bundleExternalKey);
+        final Bundle newBundle = killBillClient.getBundle(bundleExternalKey, requestOptions);
         assertNotEquals(newBundle.getBundleId(), originalBundle.getBundleId());
         assertEquals(newBundle.getExternalKey(), originalBundle.getExternalKey());
         assertEquals(newBundle.getAccountId(), newAccount.getAccountId());
+
+
+        final Bundles bundles = killBillClient.getAllBundlesForExternalKey(bundleExternalKey, requestOptions);
+        assertEquals(bundles.size(), 2);
+        assertEquals(bundles.get(0).getBundleId(), originalBundle.getBundleId());
+        assertEquals(bundles.get(0).getSubscriptions().get(0).getState(), EntitlementState.CANCELLED);
+        assertEquals(bundles.get(1).getBundleId(), newBundle.getBundleId());
+        assertEquals(bundles.get(1).getSubscriptions().get(0).getState(), EntitlementState.ACTIVE);
     }
 
     @Test(groups = "slow", description = "Block a bundle")
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
index 9736a04..a180f70 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPerTenantConfig.java
@@ -18,6 +18,8 @@
 package org.killbill.billing.jaxrs;
 
 import java.util.HashMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
 
 import org.killbill.billing.client.model.Account;
 import org.killbill.billing.client.model.Payments;
@@ -34,6 +36,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
+import com.jayway.awaitility.Awaitility;
+import com.jayway.awaitility.Duration;
 
 public class TestPerTenantConfig extends TestJaxrsBase {
 
@@ -55,7 +59,6 @@ public class TestPerTenantConfig extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testFailedPaymentWithPerTenantRetryConfig() throws Exception {
-
         // Create the tenant
         final String apiKeyTenant1 = "tenantSuperTuned";
         final String apiSecretTenant1 = "2367$$ffr79";
@@ -66,7 +69,7 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         killBillClient.createTenant(tenant1, createdBy, reason, comment);
 
         // Configure our plugin to fail
-        mockPaymentProviderPlugin.makeNextPaymentFailWithError();
+        mockPaymentProviderPlugin.makeAllInvoicesFailWithError(true);
 
         // Upload the config
         final ObjectMapper mapper = new ObjectMapper();
@@ -86,10 +89,6 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         // Because we have specified a retry interval of one day we should see the new attempt after moving clock 1 day (and not 8 days which is default)
         //
 
-        // Configure our plugin to fail AGAIN
-        mockPaymentProviderPlugin.makeNextPaymentFailWithError();
-
-
         //
         // Now unregister special per tenant config and we the first retry occurs one day after (and still fails), it now sets a retry date of 8 days
         //
@@ -97,17 +96,24 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         // org.killbill.tenant.broadcast.rate has been set to 1s
         crappyWaitForLackOfProperSynchonization(2000);
 
-
         clock.addDays(1);
-        crappyWaitForLackOfProperSynchonization(3000);
 
+        Awaitility.await()
+                  .atMost(4, TimeUnit.SECONDS)
+                  .pollInterval(Duration.ONE_SECOND)
+                  .until(new Callable<Boolean>() {
+                      @Override
+                      public Boolean call() throws Exception {
+
+                          return killBillClient.getPaymentsForAccount(accountJson.getAccountId()).get(0).getTransactions().size() == 2;
+                      }
+                  });
         final Payments payments2 = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
         Assert.assertEquals(payments2.size(), 1);
         Assert.assertEquals(payments2.get(0).getTransactions().size(), 2);
         Assert.assertEquals(payments2.get(0).getTransactions().get(0).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
         Assert.assertEquals(payments2.get(0).getTransactions().get(1).getStatus(), TransactionStatus.PAYMENT_FAILURE.name());
 
-
         clock.addDays(1);
         crappyWaitForLackOfProperSynchonization(3000);
 
@@ -116,9 +122,18 @@ public class TestPerTenantConfig extends TestJaxrsBase {
         Assert.assertEquals(payments3.size(), 1);
         Assert.assertEquals(payments3.get(0).getTransactions().size(), 2);
 
+        mockPaymentProviderPlugin.makeAllInvoicesFailWithError(false);
         clock.addDays(7);
-        crappyWaitForLackOfProperSynchonization(3000);
 
+        Awaitility.await()
+                  .atMost(4, TimeUnit.SECONDS)
+                  .pollInterval(Duration.ONE_SECOND)
+                  .until(new Callable<Boolean>() {
+                      @Override
+                      public Boolean call() throws Exception {
+                          return killBillClient.getPaymentsForAccount(accountJson.getAccountId()).get(0).getTransactions().size() == 3;
+                      }
+                  });
         final Payments payments4 = killBillClient.getPaymentsForAccount(accountJson.getAccountId());
         Assert.assertEquals(payments4.size(), 1);
         Assert.assertEquals(payments4.get(0).getTransactions().size(), 3);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
index 6b157c2..820c07f 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
@@ -182,8 +182,7 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
 
     private boolean onPhaseEvent(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent readyPhaseEvent, final InternalCallContext context) {
         try {
-            final DateTime now = clock.getUTCNow();
-            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, context);
+            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, readyPhaseEvent.getEffectiveDate(), context);
             final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                               PhaseEventData.createNextPhaseEvent(subscription.getId(),
                                                                                   nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) :
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();
+    }
 }
diff --git a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
index a451153..3ab047c 100644
--- a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
+++ b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
@@ -25,15 +25,10 @@ import org.killbill.clock.ClockUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
-
-public class BillCycleDayCalculator {
+public abstract class BillCycleDayCalculator {
 
     private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
 
-    public BillCycleDayCalculator() {
-    }
-
     public static int calculateBcdForAlignment(final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final BillingAlignment alignment, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal) {
         int result = 0;
         switch (alignment) {
@@ -50,12 +45,11 @@ public class BillCycleDayCalculator {
         return result;
     }
 
-    @VisibleForTesting
-    static int calculateBcdFromSubscription(final SubscriptionBase subscription, final DateTimeZone accountTimeZone) {
+    private static int calculateBcdFromSubscription(final SubscriptionBase subscription, final DateTimeZone accountTimeZone) {
         final DateTime date = subscription.getDateOfFirstRecurringNonZeroCharge();
         final int bcdLocal = ClockUtil.toDateTime(date, accountTimeZone).getDayOfMonth();
-        log.info("Calculated BCD: subscriptionId='{}', subscriptionStartDate='{}', accountTimeZone='{}', bcd='{}'",
-                 subscription.getId(), date.toDateTimeISO(), accountTimeZone, bcdLocal);
+        log.debug("Calculated BCD: subscriptionId='{}', subscriptionStartDate='{}', accountTimeZone='{}', bcd='{}'",
+                  subscription.getId(), date.toDateTimeISO(), accountTimeZone, bcdLocal);
         return bcdLocal;
     }
 }