killbill-aplcache

Changes

Details

diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java b/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java
index e1df215..73e5bd6 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultImmutableAccountData.java
@@ -28,16 +28,21 @@ public class DefaultImmutableAccountData implements ImmutableAccountData {
     private final String externalKey;
     private final Currency currency;
     private final DateTimeZone dateTimeZone;
+    private final UUID parentAccountId;
+    private final boolean isPaymentDelegatedToParent;
 
-    public DefaultImmutableAccountData(final UUID id, final String externalKey, final Currency currency, final DateTimeZone dateTimeZone) {
+    public DefaultImmutableAccountData(final UUID id, final String externalKey, final Currency currency, final DateTimeZone dateTimeZone,
+                                       final UUID parentAccountId, final boolean isPaymentDelegatedToParent) {
         this.id = id;
         this.externalKey = externalKey;
         this.currency = currency;
         this.dateTimeZone = dateTimeZone;
+        this.parentAccountId = parentAccountId;
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
     }
 
     public DefaultImmutableAccountData(final Account account) {
-        this(account.getId(), account.getExternalKey(), account.getCurrency(), account.getTimeZone());
+        this(account.getId(), account.getExternalKey(), account.getCurrency(), account.getTimeZone(), account.getParentAccountId(), account.isPaymentDelegatedToParent());
     }
 
     @Override
@@ -59,4 +64,15 @@ public class DefaultImmutableAccountData implements ImmutableAccountData {
     public DateTimeZone getTimeZone() {
         return dateTimeZone;
     }
+
+    @Override
+    public UUID getParentAccountId() {
+        return parentAccountId;
+    }
+
+    @Override
+    public Boolean isPaymentDelegatedToParent() {
+        return isPaymentDelegatedToParent;
+    }
+
 }
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index 4d114c4..e8a325e 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -372,6 +372,23 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                                        .build();
     }
 
+    protected AccountData getChildAccountData(final int billingDay, final UUID parentAccountId, final boolean isPaymentDelegatedToParent) {
+        return new MockAccountBuilder().name(UUID.randomUUID().toString().substring(1, 8))
+                                       .firstNameLength(6)
+                                       .email(UUID.randomUUID().toString().substring(1, 8))
+                                       .phone(UUID.randomUUID().toString().substring(1, 8))
+                                       .migrated(false)
+                                       .isNotifiedForInvoices(false)
+                                       .externalKey(UUID.randomUUID().toString().substring(1, 8))
+                                       .billingCycleDayLocal(billingDay)
+                                       .currency(Currency.USD)
+                                       .paymentMethodId(UUID.randomUUID())
+                                       .timeZone(DateTimeZone.UTC)
+                                       .parentAccountId(parentAccountId)
+                                       .isPaymentDelegatedToParent(isPaymentDelegatedToParent)
+                                       .build();
+    }
+
     protected void addMonthsAndCheckForCompletion(final int nbMonth, final NextEvent... events) {
         doCallAndCheckForCompletion(new Function<Void, Void>() {
             @Override
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
index 3777ab5..9bf78b2 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationInvoice.java
@@ -27,6 +27,7 @@ import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
 import org.killbill.billing.catalog.api.BillingPeriod;
@@ -37,6 +38,7 @@ import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
+import org.killbill.billing.invoice.api.InvoiceStatus;
 import org.killbill.billing.invoice.model.ExternalChargeInvoiceItem;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PluginProperty;
@@ -335,4 +337,71 @@ public class TestIntegrationInvoice extends TestIntegrationBase {
 
     }
 
+    @Test(groups = "slow")
+    public void testParentInvoiceGeneration() throws Exception {
+
+        final int billingDay = 14;
+        final DateTime initialCreationDate = new DateTime(2015, 5, 15, 0, 0, 0, 0, testTimeZone);
+
+        log.info("Beginning test with BCD of " + billingDay);
+        final Account parentAccount = createAccountWithNonOsgiPaymentMethod(getAccountData(billingDay));
+        final Account child1Account = createAccountWithNonOsgiPaymentMethod(getChildAccountData(billingDay, parentAccount.getId(), true));
+        final Account child2Account = createAccountWithNonOsgiPaymentMethod(getChildAccountData(billingDay, parentAccount.getId(), true));
+
+        // set clock to the initial start date
+        clock.setTime(initialCreationDate);
+
+        //
+        // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
+        //
+        DefaultEntitlement baseEntitlementChild1 = createBaseEntitlementAndCheckForCompletion(child1Account.getId(), "bundleKey1", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE);
+        DefaultEntitlement baseEntitlementChild2 = createBaseEntitlementAndCheckForCompletion(child2Account.getId(), "bundleKey2", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE);
+
+        // First Parent invoice over TRIAL period
+
+        List<Invoice> parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), callContext);
+        assertEquals(parentInvoices.size(), 1);
+
+        Invoice parentInvoice = parentInvoices.get(0);
+        assertEquals(parentInvoice.getNumberOfItems(), 2);
+        assertEquals(parentInvoice.getStatus(), InvoiceStatus.DRAFT);
+        assertTrue(parentInvoice.isParentInvoice());
+        //assertEquals(parentInvoice.getBalance(), BigDecimal.ZERO);
+
+        // No payment is expected because balance is 0
+        busHandler.pushExpectedEvents(NextEvent.INVOICE);
+        invoiceUserApi.commitInvoice(parentInvoice.getId(), callContext);
+        assertListenerStatus();
+
+        parentInvoice = invoiceUserApi.getInvoice(parentInvoice.getId(), callContext);
+        assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
+
+        // Move through time and verify new parent Invoice
+        busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE,
+                                      NextEvent.INVOICE, NextEvent.INVOICE,
+                                      NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT,
+                                      NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT); // TODO fix when refactor invoice.getBalance
+        clock.addDays(31);
+        assertListenerStatus();
+
+        // Second Parent invoice over Recurring period
+
+        parentInvoices = invoiceUserApi.getInvoicesByAccount(parentAccount.getId(), callContext);
+        assertEquals(parentInvoices.size(), 2);
+
+        parentInvoice = parentInvoices.get(1);
+        assertEquals(parentInvoice.getNumberOfItems(), 2);
+        assertEquals(parentInvoice.getStatus(), InvoiceStatus.DRAFT);
+        assertTrue(parentInvoice.isParentInvoice());
+
+        // now payment is expected
+        busHandler.pushExpectedEvents(NextEvent.INVOICE); // TODO NextEvent.PAYMENT
+        invoiceUserApi.commitInvoice(parentInvoice.getId(), callContext);
+        assertListenerStatus();
+
+        parentInvoice = invoiceUserApi.getInvoice(parentInvoice.getId(), callContext);
+        assertEquals(parentInvoice.getStatus(), InvoiceStatus.COMMITTED);
+
+    }
+
 }
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 7a77888..04ab792 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
@@ -85,7 +85,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                                                                                         .onResultOf(new Function<InvoiceModelDao, Comparable>() {
                                                                                             @Override
                                                                                             public Comparable apply(final InvoiceModelDao invoice) {
-                                                                                                return invoice.getTargetDate();
+                                                                                                return invoice.getTargetDate() == null ? invoice.getCreatedDate() : invoice.getTargetDate();
                                                                                             }
                                                                                         });
 
@@ -268,7 +268,9 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                         createInvoiceItemFromTransaction(transInvoiceItemSqlDao, invoiceItemModelDao, context);
                     }
                     cbaDao.addCBAComplexityFromTransaction(invoice, entitySqlDaoWrapperFactory, context);
-                    notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context);
+                    if (InvoiceStatus.COMMITTED.equals(invoice.getStatus())) {
+                        notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context);
+                    }
                 }
                 return null;
             }
@@ -946,6 +948,7 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
                 if (InvoiceStatus.COMMITTED.equals(newStatus)) {
                     // notify invoice creation event
                     notifyBusOfInvoiceCreation(entitySqlDaoWrapperFactory, invoice, context);
+                    // notifyOfFutureBillingEvents(entitySqlDaoWrapperFactory, invoice.getAccountId(), callbackDateTimePerSubscriptions, context);
                 }
 
                 return null;
@@ -966,4 +969,26 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
         }
     }
 
+    @Override
+    public void createParentChildInvoiceRelation(final InvoiceParentChildModelDao invoiceRelation, final InternalCallContext context) throws InvoiceApiException {
+        transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
+            @Override
+            public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+                final InvoiceParentChildrenSqlDao transactional = entitySqlDaoWrapperFactory.become(InvoiceParentChildrenSqlDao.class);
+                transactional.create(invoiceRelation, context);
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public InvoiceModelDao getParentDraftInvoice(final UUID parentAccountId, final InternalCallContext context) throws InvoiceApiException {
+        return transactionalSqlDao.execute(InvoiceApiException.class, new EntitySqlDaoTransactionWrapper<InvoiceModelDao>() {
+            @Override
+            public InvoiceModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+                final InvoiceSqlDao invoiceSqlDao = entitySqlDaoWrapperFactory.become(InvoiceSqlDao.class);
+                return invoiceSqlDao.getParentDraftInvoice(parentAccountId.toString(), 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 7798545..4dec8ec 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
@@ -149,4 +149,22 @@ public interface InvoiceDao extends EntityDao<InvoiceModelDao, Invoice, InvoiceA
      * @throws InvoiceApiException
      */
     void changeInvoiceStatus(UUID invoiceId, InvoiceStatus newState, InternalCallContext context) throws InvoiceApiException;
+
+    /**
+     * Save parent/child invoice relationship
+     *
+     * @param invoiceRelation the invoice relation object
+     * @param context the tenant context
+     * @throws InvoiceApiException
+     */
+    void createParentChildInvoiceRelation(final InvoiceParentChildModelDao invoiceRelation, final InternalCallContext context) throws InvoiceApiException;
+
+    /**
+     * Retrieve parent invoice by the parent account id
+     *
+     * @param parentAccountId the parent account id
+     * @param context the tenant context
+     * @return
+     */
+    InvoiceModelDao getParentDraftInvoice(UUID parentAccountId, InternalCallContext context) throws InvoiceApiException;
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemModelDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemModelDao.java
index 9254e11..8754a96 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemModelDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceItemModelDao.java
@@ -34,6 +34,7 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
     private InvoiceItemType type;
     private UUID invoiceId;
     private UUID accountId;
+    private UUID childAccountId;
     private UUID bundleId;
     private UUID subscriptionId;
     private String description;
@@ -49,14 +50,15 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
 
     public InvoiceItemModelDao() { /* For the DAO mapper */ }
 
-    public InvoiceItemModelDao(final UUID id, final DateTime createdDate, final InvoiceItemType type, final UUID invoiceId,
-                               final UUID accountId, final UUID bundleId, final UUID subscriptionId, final String description, final String planName,
+    public InvoiceItemModelDao(final UUID id, final DateTime createdDate, final InvoiceItemType type, final UUID invoiceId, final UUID accountId,
+                               final UUID childAccountId, final UUID bundleId, final UUID subscriptionId, final String description, final String planName,
                                final String phaseName, final String usageName, final LocalDate startDate, final LocalDate endDate, final BigDecimal amount,
                                final BigDecimal rate, final Currency currency, final UUID linkedItemId) {
         super(id, createdDate, createdDate);
         this.type = type;
         this.invoiceId = invoiceId;
         this.accountId = accountId;
+        this.childAccountId = childAccountId;
         this.bundleId = bundleId;
         this.subscriptionId = subscriptionId;
         this.description = description;
@@ -75,12 +77,12 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
                                final UUID bundleId, final UUID subscriptionId, final String description, final String planName,
                                final String phaseName, final String usageName, final LocalDate startDate, final LocalDate endDate, final BigDecimal amount,
                                final BigDecimal rate, final Currency currency, final UUID linkedItemId) {
-        this(UUIDs.randomUUID(), createdDate, type, invoiceId, accountId, bundleId, subscriptionId, description, planName, phaseName, usageName,
+        this(UUIDs.randomUUID(), createdDate, type, invoiceId, accountId, null, bundleId, subscriptionId, description, planName, phaseName, usageName,
              startDate, endDate, amount, rate, currency, linkedItemId);
     }
 
     public InvoiceItemModelDao(final InvoiceItem invoiceItem) {
-        this(invoiceItem.getId(), invoiceItem.getCreatedDate(), invoiceItem.getInvoiceItemType(), invoiceItem.getInvoiceId(), invoiceItem.getAccountId(), invoiceItem.getBundleId(),
+        this(invoiceItem.getId(), invoiceItem.getCreatedDate(), invoiceItem.getInvoiceItemType(), invoiceItem.getInvoiceId(), invoiceItem.getAccountId(), invoiceItem.getChildAccountId(), invoiceItem.getBundleId(),
              invoiceItem.getSubscriptionId(), invoiceItem.getDescription(), invoiceItem.getPlanName(), invoiceItem.getPhaseName(), invoiceItem.getUsageName(), invoiceItem.getStartDate(), invoiceItem.getEndDate(),
              invoiceItem.getAmount(), invoiceItem.getRate(), invoiceItem.getCurrency(), invoiceItem.getLinkedItemId());
     }
@@ -97,6 +99,10 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
         return accountId;
     }
 
+    public UUID getChildAccountId() {
+        return childAccountId;
+    }
+
     public UUID getBundleId() {
         return bundleId;
     }
@@ -157,6 +163,10 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
         this.accountId = accountId;
     }
 
+    public void setChildAccountId(final UUID childAccountId) {
+        this.childAccountId = childAccountId;
+    }
+
     public void setBundleId(final UUID bundleId) {
         this.bundleId = bundleId;
     }
@@ -207,6 +217,7 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
         sb.append("type=").append(type);
         sb.append(", invoiceId=").append(invoiceId);
         sb.append(", accountId=").append(accountId);
+        sb.append(", childAccountId=").append(childAccountId);
         sb.append(", bundleId=").append(bundleId);
         sb.append(", subscriptionId=").append(subscriptionId);
         sb.append(", description='").append(description).append('\'');
@@ -240,6 +251,9 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
         if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
             return false;
         }
+        if (childAccountId != null ? !childAccountId.equals(that.childAccountId) : that.childAccountId != null) {
+            return false;
+        }
         if (amount != null ? amount.compareTo(that.amount) != 0 : that.amount != null) {
             return false;
         }
@@ -292,6 +306,7 @@ public class InvoiceItemModelDao extends EntityModelDaoBase implements EntityMod
         result = 31 * result + (type != null ? type.hashCode() : 0);
         result = 31 * result + (invoiceId != null ? invoiceId.hashCode() : 0);
         result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (childAccountId != null ? childAccountId.hashCode() : 0);
         result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
         result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
         result = 31 * result + (description != null ? description.hashCode() : 0);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDao.java
index e172ee8..0919880 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceModelDao.java
@@ -44,6 +44,7 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
     private Currency currency;
     private boolean migrated;
     private InvoiceStatus status;
+    private boolean parentInvoice;
 
     // Not in the database, for convenience only
     private List<InvoiceItemModelDao> invoiceItems = new LinkedList<InvoiceItemModelDao>();
@@ -56,7 +57,7 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
 
     public InvoiceModelDao(final UUID id, @Nullable final DateTime createdDate, final UUID accountId,
                            @Nullable final Integer invoiceNumber, final LocalDate invoiceDate, final LocalDate targetDate,
-                           final Currency currency, final boolean migrated, final InvoiceStatus status) {
+                           final Currency currency, final boolean migrated, final InvoiceStatus status, final boolean parentInvoice) {
         super(id, createdDate, createdDate);
         this.accountId = accountId;
         this.invoiceNumber = invoiceNumber;
@@ -66,23 +67,28 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         this.migrated = migrated;
         this.isWrittenOff = false;
         this.status = status;
+        this.parentInvoice = parentInvoice;
     }
 
     public InvoiceModelDao(final UUID accountId, final LocalDate invoiceDate, final LocalDate targetDate, final Currency currency, final boolean migrated) {
-        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, migrated, InvoiceStatus.COMMITTED);
+        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, migrated, InvoiceStatus.COMMITTED, false);
     }
 
     public InvoiceModelDao(final UUID accountId, final LocalDate invoiceDate, final LocalDate targetDate, final Currency currency, final boolean migrated, final InvoiceStatus status) {
-        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, migrated, status);
+        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, migrated, status, false);
     }
 
     public InvoiceModelDao(final UUID accountId, final LocalDate invoiceDate, final LocalDate targetDate, final Currency currency) {
-        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, false, InvoiceStatus.COMMITTED);
+        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, targetDate, currency, false, InvoiceStatus.COMMITTED, false);
+    }
+
+    public InvoiceModelDao(final UUID accountId, final LocalDate invoiceDate, final Currency currency, final InvoiceStatus status, final boolean isParentInvoice) {
+        this(UUIDs.randomUUID(), null, accountId, null, invoiceDate, null, currency, false, status, isParentInvoice);
     }
 
     public InvoiceModelDao(final Invoice invoice) {
         this(invoice.getId(), invoice.getCreatedDate(), invoice.getAccountId(), invoice.getInvoiceNumber(), invoice.getInvoiceDate(),
-             invoice.getTargetDate(), invoice.getCurrency(), invoice.isMigrationInvoice(), invoice.getStatus());
+             invoice.getTargetDate(), invoice.getCurrency(), invoice.isMigrationInvoice(), invoice.getStatus(), invoice.isParentInvoice());
     }
 
     public void addInvoiceItems(final List<InvoiceItemModelDao> invoiceItems) {
@@ -137,6 +143,14 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         return migrated;
     }
 
+    public InvoiceStatus getStatus() {
+        return status;
+    }
+
+    public boolean isParentInvoice() {
+        return parentInvoice;
+    }
+
     public void setAccountId(final UUID accountId) {
         this.accountId = accountId;
     }
@@ -177,14 +191,14 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         this.isWrittenOff = isWrittenOff;
     }
 
-    public InvoiceStatus getStatus() {
-        return status;
-    }
-
     public void setStatus(final InvoiceStatus status) {
         this.status = status;
     }
 
+    public void setParentInvoice(final boolean parentInvoice) {
+        this.parentInvoice = parentInvoice;
+    }
+
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("InvoiceModelDao{");
@@ -199,6 +213,7 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         sb.append(", invoicePayments=").append(invoicePayments);
         sb.append(", processedCurrency=").append(processedCurrency);
         sb.append(", isWrittenOff=").append(isWrittenOff);
+        sb.append(", parentInvoice=").append(parentInvoice);
         sb.append('}');
         return sb.toString();
     }
@@ -247,8 +262,10 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         if (invoicePayments != null ? !invoicePayments.equals(that.invoicePayments) : that.invoicePayments != null) {
             return false;
         }
+        if (parentInvoice != that.parentInvoice) {
+            return false;
+        }
         return processedCurrency == that.processedCurrency;
-
     }
 
     @Override
@@ -265,6 +282,7 @@ public class InvoiceModelDao extends EntityModelDaoBase implements EntityModelDa
         result = 31 * result + (invoicePayments != null ? invoicePayments.hashCode() : 0);
         result = 31 * result + (processedCurrency != null ? processedCurrency.hashCode() : 0);
         result = 31 * result + (isWrittenOff ? 1 : 0);
+        result = 31 * result + (parentInvoice ? 1 : 0);
         return result;
     }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildModelDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildModelDao.java
new file mode 100644
index 0000000..35d28ca
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildModelDao.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.dao;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.invoice.api.InvoiceParentChild;
+import org.killbill.billing.util.dao.TableName;
+import org.killbill.billing.util.entity.dao.EntityModelDao;
+import org.killbill.billing.util.entity.dao.EntityModelDaoBase;
+
+public class InvoiceParentChildModelDao extends EntityModelDaoBase implements EntityModelDao<InvoiceParentChild> {
+
+    private UUID parentInvoiceId;
+    private UUID childInvoiceId;
+    private UUID childAccountId;
+
+    public InvoiceParentChildModelDao() { /* For the DAO mapper */ };
+
+    public InvoiceParentChildModelDao(final UUID parentInvoiceId, final UUID childInvoiceId, final UUID childAccountId) {
+        this(UUID.randomUUID(), DateTime.now(), parentInvoiceId, childInvoiceId, childAccountId);
+    }
+
+    public InvoiceParentChildModelDao(final UUID id, @Nullable final DateTime createdDate, final UUID parentInvoiceId, final UUID childInvoiceId, final UUID childAccountId) {
+        super(id, createdDate, createdDate);
+        this.parentInvoiceId = parentInvoiceId;
+        this.childInvoiceId = childInvoiceId;
+        this.childAccountId = childAccountId;
+    }
+
+    public InvoiceParentChildModelDao(final InvoiceParentChild invoiceParentChild) {
+        this(invoiceParentChild.getParentInvoiceId(), invoiceParentChild.getChildInvoiceId(), invoiceParentChild.getChildAccountId());
+    }
+
+    public UUID getParentInvoiceId() {
+        return parentInvoiceId;
+    }
+
+    public void setParentInvoiceId(final UUID parentInvoiceId) {
+        this.parentInvoiceId = parentInvoiceId;
+    }
+
+    public UUID getChildInvoiceId() {
+        return childInvoiceId;
+    }
+
+    public void setChildInvoiceId(final UUID childInvoiceId) {
+        this.childInvoiceId = childInvoiceId;
+    }
+
+    public UUID getChildAccountId() {
+        return childAccountId;
+    }
+
+    public void setChildAccountId(final UUID childAccountId) {
+        this.childAccountId = childAccountId;
+    }
+
+    @Override
+    public String toString() {
+        return "InvoiceParentChildModelDao{" +
+               "parentInvoiceId=" + parentInvoiceId +
+               ", childInvoiceId=" + childInvoiceId +
+               ", childAccountId=" + childAccountId +
+               '}';
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+
+        final InvoiceParentChildModelDao that = (InvoiceParentChildModelDao) o;
+
+        if (parentInvoiceId != null ? !parentInvoiceId.equals(that.parentInvoiceId) : that.parentInvoiceId != null) {
+            return false;
+        }
+        if (childInvoiceId != null ? !childInvoiceId.equals(that.childInvoiceId) : that.childInvoiceId != null) {
+            return false;
+        }
+        return childAccountId != null ? childAccountId.equals(that.childAccountId) : that.childAccountId == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (parentInvoiceId != null ? parentInvoiceId.hashCode() : 0);
+        result = 31 * result + (childInvoiceId != null ? childInvoiceId.hashCode() : 0);
+        result = 31 * result + (childAccountId != null ? childAccountId.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public TableName getTableName() {
+        return TableName.INVOICE_PARENT_CHILDREN;
+    }
+
+    @Override
+    public TableName getHistoryTableName() {
+        return null;
+    }
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java
new file mode 100644
index 0000000..3d62a1a
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.dao;
+
+import org.killbill.billing.invoice.api.InvoiceParentChild;
+import org.killbill.billing.util.entity.dao.EntitySqlDao;
+import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+
+@EntitySqlDaoStringTemplate
+public interface InvoiceParentChildrenSqlDao extends EntitySqlDao<InvoiceParentChildModelDao, InvoiceParentChild> {
+
+
+}
+
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
index ffecc24..1907037 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/dao/InvoiceSqlDao.java
@@ -44,8 +44,12 @@ public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
-    public void updateStatus(@Bind("id") String invoiceId,
+    void updateStatus(@Bind("id") String invoiceId,
                              @Bind("status") String status,
                              @BindBean final InternalCallContext context);
+
+    @SqlQuery
+    InvoiceModelDao getParentDraftInvoice(@Bind("accountId") final String parentAccountId,
+                               @BindBean final InternalTenantContext context);
 }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
index 5da49d2..c31efad 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -40,6 +40,7 @@ import org.killbill.billing.junction.BillingEventSet;
 import org.killbill.billing.util.config.InvoiceConfig;
 import org.killbill.clock.Clock;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Inject;
 
@@ -105,7 +106,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
         LocalDate maxDate = targetDate;
 
         for (final Invoice invoice : existingInvoices) {
-            if (invoice.getTargetDate().isAfter(maxDate)) {
+            if ((invoice.getTargetDate() != null) && invoice.getTargetDate().isAfter(maxDate)) {
                 maxDate = invoice.getTargetDate();
             }
         }
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 4253d46..d35ee7e 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -34,6 +34,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
+import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
@@ -65,9 +66,11 @@ 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;
 import org.killbill.billing.invoice.dao.InvoiceDao;
 import org.killbill.billing.invoice.dao.InvoiceItemModelDao;
 import org.killbill.billing.invoice.dao.InvoiceModelDao;
+import org.killbill.billing.invoice.dao.InvoiceParentChildModelDao;
 import org.killbill.billing.invoice.generator.InvoiceGenerator;
 import org.killbill.billing.invoice.generator.InvoiceWithMetadata;
 import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFutureNotificationDates;
@@ -75,6 +78,7 @@ import org.killbill.billing.invoice.generator.InvoiceWithMetadata.SubscriptionFu
 import org.killbill.billing.invoice.model.DefaultInvoice;
 import org.killbill.billing.invoice.model.FixedPriceInvoiceItem;
 import org.killbill.billing.invoice.model.InvoiceItemFactory;
+import org.killbill.billing.invoice.model.ParentInvoiceItem;
 import org.killbill.billing.invoice.model.RecurringInvoiceItem;
 import org.killbill.billing.invoice.notification.DefaultNextBillingDateNotifier;
 import org.killbill.billing.invoice.notification.NextBillingDateNotificationKey;
@@ -700,4 +704,35 @@ public class InvoiceDispatcher {
             return null;
         }
     }
+
+    public void processParentInvoiceForInvoiceGeneration(final ImmutableAccountData account, final UUID invoiceId, final InternalCallContext context) throws InvoiceApiException {
+
+        final InvoiceModelDao invoiceModelDao = invoiceDao.getById(invoiceId, context);
+        final Invoice invoice = new DefaultInvoice(invoiceModelDao);
+
+        BigDecimal invoiceAmount = InvoiceCalculatorUtils.computeInvoiceBalance(invoice.getCurrency(), invoice.getInvoiceItems(), invoice.getPayments());
+        InvoiceModelDao parentInvoice = invoiceDao.getParentDraftInvoice(account.getParentAccountId(), context);
+
+        final Long parentAccountRecordId = internalCallContextFactory.getRecordIdFromObject(account.getParentAccountId(), ObjectType.ACCOUNT, buildTenantContext(context));
+        final InternalCallContext parentContext = new InternalCallContext(context, parentAccountRecordId);
+
+        if (parentInvoice != null) {
+            InvoiceItem invoiceItem = new ParentInvoiceItem(UUID.randomUUID(), DateTime.now(), parentInvoice.getId(), account.getParentAccountId(), account.getId(), invoiceAmount, account.getCurrency());
+            parentInvoice.addInvoiceItem(new InvoiceItemModelDao(invoiceItem));
+            List<InvoiceModelDao> invoices = new ArrayList<InvoiceModelDao>();
+            invoices.add(parentInvoice);
+            invoiceDao.createInvoices(invoices, parentContext);
+        } else {
+            parentInvoice = new InvoiceModelDao(account.getParentAccountId(), LocalDate.now(), account.getCurrency(), InvoiceStatus.DRAFT, true);
+            InvoiceItem invoiceItem = new ParentInvoiceItem(UUID.randomUUID(), DateTime.now(), parentInvoice.getId(), account.getParentAccountId(), account.getId(), invoiceAmount, account.getCurrency());
+            parentInvoice.addInvoiceItem(new InvoiceItemModelDao(invoiceItem));
+            invoiceDao.createInvoice(parentInvoice, parentInvoice.getInvoiceItems(), true, null, parentContext);
+        }
+
+        // save parent child invoice relation
+        final InvoiceParentChildModelDao invoiceRelation = new InvoiceParentChildModelDao(parentInvoice.getId(), invoiceId, account.getId());
+        invoiceDao.createParentChildInvoiceRelation(invoiceRelation, parentContext);
+
+    }
+
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
index ca63e2b..db59d84 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
@@ -19,23 +19,26 @@ package org.killbill.billing.invoice;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.clock.Clock;
+import org.killbill.billing.account.api.ImmutableAccountData;
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.events.BlockingTransitionInternalEvent;
-import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
+import org.killbill.billing.events.EffectiveEntitlementInternalEvent;
+import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
+import org.killbill.billing.events.InvoiceCreationInternalEvent;
+import org.killbill.billing.events.RepairSubscriptionInternalEvent;
 import org.killbill.billing.invoice.api.InvoiceApiException;
+import org.killbill.billing.invoice.api.InvoiceInternalApi;
+import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.events.EffectiveEntitlementInternalEvent;
-import org.killbill.billing.events.EffectiveSubscriptionInternalEvent;
-import org.killbill.billing.events.RepairSubscriptionInternalEvent;
 import org.killbill.billing.util.config.InvoiceConfig;
+import org.killbill.clock.Clock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
@@ -48,17 +51,19 @@ public class InvoiceListener {
     private final InvoiceDispatcher dispatcher;
     private final InternalCallContextFactory internalCallContextFactory;
     private final AccountInternalApi accountApi;
+    private final InvoiceInternalApi invoiceApi;
     private final InvoiceConfig invoiceConfig;
     private final Clock clock;
 
     @Inject
     public InvoiceListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory,
-                           final InvoiceConfig invoiceConfig, final InvoiceDispatcher dispatcher) {
+                           final InvoiceConfig invoiceConfig, final InvoiceDispatcher dispatcher, InvoiceInternalApi invoiceApi) {
         this.accountApi = accountApi;
         this.dispatcher = dispatcher;
         this.invoiceConfig = invoiceConfig;
         this.internalCallContextFactory = internalCallContextFactory;
         this.clock = clock;
+        this.invoiceApi = invoiceApi;
     }
 
     @AllowConcurrentEvents
@@ -141,4 +146,29 @@ public class InvoiceListener {
             log.error(e.getMessage());
         }
     }
+
+    @AllowConcurrentEvents
+    @Subscribe
+    public void handleChildrenInvoiceCreationEvent(final InvoiceCreationInternalEvent event) {
+
+        try {
+            final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "CreateParentInvoice", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
+            final ImmutableAccountData account = accountApi.getImmutableAccountDataById(event.getAccountId(), context);
+
+            // catch children invoices and populate the parent summary invoice
+            if (isChildrenAccountAndPaymentDelegated(account)) {
+                dispatcher.processParentInvoiceForInvoiceGeneration(account, event.getInvoiceId(), context);
+            }
+
+        } catch (InvoiceApiException e) {
+            log.error(e.getMessage());
+        } catch (AccountApiException e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    private boolean isChildrenAccountAndPaymentDelegated(final ImmutableAccountData account) {
+        return account.getParentAccountId() != null && account.isPaymentDelegatedToParent();
+    }
+
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
index 640936d..a9c7f06 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/DefaultInvoice.java
@@ -56,6 +56,7 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
 
     private final Currency processedCurrency;
     private final InvoiceStatus status;
+    private final boolean parentInvoice;
 
 
     // Used to create a new invoice
@@ -69,7 +70,7 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
 
     public DefaultInvoice(final UUID invoiceId, final UUID accountId, @Nullable final Integer invoiceNumber, final LocalDate invoiceDate,
                           final LocalDate targetDate, final Currency currency, final boolean isMigrationInvoice, final InvoiceStatus status) {
-        this(invoiceId, null, accountId, invoiceNumber, invoiceDate, targetDate, currency, currency, isMigrationInvoice, false, status);
+        this(invoiceId, null, accountId, invoiceNumber, invoiceDate, targetDate, currency, currency, isMigrationInvoice, false, status, false);
     }
 
 
@@ -78,7 +79,7 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
         this(invoiceModelDao.getId(), invoiceModelDao.getCreatedDate(), invoiceModelDao.getAccountId(),
              invoiceModelDao.getInvoiceNumber(), invoiceModelDao.getInvoiceDate(), invoiceModelDao.getTargetDate(),
              invoiceModelDao.getCurrency(), invoiceModelDao.getProcessedCurrency(), invoiceModelDao.isMigrated(),
-             invoiceModelDao.isWrittenOff(), invoiceModelDao.getStatus());
+             invoiceModelDao.isWrittenOff(), invoiceModelDao.getStatus(), invoiceModelDao.isParentInvoice());
         addInvoiceItems(Collections2.transform(invoiceModelDao.getInvoiceItems(), new Function<InvoiceItemModelDao, InvoiceItem>() {
             @Override
             public InvoiceItem apply(final InvoiceItemModelDao input) {
@@ -93,10 +94,16 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
         }));
     }
 
+    // Used to create a new parent invoice
+    public DefaultInvoice(final UUID accountId, final LocalDate invoiceDate, final Currency currency) {
+        this(UUID.randomUUID(), null, accountId, null, invoiceDate, null, currency, currency, false, false, InvoiceStatus.DRAFT, true);
+    }
+
     private DefaultInvoice(final UUID invoiceId, @Nullable final DateTime createdDate, final UUID accountId,
-                          @Nullable final Integer invoiceNumber, final LocalDate invoiceDate,
-                          final LocalDate targetDate, final Currency currency, final Currency processedCurrency,
-                           final boolean isMigrationInvoice, final boolean isWrittenOff, final InvoiceStatus status) {
+                           @Nullable final Integer invoiceNumber, final LocalDate invoiceDate,
+                           @Nullable final LocalDate targetDate, final Currency currency, final Currency processedCurrency,
+                           final boolean isMigrationInvoice, final boolean isWrittenOff,
+                           final InvoiceStatus status, final boolean parentInvoice) {
         super(invoiceId, createdDate, createdDate);
         this.accountId = accountId;
         this.invoiceNumber = invoiceNumber;
@@ -109,13 +116,14 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
         this.invoiceItems = new ArrayList<InvoiceItem>();
         this.payments = new ArrayList<InvoicePayment>();
         this.status = status;
+        this.parentInvoice = parentInvoice;
     }
 
 
     // Semi deep copy where we copy the lists but not the elements in the lists since they are immutables.
     @Override
     public Object clone() {
-        final Invoice clonedInvoice = new DefaultInvoice(getId(),  getCreatedDate(), getAccountId(), getInvoiceNumber(), getInvoiceDate(), getTargetDate(), getCurrency(), getProcessedCurrency(), isMigrationInvoice(), isWrittenOff(), getStatus());
+        final Invoice clonedInvoice = new DefaultInvoice(getId(),  getCreatedDate(), getAccountId(), getInvoiceNumber(), getInvoiceDate(), getTargetDate(), getCurrency(), getProcessedCurrency(), isMigrationInvoice(), isWrittenOff(), getStatus(), isParentInvoice());
         clonedInvoice.getInvoiceItems().addAll(getInvoiceItems());
         clonedInvoice.getPayments().addAll(getPayments());
         return clonedInvoice;
@@ -251,8 +259,15 @@ public class DefaultInvoice extends EntityBase implements Invoice, Cloneable {
     }
 
     @Override
+    public boolean isParentInvoice() {
+        return parentInvoice;
+    }
+
+    @Override
     public String toString() {
-        return "DefaultInvoice [items=" + invoiceItems + ", payments=" + payments + ", id=" + id + ", accountId=" + accountId + ", invoiceDate=" + invoiceDate + ", targetDate=" + targetDate + ", currency=" + currency + ", amountPaid=" + getPaidAmount() + ", Status=" + status + "]";
+        return "DefaultInvoice [items=" + invoiceItems + ", payments=" + payments + ", id=" + id + ", accountId=" + accountId
+               + ", invoiceDate=" + invoiceDate + ", targetDate=" + targetDate + ", currency=" + currency + ", amountPaid=" + getPaidAmount()
+               + ", status=" + status + ", isParentInvoice=" + parentInvoice + "]";
     }
 
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemBase.java
index b3f12d8..d85ab27 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemBase.java
@@ -33,6 +33,7 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     /* Common to all items */
     protected final UUID invoiceId;
     protected final UUID accountId;
+    protected final UUID childAccountId;
     protected final LocalDate startDate;
     protected final LocalDate endDate;
     protected final BigDecimal amount;
@@ -77,30 +78,37 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     public InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
                            @Nullable final UUID subscriptionId, @Nullable final String description, @Nullable final String planName, @Nullable final String phaseName, @Nullable final String usageName,
                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency) {
-        this(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, null, currency, null);
+        this(id, createdDate, invoiceId, accountId, null, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, null, currency, null);
     }
 
     // With rate but no reversing item
     public InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
                            @Nullable final UUID subscriptionId, @Nullable final String description, @Nullable final String planName, @Nullable final String phaseName, @Nullable final String usageName,
                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final BigDecimal rate, final Currency currency) {
-        this(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, rate, currency, null);
+        this(id, createdDate, invoiceId, accountId, null, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, rate, currency, null);
     }
 
     // With  reversing item, no rate
     public InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
                            @Nullable final UUID subscriptionId, @Nullable final String description, @Nullable final String planName, @Nullable final String phaseName, @Nullable final String usageName,
                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final Currency currency, final UUID reversedItemId) {
-        this(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, null, currency, reversedItemId);
+        this(id, createdDate, invoiceId, accountId, null, bundleId, subscriptionId, description, planName, phaseName, usageName, startDate, endDate, amount, null, currency, reversedItemId);
     }
 
-    private InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID bundleId,
+    // For parent invoices
+    public InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, final UUID childAccountId,
+                             final BigDecimal amount, final Currency currency) {
+        this(id, createdDate, invoiceId, accountId, childAccountId, null, null, null, null, null, null, null, null, amount, null, currency, null);
+    }
+
+    private InvoiceItemBase(final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, @Nullable final UUID childAccountId, @Nullable final UUID bundleId,
                             @Nullable final UUID subscriptionId, @Nullable final String description, @Nullable final String planName, @Nullable final String phaseName, @Nullable final String usageName,
-                            final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final BigDecimal rate, final Currency currency,
+                            @Nullable final LocalDate startDate, final LocalDate endDate, final BigDecimal amount, final BigDecimal rate, final Currency currency,
                             final UUID reversedItemId) {
         super(id, createdDate, createdDate);
         this.invoiceId = invoiceId;
         this.accountId = accountId;
+        this.childAccountId = childAccountId;
         this.subscriptionId = subscriptionId;
         this.bundleId = bundleId;
         this.description = description;
@@ -181,6 +189,11 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     }
 
     @Override
+    public UUID getChildAccountId() {
+        return childAccountId;
+    }
+
+    @Override
     public boolean equals(final Object o) {
 
         if (!matches(o)) {
@@ -216,6 +229,9 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
         if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
             return false;
         }
+        if (childAccountId != null ? !childAccountId.equals(that.childAccountId) : that.childAccountId != null) {
+            return false;
+        }
         if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
             return false;
         }
@@ -251,6 +267,7 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
         int result = super.hashCode();
         result = 31 * result + (invoiceId != null ? invoiceId.hashCode() : 0);
         result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (childAccountId != null ? childAccountId.hashCode() : 0);
         result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
         result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
         result = 31 * result + (amount != null ? amount.hashCode() : 0);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
index 77fd9e3..e60f77c 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/InvoiceItemFactory.java
@@ -41,6 +41,7 @@ public class InvoiceItemFactory {
         final DateTime createdDate = invoiceItemModelDao.getCreatedDate();
         final UUID invoiceId = invoiceItemModelDao.getInvoiceId();
         final UUID accountId = invoiceItemModelDao.getAccountId();
+        final UUID childAccountId = invoiceItemModelDao.getChildAccountId();
         final UUID bundleId = invoiceItemModelDao.getBundleId();
         final UUID subscriptionId = invoiceItemModelDao.getSubscriptionId();
         final String planName = invoiceItemModelDao.getPlanName();
@@ -87,6 +88,9 @@ public class InvoiceItemFactory {
             case TAX:
                 item = new TaxInvoiceItem(id, createdDate, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, usageName, startDate, description, amount, currency, linkedItemId);
                 break;
+            case PARENT_SUMMARY:
+                item = new ParentInvoiceItem(id, createdDate, invoiceId, accountId, childAccountId, amount, currency);
+                break;
             default:
                 throw new RuntimeException("Unexpected type of event item " + type);
         }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/model/ParentInvoiceItem.java b/invoice/src/main/java/org/killbill/billing/invoice/model/ParentInvoiceItem.java
new file mode 100644
index 0000000..cef9630
--- /dev/null
+++ b/invoice/src/main/java/org/killbill/billing/invoice/model/ParentInvoiceItem.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.invoice.model;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.invoice.api.InvoiceItemType;
+
+import com.google.common.base.MoreObjects;
+
+public class ParentInvoiceItem extends InvoiceItemBase {
+
+    public ParentInvoiceItem(@Nullable final UUID id, @Nullable final DateTime createdDate, final UUID invoiceId, final UUID accountId, final UUID childAccountId,
+                             final BigDecimal amount, final Currency currency) {
+        super(id, createdDate, invoiceId, accountId, childAccountId, amount, currency);
+    }
+
+    @Override
+    public InvoiceItemType getInvoiceItemType() {
+        return InvoiceItemType.PARENT_SUMMARY;
+    }
+
+    @Override
+    public String getDescription() {
+        return MoreObjects.firstNonNull(description, "Parent summary");
+    }
+}
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index 70afdec..29a86aa 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -347,6 +347,11 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
         return invoice.getStatus();
     }
 
+    @Override
+    public boolean isParentInvoice() {
+        return invoice.isParentInvoice();
+    }
+
     // Expose the fields for children classes. This is useful for further customization of the invoices
 
     @SuppressWarnings("UnusedDeclaration")
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index c6185a9..cbcc8c6 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -123,6 +123,11 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
     }
 
     @Override
+    public UUID getChildAccountId() {
+        return item.getChildAccountId();
+    }
+
+    @Override
     public UUID getBundleId() {
         return item.getBundleId();
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
index 1f6ec8d..faa66f0 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/tree/AccountItemTree.java
@@ -113,6 +113,8 @@ public class AccountItemTree {
             case FIXED:
             case ITEM_ADJ:
                 break;
+            case PARENT_SUMMARY:
+                break;
 
             default:
                 Preconditions.checkState(false, "Unknown invoice item type " + existingItem.getInvoiceItemType());
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
index 8470a77..48d9cf8 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
@@ -6,6 +6,7 @@ tableFields(prefix) ::= <<
   <prefix>type
 , <prefix>invoice_id
 , <prefix>account_id
+, <prefix>child_account_id
 , <prefix>bundle_id
 , <prefix>subscription_id
 , <prefix>description
@@ -26,6 +27,7 @@ tableValues() ::= <<
   :type
 , :invoiceId
 , :accountId
+, :childAccountId
 , :bundleId
 , :subscriptionId
 , :description
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg
new file mode 100644
index 0000000..813154d
--- /dev/null
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceParentChildrenSqlDao.sql.stg
@@ -0,0 +1,33 @@
+group InvoiceParentChildrenSqlDao: EntitySqlDao;
+
+tableName() ::= "invoice_parent_children"
+
+tableFields(prefix) ::= <<
+  <prefix>parent_invoice_id
+, <prefix>child_invoice_id
+, <prefix>child_account_id
+, <prefix>created_by
+, <prefix>created_date
+>>
+
+allTableFields(prefix) ::= <<
+  <prefix>record_id
+, <tableFields(prefix)>
+>>
+
+tableValues() ::= <<
+  :parentInvoiceId
+, :childInvoiceId
+, :childAccountId
+, :createdBy
+, :createdDate
+>>
+
+allTableValues() ::= <<
+  :recordId
+, <tableValues()>
+>>
+
+
+
+
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 5fe6558..1e3008d 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -9,6 +9,7 @@ tableFields(prefix) ::= <<
 , <prefix>currency
 , <prefix>status
 , <prefix>migrated
+, <prefix>parent_invoice
 , <prefix>created_by
 , <prefix>created_date
 >>
@@ -20,6 +21,7 @@ tableValues() ::= <<
 , :currency
 , :status
 , :migrated
+, :parentInvoice
 , :createdBy
 , :createdDate
 >>
@@ -58,4 +60,12 @@ updateStatus() ::= <<
     SET status = :status
     WHERE id = :id
     <AND_CHECK_TENANT()>;
+>>
+
+getParentDraftInvoice() ::= <<
+  SELECT <allTableFields()>
+    FROM <tableName()>
+   WHERE account_id = :accountId
+     AND status = 'DRAFT'
+   <AND_CHECK_TENANT()>
 >>
\ No newline at end of file
diff --git a/invoice/src/main/resources/org/killbill/billing/invoice/ddl.sql b/invoice/src/main/resources/org/killbill/billing/invoice/ddl.sql
index b81af02..dd547fb 100644
--- a/invoice/src/main/resources/org/killbill/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/org/killbill/billing/invoice/ddl.sql
@@ -7,13 +7,14 @@ CREATE TABLE invoice_items (
     type varchar(24) NOT NULL,
     invoice_id varchar(36) NOT NULL,
     account_id varchar(36) NOT NULL,
+    child_account_id varchar(36),
     bundle_id varchar(36),
     subscription_id varchar(36),
     description varchar(255),
     plan_name varchar(50),
     phase_name varchar(50),
     usage_name varchar(50),
-    start_date date NOT NULL,
+    start_date date,
     end_date date,
     amount numeric(15,9) NOT NULL,
     rate numeric(15,9) NULL,
@@ -38,10 +39,11 @@ CREATE TABLE invoices (
     id varchar(36) NOT NULL,
     account_id varchar(36) NOT NULL,
     invoice_date date NOT NULL,
-    target_date date NOT NULL,
+    target_date date,
     currency varchar(3) NOT NULL,
     status varchar(15) NOT NULL DEFAULT 'COMMITTED',
     migrated bool NOT NULL,
+    parent_invoice bool NOT NULL DEFAULT FALSE,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
     account_record_id bigint /*! unsigned */ not null,
@@ -77,3 +79,20 @@ CREATE UNIQUE INDEX idx_invoice_payments ON invoice_payments(payment_id, type);
 CREATE INDEX invoice_payments_invoice_id ON invoice_payments(invoice_id);
 CREATE INDEX invoice_payments_reversals ON invoice_payments(linked_invoice_payment_id);
 CREATE INDEX invoice_payments_tenant_account_record_id ON invoice_payments(tenant_record_id, account_record_id);
+
+DROP TABLE IF EXISTS invoice_parent_children;
+CREATE TABLE invoice_parent_children (
+    record_id serial unique,
+    id varchar(36) NOT NULL,
+    parent_invoice_id varchar(36) NOT NULL,
+    child_invoice_id varchar(36) NOT NULL,
+    child_account_id varchar(36) NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    account_record_id bigint /*! unsigned */ not null,
+    tenant_record_id bigint /*! unsigned */ not null default 0,
+    PRIMARY KEY(record_id)
+) /*! CHARACTER SET utf8 COLLATE utf8_bin */;
+CREATE UNIQUE INDEX invoice_parent_children_id ON invoice_parent_children(id);
+CREATE INDEX invoice_parent_children_invoice_id ON invoice_parent_children(parent_invoice_id);
+CREATE INDEX invoice_parent_children_tenant_account_record_id ON invoice_parent_children(tenant_record_id, account_record_id);
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 d3a841c..8c8310f 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
@@ -367,4 +367,14 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
     public void changeInvoiceStatus(final UUID invoiceId, final InvoiceStatus newState, final InternalCallContext context) throws InvoiceApiException {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void createParentChildInvoiceRelation(final InvoiceParentChildModelDao invoiceRelation, final InternalCallContext context) throws InvoiceApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InvoiceModelDao getParentDraftInvoice(final UUID parentAccountId, final InternalCallContext context) throws InvoiceApiException {
+        throw new UnsupportedOperationException();
+    }
 }
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 3cc1c21..37572d0 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -249,6 +249,24 @@ public class TestInvoiceHelper {
         return accountUserApi.createAccount(accountData, callContext);
     }
 
+    public Account createChildAccount(final UUID parentAccountId, final CallContext callContext) throws AccountApiException {
+        final AccountData accountData = new MockAccountBuilder().name(UUID.randomUUID().toString().substring(1, 8))
+                                                                .firstNameLength(6)
+                                                                .email(UUID.randomUUID().toString().substring(1, 8))
+                                                                .phone(UUID.randomUUID().toString().substring(1, 8))
+                                                                .migrated(false)
+                                                                .isNotifiedForInvoices(true)
+                                                                .externalKey(UUID.randomUUID().toString().substring(1, 8))
+                                                                .billingCycleDayLocal(31)
+                                                                .currency(accountCurrency)
+                                                                .paymentMethodId(UUID.randomUUID())
+                                                                .timeZone(DateTimeZone.UTC)
+                                                                .parentAccountId(parentAccountId)
+                                                                .isPaymentDelegatedToParent(false)
+                                                                .build();
+        return accountUserApi.createAccount(accountData, callContext);
+    }
+
     public void createInvoiceItem(final InvoiceItem invoiceItem, final InternalCallContext internalCallContext) throws EntityPersistenceException {
         invoiceItemSqlDao.create(new InvoiceItemModelDao(invoiceItem), internalCallContext);
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
index 9cda9fa..128616f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
 import org.joda.time.DateTime;
 
 import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.invoice.api.InvoiceInternalApi;
 import org.killbill.clock.Clock;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 
@@ -32,8 +33,8 @@ public class TestInvoiceNotificationQListener extends InvoiceListener {
     UUID latestSubscriptionId = null;
 
     @Inject
-    public TestInvoiceNotificationQListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher) {
-        super(accountApi, clock, internalCallContextFactory, null, dispatcher);
+    public TestInvoiceNotificationQListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher, final InvoiceInternalApi invoiceApi) {
+        super(accountApi, clock, internalCallContextFactory, null, dispatcher, invoiceApi);
     }
 
     @Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
index a476a22..83eef7c 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceItemJson.java
@@ -43,6 +43,8 @@ public class InvoiceItemJson extends JsonBase {
     private final String linkedInvoiceItemId;
     @ApiModelProperty(dataType = "java.util.UUID", required = true)
     private final String accountId;
+    @ApiModelProperty(dataType = "java.util.UUID", required = false)
+    private final String childAccountId;
     @ApiModelProperty(dataType = "java.util.UUID")
     private final String bundleId;
     @ApiModelProperty(dataType = "java.util.UUID")
@@ -62,6 +64,7 @@ public class InvoiceItemJson extends JsonBase {
                            @JsonProperty("invoiceId") final String invoiceId,
                            @JsonProperty("linkedInvoiceItemId") final String linkedInvoiceItemId,
                            @JsonProperty("accountId") final String accountId,
+                           @JsonProperty("childAccountId") final String childAccountId,
                            @JsonProperty("bundleId") final String bundleId,
                            @JsonProperty("subscriptionId") final String subscriptionId,
                            @JsonProperty("planName") final String planName,
@@ -79,6 +82,7 @@ public class InvoiceItemJson extends JsonBase {
         this.invoiceId = invoiceId;
         this.linkedInvoiceItemId = linkedInvoiceItemId;
         this.accountId = accountId;
+        this.childAccountId = childAccountId;
         this.bundleId = bundleId;
         this.subscriptionId = subscriptionId;
         this.planName = planName;
@@ -94,7 +98,7 @@ public class InvoiceItemJson extends JsonBase {
 
     public InvoiceItemJson(final InvoiceItem item, @Nullable final List<AuditLog> auditLogs) {
         this(toString(item.getId()), toString(item.getInvoiceId()), toString(item.getLinkedItemId()),
-             toString(item.getAccountId()), toString(item.getBundleId()), toString(item.getSubscriptionId()),
+             toString(item.getAccountId()), toString(item.getChildAccountId()), toString(item.getBundleId()), toString(item.getSubscriptionId()),
              item.getPlanName(), item.getPhaseName(), item.getUsageName(), item.getInvoiceItemType().toString(),
              item.getDescription(), item.getStartDate(), item.getEndDate(),
              item.getAmount(), item.getCurrency(), toAuditLogJson(auditLogs));
@@ -118,6 +122,11 @@ public class InvoiceItemJson extends JsonBase {
             }
 
             @Override
+            public UUID getChildAccountId() {
+                return childAccountId != null ? UUID.fromString(childAccountId) : null;
+            }
+
+            @Override
             public LocalDate getStartDate() {
                 return startDate;
             }
@@ -219,6 +228,10 @@ public class InvoiceItemJson extends JsonBase {
         return accountId;
     }
 
+    public String getChildAccountId() {
+        return childAccountId;
+    }
+
     public String getBundleId() {
         return bundleId;
     }
@@ -271,6 +284,7 @@ public class InvoiceItemJson extends JsonBase {
         sb.append(", invoiceId='").append(invoiceId).append('\'');
         sb.append(", linkedInvoiceItemId='").append(linkedInvoiceItemId).append('\'');
         sb.append(", accountId='").append(accountId).append('\'');
+        sb.append(", childAccountId='").append(childAccountId).append('\'');
         sb.append(", bundleId='").append(bundleId).append('\'');
         sb.append(", subscriptionId='").append(subscriptionId).append('\'');
         sb.append(", planName='").append(planName).append('\'');
@@ -299,6 +313,9 @@ public class InvoiceItemJson extends JsonBase {
         if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
             return false;
         }
+        if (childAccountId != null ? !childAccountId.equals(that.childAccountId) : that.childAccountId != null) {
+            return false;
+        }
         if (!((amount == null && that.amount == null) ||
               (amount != null && that.amount != null && amount.compareTo(that.amount) == 0))) {
             return false;
@@ -351,6 +368,7 @@ public class InvoiceItemJson extends JsonBase {
         result = 31 * result + (invoiceItemId != null ? invoiceItemId.hashCode() : 0);
         result = 31 * result + (linkedInvoiceItemId != null ? linkedInvoiceItemId.hashCode() : 0);
         result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (childAccountId != null ? childAccountId.hashCode() : 0);
         result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
         result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
         result = 31 * result + (planName != null ? planName.hashCode() : 0);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
index 4fa9335..dd703a2 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/InvoiceJson.java
@@ -51,6 +51,7 @@ public class InvoiceJson extends JsonBase {
     private final String bundleKeys;
     private final List<CreditJson> credits;
     private final String status;
+    private final Boolean isParentInvoice;
 
     @JsonCreator
     public InvoiceJson(@JsonProperty("amount") final BigDecimal amount,
@@ -67,6 +68,7 @@ public class InvoiceJson extends JsonBase {
                        @JsonProperty("externalBundleKeys") final String bundleKeys,
                        @JsonProperty("credits") final List<CreditJson> credits,
                        @JsonProperty("items") final List<InvoiceItemJson> items,
+                       @JsonProperty("isParentInvoice") final Boolean isParentInvoice,
                        @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
         super(auditLogs);
         this.amount = amount;
@@ -83,6 +85,7 @@ public class InvoiceJson extends JsonBase {
         this.bundleKeys = bundleKeys;
         this.credits = credits;
         this.items = items;
+        this.isParentInvoice = isParentInvoice;
     }
 
     public InvoiceJson(final Invoice input) {
@@ -92,7 +95,7 @@ public class InvoiceJson extends JsonBase {
     public InvoiceJson(final Invoice input, final String bundleKeys, final List<CreditJson> credits, final List<AuditLog> auditLogs) {
         this(input.getChargedAmount(), input.getCurrency().toString(), input.getStatus().toString(), input.getCreditedAmount(), input.getRefundedAmount(),
              input.getId().toString(), input.getInvoiceDate(), input.getTargetDate(), String.valueOf(input.getInvoiceNumber()),
-             input.getBalance(), input.getAccountId().toString(), bundleKeys, credits, null, toAuditLogJson(auditLogs));
+             input.getBalance(), input.getAccountId().toString(), bundleKeys, credits, null, input.isParentInvoice(), toAuditLogJson(auditLogs));
     }
 
     public InvoiceJson(final Invoice input, final boolean withItems, @Nullable final AccountAuditLogs accountAuditLogs) {
@@ -116,6 +119,7 @@ public class InvoiceJson extends JsonBase {
         this.accountId = input.getAccountId().toString();
         this.bundleKeys = null;
         this.credits = null;
+        this.isParentInvoice = input.isParentInvoice();
     }
 
     public BigDecimal getAmount() {
@@ -174,6 +178,10 @@ public class InvoiceJson extends JsonBase {
         return status;
     }
 
+    public Boolean getIsParentInvoice() {
+        return isParentInvoice;
+    }
+
     @Override
     public String toString() {
         return "InvoiceJson{" +
@@ -191,6 +199,7 @@ public class InvoiceJson extends JsonBase {
                ", items=" + items +
                ", bundleKeys='" + bundleKeys + '\'' +
                ", credits=" + credits +
+               ", isParentInvoice=" + isParentInvoice +
                '}';
     }
 
@@ -247,6 +256,9 @@ public class InvoiceJson extends JsonBase {
         if (status != null ? !status.equals(that.status) : that.status != null) {
             return false;
         }
+        if (isParentInvoice != null ? !isParentInvoice.equals(that.isParentInvoice) : that.isParentInvoice != null) {
+            return false;
+        }
 
         return true;
     }
@@ -267,6 +279,7 @@ public class InvoiceJson extends JsonBase {
         result = 31 * result + (items != null ? items.hashCode() : 0);
         result = 31 * result + (bundleKeys != null ? bundleKeys.hashCode() : 0);
         result = 31 * result + (credits != null ? credits.hashCode() : 0);
+        result = 31 * result + (isParentInvoice != null ? isParentInvoice.hashCode() : 0);
         return result;
     }
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index 2f94dd6..58ab21b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -522,6 +522,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                         return new InvoiceItemJson(null,
                                                    input.getInvoiceId(),
                                                    null, input.getAccountId(),
+                                                   input.getChildAccountId(),
                                                    input.getBundleId(),
                                                    input.getSubscriptionId(),
                                                    input.getPlanName(),
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
index 96eb7a7..ef5b359 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceItemJsonSimple.java
@@ -40,6 +40,7 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         final String invoiceId = UUID.randomUUID().toString();
         final String linkedInvoiceItemId = UUID.randomUUID().toString();
         final String accountId = UUID.randomUUID().toString();
+        final String childAccountId = UUID.randomUUID().toString();
         final String bundleId = UUID.randomUUID().toString();
         final String subscriptionId = UUID.randomUUID().toString();
         final String planName = UUID.randomUUID().toString();
@@ -52,13 +53,14 @@ public class TestInvoiceItemJsonSimple extends JaxrsTestSuiteNoDB {
         final BigDecimal amount = BigDecimal.TEN;
         final Currency currency = Currency.MXN;
         final List<AuditLogJson> auditLogs = createAuditLogsJson(clock.getUTCNow());
-        final InvoiceItemJson invoiceItemJson = new InvoiceItemJson(invoiceItemId, invoiceId, linkedInvoiceItemId, accountId,
+        final InvoiceItemJson invoiceItemJson = new InvoiceItemJson(invoiceItemId, invoiceId, linkedInvoiceItemId, accountId, childAccountId,
                                                                                       bundleId, subscriptionId, planName, phaseName, usageName, type, description,
                                                                                       startDate, endDate, amount, currency, auditLogs);
         Assert.assertEquals(invoiceItemJson.getInvoiceItemId(), invoiceItemId);
         Assert.assertEquals(invoiceItemJson.getInvoiceId(), invoiceId);
         Assert.assertEquals(invoiceItemJson.getLinkedInvoiceItemId(), linkedInvoiceItemId);
         Assert.assertEquals(invoiceItemJson.getAccountId(), accountId);
+        Assert.assertEquals(invoiceItemJson.getChildAccountId(), childAccountId);
         Assert.assertEquals(invoiceItemJson.getBundleId(), bundleId);
         Assert.assertEquals(invoiceItemJson.getSubscriptionId(), subscriptionId);
         Assert.assertEquals(invoiceItemJson.getPlanName(), planName);
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
index e473117..e5e369e 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestInvoiceJsonWithBundleKeys.java
@@ -54,7 +54,7 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         final InvoiceJson invoiceJsonSimple = new InvoiceJson(amount, Currency.USD.toString(), InvoiceStatus.COMMITTED.toString(),
                                                               creditAdj, refundAdj, invoiceId, invoiceDate,
                                                               targetDate, invoiceNumber, balance, accountId, bundleKeys,
-                                                              credits, null, auditLogs);
+                                                              credits, null, false, auditLogs);
         Assert.assertEquals(invoiceJsonSimple.getAmount(), amount);
         Assert.assertEquals(invoiceJsonSimple.getCreditAdj(), creditAdj);
         Assert.assertEquals(invoiceJsonSimple.getRefundAdj(), refundAdj);
@@ -68,6 +68,7 @@ public class TestInvoiceJsonWithBundleKeys extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(invoiceJsonSimple.getCredits(), credits);
         Assert.assertEquals(invoiceJsonSimple.getAuditLogs(), auditLogs);
         Assert.assertEquals(invoiceJsonSimple.getStatus(), InvoiceStatus.COMMITTED.toString());
+        Assert.assertFalse(invoiceJsonSimple.getIsParentInvoice());
 
         final String asJson = mapper.writeValueAsString(invoiceJsonSimple);
         final InvoiceJson fromJson = mapper.readValue(asJson, InvoiceJson.class);
diff --git a/payment/src/test/java/org/killbill/billing/payment/MockInvoice.java b/payment/src/test/java/org/killbill/billing/payment/MockInvoice.java
index 8bf8640..0100b74 100644
--- a/payment/src/test/java/org/killbill/billing/payment/MockInvoice.java
+++ b/payment/src/test/java/org/killbill/billing/payment/MockInvoice.java
@@ -44,15 +44,16 @@ public class MockInvoice extends EntityBase implements Invoice {
     private final Currency currency;
     private final boolean migrationInvoice;
     private final InvoiceStatus status;
+    private final boolean parentInvoice;
 
     // used to create a new invoice
     public MockInvoice(final UUID accountId, final LocalDate invoiceDate, final LocalDate targetDate, final Currency currency) {
-        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false, InvoiceStatus.COMMITTED);
+        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false, InvoiceStatus.COMMITTED, false);
     }
 
     // used to hydrate invoice from persistence layer
     public MockInvoice(final UUID invoiceId, final UUID accountId, @Nullable final Integer invoiceNumber, final LocalDate invoiceDate,
-                       final LocalDate targetDate, final Currency currency, final boolean isMigrationInvoice, InvoiceStatus status) {
+                       @Nullable final LocalDate targetDate, final Currency currency, final boolean isMigrationInvoice, final InvoiceStatus status, final boolean parentInvoice) {
         super(invoiceId);
         this.accountId = accountId;
         this.invoiceNumber = invoiceNumber;
@@ -61,6 +62,7 @@ public class MockInvoice extends EntityBase implements Invoice {
         this.currency = currency;
         this.migrationInvoice = isMigrationInvoice;
         this.status = status;
+        this.parentInvoice = parentInvoice;
     }
 
     @Override
@@ -203,7 +205,7 @@ public class MockInvoice extends EntityBase implements Invoice {
 
     @Override
     public String toString() {
-        return "DefaultInvoice [items=" + invoiceItems + ", payments=" + payments + ", id=" + id + ", accountId=" + accountId + ", invoiceDate=" + invoiceDate + ", targetDate=" + targetDate + ", currency=" + currency + ", amountPaid=" + getPaidAmount() + ", status=" + status + "]";
+        return "DefaultInvoice [items=" + invoiceItems + ", payments=" + payments + ", id=" + id + ", accountId=" + accountId + ", invoiceDate=" + invoiceDate + ", targetDate=" + targetDate + ", currency=" + currency + ", amountPaid=" + getPaidAmount() + ", status=" + status + ", parentInvoice=" + parentInvoice + "]";
     }
 
     @Override
@@ -215,5 +217,10 @@ public class MockInvoice extends EntityBase implements Invoice {
     public BigDecimal getOriginalChargedAmount() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean isParentInvoice() {
+        return parentInvoice;
+    }
 }
 
diff --git a/payment/src/test/java/org/killbill/billing/payment/MockRecurringInvoiceItem.java b/payment/src/test/java/org/killbill/billing/payment/MockRecurringInvoiceItem.java
index cf3eb92..6cb7be3 100644
--- a/payment/src/test/java/org/killbill/billing/payment/MockRecurringInvoiceItem.java
+++ b/payment/src/test/java/org/killbill/billing/payment/MockRecurringInvoiceItem.java
@@ -185,6 +185,10 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem 
         return rate;
     }
 
+    @Override
+    public UUID getChildAccountId() {
+        return null;
+    }
 
     @Override
     public String toString() {
diff --git a/util/src/main/java/org/killbill/billing/util/dao/TableName.java b/util/src/main/java/org/killbill/billing/util/dao/TableName.java
index 974238e..9cd5cb6 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/TableName.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/TableName.java
@@ -35,6 +35,7 @@ public enum TableName {
     INVOICE_ITEMS("invoice_items", ObjectType.INVOICE_ITEM),
     INVOICE_PAYMENTS("invoice_payments", ObjectType.INVOICE_PAYMENT),
     INVOICES("invoices", ObjectType.INVOICE),
+    INVOICE_PARENT_CHILDREN("invoice_parent_children", ObjectType.INVOICE_PARENT_CHILD),
     NODE_INFOS("node_infos"),
     PAYMENT_ATTEMPT_HISTORY("payment_attempt_history"),
     PAYMENT_ATTEMPTS("payment_attempts", ObjectType.PAYMENT_ATTEMPT, PAYMENT_ATTEMPT_HISTORY),
diff --git a/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java b/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
index b64454d..bee5f0b 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
@@ -20,7 +20,6 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.account.api.MutableAccountData;
@@ -35,6 +34,7 @@ public class MockAccountBuilder {
     private int firstNameLength;
     private Currency currency = Currency.USD;
     private UUID parentAccountId;
+    private boolean isPaymentDelegatedToParent = false;
     private int billingCycleDayLocal;
     private UUID paymentMethodId;
     private DateTimeZone timeZone = DateTimeZone.UTC;
@@ -70,6 +70,7 @@ public class MockAccountBuilder {
         this.country(data.getCountry());
         this.currency(data.getCurrency());
         this.parentAccountId(data.getParentAccountId());
+        this.isPaymentDelegatedToParent(data.isPaymentDelegatedToParent());
         this.email(data.getEmail());
         this.externalKey(data.getExternalKey());
         this.firstNameLength(data.getFirstNameLength());
@@ -119,6 +120,11 @@ public class MockAccountBuilder {
         return this;
     }
 
+    public MockAccountBuilder isPaymentDelegatedToParent(final boolean isPaymentDelegatedToParent) {
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
+        return this;
+    }
+
     public MockAccountBuilder paymentMethodId(final UUID paymentMethodId) {
         this.paymentMethodId = paymentMethodId;
         return this;
@@ -326,7 +332,7 @@ public class MockAccountBuilder {
 
             @Override
             public Boolean isPaymentDelegatedToParent() {
-                return false;
+                return isPaymentDelegatedToParent;
             }
 
             @Override