killbill-uncached

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

jaxrs/pom.xml 2(+1 -1)

junction/pom.xml 2(+1 -1)

overdue/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

server/pom.xml 2(+1 -1)

tenant/pom.xml 2(+1 -1)

usage/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 44ab661..6b8ee73 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>
diff --git a/analytics/pom.xml b/analytics/pom.xml
index 096b0c5..1eec05b 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-analytics</artifactId>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index aa681d7..b400caa 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-api</artifactId>

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 7ae3fcc..f982d64 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
index 5f20021..853d074 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/DefaultLifecycle.java
@@ -94,10 +94,10 @@ public class DefaultLifecycle implements Lifecycle {
         final Set<KillbillService> result = new HashSet<KillbillService>();
         final Set<Class<? extends KillbillService>> services = serviceFinder.getServices();
         for (final Class<? extends KillbillService> cur : services) {
-            log.info("Found service {}", cur.getName());
+            log.debug("Found service {}", cur.getName());
             try {
                 final KillbillService instance = injector.getInstance(cur);
-                log.info("got instance {}", instance.getName());
+                log.debug("got instance {}", instance.getName());
                 result.add(instance);
             } catch (final Exception e) {
                 logWarn("Failed to inject " + cur.getName(), e);

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 6c51d5e..b2b8614 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index 5996b1d..c140c0a 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index b330f37..39d4a38 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
+
 package com.ning.billing.entitlement.api.svcs;
 
 import java.util.ArrayList;
@@ -25,6 +26,8 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.joda.time.LocalTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ErrorCode;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
@@ -50,7 +53,10 @@ import com.google.inject.Inject;
 
 public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
 
+    private final Logger log = LoggerFactory.getLogger(DefaultEntitlementInternalApi.class);
+
     private final EntitlementDao dao;
+
     private final DefaultSubscriptionApiService apiService;
     private final Clock clock;
 
@@ -64,8 +70,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     }
 
     @Override
-    public List<SubscriptionBundle> getBundlesForAccount(UUID accountId,
-            InternalTenantContext context) {
+    public List<SubscriptionBundle> getBundlesForAccount(final UUID accountId, final InternalTenantContext context) {
         return dao.getSubscriptionBundleForAccount(accountId, context);
     }
 
@@ -87,6 +92,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     }
 
     @Override
+
     public Subscription getSubscriptionFromId(UUID id,
             InternalTenantContext context) throws EntitlementUserApiException {
         final Subscription result = dao.getSubscriptionFromId(id, context);
@@ -97,8 +103,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     }
 
     @Override
-    public SubscriptionBundle getBundleFromId(UUID id,
-            InternalTenantContext context) throws EntitlementUserApiException {
+    public SubscriptionBundle getBundleFromId(final UUID id, final InternalTenantContext context) throws EntitlementUserApiException {
         final SubscriptionBundle result = dao.getSubscriptionBundleFromId(id, context);
         if (result == null) {
             throw new EntitlementUserApiException(ErrorCode.ENT_GET_INVALID_BUNDLE_ID, id.toString());
@@ -107,9 +112,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     }
 
     @Override
-    public UUID getAccountIdFromSubscriptionId(UUID subscriptionId,
-            InternalTenantContext context)
-            throws EntitlementUserApiException {
+    public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId, final InternalTenantContext context) throws EntitlementUserApiException {
         return dao.getAccountIdFromSubscriptionId(subscriptionId, context);
     }
 
@@ -121,6 +124,8 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
         final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
                 .setChargedThroughDate(chargedThroughDate)
                 .setPaidThroughDate(subscription.getPaidThroughDate());
+
+        log.info("Setting CTD for subscription {} to {} ({} local)", new Object[]{subscriptionId, chargedThroughDate, localChargedThruDate});
         dao.updateChargedThroughDate(new SubscriptionData(builder), context);
     }
 
@@ -131,13 +136,13 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     }
 
     @Override
-    public List<EffectiveSubscriptionInternalEvent> getBillingTransitions(Subscription subscription, final InternalTenantContext context) {
+    public List<EffectiveSubscriptionInternalEvent> getBillingTransitions(final Subscription subscription, final InternalTenantContext context) {
         final List<SubscriptionTransitionData> transitions = ((SubscriptionData) subscription).getBillingTransitions();
         return convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(subscription, context, transitions);
     }
 
     private List<EffectiveSubscriptionInternalEvent> convertEffectiveSubscriptionInternalEventFromSubscriptionTransitions(final Subscription subscription,
-            final InternalTenantContext context, final List<SubscriptionTransitionData> transitions) {
+                                                                                                                          final InternalTenantContext context, final List<SubscriptionTransitionData> transitions) {
         return ImmutableList.<EffectiveSubscriptionInternalEvent>copyOf(Collections2.transform(transitions, new Function<SubscriptionTransitionData, EffectiveSubscriptionInternalEvent>() {
             @Override
             @Nullable

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 5712d51..06e28a5 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index fe64a71..e928a24 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -19,6 +19,7 @@ package com.ning.billing.invoice.dao;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -55,8 +56,8 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Ordering;
 import com.google.inject.Inject;
 
 public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, InvoiceApiException> implements InvoiceDao {
@@ -199,13 +200,16 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                         transInvoiceItemSqlDao.create(invoiceItemModelDao, context);
                     }
 
+                    // Now we check whether we generated any credit that could be used on some unpaid invoices
+                    useExistingCBAFromTransaction(invoice.getAccountId(), entitySqlDaoWrapperFactory, context);
+
                     notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions);
 
                     // Create associated payments
                     final InvoicePaymentSqlDao invoicePaymentSqlDao = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class);
                     invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
-                }
 
+                }
                 return null;
             }
         });
@@ -259,18 +263,12 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceModelDao>>() {
             @Override
             public List<InvoiceModelDao> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final List<InvoiceModelDao> invoices = getAllInvoicesByAccountFromTransaction(accountId, entitySqlDaoWrapperFactory, context);
-                final Collection<InvoiceModelDao> unpaidInvoices = Collections2.filter(invoices, new Predicate<InvoiceModelDao>() {
-                    @Override
-                    public boolean apply(final InvoiceModelDao in) {
-                        return (InvoiceModelDaoHelper.getBalance(in).compareTo(BigDecimal.ZERO) >= 1) && (upToDate == null || !in.getTargetDate().isAfter(upToDate));
-                    }
-                });
-                return new ArrayList<InvoiceModelDao>(unpaidInvoices);
+                return getUnpaidInvoicesByAccountFromTransaction(accountId, entitySqlDaoWrapperFactory, upToDate, context);
             }
         });
     }
 
+
     @Override
     public UUID getInvoiceIdByPaymentId(final UUID paymentId, final InternalTenantContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<UUID>() {
@@ -292,7 +290,6 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     }
 
     @Override
-
     public InvoicePaymentModelDao createRefund(final UUID paymentId, final BigDecimal requestedRefundAmount, final boolean isInvoiceAdjusted,
                                                final Map<UUID, BigDecimal> invoiceItemIdsWithNullAmounts, final UUID paymentCookieId,
                                                final InternalCallContext context)
@@ -368,6 +365,9 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                     }
                 }
 
+                // Now we check whether we have any credit that could be used on some unpaid invoices (for which payment was just refunded)
+                useExistingCBAFromTransaction(invoice.getAccountId(), entitySqlDaoWrapperFactory, context);
+
                 // Notify the bus since the balance of the invoice changed
                 notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, invoice.getId(), invoice.getAccountId(), context.getUserToken(), context);
 
@@ -496,18 +496,20 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 final InvoicePaymentModelDao payment = entitySqlDaoWrapperFactory.become(InvoicePaymentSqlDao.class).getById(invoicePaymentId.toString(), context);
                 if (payment == null) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, invoicePaymentId.toString());
-                } else {
-                    final InvoicePaymentModelDao chargeBack = new InvoicePaymentModelDao(UUID.randomUUID(), context.getCreatedDate(), InvoicePaymentType.CHARGED_BACK,
-                                                                                         payment.getInvoiceId(), payment.getPaymentId(), context.getCreatedDate(),
-                                                                                         requestedChargedBackAmout.negate(), payment.getCurrency(), null, payment.getId());
-                    transactional.create(chargeBack, context);
+                }
+                final InvoicePaymentModelDao chargeBack = new InvoicePaymentModelDao(UUID.randomUUID(), context.getCreatedDate(), InvoicePaymentType.CHARGED_BACK,
+                                                                                     payment.getInvoiceId(), payment.getPaymentId(), context.getCreatedDate(),
+                                                                                     requestedChargedBackAmout.negate(), payment.getCurrency(), null, payment.getId());
+                transactional.create(chargeBack, context);
 
-                    // Notify the bus since the balance of the invoice changed
-                    final UUID accountId = transactional.getAccountIdFromInvoicePaymentId(chargeBack.getId().toString(), context);
-                    notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, payment.getInvoiceId(), accountId, context.getUserToken(), context);
+                // Notify the bus since the balance of the invoice changed
+                final UUID accountId = transactional.getAccountIdFromInvoicePaymentId(chargeBack.getId().toString(), context);
+                notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, payment.getInvoiceId(), accountId, context.getUserToken(), context);
 
-                    return chargeBack;
-                }
+                // Now we check whether we have any credit that could be used on some unpaid invoices (for which payment was just charged back)
+                useExistingCBAFromTransaction(accountId, entitySqlDaoWrapperFactory, context);
+
+                return chargeBack;
             }
         });
     }
@@ -625,18 +627,8 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 }
                 populateChildren(invoice, entitySqlDaoWrapperFactory, context);
 
-                final BigDecimal accountCbaAvailable = getAccountCBAFromTransaction(invoice.getAccountId(), entitySqlDaoWrapperFactory, context);
-                final BigDecimal balance = InvoiceModelDaoHelper.getBalance(invoice);
-                if (accountCbaAvailable.compareTo(BigDecimal.ZERO) > 0 && balance.compareTo(BigDecimal.ZERO) > 0) {
-                    final BigDecimal cbaAmountToConsume = accountCbaAvailable.compareTo(balance) > 0 ? balance.negate() : accountCbaAvailable.negate();
-                    final InvoiceItemModelDao cbaAdjItem = new InvoiceItemModelDao(context.getCreatedDate(), InvoiceItemType.CBA_ADJ,
-                                                                                   invoice.getId(), invoice.getAccountId(),
-                                                                                   null, null, null, null,
-                                                                                   context.getCreatedDate().toLocalDate(),
-                                                                                   null, cbaAmountToConsume, null,
-                                                                                   invoice.getCurrency(), null);
-                    transInvoiceItemDao.create(cbaAdjItem, context);
-                }
+                // Now we check whether we have any credit that could be used towards that charge
+                useExistingCBAFromTransaction(accountId, entitySqlDaoWrapperFactory, context);
 
                 // Notify the bus since the balance of the invoice changed
                 notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, invoiceId, accountId, context.getUserToken(), context);
@@ -799,6 +791,58 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         });
     }
 
+    private void useExistingCBAFromTransaction(final UUID accountId, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context) throws InvoiceApiException, EntityPersistenceException {
+
+        final BigDecimal accountCBA = getAccountCBAFromTransaction(accountId, entitySqlDaoWrapperFactory, context);
+        if (accountCBA.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+
+        final List<InvoiceModelDao> unpaidInvoices = getUnpaidInvoicesByAccountFromTransaction(accountId, entitySqlDaoWrapperFactory, null, context);
+        // We order the same os BillingStateCalculator-- should really share the comparator
+        final List<InvoiceModelDao> orderedUnpaidInvoices = Ordering.from(new Comparator<InvoiceModelDao>() {
+            @Override
+            public int compare(final InvoiceModelDao i1, final InvoiceModelDao i2) {
+                return i1.getInvoiceDate().compareTo(i2.getInvoiceDate());
+            }
+        }).immutableSortedCopy(unpaidInvoices);
+
+        BigDecimal remainingAccountCBA = accountCBA;
+        for (InvoiceModelDao cur : orderedUnpaidInvoices) {
+            final BigDecimal curInvoiceBalance = InvoiceModelDaoHelper.getBalance(cur);
+            final BigDecimal cbaToApplyOnInvoice = remainingAccountCBA.compareTo(curInvoiceBalance) <= 0 ? remainingAccountCBA : curInvoiceBalance;
+            remainingAccountCBA = remainingAccountCBA.subtract(cbaToApplyOnInvoice);
+
+
+            final InvoiceItemModelDao cbaAdjItem = new InvoiceItemModelDao(context.getCreatedDate(), InvoiceItemType.CBA_ADJ,
+                                                                           cur.getId(), cur.getAccountId(),
+                                                                           null, null, null, null,
+                                                                           context.getCreatedDate().toLocalDate(),
+                                                                           null, cbaToApplyOnInvoice.negate(), null,
+                                                                           cur.getCurrency(), null);
+
+            final InvoiceItemSqlDao transInvoiceItemDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
+            transInvoiceItemDao.create(cbaAdjItem, context);
+
+            if (remainingAccountCBA.compareTo(BigDecimal.ZERO) <= 0) {
+                break;
+            }
+        }
+    }
+
+
+    private List<InvoiceModelDao> getUnpaidInvoicesByAccountFromTransaction(final UUID accountId, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final LocalDate upToDate, final InternalTenantContext context) {
+        final List<InvoiceModelDao> invoices = getAllInvoicesByAccountFromTransaction(accountId, entitySqlDaoWrapperFactory, context);
+        final Collection<InvoiceModelDao> unpaidInvoices = Collections2.filter(invoices, new Predicate<InvoiceModelDao>() {
+            @Override
+            public boolean apply(final InvoiceModelDao in) {
+                return (InvoiceModelDaoHelper.getBalance(in).compareTo(BigDecimal.ZERO) >= 1) && (upToDate == null || !in.getTargetDate().isAfter(upToDate));
+            }
+        });
+        return new ArrayList<InvoiceModelDao>(unpaidInvoices);
+    }
+
+
     /**
      * Create an adjustment for a given invoice item. This just creates the object in memory, it doesn't write it to disk.
      *
@@ -940,9 +984,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     }
 
     private void notifyOfFutureBillingEvents(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final UUID accountId, final Map<UUID, DateTime> callbackDateTimePerSubscriptions) {
-
-
-        for (UUID subscriptionId : callbackDateTimePerSubscriptions.keySet()) {
+        for (final UUID subscriptionId : callbackDateTimePerSubscriptions.keySet()) {
             final DateTime callbackDateTimeUTC = callbackDateTimePerSubscriptions.get(subscriptionId);
             nextBillingDatePoster.insertNextBillingNotification(entitySqlDaoWrapperFactory, accountId, subscriptionId, callbackDateTimeUTC);
         }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
index af67913..0b6e32e 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -305,8 +305,13 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             return items;
         }
 
-        final Iterator<BillingEvent> eventIt = events.iterator();
+        // Pretty-print the generated invoice items from the junction events
+        final StringBuilder logStringBuilder = new StringBuilder("Invoice items generated for invoiceId ")
+                .append(invoiceId)
+                .append(" and accountId ")
+                .append(accountId);
 
+        final Iterator<BillingEvent> eventIt = events.iterator();
         BillingEvent nextEvent = eventIt.next();
         while (eventIt.hasNext()) {
             final BillingEvent thisEvent = nextEvent;
@@ -314,29 +319,20 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             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;
-                items.addAll(processEvents(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, accountTimeZone, currency));
+                items.addAll(processEvents(invoiceId, accountId, thisEvent, adjustedNextEvent, targetDate, accountTimeZone, currency, logStringBuilder));
             }
         }
-        items.addAll(processEvents(invoiceId, accountId, nextEvent, null, targetDate, accountTimeZone, currency));
-
-        // The above should reproduce the semantics of the code below using iterator instead of list.
-        //
-        //        for (int i = 0; i < events.size(); i++) {
-        //            BillingEvent thisEvent = events.get(i);
-        //            BillingEvent nextEvent = events.isLast(thisEvent) ? null : events.get(i + 1);
-        //            if (nextEvent != null) {
-        //                nextEvent = (thisEvent.getSubscription().getId() == nextEvent.getSubscription().getId()) ? nextEvent : null;
-        //            }
-        //
-        //            items.addAll(processEvents(invoiceId, accountId, thisEvent, nextEvent, targetDate, currency));
-        //        }
+        items.addAll(processEvents(invoiceId, accountId, nextEvent, null, targetDate, accountTimeZone, currency, logStringBuilder));
+
+        log.info(logStringBuilder.toString());
 
         return items;
     }
 
     // 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> processEvents(final UUID invoiceId, final UUID accountId, final BillingEvent thisEvent, @Nullable final BillingEvent nextEvent,
-                                            final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency) throws InvoiceApiException {
+                                            final LocalDate targetDate, final DateTimeZone accountTimeZone, final Currency currency,
+                                            final StringBuilder logStringBuilder) throws InvoiceApiException {
         final List<InvoiceItem> items = new ArrayList<InvoiceItem>();
 
         // Handle fixed price items
@@ -383,7 +379,14 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             }
         }
 
-        log.info("Generated invoice items [{}] from event [{}]", items, thisEvent);
+        // For debugging purposes
+        logStringBuilder.append("\n")
+                        .append(thisEvent);
+        for (final InvoiceItem item : items) {
+            logStringBuilder.append("\n\t")
+                            .append(item);
+        }
+
         return items;
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 7873fe6..5c30c08 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -116,7 +116,6 @@ public class InvoiceDispatcher {
                                     final InternalCallContext context) throws InvoiceApiException {
         final UUID subscriptionId = transition.getSubscriptionId();
         final DateTime targetDate = transition.getEffectiveTransitionTime();
-        log.info("Got subscription transition: type: " + transition.getTransitionType().toString() + "; id: " + subscriptionId.toString() + "; targetDate: " + targetDate.toString());
         processSubscription(subscriptionId, targetDate, context);
     }
 
@@ -179,14 +178,15 @@ public class InvoiceDispatcher {
 
             final Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoices, targetDate, account.getTimeZone(), targetCurrency);
             if (invoice == null) {
-                log.info("Generated null invoice.");
+                log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
                 if (!dryRun) {
                     final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(), context.getUserToken(),
                                                                                context.getAccountRecordId(), context.getTenantRecordId());
                     postEvent(event, accountId, context);
                 }
             } else {
-                log.info("Generated invoice {} with {} items.", invoice.getId().toString(), invoice.getNumberOfItems());
+                log.info("Generated invoice {} with {} items for accountId {} and targetDate {} (targetDateTime {})", new Object[]{invoice.getId(), invoice.getNumberOfItems(),
+                                                                                                                                   accountId, targetDate, targetDateTime});
                 if (!dryRun) {
                     // We need to check whether this is just a 'shell' invoice or a real invoice with items on it
                     final boolean isRealInvoiceWithItems = Collections2.filter(invoice.getInvoiceItems(), new Predicate<InvoiceItem>() {
@@ -288,7 +288,6 @@ public class InvoiceDispatcher {
         for (final UUID subscriptionId : chargeThroughDates.keySet()) {
             if (subscriptionId != null) {
                 final LocalDate chargeThroughDate = chargeThroughDates.get(subscriptionId);
-                log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
                 entitlementApi.setChargedThroughDate(subscriptionId, chargeThroughDate, context);
             }
         }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
index 3763053..e0305ba 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
@@ -84,20 +84,6 @@ public class ExternalChargeInvoiceItem extends InvoiceItemBase {
     }
 
     @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("InvoiceItem = {").append("id = ").append(id.toString()).append(", ");
-        sb.append("invoiceId = ").append(invoiceId.toString()).append(", ");
-        sb.append("accountId = ").append(accountId.toString()).append(", ");
-        sb.append("bundleId = ").append(bundleId == null ? "null" : bundleId.toString()).append(", ");
-        sb.append("description = ").append(planName).append(", ");
-        sb.append("startDate = ").append(startDate.toString()).append(", ");
-        sb.append("amount = ").append(amount == null ? "null" : amount.toString()).append(", ");
-        sb.append("}");
-        return sb.toString();
-    }
-
-    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
index d99a84b..d1635bc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
@@ -95,29 +95,6 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
     }
 
     @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("InvoiceItem = {").append("id = ").append(id.toString()).append(", ");
-        sb.append("invoiceId = ").append(invoiceId.toString()).append(", ");
-        sb.append("accountId = ").append(accountId.toString()).append(", ");
-        sb.append("subscriptionId = ").append(subscriptionId == null ? null : subscriptionId.toString()).append(", ");
-        sb.append("bundleId = ").append(bundleId == null ? null : bundleId.toString()).append(", ");
-        sb.append("planName = ").append(planName).append(", ");
-        sb.append("phaseName = ").append(phaseName).append(", ");
-        sb.append("startDate = ").append(startDate.toString()).append(", ");
-
-        sb.append("amount = ");
-        if (amount == null) {
-            sb.append("null");
-        } else {
-            sb.append(amount.toString());
-        }
-
-        sb.append("}");
-        return sb.toString();
-    }
-
-    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
index f347a45..a49cb62 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
@@ -53,12 +53,18 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
 
     @Override
     public String toString() {
-        return getInvoiceItemType() + ": [startDate=" + startDate + ", endDate="
-               + endDate + ", amount=" + amount + ", currency=" + currency
-               + ", invoiceId=" + invoiceId
-               + ", subscriptionId=" + subscriptionId + ", planName="
-               + planName + ", phaseName=" + phaseName + ", rate=" + rate
-               + ", linkedItemId=" + linkedItemId + "]";
+        // Note: we don't use all fields here, as the output would be overwhelming
+        // (we output all invoice items as they are generated).
+        final StringBuilder sb = new StringBuilder();
+        sb.append(getInvoiceItemType());
+        sb.append("{startDate=").append(startDate);
+        sb.append(", endDate=").append(endDate);
+        sb.append(", amount=").append(amount);
+        sb.append(", rate=").append(rate);
+        sb.append(", subscriptionId=").append(subscriptionId);
+        sb.append(", linkedItemId=").append(linkedItemId);
+        sb.append('}');
+        return sb.toString();
     }
 
     /*
diff --git a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDatePoster.java b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDatePoster.java
index 4e8faf6..f923aff 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDatePoster.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDatePoster.java
@@ -59,14 +59,14 @@ public class DefaultNextBillingDatePoster implements NextBillingDatePoster {
         try {
             nextBillingQueue = notificationQueueService.getNotificationQueue(DefaultInvoiceService.INVOICE_SERVICE_NAME,
                                                                              DefaultNextBillingDateNotifier.NEXT_BILLING_DATE_NOTIFIER_QUEUE);
-            log.info("Queuing next billing date notification. id: {}, timestamp: {}", subscriptionId.toString(), futureNotificationTime.toString());
+            log.info("Queuing next billing date notification at {} for subscriptionId {}", futureNotificationTime.toString(), subscriptionId.toString());
 
             nextBillingQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory, futureNotificationTime, accountId,
                                                                      new NextBillingDateNotificationKey(subscriptionId), context);
         } catch (NoSuchNotificationQueue e) {
             log.error("Attempting to put items on a non-existent queue (NextBillingDateNotifier).", e);
         } catch (IOException e) {
-            log.error("Failed to serialize notficationKey for subscriptionId {}", subscriptionId);
+            log.error("Failed to serialize notificationKey for subscriptionId {}", subscriptionId);
         }
     }
 
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
index 43269b5..736bfe3 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
@@ -631,14 +631,16 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final boolean partialRefund = refundAmount.compareTo(amount) < 0;
         final BigDecimal cba = invoiceDao.getAccountCBA(accountId, internalCallContext);
         final InvoiceModelDao savedInvoice = invoiceDao.getById(invoice.getId(), internalCallContext);
-        assertEquals(cba.compareTo(new BigDecimal("20.0")), 0);
+
+        final BigDecimal expectedCba = balance.compareTo(BigDecimal.ZERO) < 0 ? balance.negate() : BigDecimal.ZERO;
+        assertEquals(cba.compareTo(expectedCba), 0);
         if (partialRefund) {
             // IB = 20 (rec) - 20 (repair) + 20 (cba) - (20 -7) = 7;  AB = IB - CBA = 7 - 20 = -13
             assertEquals(balance.compareTo(new BigDecimal("-13.0")), 0);
-            assertEquals(savedInvoice.getInvoiceItems().size(), 3);
+            assertEquals(savedInvoice.getInvoiceItems().size(), 4);
         } else {
             assertEquals(balance.compareTo(new BigDecimal("0.0")), 0);
-            assertEquals(savedInvoice.getInvoiceItems().size(), 3);
+            assertEquals(savedInvoice.getInvoiceItems().size(), 4);
         }
     }
 
@@ -730,7 +732,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         balance = invoiceDao.getAccountBalance(accountId, internalCallContext);
         assertEquals(balance.compareTo(expectedFinalBalance), 0);
         cba = invoiceDao.getAccountCBA(accountId, internalCallContext);
-        assertEquals(cba.compareTo(new BigDecimal("10.00")), 0);
+        final BigDecimal expectedCba = balance.compareTo(BigDecimal.ZERO) < 0 ? balance.negate() : BigDecimal.ZERO;
+        assertEquals(cba.compareTo(expectedCba), 0);
     }
 
     @Test(groups = "slow")
@@ -738,13 +741,8 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         final UUID accountId = UUID.randomUUID();
         final UUID bundleId = UUID.randomUUID();
-        final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
-        final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        createInvoice(invoice1, true, internalCallContext);
 
-        // CREATE INVOICE WITH A (just) CBA. Should not happen, but that does not matter for that test
-        final CreditBalanceAdjInvoiceItem cbaItem = new CreditBalanceAdjInvoiceItem(invoice1.getId(), accountId, new LocalDate(), new BigDecimal("20.0"), Currency.USD);
-        createInvoiceItem(cbaItem, internalCallContext);
+        invoiceDao.insertCredit(accountId, null,  new BigDecimal("20.0"), new LocalDate(), Currency.USD, internalCallContext);
 
         final InvoiceItemModelDao charge = invoiceDao.insertExternalCharge(accountId, null, bundleId, "bla", new BigDecimal("15.0"), clock.getUTCNow().toLocalDate(), Currency.USD, internalCallContext);
 
@@ -1358,7 +1356,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
     }
 
     @Test(groups = "slow")
-    public void testDeleteCBAPartiallyConsumed() throws Exception {
+    public void testRefundWithCBAPartiallyConsumed() throws Exception {
         final UUID accountId = UUID.randomUUID();
 
         // Create invoice 1
@@ -1377,6 +1375,12 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem1 = new CreditBalanceAdjInvoiceItem(fixedItem1.getInvoiceId(), fixedItem1.getAccountId(),
                                                                                                          fixedItem1.getStartDate(), fixedItem1.getAmount(),
                                                                                                          fixedItem1.getCurrency());
+
+        final UUID paymentId = UUID.randomUUID();
+        final DefaultInvoicePayment defaultInvoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoice1.getId(), clock.getUTCNow().plusDays(12), new BigDecimal("10.0"), Currency.USD);
+
+        invoiceDao.notifyOfPayment(new InvoicePaymentModelDao(defaultInvoicePayment), internalCallContext);
+
         createInvoice(invoice1, true, internalCallContext);
         createInvoiceItem(fixedItem1, internalCallContext);
         createInvoiceItem(repairAdjInvoiceItem, internalCallContext);
@@ -1398,20 +1402,20 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Verify scenario - half of the CBA should have been used
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, internalCallContext).doubleValue(), 5.00);
-        verifyInvoice(invoice1.getId(), 10.00, 10.00);
+        verifyInvoice(invoice1.getId(), 0.00, 10.00);
         verifyInvoice(invoice2.getId(), 0.00, -5.00);
 
-        // Delete the CBA on invoice 1
-        invoiceDao.deleteCBA(accountId, invoice1.getId(), creditBalanceAdjInvoiceItem1.getId(), internalCallContext);
+        // Refund Payment before we can deleted CBA
+        invoiceDao.createRefund(paymentId, new BigDecimal("10.0"), false, ImmutableMap.<UUID,BigDecimal>of(), UUID.randomUUID(), internalCallContext);
 
         // Verify all three invoices were affected
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, internalCallContext).doubleValue(), 0.00);
-        verifyInvoice(invoice1.getId(), 0.00, 0.00);
-        verifyInvoice(invoice2.getId(), 5.00, 0.00);
+        verifyInvoice(invoice1.getId(), 5.00, 5.00);
+        verifyInvoice(invoice2.getId(), 0.00, -5.00);
     }
 
     @Test(groups = "slow")
-    public void testDeleteCBAFullyConsumedTwice() throws Exception {
+    public void testRefundCBAFullyConsumedTwice() throws Exception {
         final UUID accountId = UUID.randomUUID();
 
         // Create invoice 1
@@ -1435,6 +1439,13 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
         createInvoiceItem(repairAdjInvoiceItem, internalCallContext);
         createInvoiceItem(creditBalanceAdjInvoiceItem1, internalCallContext);
 
+
+        final BigDecimal paymentAmount = new BigDecimal("10.00");
+        final UUID paymentId = UUID.randomUUID();
+
+        final DefaultInvoicePayment defaultInvoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoice1.getId(), clock.getUTCNow().plusDays(12), paymentAmount, Currency.USD);
+        invoiceDao.notifyOfPayment(new InvoicePaymentModelDao(defaultInvoicePayment), internalCallContext);
+
         // Create invoice 2
         // Scenario: single item
         // * $5 item
@@ -1465,18 +1476,17 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
 
         // Verify scenario - all CBA should have been used
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, internalCallContext).doubleValue(), 0.00);
-        verifyInvoice(invoice1.getId(), 10.00, 10.00);
+        verifyInvoice(invoice1.getId(), 0.00, 10.00);
         verifyInvoice(invoice2.getId(), 0.00, -5.00);
         verifyInvoice(invoice3.getId(), 0.00, -5.00);
 
-        // Delete the CBA on invoice 1
-        invoiceDao.deleteCBA(accountId, invoice1.getId(), creditBalanceAdjInvoiceItem1.getId(), internalCallContext);
+        invoiceDao.createRefund(paymentId, paymentAmount, false, ImmutableMap.<UUID, BigDecimal>of(), UUID.randomUUID(), internalCallContext);
 
         // Verify all three invoices were affected
         Assert.assertEquals(invoiceDao.getAccountCBA(accountId, internalCallContext).doubleValue(), 0.00);
-        verifyInvoice(invoice1.getId(), 0.00, 0.00);
-        verifyInvoice(invoice2.getId(), 5.00, 0.00);
-        verifyInvoice(invoice3.getId(), 5.00, 0.00);
+        verifyInvoice(invoice1.getId(), 10.00, 10.00);
+        verifyInvoice(invoice2.getId(), 0.00, -5.00);
+        verifyInvoice(invoice3.getId(), 0.00, -5.00);
     }
 
     @Test(groups = "slow")

jaxrs/pom.xml 2(+1 -1)

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 2384e37..2045524 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>

junction/pom.xml 2(+1 -1)

diff --git a/junction/pom.xml b/junction/pom.xml
index 6bf158a..a60f4c2 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 905ef93..0ffa7fd 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -225,23 +225,16 @@ public class DefaultBillingEvent implements BillingEvent {
 
     @Override
     public String toString() {
+        // Note: we don't use all fields here, as the output would be overwhelming
+        // (these events are printed in the logs in junction and invoice).
         final StringBuilder sb = new StringBuilder();
         sb.append("DefaultBillingEvent");
-        sb.append("{account=").append(account);
-        sb.append(", billCycleDay=").append(billCycleDay);
-        sb.append(", subscription=").append(subscription);
+        sb.append("{type=").append(type);
         sb.append(", effectiveDate=").append(effectiveDate);
-        sb.append(", planPhase=").append(planPhase);
-        sb.append(", plan=").append(plan);
-        sb.append(", fixedPrice=").append(fixedPrice);
-        sb.append(", recurringPrice=").append(recurringPrice);
-        sb.append(", currency=").append(currency);
-        sb.append(", description='").append(description).append('\'');
-        sb.append(", billingModeType=").append(billingModeType);
-        sb.append(", billingPeriod=").append(billingPeriod);
-        sb.append(", type=").append(type);
+        sb.append(", planPhaseName=").append(planPhase.getName());
+        sb.append(", subscriptionId=").append(subscription.getId());
         sb.append(", totalOrdering=").append(totalOrdering);
-        sb.append(", timeZone=").append(timeZone);
+        sb.append(", accountId=").append(account.getId());
         sb.append('}');
         return sb.toString();
     }
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 2804a04..8fecc53 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -17,7 +17,6 @@
 package com.ning.billing.junction.plumbing.billing;
 
 import java.util.List;
-import java.util.Map;
 import java.util.SortedSet;
 import java.util.UUID;
 
@@ -58,10 +57,10 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
     @Inject
     public DefaultInternalBillingApi(final AccountInternalApi accountApi,
-            final BillCycleDayCalculator bcdCalculator,
-            final EntitlementInternalApi entitlementApi,
-            final BlockingCalculator blockCalculator,
-            final CatalogService catalogService, final TagInternalApi tagApi) {
+                                     final BillCycleDayCalculator bcdCalculator,
+                                     final EntitlementInternalApi entitlementApi,
+                                     final BlockingCalculator blockCalculator,
+                                     final CatalogService catalogService, final TagInternalApi tagApi) {
         this.accountApi = accountApi;
         this.bcdCalculator = bcdCalculator;
         this.entitlementApi = entitlementApi;
@@ -72,9 +71,6 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
 
     @Override
     public BillingEventSet getBillingEventsForAccountAndUpdateAccountBCD(final UUID accountId, final InternalCallContext context) {
-
-        //final TenantContext context = factory.createTenantContext(API_USER_NAME, CallOrigin.INTERNAL, UserType.SYSTEM);
-
         final List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(accountId, context);
         final DefaultBillingEventSet result = new DefaultBillingEventSet();
 
@@ -95,23 +91,25 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
             log.warn("Failed while getting BillingEvent", e);
         }
 
-        debugLog(result, "********* Billing Events Raw");
+        // 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);
+        eventsToString(logStringBuilder, result, "\nBilling Events Raw");
         blockCalculator.insertBlockingEvents(result, context);
-        debugLog(result, "*********  Billing Events After Blocking");
+        eventsToString(logStringBuilder, result, "\nBilling Events After Blocking");
+        log.info(logStringBuilder.toString());
 
         return result;
     }
 
-
-    private void debugLog(final SortedSet<BillingEvent> result, final String title) {
-        log.info(title);
-        for (final BillingEvent aResult : result) {
-            log.info(aResult.toString());
+    private void eventsToString(final StringBuilder stringBuilder, final SortedSet<BillingEvent> events, final String title) {
+        stringBuilder.append(title);
+        for (final BillingEvent event : events) {
+            stringBuilder.append("\n").append(event.toString());
         }
     }
 
     private void addBillingEventsForBundles(final List<SubscriptionBundle> bundles, final Account account, final InternalCallContext context,
-            final DefaultBillingEventSet result) {
+                                            final DefaultBillingEventSet result) {
         for (final SubscriptionBundle bundle : bundles) {
             final List<Subscription> subscriptions = entitlementApi.getSubscriptionsForBundle(bundle.getId(), context);
 
@@ -151,29 +149,11 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                     result.add(event);
                 } catch (CatalogApiException e) {
                     log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
-                            transition.getId().toString(), e);
+                              transition.getId().toString(), e);
                 } catch (Exception e) {
                     log.warn("Failed while getting BillingEvent", e);
                 }
             }
         }
     }
-
-    /*
-
-    @Override
-    public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId, final InternalTenantContext context) throws EntitlementUserApiException {
-        final UUID result = entitlementApi.getAccountIdFromSubscriptionId(subscriptionId, context);
-        if (result == null) {
-            throw new EntitlementBillingApiException(ErrorCode.ENT_INVALID_SUBSCRIPTION_ID, subscriptionId.toString());
-        }
-        return result;
-    }
-
-    @Override
-    public void setChargedThroughDate(final UUID subscriptionId, final LocalDate ctd, final InternalCallContext context) {
-        entitlementApi.setChargedThroughDate(subscriptionId, ctd, context);
-    }
-
-     */
 }
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
index 4a4c1cc..58145d2 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
@@ -30,6 +30,7 @@ import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.catalog.DefaultPrice;
 import com.ning.billing.catalog.MockInternationalPrice;
 import com.ning.billing.catalog.MockPlan;
@@ -42,6 +43,7 @@ import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.junction.JunctionTestSuite;
+import com.ning.billing.mock.MockAccountBuilder;
 import com.ning.billing.mock.api.MockBillCycleDay;
 import com.ning.billing.util.svcapi.junction.BillingEvent;
 import com.ning.billing.util.svcapi.junction.BillingModeType;
@@ -168,6 +170,13 @@ public class TestDefaultBillingEvent extends JunctionTestSuite {
         Assert.assertEquals(event2, it.next());
     }
 
+    @Test(groups = "fast")
+    public void testToString() throws Exception {
+        // Simple test to ensure we have an easy to read toString representation
+        final BillingEvent event = createEvent(subscription(ID_ZERO), new DateTime("2012-01-01T00:02:04.000Z", DateTimeZone.UTC), SubscriptionTransitionType.CREATE);
+        Assert.assertEquals(event.toString(), "DefaultBillingEvent{type=CREATE, effectiveDate=2012-01-01T00:02:04.000Z, planPhaseName=Test-trial, subscriptionId=00000000-0000-0000-0000-000000000000, totalOrdering=1, accountId=" + event.getAccount().getId().toString() + "}");
+    }
+
     private BillingEvent createEvent(final Subscription sub, final DateTime effectiveDate, final SubscriptionTransitionType type) {
         return createEvent(sub, effectiveDate, type, 1L);
     }
@@ -178,7 +187,8 @@ public class TestDefaultBillingEvent extends JunctionTestSuite {
         final Plan shotgun = new MockPlan();
         final PlanPhase shotgunMonthly = createMockMonthlyPlanPhase(null, BigDecimal.ZERO, PhaseType.TRIAL);
 
-        return new DefaultBillingEvent(null, sub, effectiveDate,
+        final Account account = new MockAccountBuilder().build();
+        return new DefaultBillingEvent(account, sub, effectiveDate,
                                        shotgun, shotgunMonthly,
                                        BigDecimal.ZERO, null, Currency.USD, BillingPeriod.NO_BILLING_PERIOD, new MockBillCycleDay(billCycleDay),
                                        BillingModeType.IN_ADVANCE, "Test Event 1", totalOrdering, type, DateTimeZone.UTC);

overdue/pom.xml 2(+1 -1)

diff --git a/overdue/pom.xml b/overdue/pom.xml
index d5885ce..a887690 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>
diff --git a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
index 82568b0..2419bed 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/api/DefaultOverdueUserApi.java
@@ -72,14 +72,14 @@ public class DefaultOverdueUserApi implements OverdueUserApi {
 
     @Override
     public <T extends Blockable> BillingState<T> getBillingStateFor(final T overdueable, final TenantContext context) throws OverdueException {
-        log.info(String.format("Billing state of of %s requested", overdueable.getId()));
+        log.debug("Billing state of of {} requested", overdueable.getId());
         final OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(overdueable);
         return wrapper.billingState(internalCallContextFactory.createInternalTenantContext(context));
     }
 
     @Override
     public <T extends Blockable> OverdueState<T> refreshOverdueStateFor(final T blockable, final CallContext context) throws OverdueException, OverdueApiException {
-        log.info(String.format("Refresh of %s requested", blockable.getId()));
+        log.info("Refresh of blockable {} ({}) requested", blockable.getId(), blockable.getClass());
         final OverdueWrapper<T> wrapper = factory.createOverdueWrapperFor(blockable);
         return wrapper.refresh(createInternalCallContext(blockable, context));
     }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
index 03540d0..95450ea 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueDispatcher.java
@@ -22,11 +22,11 @@ import java.util.UUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.junction.api.Blockable;
-import com.ning.billing.overdue.OverdueApiException;
-import com.ning.billing.overdue.config.api.OverdueException;
+import com.ning.billing.junction.api.Blockable.Type;
 import com.ning.billing.overdue.wrapper.OverdueWrapperFactory;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
@@ -34,15 +34,15 @@ import com.ning.billing.util.svcapi.entitlement.EntitlementInternalApi;
 import com.google.inject.Inject;
 
 public class OverdueDispatcher {
+
     Logger log = LoggerFactory.getLogger(OverdueDispatcher.class);
 
     private final EntitlementInternalApi entitlementApi;
     private final OverdueWrapperFactory factory;
 
     @Inject
-    public OverdueDispatcher(
-            final EntitlementInternalApi entitlementApi,
-            final OverdueWrapperFactory factory) {
+    public OverdueDispatcher(final EntitlementInternalApi entitlementApi,
+                             final OverdueWrapperFactory factory) {
         this.entitlementApi = entitlementApi;
         this.factory = factory;
     }
@@ -50,37 +50,32 @@ public class OverdueDispatcher {
     public void processOverdueForAccount(final UUID accountId, final InternalCallContext context) {
         final List<SubscriptionBundle> bundles = entitlementApi.getBundlesForAccount(accountId, context);
         for (final SubscriptionBundle bundle : bundles) {
-            processOverdue(bundle, context);
+            processOverdue(Type.SUBSCRIPTION_BUNDLE, bundle, context);
         }
     }
 
     public void processOverdueForBundle(final UUID bundleId, final InternalCallContext context) {
         try {
             final SubscriptionBundle bundle = entitlementApi.getBundleFromId(bundleId, context);
-            processOverdue(bundle, context);
+            processOverdue(Type.SUBSCRIPTION_BUNDLE, bundle, context);
         } catch (EntitlementUserApiException e) {
-            log.error("Error processing Overdue for Bundle with id: " + bundleId.toString(), e);
+            log.error("Error processing Overdue for bundle with id: " + bundleId.toString(), e);
         }
     }
 
-    public void processOverdue(final Blockable blockable, final InternalCallContext context) {
+    public void processOverdue(final Blockable.Type type, final Blockable blockable, final InternalCallContext context) {
         try {
             factory.createOverdueWrapperFor(blockable).refresh(context);
-        } catch (OverdueException e) {
-            log.error("Error processing Overdue for Blockable with id: " + blockable.getId().toString(), e);
-        } catch (OverdueApiException e) {
-            log.error("Error processing Overdue for Blockable with id: " + blockable.getId().toString(), e);
+        } catch (BillingExceptionBase e) {
+            log.error(String.format("Error processing Overdue for blockable %s (type %s)", blockable.getId(), type), e);
         }
     }
 
     public void processOverdue(final Blockable.Type type, final UUID blockableId, final InternalCallContext context) {
         try {
             factory.createOverdueWrapperFor(type, blockableId, context).refresh(context);
-        } catch (OverdueException e) {
-            log.error("Error processing Overdue for Blockable with id: " + blockableId.toString(), e);
-        } catch (OverdueApiException e) {
-            log.error("Error processing Overdue for Blockable with id: " + blockableId.toString(), e);
+        } catch (BillingExceptionBase e) {
+            log.error(String.format("Error processing Overdue for blockable %s (type %s)", blockableId, type), e);
         }
     }
-
 }
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
index 7b3d02d..86af3de 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
@@ -49,20 +49,20 @@ public class OverdueListener {
 
     @Subscribe
     public void handlePaymentInfoEvent(final PaymentInfoInternalEvent event) {
-        log.info(String.format("Received PaymentInfo event %s", event.toString()));
+        log.debug("Received PaymentInfo event {}", event);
         dispatcher.processOverdueForAccount(event.getAccountId(), createCallContext(event.getUserToken(), event.getAccountRecordId(), event.getTenantRecordId()));
     }
 
     @Subscribe
     public void handlePaymentErrorEvent(final PaymentErrorInternalEvent event) {
-        log.info(String.format("Received PaymentError event %s", event.toString()));
+        log.debug("Received PaymentError event {}", event);
         final UUID accountId = event.getAccountId();
         dispatcher.processOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getAccountRecordId(), event.getTenantRecordId()));
     }
 
     @Subscribe
     public void handleInvoiceAdjustmentEvent(final InvoiceAdjustmentInternalEvent event) {
-        log.info(String.format("Received InvoiceAdjustment event %s", event.toString()));
+        log.debug("Received InvoiceAdjustment event {}", event);
         final UUID accountId = event.getAccountId();
         dispatcher.processOverdueForAccount(accountId, createCallContext(event.getUserToken(), event.getAccountRecordId(), event.getTenantRecordId()));
     }

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index 5b901f2..014d231 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index dd82327..1d86c33 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
     <groupId>com.ning.billing</groupId>
     <artifactId>killbill</artifactId>
     <packaging>pom</packaging>
-    <version>0.1.44-SNAPSHOT</version>
+    <version>0.1.45-SNAPSHOT</version>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
     <url>http://github.com/killbill/killbill</url>

server/pom.xml 2(+1 -1)

diff --git a/server/pom.xml b/server/pom.xml
index a563f22..1cc4442 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-server</artifactId>

tenant/pom.xml 2(+1 -1)

diff --git a/tenant/pom.xml b/tenant/pom.xml
index af783c5..80ff7ff 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

usage/pom.xml 2(+1 -1)

diff --git a/usage/pom.xml b/usage/pom.xml
index 180aa93..6b03f41 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 330a0bc..743c8e7 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.44-SNAPSHOT</version>
+        <version>0.1.45-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/com/ning/billing/util/template/translation/DefaultTranslatorBase.java b/util/src/main/java/com/ning/billing/util/template/translation/DefaultTranslatorBase.java
index 421c84f..fbc2b7d 100644
--- a/util/src/main/java/com/ning/billing/util/template/translation/DefaultTranslatorBase.java
+++ b/util/src/main/java/com/ning/billing/util/template/translation/DefaultTranslatorBase.java
@@ -27,13 +27,13 @@ import java.util.ResourceBundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.ning.billing.ErrorCode;
 import com.ning.billing.util.LocaleUtils;
 import com.ning.billing.util.config.catalog.UriAccessor;
 
 import com.google.inject.Inject;
 
 public abstract class DefaultTranslatorBase implements Translator {
+
     protected final TranslatorConfig config;
     protected final Logger log = LoggerFactory.getLogger(DefaultTranslatorBase.class);
 
@@ -58,7 +58,7 @@ public abstract class DefaultTranslatorBase implements Translator {
             return bundle.getString(originalText);
         } else {
             if (config.getDefaultLocale() == null) {
-                log.warn(String.format(ErrorCode.MISSING_DEFAULT_TRANSLATION_RESOURCE.toString(), getTranslationType()));
+                log.debug("No default locale configured, returning original text");
                 return originalText;
             }
 
@@ -72,7 +72,7 @@ public abstract class DefaultTranslatorBase implements Translator {
                     return originalText;
                 }
             } catch (MissingResourceException mrex) {
-                log.warn(String.format(ErrorCode.MISSING_TRANSLATION_RESOURCE.toString(), getTranslationType()));
+                log.warn("Missing translation bundle for locale {}", defaultLocale);
                 return originalText;
             }
         }
@@ -95,9 +95,6 @@ public abstract class DefaultTranslatorBase implements Translator {
             bundle = getBundleFromPropertiesFile(propertiesFileName);
         }
 
-        if (bundle == null) {
-            log.warn(String.format(ErrorCode.MISSING_TRANSLATION_RESOURCE.toString(), getTranslationType()));
-        }
         return bundle;
     }