killbill-memoizeit

invoice: unify createInvoice and createInvoices DAO APIs This

3/11/2017 9:32:37 PM

Details

diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
index 8fd9f9d..18f2da2 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoiceWithRepairLogic.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -727,7 +727,8 @@ public class TestIntegrationInvoiceWithRepairLogic extends TestIntegrationBase {
         newItems.add(repair23);
         newItems.add(recurring3);
         newItems.add(repair3);
-        invoiceDao.createInvoice(shellInvoice, newItems, false, new FutureAccountNotifications(new HashMap<UUID, List<SubscriptionNotification>>()), internalCallContext);
+        shellInvoice.addInvoiceItems(newItems);
+        invoiceDao.createInvoice(shellInvoice, new FutureAccountNotifications(new HashMap<UUID, List<SubscriptionNotification>>()), internalCallContext);
 
 
         // Move ahead one month, verify nothing from previous data was generated
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 3cad92b..c19bb7c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -499,8 +499,9 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
 
             }
         }));
+        migrationInvoice.addInvoiceItems(itemModelDaos);
 
-        dao.createInvoice(migrationInvoice, itemModelDaos, true, new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
+        dao.createInvoices(ImmutableList.<InvoiceModelDao>of(migrationInvoice), internalCallContext);
         return migrationInvoice.getId();
     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
index 4d64d57..e20bef5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/DefaultInvoiceDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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.invoice.dao;
 
 import java.math.BigDecimal;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -79,6 +80,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Ordering;
@@ -257,42 +259,37 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
     }
 
     @Override
-    public void createInvoice(final InvoiceModelDao invoice, final List<InvoiceItemModelDao> invoiceItems,
-                              final boolean isRealInvoice, final FutureAccountNotifications callbackDateTimePerSubscriptions,
+    public void createInvoice(final InvoiceModelDao invoice,
+                              final FutureAccountNotifications callbackDateTimePerSubscriptions,
                               final InternalCallContext context) {
-        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
-            @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
-                final InvoiceSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
+        createInvoices(ImmutableList.<InvoiceModelDao>of(invoice), callbackDateTimePerSubscriptions, context);
+    }
 
-                final InvoiceModelDao currentInvoice = transactional.getById(invoice.getId().toString(), context);
-                if (currentInvoice == null) {
-                    // We only want to insert that invoice if there are real invoiceItems associated to it -- if not, this is just
-                    // a shell invoice and we only need to insert the invoiceItems -- for the already existing invoices
-                    if (isRealInvoice) {
-                        transactional.create(invoice, context);
-                    }
+    @Override
+    public List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoices,
+                                                    final InternalCallContext context) {
+        return createInvoices(invoices, new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of()), context);
+    }
 
-                    // Create the invoice items
-                    final InvoiceItemSqlDao transInvoiceItemSqlDao = entitySqlDaoWrapperFactory.become(InvoiceItemSqlDao.class);
-                    for (final InvoiceItemModelDao invoiceItemModelDao : invoiceItems) {
-                        createInvoiceItemFromTransaction(transInvoiceItemSqlDao, invoiceItemModelDao, context);
-                    }
-                    cbaDao.addCBAComplexityFromTransaction(invoice, entitySqlDaoWrapperFactory, context);
-                    if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
-                        notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context);
-                    }
-                    if (invoice.isParentInvoice()) {
-                        notifyOfParentInvoiceCreation(entitySqlDaoWrapperFactory, invoice, callbackDateTimePerSubscriptions, context);
-                    }
-                }
-                return null;
+    private List<InvoiceItemModelDao> createInvoices(final Iterable<InvoiceModelDao> invoices,
+                                                     final FutureAccountNotifications callbackDateTimePerSubscriptions,
+                                                     final InternalCallContext context) {
+        final Collection<UUID> createdInvoiceIds = new HashSet<UUID>();
+        final Collection<UUID> adjustedInvoiceIds = new HashSet<UUID>();
+        final Collection<UUID> committedInvoiceIds = new HashSet<UUID>();
+
+        final Collection<UUID> uniqueInvoiceIds = new HashSet<UUID>();
+        for (final InvoiceModelDao invoiceModelDao : invoices) {
+            for (final InvoiceItemModelDao invoiceItemModelDao : invoiceModelDao.getInvoiceItems()) {
+                uniqueInvoiceIds.add(invoiceItemModelDao.getInvoiceId());
             }
-        });
-    }
+        }
+
+        if (Iterables.<InvoiceModelDao>isEmpty(invoices)) {
+            return ImmutableList.<InvoiceItemModelDao>of();
+        }
+        final UUID accountId = invoices.iterator().next().getAccountId();
 
-    @Override
-    public List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoices, final InternalCallContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<InvoiceItemModelDao>>() {
             @Override
             public List<InvoiceItemModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
@@ -301,37 +298,49 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
 
                 final List<InvoiceItemModelDao> createdInvoiceItems = new LinkedList<InvoiceItemModelDao>();
                 for (final InvoiceModelDao invoiceModelDao : invoices) {
-                    boolean madeChanges = false;
-                    boolean newInvoice = false;
+                    final boolean isRealInvoice = uniqueInvoiceIds.remove(invoiceModelDao.getId());
 
                     // Create the invoice if needed
                     if (invoiceSqlDao.getById(invoiceModelDao.getId().toString(), context) == null) {
-                        invoiceSqlDao.create(invoiceModelDao, context);
-                        madeChanges = true;
-                        newInvoice = true;
+                        // We only want to insert that invoice if there are real invoiceItems associated to it -- if not, this is just
+                        // a shell invoice and we only need to insert the invoiceItems -- for the already existing invoices
+                        if (isRealInvoice) {
+                            invoiceSqlDao.create(invoiceModelDao, context);
+                            createdInvoiceIds.add(invoiceModelDao.getId());
+                        }
                     }
 
-                    // Create the invoice items if needed
+                    // Create the invoice items if needed (note: they may not necessarily belong to that invoice)
                     for (final InvoiceItemModelDao invoiceItemModelDao : invoiceModelDao.getInvoiceItems()) {
                         if (transInvoiceItemSqlDao.getById(invoiceItemModelDao.getId().toString(), context) == null) {
                             createInvoiceItemFromTransaction(transInvoiceItemSqlDao, invoiceItemModelDao, context);
                             createdInvoiceItems.add(transInvoiceItemSqlDao.getById(invoiceItemModelDao.getId().toString(), context));
-                            madeChanges = true;
-                        }
-                    }
 
-                    if (madeChanges) {
-                        cbaDao.addCBAComplexityFromTransaction(invoiceModelDao.getId(), entitySqlDaoWrapperFactory, context);
+                            adjustedInvoiceIds.add(invoiceItemModelDao.getInvoiceId());
+                        }
                     }
 
+                    final boolean wasInvoiceCreated = createdInvoiceIds.contains(invoiceModelDao.getId());
                     if (InvoiceStatus.COMMITTED.equals(invoiceModelDao.getStatus())) {
-                        if (newInvoice) {
+                        committedInvoiceIds.add(invoiceModelDao.getId());
+
+                        notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoiceModelDao.getAccountId(), callbackDateTimePerSubscriptions, context);
+
+                        if (wasInvoiceCreated) {
                             notifyBusOfInvoiceCreation(entitySqlDaoWrapperFactory, invoiceModelDao, context);
-                        } else if (madeChanges) {
-                            // Notify the bus since the balance of the invoice changed (only if the invoice is COMMITTED)
-                            // TODO should we post an InvoiceCreationInternalEvent event instead? Note! This will trigger a payment (see InvoiceHandler)
-                            notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, invoiceModelDao.getId(), invoiceModelDao.getAccountId(), context.getUserToken(), context);
                         }
+                    } else if (wasInvoiceCreated && invoiceModelDao.isParentInvoice()) {
+                        // Commit queue
+                        notifyOfParentInvoiceCreation(entitySqlDaoWrapperFactory, invoiceModelDao, context);
+                    }
+                }
+
+                for (final UUID adjustedInvoiceId : adjustedInvoiceIds) {
+                    cbaDao.addCBAComplexityFromTransaction(adjustedInvoiceId, entitySqlDaoWrapperFactory, context);
+
+                    if (committedInvoiceIds.contains(adjustedInvoiceId) && !createdInvoiceIds.contains(adjustedInvoiceId)) {
+                        // Notify the bus since the balance of the invoice changed (only if the invoice is COMMITTED)
+                        notifyBusOfInvoiceAdjustment(entitySqlDaoWrapperFactory, adjustedInvoiceId, accountId, context.getUserToken(), context);
                     }
                 }
 
@@ -1040,9 +1049,10 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         }
     }
 
-    private void notifyOfParentInvoiceCreation(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InvoiceModelDao parentInvoice,
-                                               final FutureAccountNotifications callbackDateTime, final InternalCallContext context) {
-        DateTime futureNotificationDate = parentInvoice.getCreatedDate().withTimeAtStartOfDay().plusDays(1);
+    private void notifyOfParentInvoiceCreation(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory,
+                                               final InvoiceModelDao parentInvoice,
+                                               final InternalCallContext context) {
+        final DateTime futureNotificationDate = parentInvoice.getCreatedDate().withTimeAtStartOfDay().plusDays(1);
         parentInvoiceCommitmentPoster.insertParentInvoiceFromTransactionInternal(entitySqlDaoWrapperFactory, parentInvoice.getId(), futureNotificationDate, context);
     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
index ca7c49b..377b150 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceDao.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -39,15 +39,15 @@ import org.killbill.billing.util.entity.dao.EntityDao;
 
 public interface InvoiceDao extends EntityDao<InvoiceModelDao, Invoice, InvoiceApiException> {
 
-    void createInvoice(final InvoiceModelDao invoice, final List<InvoiceItemModelDao> invoiceItems,
-                       final boolean isRealInvoice, final FutureAccountNotifications callbackDateTimePerSubscriptions,
+    void createInvoice(final InvoiceModelDao invoice,
+                       final FutureAccountNotifications callbackDateTimePerSubscriptions,
                        final InternalCallContext context);
 
+    List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoices, final InternalCallContext context);
+
     public void setFutureAccountNotificationsForEmptyInvoice(final UUID accountId, final FutureAccountNotifications callbackDateTimePerSubscriptions,
                                                              final InternalCallContext context);
 
-    List<InvoiceItemModelDao> createInvoices(final List<InvoiceModelDao> invoices, final InternalCallContext context);
-
     InvoiceModelDao getByNumber(Integer number, InternalTenantContext context) throws InvoiceApiException;
 
     List<InvoiceModelDao> getInvoicesByAccount(InternalTenantContext context);
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 cc85579..6dc0826 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -66,7 +66,6 @@ import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.invoice.api.InvoiceNotifier;
 import org.killbill.billing.invoice.api.InvoiceStatus;
 import org.killbill.billing.invoice.api.user.DefaultInvoiceAdjustmentEvent;
-import org.killbill.billing.invoice.api.user.DefaultInvoiceCreationEvent;
 import org.killbill.billing.invoice.api.user.DefaultInvoiceNotificationInternalEvent;
 import org.killbill.billing.invoice.api.user.DefaultNullInvoiceEvent;
 import org.killbill.billing.invoice.calculator.InvoiceCalculatorUtils;
@@ -119,7 +118,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
@@ -406,7 +404,7 @@ public class InvoiceDispatcher {
                     final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(),
                                                                                context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
 
-                    commitInvoiceAndSetFutureNotifications(account, null, ImmutableList.<InvoiceItemModelDao>of(), futureAccountNotifications, false, context);
+                    commitInvoiceAndSetFutureNotifications(account, null, futureAccountNotifications, context);
                     postEvent(event);
                 }
                 return null;
@@ -434,18 +432,17 @@ public class InvoiceDispatcher {
 
                 // Transformation to Invoice -> InvoiceModelDao
                 final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
-                final Iterable<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
+                final List<InvoiceItemModelDao> invoiceItemModelDaos = transformToInvoiceModelDao(invoice.getInvoiceItems());
+                invoiceModelDao.addInvoiceItems(invoiceItemModelDaos);
 
                 // Commit invoice on disk
-                final boolean isThereAnyItemsLeft = commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, invoiceItemModelDaos, futureAccountNotifications, isRealInvoiceWithItems, context);
+                final boolean isThereAnyItemsLeft = commitInvoiceAndSetFutureNotifications(account, invoiceModelDao, futureAccountNotifications, context);
 
                 final boolean isRealInvoiceWithNonEmptyItems = isThereAnyItemsLeft ? isRealInvoiceWithItems : false;
 
                 setChargedThroughDates(invoice.getInvoiceItems(FixedPriceInvoiceItem.class), invoice.getInvoiceItems(RecurringInvoiceItem.class), context);
 
                 if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
-                    // TODO we should send bus events when we commit the invoice on disk in commitInvoice
-                    postEvents(account, invoice, adjustedUniqueOtherInvoiceId, isRealInvoiceWithNonEmptyItems, context);
                     notifyAccountIfEnabled(account, invoice, isRealInvoiceWithNonEmptyItems, context);
                 }
 
@@ -502,8 +499,8 @@ public class InvoiceDispatcher {
         return new FutureAccountNotifications(result);
     }
 
-    private Iterable<InvoiceItemModelDao> transformToInvoiceModelDao(final List<InvoiceItem> invoiceItems) {
-        return Iterables.transform(invoiceItems,
+    private List<InvoiceItemModelDao> transformToInvoiceModelDao(final List<InvoiceItem> invoiceItems) {
+        return Lists.transform(invoiceItems,
                                    new Function<InvoiceItem, InvoiceItemModelDao>() {
                                        @Override
                                        public InvoiceItemModelDao apply(final InvoiceItem input) {
@@ -539,37 +536,19 @@ public class InvoiceDispatcher {
         log.info(tmp.toString());
     }
 
-    private boolean commitInvoiceAndSetFutureNotifications(final ImmutableAccountData account, final InvoiceModelDao invoiceModelDao,
-                                                           final Iterable<InvoiceItemModelDao> invoiceItemModelDaos,
+    private boolean commitInvoiceAndSetFutureNotifications(final ImmutableAccountData account,
+                                                           @Nullable final InvoiceModelDao invoiceModelDao,
                                                            final FutureAccountNotifications futureAccountNotifications,
-                                                           final boolean isRealInvoiceWithItems, final InternalCallContext context) throws SubscriptionBaseApiException, InvoiceApiException {
-        final boolean isThereAnyItemsLeft = invoiceItemModelDaos.iterator().hasNext();
+                                                           final InternalCallContext context) throws SubscriptionBaseApiException, InvoiceApiException {
+        final boolean isThereAnyItemsLeft = invoiceModelDao != null && !invoiceModelDao.getInvoiceItems().isEmpty();
         if (isThereAnyItemsLeft) {
-            invoiceDao.createInvoice(invoiceModelDao, ImmutableList.copyOf(invoiceItemModelDaos), isRealInvoiceWithItems, futureAccountNotifications, context);
+            invoiceDao.createInvoice(invoiceModelDao, futureAccountNotifications, context);
         } else {
             invoiceDao.setFutureAccountNotificationsForEmptyInvoice(account.getId(), futureAccountNotifications, context);
         }
         return isThereAnyItemsLeft;
     }
 
-    private void postEvents(final ImmutableAccountData account, final Invoice invoice, final Set<UUID> adjustedUniqueOtherInvoiceId, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) {
-
-        final List<InvoiceInternalEvent> events = new ArrayList<InvoiceInternalEvent>();
-        if (isRealInvoiceWithNonEmptyItems) {
-            events.add(new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
-                                                       invoice.getBalance(), invoice.getCurrency(),
-                                                       context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()));
-        }
-        for (final UUID cur : adjustedUniqueOtherInvoiceId) {
-            final InvoiceAdjustmentInternalEvent event = new DefaultInvoiceAdjustmentEvent(cur, invoice.getAccountId(),
-                                                                                           context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
-            events.add(event);
-        }
-        for (final InvoiceInternalEvent event : events) {
-            postEvent(event);
-        }
-    }
-
     private void notifyAccountIfEnabled(final ImmutableAccountData account, final Invoice invoice, final boolean isRealInvoiceWithNonEmptyItems, final InternalCallContext context) throws InvoiceApiException, AccountApiException {
         // Ideally we would retrieve the cached version, all the invoice code has been modified to only use ImmutableAccountData, except for the
         // isNotifiedForInvoice piece that should probably live outside of invoice code anyways... (see https://github.com/killbill/killbill-email-notifications-plugin)
@@ -823,11 +802,8 @@ public class InvoiceDispatcher {
             final InvoiceItem parentInvoiceItem = new ParentInvoiceItem(UUID.randomUUID(), context.getCreatedDate(), draftParentInvoice.getId(), childAccount.getParentAccountId(), childAccount.getId(), childInvoiceAmount, childAccount.getCurrency(), description);
             draftParentInvoice.addInvoiceItem(new InvoiceItemModelDao(parentInvoiceItem));
 
-            // build account date time zone
-            final FutureAccountNotifications futureAccountNotifications = new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of());
-
             log.info("Adding new itemId='{}', amount='{}' on new DRAFT invoiceId='{}'", parentInvoiceItem.getId(), childInvoiceAmount, draftParentInvoice.getId());
-            invoiceDao.createInvoice(draftParentInvoice, draftParentInvoice.getInvoiceItems(), true, futureAccountNotifications, parentContext);
+            invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(draftParentInvoice), parentContext);
         }
 
         // save parent child invoice relation
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
index 8ba0cc8..8ddb1f2 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/MockInvoiceDao.java
@@ -61,8 +61,8 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
     }
 
     @Override
-    public void createInvoice(final InvoiceModelDao invoice, final List<InvoiceItemModelDao> invoiceItems,
-                              final boolean isRealInvoice, final FutureAccountNotifications callbackDateTimePerSubscriptions, final InternalCallContext context) {
+    public void createInvoice(final InvoiceModelDao invoice,
+                              final FutureAccountNotifications callbackDateTimePerSubscriptions, final InternalCallContext context) {
         synchronized (monitor) {
             storeInvoice(invoice, context);
         }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
index 1bf8600..44d6178 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceDao.java
@@ -45,8 +45,6 @@ import org.killbill.billing.catalog.api.PhaseType;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.entity.EntityPersistenceException;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications;
-import org.killbill.billing.invoice.InvoiceDispatcher.FutureAccountNotifications.SubscriptionNotification;
 import org.killbill.billing.invoice.InvoiceTestSuiteWithEmbeddedDB;
 import org.killbill.billing.invoice.MockBillingEventSet;
 import org.killbill.billing.invoice.api.Invoice;
@@ -106,7 +104,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     public void testSimple() throws Exception {
         final UUID accountId = account.getId();
         final Invoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), clock.getUTCToday(), Currency.USD);
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final InvoiceModelDao retrievedInvoice = invoiceDao.getById(invoice.getId(), context);
         invoiceUtil.checkInvoicesEqual(retrievedInvoice, invoice);
@@ -114,12 +112,12 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testCreationAndRetrievalByAccount() {
+    public void testCreationAndRetrievalByAccount() throws EntityPersistenceException {
         final UUID accountId = account.getId();
         final Invoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), clock.getUTCToday(), Currency.USD);
         final LocalDate invoiceDate = invoice.getInvoiceDate();
 
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final List<InvoiceModelDao> invoices = invoiceDao.getInvoicesByAccount(context);
         assertNotNull(invoices);
@@ -133,7 +131,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testInvoicePayment() throws InvoiceApiException {
+    public void testInvoicePayment() throws InvoiceApiException, EntityPersistenceException {
         final UUID accountId = account.getId();
         final Invoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), clock.getUTCToday(), Currency.USD);
         final UUID invoiceId = invoice.getId();
@@ -145,7 +143,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                  new BigDecimal("21.00"), new BigDecimal("7.00"), Currency.USD);
 
         invoice.addInvoiceItem(invoiceItem);
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final InvoiceModelDao savedInvoice = invoiceDao.getById(invoiceId, context);
         assertNotNull(savedInvoice);
@@ -239,7 +237,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Create invoice 1 (subscriptions 1-4)
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final UUID invoiceId1 = invoice1.getId();
 
@@ -264,7 +262,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Create invoice 2 (subscriptions 1-3)
         final DefaultInvoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final UUID invoiceId2 = invoice2.getId();
 
@@ -315,7 +313,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Create invoice 1 (subscriptions 1-4)
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final UUID invoiceId1 = invoice1.getId();
 
@@ -340,7 +338,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // create invoice 2 (subscriptions 1-3)
         final DefaultInvoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final UUID invoiceId2 = invoice2.getId();
 
@@ -390,7 +388,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // Create invoice 1 (subscriptions 1-4)
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final UUID invoiceId1 = invoice1.getId();
 
@@ -431,7 +429,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         // create invoice 2 (subscriptions 1-3)
         final DefaultInvoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final UUID invoiceId2 = invoice2.getId();
 
@@ -476,15 +474,15 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testGetInvoicesForAccountAfterDate() {
+    public void testGetInvoicesForAccountAfterDate() throws EntityPersistenceException {
         final UUID accountId = account.getId();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate targetDate2 = new LocalDate(2011, 12, 6);
         final Invoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate2, Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         List<InvoiceModelDao> invoices;
         invoices = invoiceDao.getInvoicesByAccount(new LocalDate(2011, 1, 1), context);
@@ -509,7 +507,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -539,7 +537,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -563,7 +561,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice  invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -588,7 +586,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID accountId = account.getId();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final BigDecimal payment1 = new BigDecimal("48.0");
         final InvoicePayment payment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD, Currency.USD, null, true);
@@ -609,7 +607,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -659,7 +657,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
 
         final Invoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -747,7 +745,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -843,7 +841,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -906,7 +904,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         // NEXT RECURRING on invoice 2
 
         final Invoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1.plusMonths(1), Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final RecurringInvoiceItem nextItem = new RecurringInvoiceItem(invoice2.getId(), accountId, bundleId, UUID.randomUUID(), "test plan", "test bla", startDate.plusMonths(1),
                                                                        endDate.plusMonths(1), rate2, rate2, Currency.USD);
@@ -987,7 +985,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         // Create one invoice with a fixed invoice item
         final LocalDate targetDate = new LocalDate(2011, 2, 15);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
 
@@ -1030,7 +1028,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -1059,7 +1057,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         final LocalDate targetDate2 = new LocalDate(2011, 7, 1);
         final Invoice invoice2 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate2, Currency.USD);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final LocalDate startDate2 = new LocalDate(2011, 6, 1);
         final LocalDate endDate2 = startDate2.plusMonths(3);
@@ -1085,7 +1083,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final UUID bundleId = UUID.randomUUID();
         final LocalDate targetDate1 = new LocalDate(2011, 10, 6);
         final Invoice invoice1 = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate1, Currency.USD);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
 
         final LocalDate startDate = new LocalDate(2011, 3, 1);
         final LocalDate endDate = startDate.plusMonths(1);
@@ -1134,7 +1132,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
      *
      */
     @Test(groups = "slow")
-    public void testInvoiceGenerationForImmediateChanges() throws InvoiceApiException, CatalogApiException {
+    public void testInvoiceGenerationForImmediateChanges() throws InvoiceApiException, CatalogApiException, EntityPersistenceException {
         final UUID accountId = account.getId();
         final List<Invoice> invoiceList = new ArrayList<Invoice>();
         final LocalDate targetDate = new LocalDate(2011, 2, 16);
@@ -1181,8 +1179,8 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertEquals(invoice2.getBalance(), KillBillMoney.of(FIVE, invoice2.getCurrency()));
         invoiceList.add(invoice2);
 
-        invoiceUtil.createInvoice(invoice1, true, context);
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
+        invoiceUtil.createInvoice(invoice2, context);
 
         final InvoiceModelDao savedInvoice1 = invoiceDao.getById(invoice1.getId(), context);
         assertEquals(InvoiceModelDaoHelper.getBalance(savedInvoice1), KillBillMoney.of(TEN, savedInvoice1.getCurrency()));
@@ -1297,7 +1295,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testMixedModeInvoicePersistence() throws InvoiceApiException, CatalogApiException {
+    public void testMixedModeInvoicePersistence() throws InvoiceApiException, CatalogApiException, EntityPersistenceException {
         final Currency currency = Currency.USD;
         final DefaultPrice zeroPrice = new DefaultPrice(BigDecimal.ZERO, Currency.USD);
         final MockInternationalPrice fixedPrice = new MockInternationalPrice(zeroPrice);
@@ -1332,7 +1330,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         assertEquals(invoice.getNumberOfItems(), 2);
         assertEquals(invoice.getBalance().compareTo(cheapAmount), 0);
 
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
         final InvoiceModelDao savedInvoice = invoiceDao.getById(invoice.getId(), context);
 
         assertNotNull(savedInvoice);
@@ -1341,7 +1339,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testRefundedInvoiceWithInvoiceItemAdjustmentWithRepair() throws InvoiceApiException {
+    public void testRefundedInvoiceWithInvoiceItemAdjustmentWithRepair() throws InvoiceApiException, EntityPersistenceException {
         final UUID accountId = account.getId();
         final UUID subscriptionId = UUID.randomUUID();
         final UUID bundleId = UUID.randomUUID();
@@ -1361,7 +1359,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                  recuringStartDate, recuringEndDate, new BigDecimal("239.00"), new BigDecimal("239.00"), Currency.USD);
 
         invoice.addInvoiceItem(invoiceItem);
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         ((ClockMock) clock).addDays(1);
 
@@ -1400,7 +1398,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         events.add(event1);
         final InvoiceWithMetadata newInvoiceWithMetadata = generator.generateInvoice(account, events, invoices, targetDate, Currency.USD, context);
         final Invoice newInvoice = newInvoiceWithMetadata.getInvoice();
-        invoiceUtil.createInvoice(newInvoice, true, context);
+        invoiceUtil.createInvoice(newInvoice, context);
 
         // VERIFY THAT WE STILL HAVE ONLY 2 ITEMS, MEANING THERE WERE NO REPAIR AND NO CBA GENERATED
         final Invoice firstInvoice = new DefaultInvoice(invoiceDao.getById(invoiceId, context));
@@ -1409,7 +1407,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testInvoiceNumber() throws InvoiceApiException {
+    public void testInvoiceNumber() throws InvoiceApiException, EntityPersistenceException {
         final Currency currency = Currency.USD;
         final DateTime targetDate1 = clock.getUTCNow().plusMonths(1);
         final DateTime targetDate2 = clock.getUTCNow().plusMonths(2);
@@ -1437,7 +1435,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         InvoiceWithMetadata invoiceWithMetadata1 = generator.generateInvoice(account, events, invoices, new LocalDate(targetDate1), Currency.USD, context);
         Invoice invoice1 = invoiceWithMetadata1.getInvoice();
         invoices.add(invoice1);
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
         invoice1 = new DefaultInvoice(invoiceDao.getById(invoice1.getId(), context));
         assertNotNull(invoice1.getInvoiceNumber());
 
@@ -1448,7 +1446,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         events.add(event2);
         InvoiceWithMetadata invoiceWithMetadata2 = generator.generateInvoice(account, events, invoices, new LocalDate(targetDate2), Currency.USD, context);
         Invoice invoice2 = invoiceWithMetadata2.getInvoice();
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
         invoice2 = new DefaultInvoice(invoiceDao.getById(invoice2.getId(), context));
         assertNotNull(invoice2.getInvoiceNumber());
     }
@@ -1473,7 +1471,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem1 = new CreditBalanceAdjInvoiceItem(fixedItem1.getInvoiceId(), fixedItem1.getAccountId(),
                                                                                                          fixedItem1.getStartDate(), fixedItem1.getAmount(),
                                                                                                          fixedItem1.getCurrency());
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
         invoiceUtil.createInvoiceItem(fixedItem1, context);
         invoiceUtil.createInvoiceItem(repairAdjInvoiceItem, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem1, context);
@@ -1511,7 +1509,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
                                                                                                          fixedItem1.getStartDate(), fixedItem1.getAmount(),
                                                                                                          fixedItem1.getCurrency());
 
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
         invoiceUtil.createInvoiceItem(fixedItem1, context);
         invoiceUtil.createInvoiceItem(repairAdjInvoiceItem, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem1, context);
@@ -1532,7 +1530,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem2 = new CreditBalanceAdjInvoiceItem(fixedItem2.getInvoiceId(), fixedItem2.getAccountId(),
                                                                                                          fixedItem2.getStartDate(), fixedItem2.getAmount().negate(),
                                                                                                          fixedItem2.getCurrency());
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
         invoiceUtil.createInvoiceItem(fixedItem2, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem2, context);
 
@@ -1570,7 +1568,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem1 = new CreditBalanceAdjInvoiceItem(fixedItem1.getInvoiceId(), fixedItem1.getAccountId(),
                                                                                                          fixedItem1.getStartDate(), fixedItem1.getAmount(),
                                                                                                          fixedItem1.getCurrency());
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
         invoiceUtil.createInvoiceItem(fixedItem1, context);
         invoiceUtil.createInvoiceItem(repairAdjInvoiceItem, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem1, context);
@@ -1592,7 +1590,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem2 = new CreditBalanceAdjInvoiceItem(fixedItem2.getInvoiceId(), fixedItem2.getAccountId(),
                                                                                                          fixedItem2.getStartDate(), fixedItem2.getAmount().negate(),
                                                                                                          fixedItem2.getCurrency());
-        invoiceUtil.createInvoice(invoice2, true, context);
+        invoiceUtil.createInvoice(invoice2, context);
         invoiceUtil.createInvoiceItem(fixedItem2, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem2, context);
 
@@ -1606,7 +1604,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem3 = new CreditBalanceAdjInvoiceItem(fixedItem3.getInvoiceId(), fixedItem3.getAccountId(),
                                                                                                          fixedItem3.getStartDate(), fixedItem3.getAmount().negate(),
                                                                                                          fixedItem3.getCurrency());
-        invoiceUtil.createInvoice(invoice3, true, context);
+        invoiceUtil.createInvoice(invoice3, context);
         invoiceUtil.createInvoiceItem(fixedItem3, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem3, context);
 
@@ -1641,7 +1639,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         final CreditBalanceAdjInvoiceItem creditBalanceAdjInvoiceItem1 = new CreditBalanceAdjInvoiceItem(invoice1.getId(), invoice1.getAccountId(),
                                                                                                          invoice1.getInvoiceDate(), repairAdjInvoiceItem.getAmount().negate(),
                                                                                                          invoice1.getCurrency());
-        invoiceUtil.createInvoice(invoice1, true, context);
+        invoiceUtil.createInvoice(invoice1, context);
         invoiceUtil.createInvoiceItem(repairAdjInvoiceItem, context);
         invoiceUtil.createInvoiceItem(creditBalanceAdjInvoiceItem1, context);
 
@@ -1667,7 +1665,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     public void testWithFailedPaymentAttempt() throws Exception {
         final UUID accountId = account.getId();
         final Invoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), clock.getUTCToday(), Currency.USD);
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final UUID bundleId = UUID.randomUUID();
         final UUID subscriptionId = UUID.randomUUID();
@@ -1749,9 +1747,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
         InvoiceItem parentInvoiceItem = new ParentInvoiceItem(UUID.randomUUID(), today, parentInvoice.getId(), parentAccountId, childAccountId, BigDecimal.TEN, account.getCurrency(), "");
         parentInvoice.addInvoiceItem(new InvoiceItemModelDao(parentInvoiceItem));
 
-        // build account date time zone
-        final FutureAccountNotifications futureAccountNotifications = new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of());
-        invoiceDao.createInvoice(parentInvoice, parentInvoice.getInvoiceItems(), true, futureAccountNotifications, context);
+        invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(parentInvoice), context);
 
         final InvoiceModelDao parentDraftInvoice = invoiceDao.getParentDraftInvoice(parentAccountId, context);
 
@@ -1762,7 +1758,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testRetrieveInvoiceItemsByParentInvoice() throws InvoiceApiException {
+    public void testRetrieveInvoiceItemsByParentInvoice() throws InvoiceApiException, EntityPersistenceException {
         final UUID childAccountId = account.getId();
         final Invoice childInvoice = new DefaultInvoice(childAccountId, clock.getUTCToday(), clock.getUTCToday(), Currency.USD);
         final UUID invoiceId = childInvoice.getId();
@@ -1776,7 +1772,7 @@ public class TestInvoiceDao extends InvoiceTestSuiteWithEmbeddedDB {
 
         childInvoice.addInvoiceItem(invoiceItem);
         childInvoice.addInvoiceItem(invoiceAdj);
-        invoiceUtil.createInvoice(childInvoice, true, context);
+        invoiceUtil.createInvoice(childInvoice, context);
 
         final UUID parentInvoiceId = UUID.randomUUID();
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemDao.java b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemDao.java
index 20c682e..d5e3631 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemDao.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/dao/TestInvoiceItemDao.java
@@ -134,7 +134,7 @@ public class TestInvoiceItemDao extends InvoiceTestSuiteWithEmbeddedDB {
         final LocalDate targetDate = new LocalDate(2011, 5, 23);
         final DefaultInvoice invoice = new DefaultInvoice(accountId, clock.getUTCToday(), targetDate, Currency.USD);
 
-        invoiceUtil.createInvoice(invoice, true, context);
+        invoiceUtil.createInvoice(invoice, context);
 
         final UUID invoiceId = invoice.getId();
         final LocalDate startDate = new LocalDate(2011, 3, 1);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java b/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
index d526635..fc5f88b 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/proRations/InvoiceTestUtils.java
@@ -106,7 +106,9 @@ public class InvoiceTestUtils {
         }
         Mockito.when(invoice.getInvoiceItems()).thenReturn(invoiceItems);
 
-        invoiceDao.createInvoice(new InvoiceModelDao(invoice), invoiceModelItems, true, new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
+        final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
+        invoiceModelDao.addInvoiceItems(invoiceModelItems);
+        invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(invoiceModelDao), internalCallContext);
 
         return invoice;
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index a83301d..5a86cc3 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -189,11 +189,10 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
                                                                                  BigDecimal.ONE,
                                                                                  currency,
                                                                                  null);
-        invoiceDao.createInvoice(invoiceModelDao,
-                                 ImmutableList.<InvoiceItemModelDao>of(invoiceItemModelDao1, invoiceItemModelDao2),
-                                 true,
-                                 new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of()),
-                                 context);
+
+        invoiceModelDao.addInvoiceItem(invoiceItemModelDao1);
+        invoiceModelDao.addInvoiceItem(invoiceItemModelDao2);
+        invoiceDao.createInvoices(ImmutableList.<InvoiceModelDao>of(invoiceModelDao), context);
 
         try {
             dispatcher.processAccountFromNotificationOrBusEvent(accountId, target, new DryRunFutureDateArguments(), context);
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 38dd1af..7708eb6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -68,6 +68,7 @@ import org.killbill.billing.invoice.dao.InvoiceModelDao;
 import org.killbill.billing.invoice.dao.InvoiceModelDaoHelper;
 import org.killbill.billing.invoice.dao.InvoicePaymentModelDao;
 import org.killbill.billing.invoice.dao.InvoicePaymentSqlDao;
+import org.killbill.billing.invoice.dao.InvoiceSqlDao;
 import org.killbill.billing.invoice.generator.InvoiceGenerator;
 import org.killbill.billing.invoice.notification.NullInvoiceNotifier;
 import org.killbill.billing.junction.BillingEvent;
@@ -168,6 +169,7 @@ public class TestInvoiceHelper {
     // Low level SqlDao used by the tests to directly insert rows
     private final InvoicePaymentSqlDao invoicePaymentSqlDao;
     private final InvoiceItemSqlDao invoiceItemSqlDao;
+    private final InvoiceSqlDao invoiceSqlDao;
 
 
     @Inject
@@ -190,6 +192,7 @@ public class TestInvoiceHelper {
         this.parkedAccountsManager = parkedAccountsManager;
         this.internalCallContext = internalCallContext;
         this.internalCallContextFactory = internalCallContextFactory;
+        this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
         this.invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
         this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
         this.invoiceConfig = invoiceConfig;
@@ -290,7 +293,7 @@ public class TestInvoiceHelper {
         return invoiceItemSqlDao.getInvoiceItemsByInvoice(invoiceId.toString(), internalCallContext);
     }
 
-    public void createInvoice(final Invoice invoice, final boolean isRealInvoiceWithItems, final InternalCallContext internalCallContext) {
+    public void createInvoice(final Invoice invoice, final InternalCallContext internalCallContext) throws EntityPersistenceException {
         final InvoiceModelDao invoiceModelDao = new InvoiceModelDao(invoice);
         final List<InvoiceItemModelDao> invoiceItemModelDaos = ImmutableList.<InvoiceItemModelDao>copyOf(Collections2.transform(invoice.getInvoiceItems(),
                                                                                                                                 new Function<InvoiceItem, InvoiceItemModelDao>() {
@@ -299,17 +302,11 @@ public class TestInvoiceHelper {
                                                                                                                                         return new InvoiceItemModelDao(input);
                                                                                                                                     }
                                                                                                                                 }));
-        // Not really needed, there shouldn't be any payment at this stage
-        final List<InvoicePaymentModelDao> invoicePaymentModelDaos = ImmutableList.<InvoicePaymentModelDao>copyOf(Collections2.transform(invoice.getPayments(),
-                                                                                                                                         new Function<InvoicePayment, InvoicePaymentModelDao>() {
-                                                                                                                                             @Override
-                                                                                                                                             public InvoicePaymentModelDao apply(final InvoicePayment input) {
-                                                                                                                                                 return new InvoicePaymentModelDao(input);
-                                                                                                                                             }
-                                                                                                                                         }));
-
-        // The test does not use the invoice callback notifier hence the empty map
-        invoiceDao.createInvoice(invoiceModelDao, invoiceItemModelDaos, isRealInvoiceWithItems, new FutureAccountNotifications(ImmutableMap.<UUID, List<SubscriptionNotification>>of()), internalCallContext);
+        invoiceSqlDao.create(invoiceModelDao, internalCallContext);
+
+        for (final InvoiceItem invoiceItem : invoice.getInvoiceItems()) {
+            createInvoiceItem(invoiceItem, internalCallContext);
+        }
     }
 
     public void createPayment(final InvoicePayment invoicePayment, final InternalCallContext internalCallContext) {