killbill-memoizeit

Merge pull request #468 from matias-aguero-hs/hierarchical-accounts Hierarchical

1/19/2016 11:43:34 AM

Changes

pom.xml 2(+1 -1)

Details

diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
index 957b2e2..b367197 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultAccount.java
@@ -37,6 +37,8 @@ public class DefaultAccount extends EntityBase implements Account {
     private final String name;
     private final Integer firstNameLength;
     private final Currency currency;
+    private final UUID parentAccountId;
+    private final Boolean isPaymentDelegatedToParent;
     private final Integer billCycleDayLocal;
     private final UUID paymentMethodId;
     private final DateTimeZone timeZone;
@@ -65,6 +67,8 @@ public class DefaultAccount extends EntityBase implements Account {
              data.getName(),
              data.getFirstNameLength(),
              data.getCurrency(),
+             data.getParentAccountId(),
+             data.isPaymentDelegatedToParent(),
              data.getBillCycleDayLocal(),
              data.getPaymentMethodId(),
              data.getTimeZone(),
@@ -83,8 +87,9 @@ public class DefaultAccount extends EntityBase implements Account {
 
     // This call is used for testing and update from an existing account
     public DefaultAccount(final UUID id, final String externalKey, final String email,
-                          final String name, final Integer firstNameLength,
-                          final Currency currency, final Integer billCycleDayLocal, final UUID paymentMethodId,
+                          final String name, final Integer firstNameLength, final Currency currency,
+                          final UUID parentAccountId, final Boolean isPaymentDelegatedToParent,
+                          final Integer billCycleDayLocal, final UUID paymentMethodId,
                           final DateTimeZone timeZone, final String locale,
                           final String address1, final String address2, final String companyName,
                           final String city, final String stateOrProvince, final String country,
@@ -98,6 +103,8 @@ public class DefaultAccount extends EntityBase implements Account {
              name,
              firstNameLength,
              currency,
+             parentAccountId,
+             isPaymentDelegatedToParent,
              billCycleDayLocal,
              paymentMethodId,
              timeZone,
@@ -116,8 +123,9 @@ public class DefaultAccount extends EntityBase implements Account {
 
     public DefaultAccount(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
                           final String externalKey, final String email,
-                          final String name, final Integer firstNameLength,
-                          final Currency currency, final Integer billCycleDayLocal, final UUID paymentMethodId,
+                          final String name, final Integer firstNameLength, final Currency currency,
+                          final UUID parentAccountId, final Boolean isPaymentDelegatedToParent,
+                          final Integer billCycleDayLocal, final UUID paymentMethodId,
                           final DateTimeZone timeZone, final String locale,
                           final String address1, final String address2, final String companyName,
                           final String city, final String stateOrProvince, final String country,
@@ -129,6 +137,8 @@ public class DefaultAccount extends EntityBase implements Account {
         this.name = name;
         this.firstNameLength = firstNameLength;
         this.currency = currency;
+        this.parentAccountId = parentAccountId;
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent : false;
         this.billCycleDayLocal = billCycleDayLocal == null ? DEFAULT_BILLING_CYCLE_DAY_LOCAL : billCycleDayLocal;
         this.paymentMethodId = paymentMethodId;
         this.timeZone = timeZone;
@@ -154,6 +164,8 @@ public class DefaultAccount extends EntityBase implements Account {
              accountModelDao.getName(),
              accountModelDao.getFirstNameLength(),
              accountModelDao.getCurrency(),
+             accountModelDao.getParentAccountId(),
+             accountModelDao.getIsPaymentDelegatedToParent(),
              accountModelDao.getBillingCycleDayLocal(),
              accountModelDao.getPaymentMethodId(),
              accountModelDao.getTimeZone(),
@@ -196,6 +208,16 @@ public class DefaultAccount extends EntityBase implements Account {
     }
 
     @Override
+    public UUID getParentAccountId() {
+        return parentAccountId;
+    }
+
+    @Override
+    public Boolean isPaymentDelegatedToParent() {
+        return isPaymentDelegatedToParent;
+    }
+
+    @Override
     public Integer getBillCycleDayLocal() {
         return billCycleDayLocal;
     }
@@ -327,6 +349,8 @@ public class DefaultAccount extends EntityBase implements Account {
         accountData.setCountry(country != null ? country : currentAccount.getCountry());
         accountData.setPostalCode(postalCode != null ? postalCode : currentAccount.getPostalCode());
         accountData.setPhone(phone != null ? phone : currentAccount.getPhone());
+        accountData.setParentAccountId(parentAccountId != null ? parentAccountId : currentAccount.getParentAccountId());
+        accountData.setIsPaymentDelegatedToParent(isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent : currentAccount.isPaymentDelegatedToParent());
         final Boolean isMigrated = this.isMigrated != null ? this.isMigrated : currentAccount.isMigrated();
         if (isMigrated != null) {
             accountData.setIsMigrated(isMigrated);
@@ -351,6 +375,8 @@ public class DefaultAccount extends EntityBase implements Account {
                ", firstNameLength=" + firstNameLength +
                ", phone=" + phone +
                ", currency=" + currency +
+               ", parentAccountId=" + parentAccountId +
+               ", isPaymentDelegatedToParent=" + isPaymentDelegatedToParent +
                ", billCycleDayLocal=" + billCycleDayLocal +
                ", paymentMethodId=" + paymentMethodId +
                ", timezone=" + timeZone +
@@ -400,6 +426,12 @@ public class DefaultAccount extends EntityBase implements Account {
         if (currency != that.currency) {
             return false;
         }
+        if (parentAccountId != null ? !parentAccountId.equals(that.parentAccountId) : that.parentAccountId != null) {
+            return false;
+        }
+        if (isPaymentDelegatedToParent != null ? !isPaymentDelegatedToParent.equals(that.isPaymentDelegatedToParent) : that.isPaymentDelegatedToParent != null) {
+            return false;
+        }
         if (email != null ? !email.equals(that.email) : that.email != null) {
             return false;
         }
@@ -448,6 +480,8 @@ public class DefaultAccount extends EntityBase implements Account {
         result = 31 * result + (name != null ? name.hashCode() : 0);
         result = 31 * result + (firstNameLength != null ? firstNameLength.hashCode() : 0);
         result = 31 * result + (currency != null ? currency.hashCode() : 0);
+        result = 31 * result + (parentAccountId != null ? parentAccountId.hashCode() : 0);
+        result = 31 * result + (isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent.hashCode() : 0);
         result = 31 * result + billCycleDayLocal;
         result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
         result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
diff --git a/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java b/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
index 010a76d..63de386 100644
--- a/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
+++ b/account/src/main/java/org/killbill/billing/account/api/DefaultMutableAccountData.java
@@ -33,6 +33,8 @@ public class DefaultMutableAccountData implements MutableAccountData {
     private String name;
     private Integer firstNameLength;
     private Currency currency;
+    private UUID parentAccountId;
+    private Boolean isPaymentDelegatedToParent;
     private int billCycleDayLocal;
     private UUID paymentMethodId;
     private DateTimeZone timeZone;
@@ -49,8 +51,9 @@ public class DefaultMutableAccountData implements MutableAccountData {
     private Boolean isNotifiedForInvoices;
 
     public DefaultMutableAccountData(final String externalKey, final String email, final String name,
-                                     final int firstNameLength, final Currency currency, final int billCycleDayLocal,
-                                     final UUID paymentMethodId, final DateTimeZone timeZone,
+                                     final int firstNameLength, final Currency currency,
+                                     final UUID parentAccountId, final Boolean isPaymentDelegatedToParent,
+                                     final int billCycleDayLocal, final UUID paymentMethodId, final DateTimeZone timeZone,
                                      final String locale, final String address1, final String address2,
                                      final String companyName, final String city, final String stateOrProvince,
                                      final String country, final String postalCode, final String phone,
@@ -60,6 +63,8 @@ public class DefaultMutableAccountData implements MutableAccountData {
         this.name = name;
         this.firstNameLength = firstNameLength;
         this.currency = currency;
+        this.parentAccountId = parentAccountId;
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
         this.billCycleDayLocal = billCycleDayLocal;
         this.paymentMethodId = paymentMethodId;
         this.timeZone = timeZone;
@@ -82,6 +87,8 @@ public class DefaultMutableAccountData implements MutableAccountData {
         this.name = accountData.getName();
         this.firstNameLength = accountData.getFirstNameLength();
         this.currency = accountData.getCurrency();
+        this.parentAccountId = accountData.getParentAccountId();
+        this.isPaymentDelegatedToParent = accountData.isPaymentDelegatedToParent();
         this.billCycleDayLocal = accountData.getBillCycleDayLocal() == null ? DEFAULT_BILLING_CYCLE_DAY_LOCAL : accountData.getBillCycleDayLocal();
         this.paymentMethodId = accountData.getPaymentMethodId();
         this.timeZone = accountData.getTimeZone();
@@ -287,4 +294,24 @@ public class DefaultMutableAccountData implements MutableAccountData {
     public void setIsNotifiedForInvoices(final boolean isNotifiedForInvoices) {
         this.isNotifiedForInvoices = isNotifiedForInvoices;
     }
+
+    @Override
+    public UUID getParentAccountId() {
+        return parentAccountId;
+    }
+
+    @Override
+    public void setParentAccountId(final UUID parentAccountId) {
+        this.parentAccountId = parentAccountId;
+    }
+
+    @Override
+    public void setIsPaymentDelegatedToParent(final boolean isPaymentDelegatedToParent) {
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
+    }
+
+    @Override
+    public Boolean isPaymentDelegatedToParent() {
+        return isPaymentDelegatedToParent;
+    }
 }
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
index afd5664..b4189b0 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -110,6 +110,8 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
         private final String email;
         private final Integer billCycleDayLocal;
         private final String currency;
+        private final UUID parentAccountId;
+        private final Boolean isPaymentDelegatedToParent;
         private final UUID paymentMethodId;
         private final String timeZone;
         private final String locale;
@@ -131,6 +133,8 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
                  d.getEmail(),
                  d.getBillingCycleDayLocal(),
                  d.getCurrency() != null ? d.getCurrency().name() : null,
+                 d.getParentAccountId(),
+                 d.getIsPaymentDelegatedToParent(),
                  d.getPaymentMethodId(),
                  d.getTimeZone() != null ? d.getTimeZone().getID() : null,
                  d.getLocale(),
@@ -153,6 +157,8 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
                                   @JsonProperty("email") final String email,
                                   @JsonProperty("billCycleDayLocal") final Integer billCycleDayLocal,
                                   @JsonProperty("currency") final String currency,
+                                  @JsonProperty("parentAccountId") final UUID parentAccountId,
+                                  @JsonProperty("isPaymentDelegatedToParent") final Boolean isPaymentDelegatedToParent,
                                   @JsonProperty("paymentMethodId") final UUID paymentMethodId,
                                   @JsonProperty("timeZone") final String timeZone,
                                   @JsonProperty("locale") final String locale,
@@ -172,6 +178,8 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             this.email = email;
             this.billCycleDayLocal = billCycleDayLocal;
             this.currency = currency;
+            this.parentAccountId = parentAccountId;
+            this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
             this.paymentMethodId = paymentMethodId;
             this.timeZone = timeZone;
             this.locale = locale;
@@ -221,6 +229,17 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             }
         }
 
+        @Override
+        public UUID getParentAccountId() {
+            return parentAccountId;
+        }
+
+        @Override
+        @JsonIgnore
+        public Boolean isPaymentDelegatedToParent() {
+            return isPaymentDelegatedToParent;
+        }
+
         @JsonIgnore
         @Override
         public DateTimeZone getTimeZone() {
@@ -298,7 +317,7 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             return isNotifiedForInvoices;
         }
 
-        // These two getters are for Jackson serialization only
+        // These getters are for Jackson serialization only
 
         public Boolean getIsMigrated() {
             return isMigrated;
@@ -308,6 +327,10 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             return isNotifiedForInvoices;
         }
 
+        public Boolean getIsPaymentDelegatedToParent() {
+            return isPaymentDelegatedToParent;
+        }
+
         @Override
         public boolean equals(final Object o) {
             if (this == o) {
@@ -346,6 +369,12 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             if (currency != null ? !currency.equals(that.currency) : that.currency != null) {
                 return false;
             }
+            if (parentAccountId != null ? !parentAccountId.equals(that.parentAccountId) : that.parentAccountId != null) {
+                return false;
+            }
+            if (isPaymentDelegatedToParent != null ? !isPaymentDelegatedToParent.equals(that.isPaymentDelegatedToParent) : that.isPaymentDelegatedToParent != null) {
+                return false;
+            }
             if (email != null ? !email.equals(that.email) : that.email != null) {
                 return false;
             }
@@ -388,6 +417,8 @@ public class DefaultAccountCreationEvent extends BusEventBase implements Account
             result = 31 * result + (email != null ? email.hashCode() : 0);
             result = 31 * result + (billCycleDayLocal != null ? billCycleDayLocal.hashCode() : 0);
             result = 31 * result + (currency != null ? currency.hashCode() : 0);
+            result = 31 * result + (parentAccountId != null ? parentAccountId.hashCode() : 0);
+            result = 31 * result + (isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent.hashCode() : 0);
             result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
             result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
             result = 31 * result + (locale != null ? locale.hashCode() : 0);
diff --git a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
index b137cc0..e5f0d5d 100644
--- a/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/org/killbill/billing/account/api/user/DefaultAccountUserApi.java
@@ -32,6 +32,7 @@ import org.killbill.billing.account.api.DefaultAccountEmail;
 import org.killbill.billing.account.dao.AccountDao;
 import org.killbill.billing.account.dao.AccountEmailModelDao;
 import org.killbill.billing.account.dao.AccountModelDao;
+import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
 import org.killbill.billing.util.callcontext.CallContext;
@@ -84,8 +85,15 @@ public class DefaultAccountUserApi extends DefaultAccountApiBase implements Acco
             throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, data.getExternalKey());
         }
 
+        final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(context);
+
+        if (data.getParentAccountId() != null) {
+            // verify that parent account exists if parentAccountId is not null
+            getAccountById(data.getParentAccountId(), internalContext);
+        }
+
         final AccountModelDao account = new AccountModelDao(data);
-        accountDao.create(account, internalCallContextFactory.createInternalCallContext(context));
+        accountDao.create(account, internalContext);
 
         return new DefaultAccount(account);
     }
@@ -188,4 +196,15 @@ public class DefaultAccountUserApi extends DefaultAccountApiBase implements Acco
     public void removeEmail(final UUID accountId, final AccountEmail email, final CallContext context) {
         accountDao.removeEmail(new AccountEmailModelDao(email, false), internalCallContextFactory.createInternalCallContext(accountId, context));
     }
+
+    @Override
+    public List<Account> getChildrenAccounts(final UUID parentAccountId, final TenantContext context) throws AccountApiException {
+        return ImmutableList.<Account>copyOf(Collections2.transform(accountDao.getAccountsByParentId(parentAccountId, internalCallContextFactory.createInternalTenantContext(context)),
+                                                                         new Function<AccountModelDao, Account>() {
+                                                                             @Override
+                                                                             public Account apply(final AccountModelDao input) {
+                                                                                 return new DefaultAccount(input);
+                                                                             }
+                                                                         }));
+    }
 }
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
index c5cae6d..1446204 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountDao.java
@@ -52,4 +52,6 @@ public interface AccountDao extends EntityDao<AccountModelDao, Account, AccountA
     List<AccountEmailModelDao> getEmailsByAccountId(UUID accountId, InternalTenantContext context);
 
     Integer getAccountBCD(UUID accountId, InternalTenantContext context);
+
+    List<AccountModelDao> getAccountsByParentId(UUID parentAccountId, InternalTenantContext context);
 }
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
index ac70362..7ddf6cc 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountModelDao.java
@@ -43,6 +43,8 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
     private String name;
     private Integer firstNameLength;
     private Currency currency;
+    private UUID parentAccountId;
+    private Boolean isPaymentDelegatedToParent;
     private int billingCycleDayLocal;
     private UUID paymentMethodId;
     private DateTimeZone timeZone;
@@ -58,10 +60,12 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
     private Boolean migrated;
     private Boolean isNotifiedForInvoices;
 
+
     public AccountModelDao() { /* For the DAO mapper */ }
 
     public AccountModelDao(final UUID id, final DateTime createdDate, final DateTime updatedDate, final String externalKey,
                            final String email, final String name, final Integer firstNameLength, final Currency currency,
+                           final UUID parentAccountId, final Boolean isPaymentDelegatedToParent,
                            final int billingCycleDayLocal, final UUID paymentMethodId, final DateTimeZone timeZone,
                            final String locale, final String address1, final String address2, final String companyName,
                            final String city, final String stateOrProvince, final String country, final String postalCode,
@@ -72,6 +76,8 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
         this.name = name;
         this.firstNameLength = firstNameLength;
         this.currency = currency;
+        this.parentAccountId = parentAccountId;
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
         this.billingCycleDayLocal = billingCycleDayLocal;
         this.paymentMethodId = paymentMethodId;
         this.timeZone = MoreObjects.firstNonNull(timeZone, DateTimeZone.UTC);
@@ -97,6 +103,8 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
              account.getName(),
              account.getFirstNameLength(),
              account.getCurrency(),
+             account.getParentAccountId(),
+             account.isPaymentDelegatedToParent(),
              MoreObjects.firstNonNull(account.getBillCycleDayLocal(), DEFAULT_BILLING_CYCLE_DAY_LOCAL),
              account.getPaymentMethodId(),
              account.getTimeZone(),
@@ -162,6 +170,22 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
         this.currency = currency;
     }
 
+    public UUID getParentAccountId() {
+        return parentAccountId;
+    }
+
+    public void setParentAccountId(final UUID parentAccountId) {
+        this.parentAccountId = parentAccountId;
+    }
+
+    public Boolean getIsPaymentDelegatedToParent() {
+        return isPaymentDelegatedToParent;
+    }
+
+    public void setIsPaymentDelegatedToParent(final Boolean paymentDelegatedToParent) {
+        this.isPaymentDelegatedToParent = paymentDelegatedToParent;
+    }
+
     public Integer getBillingCycleDayLocal() {
         return billingCycleDayLocal;
     }
@@ -285,6 +309,8 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
         sb.append(", name='").append(name).append('\'');
         sb.append(", firstNameLength=").append(firstNameLength);
         sb.append(", currency=").append(currency);
+        sb.append(", parentAccountId=").append(parentAccountId);
+        sb.append(", isPaymentDelegatedToParent=").append(isPaymentDelegatedToParent);
         sb.append(", billingCycleDayLocal=").append(billingCycleDayLocal);
         sb.append(", paymentMethodId=").append(paymentMethodId);
         sb.append(", timeZone=").append(timeZone);
@@ -338,6 +364,12 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
         if (currency != that.currency) {
             return false;
         }
+        if (parentAccountId != null ? !parentAccountId.equals(that.parentAccountId) : that.parentAccountId != null) {
+            return false;
+        }
+        if (isPaymentDelegatedToParent != null ? !isPaymentDelegatedToParent.equals(that.isPaymentDelegatedToParent) : that.isPaymentDelegatedToParent != null) {
+            return false;
+        }
         if (email != null ? !email.equals(that.email) : that.email != null) {
             return false;
         }
@@ -386,6 +418,8 @@ public class AccountModelDao extends EntityModelDaoBase implements EntityModelDa
         result = 31 * result + (name != null ? name.hashCode() : 0);
         result = 31 * result + (firstNameLength != null ? firstNameLength.hashCode() : 0);
         result = 31 * result + (currency != null ? currency.hashCode() : 0);
+        result = 31 * result + (parentAccountId != null ? parentAccountId.hashCode() : 0);
+        result = 31 * result + (isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent.hashCode() : 0);
         result = 31 * result + billingCycleDayLocal;
         result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
         result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
diff --git a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
index 5395c85..d474747 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/AccountSqlDao.java
@@ -16,6 +16,7 @@
 
 package org.killbill.billing.account.dao;
 
+import java.util.List;
 import java.util.UUID;
 
 import org.killbill.billing.account.api.Account;
@@ -55,4 +56,8 @@ public interface AccountSqlDao extends EntitySqlDao<AccountModelDao, Account> {
     public void updatePaymentMethod(@Bind("id") String accountId,
                                     @Bind("paymentMethodId") String paymentMethodId,
                                     @BindBean final InternalCallContext context);
+
+    @SqlQuery
+    List<AccountModelDao> getAccountsByParentId(@Bind("parentAccountId") UUID parentAccountId,
+                                                @BindBean final InternalTenantContext context);
 }
diff --git a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
index 31c33e3..e713194 100644
--- a/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/org/killbill/billing/account/dao/DefaultAccountDao.java
@@ -255,4 +255,14 @@ public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, Account, A
             }
         });
     }
+
+    @Override
+    public List<AccountModelDao> getAccountsByParentId(final UUID parentAccountId, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AccountModelDao>>() {
+            @Override
+            public List<AccountModelDao> inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
+                return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getAccountsByParentId(parentAccountId, context);
+            }
+        });
+    }
 }
diff --git a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
index a500028..a2a86bb 100644
--- a/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/org/killbill/billing/account/dao/AccountSqlDao.sql.stg
@@ -11,6 +11,8 @@ tableFields(prefix) ::= <<
 , <prefix>first_name_length
 , <prefix>currency
 , <prefix>billing_cycle_day_local
+, <prefix>parent_account_id
+, <prefix>is_payment_delegated_to_parent
 , <prefix>payment_method_id
 , <prefix>time_zone
 , <prefix>locale
@@ -37,6 +39,8 @@ tableValues() ::= <<
 , :firstNameLength
 , :currency
 , :billingCycleDayLocal
+, :parentAccountId
+, :isPaymentDelegatedToParent
 , :paymentMethodId
 , :timeZone
 , :locale
@@ -106,3 +110,11 @@ getIdFromKey() ::= <<
     WHERE external_key = :externalKey <AND_CHECK_TENANT()>;
 >>
 
+getAccountsByParentId() ::= <<
+    select <allTableFields()>
+    from accounts
+    where parent_account_id = :parentAccountId
+    <AND_CHECK_TENANT()>
+    <defaultOrderBy()>
+    ;
+>>
\ No newline at end of file
diff --git a/account/src/main/resources/org/killbill/billing/account/ddl.sql b/account/src/main/resources/org/killbill/billing/account/ddl.sql
index 01158e4..9699c67 100644
--- a/account/src/main/resources/org/killbill/billing/account/ddl.sql
+++ b/account/src/main/resources/org/killbill/billing/account/ddl.sql
@@ -10,6 +10,8 @@ CREATE TABLE accounts (
     first_name_length int DEFAULT NULL,
     currency varchar(3) DEFAULT NULL,
     billing_cycle_day_local int DEFAULT NULL,
+    parent_account_id varchar(36) DEFAULT NULL,
+    is_payment_delegated_to_parent boolean DEFAULT FALSE,
     payment_method_id varchar(36) DEFAULT NULL,
     time_zone varchar(50) NOT NULL,
     locale varchar(5) DEFAULT NULL,
@@ -45,7 +47,9 @@ CREATE TABLE account_history (
     first_name_length int DEFAULT NULL,
     currency varchar(3) DEFAULT NULL,
     billing_cycle_day_local int DEFAULT NULL,
+    parent_account_id varchar(36) DEFAULT NULL,
     payment_method_id varchar(36) DEFAULT NULL,
+    is_payment_delegated_to_parent boolean default false,
     time_zone varchar(50) NOT NULL,
     locale varchar(5) DEFAULT NULL,
     address1 varchar(100) DEFAULT NULL,
diff --git a/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java b/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
index 9c6220d..61b1127 100644
--- a/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
+++ b/account/src/test/java/org/killbill/billing/account/AccountTestUtils.java
@@ -102,7 +102,7 @@ public abstract class AccountTestUtils {
         final String country = Locale.GERMANY.getCountry();
         final String postalCode = UUID.randomUUID().toString().substring(0, 4);
 
-        return new DefaultMutableAccountData(externalKey, email, name, firstNameLength, currency,
+        return new DefaultMutableAccountData(externalKey, email, name, firstNameLength, currency, null, false,
                                              billCycleDayLocal, paymentMethodId, timeZone,
                                              locale, address1, address2, companyName, city, stateOrProvince,
                                              country, postalCode, phone, false, true);
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
index 39bbb72..1d498ee 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -25,6 +25,7 @@ import java.util.concurrent.Callable;
 
 import org.killbill.billing.account.AccountTestSuiteWithEmbeddedDB;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountData;
 import org.killbill.billing.account.api.DefaultAccount;
 import org.killbill.billing.account.api.DefaultMutableAccountData;
@@ -70,7 +71,7 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
         final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
 
         // Update the address and leave other fields null
-        final MutableAccountData mutableAccountData = new DefaultMutableAccountData(null, null, null, 0, null, 0, null,
+        final MutableAccountData mutableAccountData = new DefaultMutableAccountData(null, null, null, 0, null, null, false, 0, null,
                                                                                     null, null, null, null, null, null,
                                                                                     null, null, null, null, false, false);
         final String newAddress1 = UUID.randomUUID().toString();
@@ -129,4 +130,36 @@ public class TestDefaultAccountUserApi extends AccountTestSuiteWithEmbeddedDB {
             return accountCreationInternalEvents;
         }
     }
+
+    @Test(groups = "slow", description = "Test Account create Parent and Child")
+    public void testCreateParentAndChildAccounts() throws Exception {
+
+        final Account parentAccount = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+
+        final AccountModelDao childAccountModel = createTestAccount();
+        childAccountModel.setParentAccountId(parentAccount.getId());
+        childAccountModel.setIsPaymentDelegatedToParent(true);
+        final AccountData childAccountData = new DefaultAccount(childAccountModel);
+        final Account childAccount = accountUserApi.createAccount(childAccountData, callContext);
+
+        final Account retrievedChildAccount = accountUserApi.getAccountById(childAccount.getId(), callContext);
+
+        Assert.assertNull(parentAccount.getParentAccountId());
+        Assert.assertNotNull(retrievedChildAccount.getParentAccountId());
+        Assert.assertEquals(retrievedChildAccount.getId(), childAccount.getId());
+        Assert.assertEquals(retrievedChildAccount.getParentAccountId(), parentAccount.getId());
+        Assert.assertEquals(retrievedChildAccount.isPaymentDelegatedToParent(), childAccount.isPaymentDelegatedToParent());
+    }
+
+    @Test(groups = "slow", description = "Test Account create Child with a non existing Parent",
+            expectedExceptions = AccountApiException.class, expectedExceptionsMessageRegExp = "Account does not exist for id .*")
+    public void testCreateChildAccountWithInvalidParent() throws Exception {
+
+        final AccountModelDao childAccountModel = createTestAccount();
+        childAccountModel.setParentAccountId(UUID.randomUUID());
+        final AccountData childAccountData = new DefaultAccount(childAccountModel);
+        final Account childAccount = accountUserApi.createAccount(childAccountData, callContext);
+
+    }
+
 }
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
index f3d7863..6d48b71 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestDefaultAccountUserApiWithMocks.java
@@ -78,7 +78,7 @@ public class TestDefaultAccountUserApiWithMocks extends AccountTestSuiteNoDB {
         final String phone = UUID.randomUUID().toString();
         final Boolean isMigrated = true;
         final Boolean isNotifiedForInvoices = false;
-        final AccountData data = new DefaultAccount(id, externalKey, email, name, firstNameLength, currency, billCycleDay,
+        final AccountData data = new DefaultAccount(id, externalKey, email, name, firstNameLength, currency, null, false, billCycleDay,
                                                     paymentMethodId, timeZone, locale, address1, address2, companyName,
                                                     city, stateOrProvince, country, postalCode, phone, isMigrated, isNotifiedForInvoices);
 
diff --git a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
index 23ccdf7..ed130b8 100644
--- a/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
+++ b/account/src/test/java/org/killbill/billing/account/api/user/TestEventJson.java
@@ -50,7 +50,7 @@ public class TestEventJson extends AccountTestSuiteNoDB {
 
     @Test(groups = "fast", description="Test Account event serialization")
     public void testAccountCreationEvent() throws Exception {
-        final DefaultAccountData data = new DefaultAccountData("dsfdsf", "bobo", 3, "bobo@yahoo.com", 12, "USD", UUID.randomUUID(),
+        final DefaultAccountData data = new DefaultAccountData("dsfdsf", "bobo", 3, "bobo@yahoo.com", 12, "USD", null, false, UUID.randomUUID(),
                                                                "UTC", "US", "21 avenue", "", "Gling", "San Franciso", "CA", "94110", "USA", "4126789887", false, false);
         final DefaultAccountCreationEvent e = new DefaultAccountCreationEvent(data, UUID.randomUUID(), 1L, 2L, null);
         final String json = mapper.writeValueAsString(e);
diff --git a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
index a06aa3f..67bbc28 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/MockAccountDao.java
@@ -50,6 +50,7 @@ import com.google.inject.Inject;
 
 public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account, AccountApiException> implements AccountDao {
 
+    private final MockEntityDaoBase<AccountModelDao, Account, AccountApiException> accountSqlDao = new MockEntityDaoBase<AccountModelDao, Account, AccountApiException>();
     private final MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException> accountEmailSqlDao = new MockEntityDaoBase<AccountEmailModelDao, AccountEmail, AccountApiException>();
     private final PersistentBus eventBus;
 
@@ -171,4 +172,13 @@ public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, Account, 
         return account != null ? account.getBillingCycleDayLocal() : 0;
     }
 
+    @Override
+    public List<AccountModelDao> getAccountsByParentId(final UUID parentAccountId, final InternalTenantContext context) {
+        return ImmutableList.<AccountModelDao>copyOf(Iterables.<AccountModelDao>filter(accountSqlDao.getAll(context), new Predicate<AccountModelDao>() {
+            @Override
+            public boolean apply(final AccountModelDao input) {
+                return parentAccountId.equals(input.getParentAccountId());
+            }
+        }));
+    }
 }
diff --git a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
index fc3fece..1ebcd3d 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
@@ -64,7 +64,7 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
     public void testMinimalFields() throws Exception {
         final String email = UUID.randomUUID().toString();
         final String name = UUID.randomUUID().toString();
-        final AccountData accountData = new DefaultMutableAccountData(null, email, name, 0, null,
+        final AccountData accountData = new DefaultMutableAccountData(null, email, name, 0, null, null, false,
                                                                       0, null, null, null, null,
                                                                       null, null, null, null, null,
                                                                       null, null, false, true);
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index c81c6e8..29ef612 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -481,4 +481,5 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
         }
         return invoice;
     }
+
 }
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 9f86bc9..1ef6f7f 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
@@ -853,4 +853,5 @@ public class DefaultInvoiceDao extends EntityDaoBase<InvoiceModelDao, Invoice, I
             throw new InvoiceApiException(ErrorCode.INVOICE_ITEM_ADJUSTMENT_ITEM_INVALID, invoiceItemToBeAdjusted.getId());
         }
     }
+
 }
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 effce52..25c9249 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
@@ -138,4 +138,5 @@ public interface InvoiceDao extends EntityDao<InvoiceModelDao, Invoice, InvoiceA
      * @param context   the callcontext
      */
     public void consumeExstingCBAOnAccountWithUnpaidInvoices(final UUID accountId, final InternalCallContext context);
+
 }
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 40551e9..3b46cf6 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
@@ -19,14 +19,13 @@ package org.killbill.billing.invoice.dao;
 import java.util.List;
 import java.util.UUID;
 
-import org.skife.jdbi.v2.sqlobject.Bind;
-import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.util.entity.dao.EntitySqlDao;
 import org.killbill.billing.util.entity.dao.EntitySqlDaoStringTemplate;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
 
 @EntitySqlDaoStringTemplate
 public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
@@ -38,5 +37,6 @@ public interface InvoiceSqlDao extends EntitySqlDao<InvoiceModelDao, Invoice> {
     @SqlQuery
     UUID getInvoiceIdByPaymentId(@Bind("paymentId") final String paymentId,
                                  @BindBean final InternalTenantContext context);
+
 }
 
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 6c1c27e..65e3b0e 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
@@ -27,7 +27,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -362,4 +361,5 @@ public class MockInvoiceDao extends MockEntityDaoBase<InvoiceModelDao, Invoice, 
     public void deleteCBA(final UUID accountId, final UUID invoiceId, final UUID invoiceItemId, final InternalCallContext context) throws InvoiceApiException {
         throw new UnsupportedOperationException();
     }
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
index 91763c0..9e44427 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/AccountJson.java
@@ -48,6 +48,9 @@ public class AccountJson extends JsonBase {
     private final Integer billCycleDayLocal;
     private final String currency;
     @ApiModelProperty(dataType = "java.util.UUID")
+    private final String parentAccountId;
+    private final Boolean isPaymentDelegatedToParent;
+    @ApiModelProperty(dataType = "java.util.UUID")
     private final String paymentMethodId;
     private final String timeZone;
     private final String address1;
@@ -73,6 +76,8 @@ public class AccountJson extends JsonBase {
         this.email = account.getEmail();
         this.billCycleDayLocal = account.getBillCycleDayLocal();
         this.currency = account.getCurrency() != null ? account.getCurrency().toString() : null;
+        this.parentAccountId = account.getParentAccountId() != null ? account.getParentAccountId().toString() : null;
+        this.isPaymentDelegatedToParent = account.isPaymentDelegatedToParent();
         this.paymentMethodId = account.getPaymentMethodId() != null ? account.getPaymentMethodId().toString() : null;
         this.timeZone = account.getTimeZone() != null ? account.getTimeZone().toString() : null;
         this.address1 = account.getAddress1();
@@ -96,6 +101,8 @@ public class AccountJson extends JsonBase {
                        @JsonProperty("email") final String email,
                        @JsonProperty("billCycleDayLocal") final Integer billCycleDayLocal,
                        @JsonProperty("currency") final String currency,
+                       @JsonProperty("parentAccountId") final String parentAccountId,
+                       @JsonProperty("isPaymentDelegatedToParent") final Boolean isPaymentDelegatedToParent,
                        @JsonProperty("paymentMethodId") final String paymentMethodId,
                        @JsonProperty("timeZone") final String timeZone,
                        @JsonProperty("address1") final String address1,
@@ -121,6 +128,8 @@ public class AccountJson extends JsonBase {
         this.email = email;
         this.billCycleDayLocal = billCycleDayLocal;
         this.currency = currency;
+        this.parentAccountId = parentAccountId;
+        this.isPaymentDelegatedToParent = isPaymentDelegatedToParent;
         this.paymentMethodId = paymentMethodId;
         this.timeZone = timeZone;
         this.address1 = address1;
@@ -245,6 +254,20 @@ public class AccountJson extends JsonBase {
             public String getAddress1() {
                 return address1;
             }
+
+            @Override
+            public UUID getParentAccountId() {
+                if (Strings.emptyToNull(parentAccountId) == null) {
+                    return null;
+                } else {
+                    return UUID.fromString(parentAccountId);
+                }
+            }
+
+            @Override
+            public Boolean isPaymentDelegatedToParent() {
+                return isPaymentDelegatedToParent;
+            }
         };
     }
 
@@ -284,6 +307,15 @@ public class AccountJson extends JsonBase {
         return currency;
     }
 
+    public String getParentAccountId() {
+        return parentAccountId;
+    }
+
+    @JsonProperty("isPaymentDelegatedToParent")
+    public Boolean isPaymentDelegatedToParent() {
+        return isPaymentDelegatedToParent;
+    }
+
     public String getPaymentMethodId() {
         return paymentMethodId;
     }
@@ -350,6 +382,8 @@ public class AccountJson extends JsonBase {
                ", email='" + email + '\'' +
                ", billCycleDayLocal=" + billCycleDayLocal +
                ", currency='" + currency + '\'' +
+               ", parentAccountId=" + parentAccountId + '\'' +
+               ", isPaymentDelegatedToParent=" + isPaymentDelegatedToParent + '\'' +
                ", paymentMethodId='" + paymentMethodId + '\'' +
                ", timeZone='" + timeZone + '\'' +
                ", address1='" + address1 + '\'' +
@@ -407,6 +441,12 @@ public class AccountJson extends JsonBase {
         if (currency != null ? !currency.equals(that.currency) : that.currency != null) {
             return false;
         }
+        if (parentAccountId != null ? !parentAccountId.equals(that.parentAccountId) : that.parentAccountId != null) {
+            return false;
+        }
+        if (isPaymentDelegatedToParent != null ? !isPaymentDelegatedToParent.equals(that.isPaymentDelegatedToParent) : that.isPaymentDelegatedToParent != null) {
+            return false;
+        }
         if (email != null ? !email.equals(that.email) : that.email != null) {
             return false;
         }
@@ -458,6 +498,8 @@ public class AccountJson extends JsonBase {
         result = 31 * result + (email != null ? email.hashCode() : 0);
         result = 31 * result + (billCycleDayLocal != null ? billCycleDayLocal.hashCode() : 0);
         result = 31 * result + (currency != null ? currency.hashCode() : 0);
+        result = 31 * result + (parentAccountId != null ? parentAccountId.hashCode() : 0);
+        result = 31 * result + (isPaymentDelegatedToParent != null ? isPaymentDelegatedToParent.hashCode() : 0);
         result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
         result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
         result = 31 * result + (address1 != null ? address1.hashCode() : 0);
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index 3a83f47..ef929a2 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -1207,4 +1207,33 @@ public class AccountResource extends JaxRsResourceBase {
     protected ObjectType getObjectType() {
         return ObjectType.ACCOUNT;
     }
+
+    // -------------------------------------
+    //      Parent and child accounts
+    // -------------------------------------
+
+    @TimedResource
+    @GET
+    @Path("/{accountId:" + UUID_PATTERN + "}/" + CHILDREN)
+    @Produces(APPLICATION_JSON)
+    @ApiOperation(value = "List children accounts", response = AccountJson.class, responseContainer = "List")
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid parent account id supplied"),
+                           @ApiResponse(code = 404, message = "Parent Account not found")})
+    public Response getChildrenAccounts(@PathParam("accountId") final String parentAccountId,
+                                        @QueryParam(QUERY_ACCOUNT_WITH_BALANCE) @DefaultValue("false") final Boolean accountWithBalance,
+                                        @QueryParam(QUERY_ACCOUNT_WITH_BALANCE_AND_CBA) @DefaultValue("false") final Boolean accountWithBalanceAndCBA,
+                                        @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
+                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
+
+        final TenantContext tenantContext = context.createContext(request);
+        final List<Account> accounts = accountUserApi.getChildrenAccounts(UUID.fromString(parentAccountId), tenantContext);
+
+        final List<AccountJson> accountJson = new ArrayList<AccountJson>();
+        for (final Account account : accounts) {
+            final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(account.getId(), auditMode.getLevel(), tenantContext);
+            accountJson.add(getAccount(account, accountWithBalance, accountWithBalanceAndCBA, accountAuditLogs, tenantContext));
+        }
+        return Response.status(Status.OK).entity(accountJson).build();
+    }
+
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 2fdd31e..f97c91a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -239,4 +239,7 @@ public interface JaxrsResource {
 
     public static final String COMBO = "combo";
 
+    public static final String CHILDREN = "children";
+    public static final String CHILDREN_PATH = PREFIX + "/" + CHILDREN;
+
 }
diff --git a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
index 4a87407..240b0eb 100644
--- a/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
+++ b/jaxrs/src/test/java/org/killbill/billing/jaxrs/json/TestAccountJson.java
@@ -51,9 +51,10 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         final String phone = UUID.randomUUID().toString();
         final Boolean isMigrated = true;
         final Boolean isNotifiedForInvoice = false;
+        final String parentAccountId = UUID.randomUUID().toString();
 
         final AccountJson accountJson = new AccountJson(accountId, name, length, externalKey,
-                                                        email, billCycleDayLocal, currency, paymentMethodId,
+                                                        email, billCycleDayLocal, currency, parentAccountId, true, paymentMethodId,
                                                         timeZone, address1, address2, postalCode, company, city, state,
                                                         country, locale, phone, isMigrated, isNotifiedForInvoice, null, null, null);
         Assert.assertEquals(accountJson.getAccountId(), accountId);
@@ -76,6 +77,8 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(accountJson.getPhone(), phone);
         Assert.assertEquals(accountJson.isMigrated(), isMigrated);
         Assert.assertEquals(accountJson.isNotifiedForInvoices(), isNotifiedForInvoice);
+        Assert.assertEquals(accountJson.getParentAccountId(), parentAccountId);
+        Assert.assertEquals(accountJson.isPaymentDelegatedToParent(), Boolean.TRUE);
 
         final String asJson = mapper.writeValueAsString(accountJson);
         final AccountJson fromJson = mapper.readValue(asJson, AccountJson.class);
@@ -105,6 +108,7 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         accountBuilder.postalCode(UUID.randomUUID().toString());
         accountBuilder.stateOrProvince(UUID.randomUUID().toString());
         accountBuilder.timeZone(DateTimeZone.UTC);
+        accountBuilder.parentAccountId(UUID.randomUUID());
         final Account account = accountBuilder.build();
 
         final AccountJson accountJson = new AccountJson(account, null, null, null);
@@ -125,5 +129,6 @@ public class TestAccountJson extends JaxrsTestSuiteNoDB {
         Assert.assertEquals(accountJson.isNotifiedForInvoices(), account.isNotifiedForInvoices());
         Assert.assertEquals(accountJson.getState(), account.getStateOrProvince());
         Assert.assertEquals(accountJson.getTimeZone(), account.getTimeZone().toString());
+        Assert.assertEquals(accountJson.getParentAccountId(), account.getParentAccountId().toString());
     }
 }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 2368655..32e5f74 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.79</version>
+        <version>0.80.ha-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.17.0.ha-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
index 3686716..e61057a 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/KillbillClient.java
@@ -173,7 +173,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         final String phone = "81 53 26 56";
 
         // Note: the accountId payload is ignored on account creation
-        return new Account(accountId, name, length, externalKey, email, null, currency, null, timeZone,
+        return new Account(accountId, name, length, externalKey, email, null, currency, null, null, null, timeZone,
                            address1, address2, postalCode, company, city, state, country, locale, phone, false, false, null, null);
     }
 
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
index 6b39e26..1f4f461 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccount.java
@@ -111,7 +111,8 @@ public class TestAccount extends TestJaxrsBase {
         // Update Account
         final Account newInput = new Account(input.getAccountId(),
                                              "zozo", 4, input.getExternalKey(), "rr@google.com", 18,
-                                             "USD", null, "UTC", "bl1", "bh2", "", "", "ca", "San Francisco", "usa", "en", "415-255-2991",
+                                             "USD", null, false, null, "UTC",
+                                             "bl1", "bh2", "", "", "ca", "San Francisco", "usa", "en", "415-255-2991",
                                              false, false, null, null);
         final Account updatedAccount = killBillClient.updateAccount(newInput, createdBy, reason, comment);
         Assert.assertTrue(updatedAccount.equals(newInput));
@@ -370,4 +371,63 @@ public class TestAccount extends TestJaxrsBase {
             Assert.assertEquals(accountsByKey.get(0), output);
         }
     }
-}
+
+    @Test(groups = "slow", description = "Can create and retrieve parent/children accounts")
+    public void testParentAccountOk() throws Exception {
+
+        final Account parentAccount = createAccount();
+
+        final Account childInput = getAccount();
+        childInput.setParentAccountId(parentAccount.getAccountId());
+        childInput.setIsPaymentDelegatedToParent(true);
+        final Account childAccount = killBillClient.createAccount(childInput, createdBy, reason, comment);
+
+        // Retrieves child account by external key
+        final Account retrievedAccount = killBillClient.getAccount(childAccount.getExternalKey());
+        Assert.assertTrue(retrievedAccount.equals(childAccount));
+        Assert.assertEquals(retrievedAccount.getParentAccountId(), parentAccount.getAccountId());
+        Assert.assertTrue(retrievedAccount.getIsPaymentDelegatedToParent());
+    }
+
+    @Test(groups = "slow", description = "retrieve children accounts by parent account id")
+    public void testGetChildrenAccounts() throws Exception {
+
+        final Account parentAccount = createAccount();
+
+        final Account childInput = getAccount();
+        childInput.setParentAccountId(parentAccount.getAccountId());
+        childInput.setIsPaymentDelegatedToParent(true);
+        final Account childAccount = killBillClient.createAccount(childInput, createdBy, reason, comment);
+
+        final Account childInput2 = getAccount();
+        childInput2.setParentAccountId(parentAccount.getAccountId());
+        childInput2.setIsPaymentDelegatedToParent(true);
+        final Account childAccount2 = killBillClient.createAccount(childInput2, createdBy, reason, comment);
+
+        // Retrieves children accounts by parent account id
+        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(parentAccount.getAccountId(), true, true);
+        Assert.assertEquals(childrenAccounts.size(), 2);
+
+        Assert.assertTrue(childrenAccounts.get(0).equals(childAccount));
+        Assert.assertTrue(childrenAccounts.get(1).equals(childAccount2));
+    }
+
+    @Test(groups = "slow", description = "retrieve an empty children accounts list by a non parent account id")
+    public void testEmptyGetChildrenAccounts() throws Exception {
+
+        // Retrieves children accounts by parent account id
+        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(UUID.randomUUID(), false, false);
+        Assert.assertEquals(childrenAccounts.size(), 0);
+
+    }
+
+    @Test(groups = "slow", description = "retrieve an empty children accounts list by a null id")
+    public void testGetChildrenAccountsByNullId() throws Exception {
+
+        // Retrieves children accounts by parent account id
+        final Accounts childrenAccounts = killBillClient.getChildrenAccounts(null, true, true);
+        Assert.assertEquals(childrenAccounts.size(), 0);
+
+    }
+
+}
\ No newline at end of file
diff --git a/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java b/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
index 18e47eb..fc586f2 100644
--- a/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
+++ b/util/src/test/java/org/killbill/billing/mock/api/MockAccountUserApi.java
@@ -22,7 +22,6 @@ import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.joda.time.DateTimeZone;
-
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountData;
@@ -167,4 +166,9 @@ public class MockAccountUserApi implements AccountUserApi {
             throws AccountApiException {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public List<Account> getChildrenAccounts(final UUID uuid, final TenantContext tenantContext) throws AccountApiException {
+        throw new UnsupportedOperationException();
+    }
 }
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 65a54d9..b64454d 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockAccountBuilder.java
@@ -34,6 +34,7 @@ public class MockAccountBuilder {
     private String name = "";
     private int firstNameLength;
     private Currency currency = Currency.USD;
+    private UUID parentAccountId;
     private int billingCycleDayLocal;
     private UUID paymentMethodId;
     private DateTimeZone timeZone = DateTimeZone.UTC;
@@ -68,6 +69,7 @@ public class MockAccountBuilder {
         this.companyName(data.getCompanyName());
         this.country(data.getCountry());
         this.currency(data.getCurrency());
+        this.parentAccountId(data.getParentAccountId());
         this.email(data.getEmail());
         this.externalKey(data.getExternalKey());
         this.firstNameLength(data.getFirstNameLength());
@@ -112,6 +114,11 @@ public class MockAccountBuilder {
         return this;
     }
 
+    public MockAccountBuilder parentAccountId(final UUID parentAccountId) {
+        this.parentAccountId = parentAccountId;
+        return this;
+    }
+
     public MockAccountBuilder paymentMethodId(final UUID paymentMethodId) {
         this.paymentMethodId = paymentMethodId;
         return this;
@@ -313,6 +320,16 @@ public class MockAccountBuilder {
             }
 
             @Override
+            public UUID getParentAccountId() {
+                return parentAccountId;
+            }
+
+            @Override
+            public Boolean isPaymentDelegatedToParent() {
+                return false;
+            }
+
+            @Override
             public UUID getId() {
                 return id;
             }