killbill-aplcache

Merge branch 'audit-rework' of github.com:killbill/killbill

11/9/2012 11:06:06 PM

Changes

Details

diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
index cb2188f..27efd2e 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccount.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.util.entity.EntityBase;
@@ -63,10 +64,6 @@ public class DefaultAccount extends EntityBase implements Account {
     private final Boolean isMigrated;
     private final Boolean isNotifiedForInvoices;
 
-    public DefaultAccount(final AccountData data) {
-        this(UUID.randomUUID(), data);
-    }
-
     /**
      * This call is used to update an existing account
      *
@@ -129,6 +126,15 @@ public class DefaultAccount extends EntityBase implements Account {
         this.isNotifiedForInvoices = isNotifiedForInvoices;
     }
 
+    public DefaultAccount(final AccountModelDao accountModelDao) {
+        this(accountModelDao.getId(), accountModelDao.getCreatedDate(), accountModelDao.getUpdatedDate(), accountModelDao.getExternalKey(),
+             accountModelDao.getEmail(), accountModelDao.getName(), accountModelDao.getFirstNameLength(), accountModelDao.getCurrency(),
+             new DefaultBillCycleDay(accountModelDao.getBillingCycleDayLocal(), accountModelDao.getBillingCycleDayUTC()), accountModelDao.getPaymentMethodId(),
+             accountModelDao.getTimeZone(), accountModelDao.getLocale(), accountModelDao.getAddress1(), accountModelDao.getAddress2(),
+             accountModelDao.getCompanyName(), accountModelDao.getCity(), accountModelDao.getStateOrProvince(), accountModelDao.getCountry(),
+             accountModelDao.getPostalCode(), accountModelDao.getPhone(), accountModelDao.getMigrated(), accountModelDao.getIsNotifiedForInvoices());
+    }
+
     @Override
     public String getExternalKey() {
         return Objects.firstNonNull(externalKey, DEFAULT_STRING_VALUE);
diff --git a/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java b/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
index b738270..d0bbbe3 100644
--- a/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
+++ b/account/src/main/java/com/ning/billing/account/api/DefaultAccountEmail.java
@@ -31,10 +31,6 @@ public class DefaultAccountEmail extends EntityBase implements AccountEmail {
         this.email = email;
     }
 
-    public DefaultAccountEmail(final AccountEmail source, final String newEmail) {
-        this(source.getAccountId(), newEmail);
-    }
-
     public DefaultAccountEmail(final UUID id, final UUID accountId, final String email) {
         super(id);
         this.accountId = accountId;
diff --git a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
index d75cc23..2dc669b 100644
--- a/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/svcs/DefaultAccountInternalApi.java
@@ -29,6 +29,7 @@ import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.AccountEmailDao;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -46,24 +47,32 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
 
     @Override
     public Account getAccountById(final UUID accountId, final InternalTenantContext context) throws AccountApiException {
-        final Account account = accountDao.getById(accountId, context);
+        final AccountModelDao account = accountDao.getById(accountId, context);
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
         }
-        return account;
+        return new DefaultAccount(account);
     }
 
     @Override
     public Account getAccountByRecordId(final Long recordId, final InternalTenantContext context) throws AccountApiException {
-        return accountDao.getByRecordId(recordId, context);
+        final AccountModelDao account = accountDao.getByRecordId(recordId, context);
+        return new DefaultAccount(account);
     }
 
     @Override
     public void updateAccount(final String externalKey, final AccountData accountData,
                               final InternalCallContext context) throws AccountApiException {
-        final Account account = getAccountByKey(externalKey, context);
-        final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
-        accountDao.update(updatedAccount, context);
+        final Account currentAccount = getAccountByKey(externalKey, context);
+        if (currentAccount == null) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, externalKey);
+        }
+
+        // Set unspecified (null) fields to their current values
+        final Account updatedAccount = new DefaultAccount(currentAccount.getId(), accountData);
+        final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), updatedAccount.mergeWithDelegate(currentAccount));
+
+        accountDao.update(accountToUpdate, context);
     }
 
     @Override
@@ -74,11 +83,11 @@ public class DefaultAccountInternalApi implements AccountInternalApi {
 
     @Override
     public Account getAccountByKey(final String key, final InternalTenantContext context) throws AccountApiException {
-        final Account account = accountDao.getAccountByKey(key, context);
-        if (account == null) {
+        final AccountModelDao accountModelDao = accountDao.getAccountByKey(key, context);
+        if (accountModelDao == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
         }
-        return account;
+        return new DefaultAccount(accountModelDao);
     }
 
     @Override
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
index 2d8ed85..f7d67f0 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountChangeEvent.java
@@ -20,8 +20,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.DefaultChangedField;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.util.events.AccountChangeInternalEvent;
 import com.ning.billing.util.events.ChangedField;
 import com.ning.billing.util.events.DefaultBusInternalEvent;
@@ -49,7 +49,7 @@ public class DefaultAccountChangeEvent extends DefaultBusInternalEvent implement
         this.changedFields = changedFields;
     }
 
-    public DefaultAccountChangeEvent(final UUID id, final UUID userToken, final Account oldData, final Account newData,
+    public DefaultAccountChangeEvent(final UUID id, final UUID userToken, final AccountModelDao oldData, final AccountModelDao newData,
                                      final Long accountRecordId, final Long tenantRecordId) {
         super(userToken, accountRecordId, tenantRecordId);
         this.accountId = id;
@@ -134,7 +134,7 @@ public class DefaultAccountChangeEvent extends DefaultBusInternalEvent implement
         return true;
     }
 
-    private List<ChangedField> calculateChangedFields(final Account oldData, final Account newData) {
+    private List<ChangedField> calculateChangedFields(final AccountModelDao oldData, final AccountModelDao newData) {
 
         final List<ChangedField> tmpChangedFields = new ArrayList<ChangedField>();
 
@@ -152,8 +152,12 @@ public class DefaultAccountChangeEvent extends DefaultBusInternalEvent implement
                           (newData.getCurrency() != null) ? newData.getCurrency().toString() : null);
 
         addIfValueChanged(tmpChangedFields,
-                          "billCycleDay",
-                          oldData.getBillCycleDay().toString(), newData.getBillCycleDay().toString());
+                          "billCycleDayLocal",
+                          String.valueOf(oldData.getBillingCycleDayLocal()), String.valueOf(newData.getBillingCycleDayLocal()));
+
+        addIfValueChanged(tmpChangedFields,
+                          "billCycleDayUTC",
+                          String.valueOf(oldData.getBillingCycleDayUTC()), String.valueOf(newData.getBillingCycleDayUTC()));
 
         addIfValueChanged(tmpChangedFields, "paymentMethodId",
                           (oldData.getPaymentMethodId() != null) ? oldData.getPaymentMethodId().toString() : null,
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
index 6980388..a43baaa 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountCreationEvent.java
@@ -20,10 +20,10 @@ import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
 
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.BillCycleDay;
 import com.ning.billing.account.api.DefaultBillCycleDay;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.events.AccountCreationInternalEvent;
 import com.ning.billing.util.events.DefaultBusInternalEvent;
@@ -48,7 +48,7 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent impleme
         this.data = data;
     }
 
-    public DefaultAccountCreationEvent(final Account data, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
+    public DefaultAccountCreationEvent(final AccountModelDao data, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
         super(userToken, accountRecordId, tenantRecordId);
         this.id = data.getId();
         this.data = new DefaultAccountData(data);
@@ -130,12 +130,12 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent impleme
         private final boolean isMigrated;
         private final boolean isNotifiedForInvoices;
 
-        public DefaultAccountData(final Account d) {
+        public DefaultAccountData(final AccountModelDao d) {
             this(d.getExternalKey() != null ? d.getExternalKey() : null,
                  d.getName(),
                  d.getFirstNameLength(),
                  d.getEmail(),
-                 new DefaultBillCycleDay(d.getBillCycleDay()),
+                 new DefaultBillCycleDay(d.getBillingCycleDayLocal(), d.getBillingCycleDayUTC()),
                  d.getCurrency() != null ? d.getCurrency().name() : null,
                  d.getPaymentMethodId(),
                  d.getTimeZone() != null ? d.getTimeZone().getID() : null,
@@ -148,8 +148,8 @@ public class DefaultAccountCreationEvent extends DefaultBusInternalEvent impleme
                  d.getPostalCode(),
                  d.getCountry(),
                  d.getPhone(),
-                 d.isMigrated(),
-                 d.isNotifiedForInvoices());
+                 d.getMigrated(),
+                 d.getIsNotifiedForInvoices());
         }
 
         @JsonCreator
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index 5986385..3e00949 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -19,6 +19,8 @@ package com.ning.billing.account.api.user;
 import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
 
 import com.ning.billing.ErrorCode;
@@ -32,11 +34,15 @@ import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.MigrationAccountData;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.AccountEmailDao;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextFactory;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.TenantContext;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 public class DefaultAccountUserApi implements AccountUserApi {
@@ -62,35 +68,41 @@ public class DefaultAccountUserApi implements AccountUserApi {
             throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, data.getExternalKey());
         }
 
-        final Account account = new DefaultAccount(data);
+        final AccountModelDao account = new AccountModelDao(data);
         accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
 
-        return account;
+        return new DefaultAccount(account);
     }
 
     @Override
     public Account getAccountByKey(final String key, final TenantContext context) throws AccountApiException {
-        final Account account = accountDao.getAccountByKey(key, internalCallContextFactory.createInternalTenantContext(context));
+        final AccountModelDao account = accountDao.getAccountByKey(key, internalCallContextFactory.createInternalTenantContext(context));
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
         }
 
-        return account;
+        return new DefaultAccount(account);
     }
 
     @Override
     public Account getAccountById(final UUID id, final TenantContext context) throws AccountApiException {
-        final Account account = accountDao.getById(id, internalCallContextFactory.createInternalTenantContext(context));
+        final AccountModelDao account = accountDao.getById(id, internalCallContextFactory.createInternalTenantContext(context));
         if (account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, id);
         }
 
-        return account;
+        return new DefaultAccount(account);
     }
 
     @Override
     public List<Account> getAccounts(final TenantContext context) {
-        return accountDao.get(internalCallContextFactory.createInternalTenantContext(context));
+        final List<AccountModelDao> accountModelDaos = accountDao.get(internalCallContextFactory.createInternalTenantContext(context));
+        return ImmutableList.<Account>copyOf(Collections2.transform(accountModelDaos, new Function<AccountModelDao, Account>() {
+            @Override
+            public Account apply(@Nullable final AccountModelDao input) {
+                return new DefaultAccount(input);
+            }
+        }));
     }
 
     @Override
@@ -100,22 +112,35 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public void updateAccount(final Account account, final CallContext context) throws AccountApiException {
-        accountDao.update(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
+        updateAccount(account.getId(), account, context);
     }
 
     @Override
     public void updateAccount(final UUID accountId, final AccountData accountData, final CallContext context) throws AccountApiException {
-        final Account account = new DefaultAccount(accountId, accountData);
-        updateAccount(account, context);
+        final Account currentAccount = getAccountById(accountId, context);
+        if (currentAccount == null) {
+            throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
+        }
+
+        updateAccount(currentAccount, accountData, context);
     }
 
     @Override
     public void updateAccount(final String externalKey, final AccountData accountData, final CallContext context) throws AccountApiException {
-        final UUID accountId = getIdFromKey(externalKey, context);
-        if (accountId == null) {
+        final Account currentAccount = getAccountByKey(externalKey, context);
+        if (currentAccount == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, externalKey);
         }
-        updateAccount(accountId, accountData, context);
+
+        updateAccount(currentAccount, accountData, context);
+    }
+
+    private void updateAccount(final Account currentAccount, final AccountData accountData, final CallContext context) throws AccountApiException {
+        // Set unspecified (null) fields to their current values
+        final Account updatedAccount = new DefaultAccount(currentAccount.getId(), accountData);
+        final AccountModelDao accountToUpdate = new AccountModelDao(currentAccount.getId(), updatedAccount.mergeWithDelegate(currentAccount));
+
+        accountDao.update(accountToUpdate, internalCallContextFactory.createInternalCallContext(accountToUpdate.getId(), context));
     }
 
     @Override
@@ -126,7 +151,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         final CallContext migrationContext = callContextFactory.toMigrationCallContext(context, createdDate, updatedDate);
 
         // Create the account
-        final Account account = new DefaultAccount(data);
+        final Account account = new DefaultAccount(UUID.randomUUID(), data);
         createAccount(account, migrationContext);
 
         // Add associated contact emails
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
index 3935b19..1755dfd 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountDao.java
@@ -18,15 +18,14 @@ package com.ning.billing.account.dao;
 
 import java.util.UUID;
 
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.dao.EntityDao;
 
-public interface AccountDao extends EntityDao<Account, AccountApiException> {
+public interface AccountDao extends EntityDao<AccountModelDao, AccountApiException> {
 
-    public Account getAccountByKey(String key, InternalTenantContext context);
+    public AccountModelDao getAccountByKey(String key, InternalTenantContext context);
 
     /**
      * @throws AccountApiException when externalKey is null
@@ -39,5 +38,5 @@ public interface AccountDao extends EntityDao<Account, AccountApiException> {
      */
     public void updatePaymentMethod(UUID accountId, UUID paymentMethodId, InternalCallContext context) throws AccountApiException;
 
-    public void update(Account account, InternalCallContext context) throws AccountApiException;
+    public void update(AccountModelDao account, InternalCallContext context) throws AccountApiException;
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
index 7beb12f..ee830d4 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailSqlDao.java
@@ -26,8 +26,10 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 
 import com.ning.billing.account.api.AccountEmail;
+import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.entity.dao.Audited;
 import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 
@@ -36,6 +38,7 @@ import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
 public interface AccountEmailSqlDao extends EntitySqlDao<AccountEmail> {
 
     @SqlUpdate
+    @Audited(ChangeType.DELETE)
     public void delete(@BindBean final AccountEmail accountEmail,
                        @BindBean final InternalCallContext context);
 
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java
new file mode 100644
index 0000000..5a06b52
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountModelDao.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.account.dao;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.entity.EntityBase;
+
+public class AccountModelDao extends EntityBase {
+
+    private final String externalKey;
+    private final String email;
+    private final String name;
+    private final Integer firstNameLength;
+    private final Currency currency;
+    private final int billingCycleDayLocal;
+    private final int billingCycleDayUTC;
+    private final UUID paymentMethodId;
+    private final DateTimeZone timeZone;
+    private final String locale;
+    private final String address1;
+    private final String address2;
+    private final String companyName;
+    private final String city;
+    private final String stateOrProvince;
+    private final String country;
+    private final String postalCode;
+    private final String phone;
+    private final Boolean isMigrated;
+    private final Boolean isNotifiedForInvoices;
+
+    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 int billingCycleDayLocal, final int billingCycleDayUTC, 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, final Boolean migrated, final Boolean notifiedForInvoices) {
+        super(id, createdDate, updatedDate);
+        this.externalKey = externalKey;
+        this.email = email;
+        this.name = name;
+        this.firstNameLength = firstNameLength;
+        this.currency = currency;
+        this.billingCycleDayLocal = billingCycleDayLocal;
+        this.billingCycleDayUTC = billingCycleDayUTC;
+        this.paymentMethodId = paymentMethodId;
+        this.timeZone = timeZone;
+        this.locale = locale;
+        this.address1 = address1;
+        this.address2 = address2;
+        this.companyName = companyName;
+        this.city = city;
+        this.stateOrProvince = stateOrProvince;
+        this.country = country;
+        this.postalCode = postalCode;
+        this.phone = phone;
+        this.isMigrated = migrated;
+        this.isNotifiedForInvoices = notifiedForInvoices;
+    }
+
+    public AccountModelDao(final UUID id, @Nullable final DateTime createdDate, final DateTime updatedDate, final AccountData account) {
+        this(id, createdDate, updatedDate, account.getExternalKey(),
+             account.getEmail(), account.getName(), account.getFirstNameLength(), account.getCurrency(), account.getBillCycleDay() == null ? 0 : account.getBillCycleDay().getDayOfMonthLocal(),
+             account.getBillCycleDay() == null ? 0 : account.getBillCycleDay().getDayOfMonthUTC(), account.getPaymentMethodId(), account.getTimeZone(), account.getLocale(), account.getAddress1(), account.getAddress2(),
+             account.getCompanyName(), account.getCity(), account.getStateOrProvince(), account.getCountry(), account.getPostalCode(),
+             account.getPhone(), account.isMigrated(), account.isNotifiedForInvoices());
+    }
+
+    public AccountModelDao(final UUID id, final AccountData account) {
+        this(id, null, null, account);
+    }
+
+    public AccountModelDao(final AccountData account) {
+        this(UUID.randomUUID(), account);
+    }
+
+    public String getExternalKey() {
+        return externalKey;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Integer getFirstNameLength() {
+        return firstNameLength;
+    }
+
+    public Currency getCurrency() {
+        return currency;
+    }
+
+    public int getBillingCycleDayLocal() {
+        return billingCycleDayLocal;
+    }
+
+    public int getBillingCycleDayUTC() {
+        return billingCycleDayUTC;
+    }
+
+    public UUID getPaymentMethodId() {
+        return paymentMethodId;
+    }
+
+    public DateTimeZone getTimeZone() {
+        return timeZone;
+    }
+
+    public String getLocale() {
+        return locale;
+    }
+
+    public String getAddress1() {
+        return address1;
+    }
+
+    public String getAddress2() {
+        return address2;
+    }
+
+    public String getCompanyName() {
+        return companyName;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public String getStateOrProvince() {
+        return stateOrProvince;
+    }
+
+    public String getCountry() {
+        return country;
+    }
+
+    public String getPostalCode() {
+        return postalCode;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public Boolean getMigrated() {
+        return isMigrated;
+    }
+
+    // TODO Required for making the BindBeanFactory with Introspector work
+    // see Introspector line 571; they look at public method.
+    public Boolean getIsNotifiedForInvoices() {
+        return isNotifiedForInvoices;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("AccountModelDao");
+        sb.append("{externalKey='").append(externalKey).append('\'');
+        sb.append(", email='").append(email).append('\'');
+        sb.append(", name='").append(name).append('\'');
+        sb.append(", firstNameLength=").append(firstNameLength);
+        sb.append(", currency=").append(currency);
+        sb.append(", billingCycleDayLocal=").append(billingCycleDayLocal);
+        sb.append(", billingCycleDayUTC=").append(billingCycleDayUTC);
+        sb.append(", paymentMethodId=").append(paymentMethodId);
+        sb.append(", timeZone=").append(timeZone);
+        sb.append(", locale='").append(locale).append('\'');
+        sb.append(", address1='").append(address1).append('\'');
+        sb.append(", address2='").append(address2).append('\'');
+        sb.append(", companyName='").append(companyName).append('\'');
+        sb.append(", city='").append(city).append('\'');
+        sb.append(", stateOrProvince='").append(stateOrProvince).append('\'');
+        sb.append(", country='").append(country).append('\'');
+        sb.append(", postalCode='").append(postalCode).append('\'');
+        sb.append(", phone='").append(phone).append('\'');
+        sb.append(", isMigrated=").append(isMigrated);
+        sb.append(", isNotifiedForInvoices=").append(isNotifiedForInvoices);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @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 AccountModelDao that = (AccountModelDao) o;
+
+        if (billingCycleDayLocal != that.billingCycleDayLocal) {
+            return false;
+        }
+        if (billingCycleDayUTC != that.billingCycleDayUTC) {
+            return false;
+        }
+        if (address1 != null ? !address1.equals(that.address1) : that.address1 != null) {
+            return false;
+        }
+        if (address2 != null ? !address2.equals(that.address2) : that.address2 != null) {
+            return false;
+        }
+        if (city != null ? !city.equals(that.city) : that.city != null) {
+            return false;
+        }
+        if (companyName != null ? !companyName.equals(that.companyName) : that.companyName != null) {
+            return false;
+        }
+        if (country != null ? !country.equals(that.country) : that.country != null) {
+            return false;
+        }
+        if (currency != that.currency) {
+            return false;
+        }
+        if (email != null ? !email.equals(that.email) : that.email != null) {
+            return false;
+        }
+        if (externalKey != null ? !externalKey.equals(that.externalKey) : that.externalKey != null) {
+            return false;
+        }
+        if (firstNameLength != null ? !firstNameLength.equals(that.firstNameLength) : that.firstNameLength != null) {
+            return false;
+        }
+        if (isMigrated != null ? !isMigrated.equals(that.isMigrated) : that.isMigrated != null) {
+            return false;
+        }
+        if (isNotifiedForInvoices != null ? !isNotifiedForInvoices.equals(that.isNotifiedForInvoices) : that.isNotifiedForInvoices != null) {
+            return false;
+        }
+        if (locale != null ? !locale.equals(that.locale) : that.locale != null) {
+            return false;
+        }
+        if (name != null ? !name.equals(that.name) : that.name != null) {
+            return false;
+        }
+        if (paymentMethodId != null ? !paymentMethodId.equals(that.paymentMethodId) : that.paymentMethodId != null) {
+            return false;
+        }
+        if (phone != null ? !phone.equals(that.phone) : that.phone != null) {
+            return false;
+        }
+        if (postalCode != null ? !postalCode.equals(that.postalCode) : that.postalCode != null) {
+            return false;
+        }
+        if (stateOrProvince != null ? !stateOrProvince.equals(that.stateOrProvince) : that.stateOrProvince != null) {
+            return false;
+        }
+        if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (externalKey != null ? externalKey.hashCode() : 0);
+        result = 31 * result + (email != null ? email.hashCode() : 0);
+        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 + billingCycleDayLocal;
+        result = 31 * result + billingCycleDayUTC;
+        result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
+        result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
+        result = 31 * result + (locale != null ? locale.hashCode() : 0);
+        result = 31 * result + (address1 != null ? address1.hashCode() : 0);
+        result = 31 * result + (address2 != null ? address2.hashCode() : 0);
+        result = 31 * result + (companyName != null ? companyName.hashCode() : 0);
+        result = 31 * result + (city != null ? city.hashCode() : 0);
+        result = 31 * result + (stateOrProvince != null ? stateOrProvince.hashCode() : 0);
+        result = 31 * result + (country != null ? country.hashCode() : 0);
+        result = 31 * result + (postalCode != null ? postalCode.hashCode() : 0);
+        result = 31 * result + (phone != null ? phone.hashCode() : 0);
+        result = 31 * result + (isMigrated != null ? isMigrated.hashCode() : 0);
+        result = 31 * result + (isNotifiedForInvoices != null ? isNotifiedForInvoices.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java b/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
index efc0a0a..7e86da0 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountSqlDao.java
@@ -19,53 +19,39 @@ package com.ning.billing.account.dao;
 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.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 
-import com.ning.billing.account.api.Account;
 import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.callcontext.InternalTenantContextBinder;
-import com.ning.billing.util.dao.EntityHistory;
 import com.ning.billing.util.dao.UuidMapper;
 import com.ning.billing.util.entity.dao.Audited;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.entity.dao.EntitySqlDaoStringTemplate;
-import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
 
 @EntitySqlDaoStringTemplate
-@RegisterMapper({UuidMapper.class, AccountMapper.class})
-public interface AccountSqlDao extends UpdatableEntitySqlDao<Account> {
+@RegisterMapper({UuidMapper.class, AccountModelDaoMapper.class})
+public interface AccountSqlDao extends EntitySqlDao<AccountModelDao> {
 
     @SqlQuery
-    public Account getAccountByKey(@Bind("externalKey") final String key,
-                                   @InternalTenantContextBinder final InternalTenantContext context);
+    public AccountModelDao getAccountByKey(@Bind("externalKey") final String key,
+                                           @BindBean final InternalTenantContext context);
 
     @SqlQuery
     public UUID getIdFromKey(@Bind("externalKey") final String key,
-                             @InternalTenantContextBinder final InternalTenantContext context);
+                             @BindBean final InternalTenantContext context);
 
-    @Override
-    @SqlUpdate
-    @Audited(ChangeType.INSERT)
-    public void create(@AccountBinder Account account,
-                       @InternalTenantContextBinder final InternalCallContext context);
-
-    @Override
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
-    public void update(@AccountBinder Account account,
-                       @InternalTenantContextBinder final InternalCallContext context);
+    public void update(@BindBean final AccountModelDao account,
+                       @BindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
     public void updatePaymentMethod(@Bind("id") String accountId,
                                     @Bind("paymentMethodId") String paymentMethodId,
-                                    @InternalTenantContextBinder final InternalCallContext context);
-
-    @Override
-    @SqlUpdate
-    public void addHistoryFromTransaction(@AccountHistoryBinder final EntityHistory<Account> account,
-                                          @InternalTenantContextBinder final InternalCallContext context);
+                                    @BindBean final InternalCallContext context);
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index b23bfe1..aa80504 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -24,7 +24,6 @@ import org.slf4j.LoggerFactory;
 
 import com.ning.billing.BillingExceptionBase;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
@@ -45,7 +44,7 @@ import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
 
 import com.google.inject.Inject;
 
-public class DefaultAccountDao extends EntityDaoBase<Account, AccountApiException> implements AccountDao {
+public class DefaultAccountDao extends EntityDaoBase<AccountModelDao, AccountApiException> implements AccountDao {
 
     private static final Logger log = LoggerFactory.getLogger(DefaultAccountDao.class);
 
@@ -60,12 +59,12 @@ public class DefaultAccountDao extends EntityDaoBase<Account, AccountApiExceptio
     }
 
     @Override
-    protected AccountApiException generateAlreadyExistsException(final Account account, final InternalCallContext context) {
+    protected AccountApiException generateAlreadyExistsException(final AccountModelDao account, final InternalCallContext context) {
         return new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, account.getExternalKey());
     }
 
     @Override
-    protected void postBusEventFromTransaction(final Account account, final Account savedAccount, final ChangeType changeType,
+    protected void postBusEventFromTransaction(final AccountModelDao account, final AccountModelDao savedAccount, final ChangeType changeType,
                                                final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context) throws BillingExceptionBase {
         // This is only called for the create call (see update below)
         switch (changeType) {
@@ -90,10 +89,10 @@ public class DefaultAccountDao extends EntityDaoBase<Account, AccountApiExceptio
     }
 
     @Override
-    public Account getAccountByKey(final String key, final InternalTenantContext context) {
-        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Account>() {
+    public AccountModelDao getAccountByKey(final String key, final InternalTenantContext context) {
+        return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<AccountModelDao>() {
             @Override
-            public Account inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
+            public AccountModelDao inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
                 return entitySqlDaoWrapperFactory.become(AccountSqlDao.class).getAccountByKey(key, context);
             }
         });
@@ -114,26 +113,24 @@ public class DefaultAccountDao extends EntityDaoBase<Account, AccountApiExceptio
     }
 
     @Override
-    public void update(final Account specifiedAccount, final InternalCallContext context) throws AccountApiException {
+    public void update(final AccountModelDao specifiedAccount, final InternalCallContext context) throws AccountApiException {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws InternalBus.EventBusException, AccountApiException {
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EventBusException, AccountApiException {
                 final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
 
                 final UUID accountId = specifiedAccount.getId();
-                final Account currentAccount = transactional.getById(accountId.toString(), context);
+                final AccountModelDao currentAccount = transactional.getById(accountId.toString(), context);
                 if (currentAccount == null) {
                     throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
                 }
 
-                // Set unspecified (null) fields to their current values
-                final Account account = specifiedAccount.mergeWithDelegate(currentAccount);
-                transactional.update(account, context);
+                transactional.update(specifiedAccount, context);
 
                 final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId,
                                                                                              context.getUserToken(),
                                                                                              currentAccount,
-                                                                                             account,
+                                                                                             specifiedAccount,
                                                                                              context.getAccountRecordId(),
                                                                                              context.getTenantRecordId());
                 if (changeEvent.hasChanges()) {
@@ -153,17 +150,17 @@ public class DefaultAccountDao extends EntityDaoBase<Account, AccountApiExceptio
     public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
             @Override
-            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException, InternalBus.EventBusException {
+            public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws EntityPersistenceException, EventBusException {
                 final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class);
 
-                final Account currentAccount = transactional.getById(accountId.toString(), context);
+                final AccountModelDao currentAccount = transactional.getById(accountId.toString(), context);
                 if (currentAccount == null) {
                     throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
                 }
                 final String thePaymentMethodId = paymentMethodId != null ? paymentMethodId.toString() : null;
                 transactional.updatePaymentMethod(accountId.toString(), thePaymentMethodId, context);
 
-                final Account account = transactional.getById(accountId.toString(), context);
+                final AccountModelDao account = transactional.getById(accountId.toString(), context);
                 final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, context.getUserToken(), currentAccount, account,
                                                                                              context.getAccountRecordId(), context.getTenantRecordId());
 
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
index aab878c..db12678 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountEmailSqlDao.sql.stg
@@ -1,5 +1,8 @@
-group account_emails: EntitySqlDao;
+group AccountEmailSqlDao: EntitySqlDao;
 
+tableName() ::= "account_emails"
+
+historyTableName() ::= "account_email_history"
 
 tableFields(prefix) ::= <<
   account_id
@@ -20,8 +23,6 @@ tableValues() ::= <<
 , :updatedDate
  >>
 
-historyTableName() ::= "account_email_history"
-
 getEmailByAccountId() ::= <<
 select
 <allTableFields()>
@@ -31,19 +32,7 @@ where account_id = :accountId
 ;
 >>
 
-updateFromTransaction() ::= <<
-    UPDATE account_emails
-    SET email = :email, updated_by = :userName, updated_date = :updatedDate
-    WHERE id = :id <AND_CHECK_TENANT()>;
->>
-
-deleteFromTransaction() ::= <<
+delete() ::= <<
     DELETE FROM account_emails
     WHERE id = :id <AND_CHECK_TENANT()>;
 >>
-
-
-getByAccountId() ::= <<
-    SELECT <fields()> FROM account_emails WHERE account_id = :accountId <AND_CHECK_TENANT()>;
->>
-
diff --git a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
index e50cc57..88f3ec4 100644
--- a/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
+++ b/account/src/main/resources/com/ning/billing/account/dao/AccountSqlDao.sql.stg
@@ -1,7 +1,8 @@
-group AccountDaoSql: EntitySqlDao;
+group AccountSqlDao: EntitySqlDao;
 
-tableName() ::= "accounts";
-historyTableName() ::= "account_history";
+tableName() ::= "accounts"
+
+historyTableName() ::= "account_history"
 
 tableFields(prefix) ::= <<
   <prefix>external_key
@@ -54,7 +55,8 @@ tableValues() ::= <<
 , :createdBy
 , :createdDate
 , :updatedBy
- >>
+, :updatedDate
+>>
 
 /** The accounts table doesn't have an account_record_id column (it's the record_id) **/
 accountRecordIdFieldWithComma(prefix) ::= ""
@@ -67,7 +69,7 @@ update() ::= <<
         payment_method_id = :paymentMethodId, time_zone = :timeZone, locale = :locale,
         address1 = :address1, address2 = :address2, company_name = :companyName, city = :city, state_or_province = :stateOrProvince,
         country = :country, postal_code = :postalCode, phone = :phone,
-        is_notified_for_invoices = :isNotifiedForInvoices, updated_date = :updatedDate, updated_by = :userName
+        is_notified_for_invoices = :isNotifiedForInvoices, updated_date = :updatedDate, updated_by = :updatedBy
     WHERE id = :id <AND_CHECK_TENANT()>;
 >>
 
@@ -76,14 +78,14 @@ updatePaymentMethod() ::= <<
     UPDATE accounts
     SET payment_method_id = :paymentMethodId
     , updated_date = :updatedDate
-    , updated_by = :userName
+    , updated_by = :updatedBy
     WHERE id = :id <AND_CHECK_TENANT()>;
 >>
 
 
 
 getAccountByKey() ::= <<
-    select <accountFields()>
+    select <allTableFields()>
     from accounts
     where external_key = :externalKey <AND_CHECK_TENANT()>;
 >>
diff --git a/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java b/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java
new file mode 100644
index 0000000..acbc9a3
--- /dev/null
+++ b/account/src/test/java/com/ning/billing/account/api/user/DefaultAccountUserApiTestWithDB.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.account.api.user;
+
+import java.util.UUID;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.account.api.BillCycleDay;
+import com.ning.billing.account.api.DefaultAccount;
+import com.ning.billing.account.api.DefaultMutableAccountData;
+import com.ning.billing.account.api.MutableAccountData;
+import com.ning.billing.account.dao.AccountDaoTestBase;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+
+public class DefaultAccountUserApiTestWithDB extends AccountDaoTestBase {
+
+    private AccountUserApi accountUserApi;
+
+    @BeforeMethod(groups = "slow")
+    public void setUp() throws Exception {
+        final DefaultCallContextFactory callContextFactory = new DefaultCallContextFactory(clock);
+        accountUserApi = new DefaultAccountUserApi(callContextFactory, internalCallContextFactory, accountDao, accountEmailDao);
+    }
+
+    @Test(groups = "slow")
+    public void testShouldBeAbleToPassNullForSomeFieldsToAvoidUpdate() throws Exception {
+        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, null, null,
+                                                                                    null, null, null, null, null, null, null,
+                                                                                    null, null, null, null, false, false);
+        final String newAddress1 = UUID.randomUUID().toString();
+        mutableAccountData.setAddress1(newAddress1);
+
+        accountUserApi.updateAccount(account.getId(), mutableAccountData, callContext);
+
+        final Account retrievedAccount = accountUserApi.getAccountById(account.getId(), callContext);
+        Assert.assertEquals(retrievedAccount.getAddress1(), newAddress1);
+        Assert.assertEquals(retrievedAccount.getAddress2(), account.getAddress2());
+        Assert.assertEquals(retrievedAccount.getCurrency(), account.getCurrency());
+        Assert.assertEquals(retrievedAccount.getExternalKey(), account.getExternalKey());
+        Assert.assertEquals(retrievedAccount.getBillCycleDay().getDayOfMonthLocal(), account.getBillCycleDay().getDayOfMonthLocal());
+        Assert.assertEquals(retrievedAccount.getBillCycleDay().getDayOfMonthUTC(), account.getBillCycleDay().getDayOfMonthUTC());
+    }
+
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateBillCycleDay() throws Exception {
+        final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+
+        final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
+        otherAccount.setBillCycleDay(new BillCycleDay() {
+            @Override
+            public int getDayOfMonthUTC() {
+                return account.getBillCycleDay().getDayOfMonthUTC() + 2;
+            }
+
+            @Override
+            public int getDayOfMonthLocal() {
+                return account.getBillCycleDay().getDayOfMonthLocal() + 2;
+            }
+        });
+
+        accountUserApi.updateAccount(new DefaultAccount(account.getId(), otherAccount), callContext);
+    }
+
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateCurrency() throws Exception {
+        final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+
+        final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
+        otherAccount.setCurrency(Currency.GBP);
+
+        accountUserApi.updateAccount(new DefaultAccount(account.getId(), otherAccount), callContext);
+    }
+
+    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
+    public void testShouldntBeAbleToUpdateExternalKey() throws Exception {
+        final Account account = accountUserApi.createAccount(new DefaultAccount(createTestAccount()), callContext);
+
+        final MutableAccountData otherAccount = new DefaultAccount(account.getId(), account).toMutableAccountData();
+        otherAccount.setExternalKey(UUID.randomUUID().toString());
+
+        accountUserApi.updateAccount(new DefaultAccount(account.getId(), otherAccount), callContext);
+    }
+}
diff --git a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
index 9dd5f33..860ad1f 100644
--- a/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/user/TestDefaultAccountUserApi.java
@@ -25,7 +25,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.account.AccountTestSuite;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.BillCycleDay;
@@ -34,6 +33,7 @@ import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.DefaultBillCycleDay;
 import com.ning.billing.account.dao.AccountDao;
 import com.ning.billing.account.dao.AccountEmailDao;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.account.dao.MockAccountDao;
 import com.ning.billing.account.dao.MockAccountEmailDao;
 import com.ning.billing.catalog.api.Currency;
@@ -89,13 +89,14 @@ public class TestDefaultAccountUserApi extends AccountTestSuite {
 
         accountUserApi.createAccount(data, callContext);
 
-        final Account account = accountDao.getAccountByKey(externalKey, tenantContext);
+        final AccountModelDao account = accountDao.getAccountByKey(externalKey, tenantContext);
         Assert.assertEquals(account.getExternalKey(), externalKey);
         Assert.assertEquals(account.getEmail(), email);
         Assert.assertEquals(account.getName(), name);
         Assert.assertEquals(account.getFirstNameLength(), firstNameLength);
         Assert.assertEquals(account.getCurrency(), currency);
-        Assert.assertEquals(account.getBillCycleDay(), billCycleDay);
+        Assert.assertEquals(account.getBillingCycleDayLocal(), billCycleDay.getDayOfMonthLocal());
+        Assert.assertEquals(account.getBillingCycleDayUTC(), billCycleDay.getDayOfMonthUTC());
         Assert.assertEquals(account.getPaymentMethodId(), paymentMethodId);
         Assert.assertEquals(account.getTimeZone(), timeZone);
         Assert.assertEquals(account.getLocale(), locale);
@@ -107,8 +108,8 @@ public class TestDefaultAccountUserApi extends AccountTestSuite {
         Assert.assertEquals(account.getCountry(), country);
         Assert.assertEquals(account.getPostalCode(), postalCode);
         Assert.assertEquals(account.getPhone(), phone);
-        Assert.assertEquals(account.isMigrated(), isMigrated);
-        Assert.assertEquals(account.isNotifiedForInvoices(), isNotifiedForInvoices);
+        Assert.assertEquals(account.getMigrated(), isMigrated);
+        Assert.assertEquals(account.getIsNotifiedForInvoices(), isNotifiedForInvoices);
     }
 
     @Test(groups = "fast")
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index 1f8a9cb..3b7b32f 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -17,14 +17,18 @@
 package com.ning.billing.account.dao;
 
 import java.io.IOException;
+import java.util.UUID;
 
+import org.joda.time.DateTimeZone;
 import org.skife.jdbi.v2.IDBI;
 import org.testng.annotations.BeforeClass;
 
 import com.ning.billing.account.AccountTestSuiteWithEmbeddedDB;
+import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.InMemoryInternalBus;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
+import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.svcsapi.bus.BusService;
 import com.ning.billing.util.svcsapi.bus.InternalBus;
@@ -35,9 +39,11 @@ import static org.testng.Assert.fail;
 public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB {
 
     protected final TagEventBuilder tagEventBuilder = new TagEventBuilder();
+    protected final Clock clock = new ClockMock();
 
     protected AccountDao accountDao;
     protected AccountEmailDao accountEmailDao;
+    protected InternalCallContextFactory internalCallContextFactory;
     protected IDBI dbi;
     protected InternalBus bus;
 
@@ -50,7 +56,8 @@ public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB 
             final BusService busService = new DefaultBusService(bus);
             ((DefaultBusService) busService).startBus();
 
-            accountDao = new DefaultAccountDao(dbi, bus, new InternalCallContextFactory(dbi, new ClockMock()));
+            internalCallContextFactory = new InternalCallContextFactory(dbi, clock);
+            accountDao = new DefaultAccountDao(dbi, bus, internalCallContextFactory);
             // Health check test to make sure MySQL is setup properly
             accountDao.test(internalCallContext);
 
@@ -61,4 +68,27 @@ public abstract class AccountDaoTestBase extends AccountTestSuiteWithEmbeddedDB 
             fail(t.toString());
         }
     }
+
+    protected AccountModelDao createTestAccount() {
+        return createTestAccount(5, UUID.randomUUID().toString().substring(0, 5));
+    }
+
+    protected AccountModelDao createTestAccount(final int billCycleDay) {
+        return createTestAccount(billCycleDay, "123-456-7890");
+    }
+
+    protected AccountModelDao createTestAccount(final int billCycleDay, final String phone) {
+        final String thisKey = "test" + UUID.randomUUID().toString();
+        final String lastName = UUID.randomUUID().toString();
+        final String thisEmail = "me@me.com" + " " + UUID.randomUUID();
+        final String firstName = "Bob";
+        final String name = firstName + " " + lastName;
+        final String locale = "EN-US";
+        final DateTimeZone timeZone = DateTimeZone.forID("America/Los_Angeles");
+        final int firstNameLength = firstName.length();
+
+        return new AccountModelDao(UUID.randomUUID(), null, null, thisKey, thisEmail, name, firstNameLength, Currency.USD,
+                                   billCycleDay, billCycleDay, UUID.randomUUID(), timeZone, locale,
+                                   null, null, null, null, null, null, null, phone, false, false);
+    }
 }
diff --git a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
index adab356..9f93178 100644
--- a/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/MockAccountDao.java
@@ -20,13 +20,13 @@ import java.util.Map;
 import java.util.UUID;
 
 import com.ning.billing.ErrorCode;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultMutableAccountData;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.callcontext.InternalCallContext;
+import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.dao.MockEntityDaoBase;
 import com.ning.billing.util.events.AccountChangeInternalEvent;
@@ -35,7 +35,7 @@ import com.ning.billing.util.svcsapi.bus.InternalBus.EventBusException;
 
 import com.google.inject.Inject;
 
-public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiException> implements AccountDao {
+public class MockAccountDao extends MockEntityDaoBase<AccountModelDao, AccountApiException> implements AccountDao {
 
     private final InternalBus eventBus;
 
@@ -45,23 +45,29 @@ public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiExcepti
     }
 
     @Override
-    public void create(final Account account, final InternalCallContext context) throws AccountApiException {
+    public void create(final AccountModelDao account, final InternalCallContext context) throws AccountApiException {
         super.create(account, context);
 
         try {
-            eventBus.post(new DefaultAccountCreationEvent(account, null, getRecordId(account.getId(), context), context.getTenantRecordId()), context);
+            final Long accountRecordId = getRecordId(account.getId(), context);
+            final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID
+                                                        : context.getTenantRecordId();
+            eventBus.post(new DefaultAccountCreationEvent(account, null, accountRecordId, tenantRecordId), context);
         } catch (final EventBusException ex) {
             throw new RuntimeException(ex);
         }
     }
 
     @Override
-    public void update(final Account account, final InternalCallContext context) {
-        final Account currentAccount = getById(account.getId(), context);
+    public void update(final AccountModelDao account, final InternalCallContext context) {
+        final AccountModelDao currentAccount = getById(account.getId(), context);
         super.update(account, context);
 
+        final Long accountRecordId = getRecordId(account.getId(), context);
+        final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID
+                                                    : context.getTenantRecordId();
         final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account,
-                                                                                     getRecordId(account.getId(), context), context.getTenantRecordId());
+                                                                                     accountRecordId, tenantRecordId);
         if (changeEvent.hasChanges()) {
             try {
                 eventBus.post(changeEvent, context);
@@ -72,9 +78,9 @@ public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiExcepti
     }
 
     @Override
-    public Account getAccountByKey(final String externalKey, final InternalTenantContext context) {
-        for (final Map<Long, Account> accountRow : entities.values()) {
-            final Account account = accountRow.values().iterator().next();
+    public AccountModelDao getAccountByKey(final String externalKey, final InternalTenantContext context) {
+        for (final Map<Long, AccountModelDao> accountRow : entities.values()) {
+            final AccountModelDao account = accountRow.values().iterator().next();
             if (account.getExternalKey().equals(externalKey)) {
                 return account;
             }
@@ -85,20 +91,21 @@ public class MockAccountDao extends MockEntityDaoBase<Account, AccountApiExcepti
 
     @Override
     public UUID getIdFromKey(final String externalKey, final InternalTenantContext context) {
-        final Account account = getAccountByKey(externalKey, context);
+        final AccountModelDao account = getAccountByKey(externalKey, context);
         return account == null ? null : account.getId();
     }
 
     @Override
     public void updatePaymentMethod(final UUID accountId, final UUID paymentMethodId, final InternalCallContext context) throws AccountApiException {
-        final Account currentAccount = getById(accountId, context);
-        if (currentAccount == null) {
+        final AccountModelDao currentAccountModelDao = getById(accountId, context);
+        if (currentAccountModelDao == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
         }
 
+        final DefaultAccount currentAccount = new DefaultAccount(currentAccountModelDao);
         final DefaultMutableAccountData updatedAccount = new DefaultMutableAccountData(currentAccount);
         updatedAccount.setPaymentMethodId(paymentMethodId);
 
-        update(new DefaultAccount(updatedAccount), context);
+        update(new AccountModelDao(accountId, updatedAccount), context);
     }
 }
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
index e69f69a..f4197a7 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestAccountDao.java
@@ -16,18 +16,17 @@
 
 package com.ning.billing.account.dao;
 
-import java.util.ArrayList;
+import java.sql.SQLException;
 import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 
 import org.joda.time.DateTimeZone;
-import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.exceptions.TransactionFailedException;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountData;
 import com.ning.billing.account.api.AccountEmail;
@@ -35,17 +34,21 @@ import com.ning.billing.account.api.BillCycleDay;
 import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.account.api.DefaultBillCycleDay;
-import com.ning.billing.account.api.DefaultMutableAccountData;
 import com.ning.billing.account.api.MutableAccountData;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.mock.MockAccountBuilder;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.billing.util.api.CustomFieldApiException;
 import com.ning.billing.util.api.TagApiException;
+import com.ning.billing.util.audit.AuditLog;
+import com.ning.billing.util.audit.dao.AuditDao;
+import com.ning.billing.util.audit.dao.DefaultAuditDao;
 import com.ning.billing.util.clock.DefaultClock;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.StringCustomField;
 import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DefaultControlTag;
@@ -65,37 +68,13 @@ import static org.testng.Assert.fail;
 
 public class TestAccountDao extends AccountDaoTestBase {
 
-    private Account createTestAccount() {
-        return createTestAccount(5, UUID.randomUUID().toString().substring(0, 5));
-    }
-
-    private Account createTestAccount(final int billCycleDay) {
-        return createTestAccount(billCycleDay, "123-456-7890");
-    }
-
-    private Account createTestAccount(final int billCycleDay, final String phone) {
-        final String thisKey = "test" + UUID.randomUUID().toString();
-        final String lastName = UUID.randomUUID().toString();
-        final String thisEmail = "me@me.com" + " " + UUID.randomUUID();
-        final String firstName = "Bob";
-        final String name = firstName + " " + lastName;
-        final String locale = "EN-US";
-        final DateTimeZone timeZone = DateTimeZone.forID("America/Los_Angeles");
-        final int firstNameLength = firstName.length();
-
-        return new DefaultAccount(UUID.randomUUID(), thisKey, thisEmail, name, firstNameLength, Currency.USD,
-                                  new DefaultBillCycleDay(billCycleDay, billCycleDay), UUID.randomUUID(), timeZone, locale,
-                                  null, null, null, null, null, null, null, // add null address fields
-                                  phone, false, false);
-    }
-
     @Test(groups = "slow")
     public void testBasic() throws AccountApiException {
-        final Account a = createTestAccount(5);
+        final AccountModelDao a = createTestAccount(5);
         accountDao.create(a, internalCallContext);
         final String key = a.getExternalKey();
 
-        Account r = accountDao.getAccountByKey(key, internalCallContext);
+        AccountModelDao r = accountDao.getAccountByKey(key, internalCallContext);
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
@@ -103,7 +82,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
-        final List<Account> all = accountDao.get(internalCallContext);
+        final List<AccountModelDao> all = accountDao.get(internalCallContext);
         assertNotNull(all);
         assertTrue(all.size() >= 1);
     }
@@ -111,23 +90,28 @@ public class TestAccountDao extends AccountDaoTestBase {
     // simple test to ensure long phone numbers can be stored
     @Test(groups = "slow")
     public void testLongPhoneNumber() throws AccountApiException {
-        final Account account = createTestAccount(1, "123456789012345678901234");
+        final AccountModelDao account = createTestAccount(1, "123456789012345678901234");
         accountDao.create(account, internalCallContext);
 
-        final Account saved = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
+        final AccountModelDao saved = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
         assertNotNull(saved);
     }
 
     // simple test to ensure excessively long phone numbers cannot be stored
-    @Test(groups = "slow", expectedExceptions = AccountApiException.class)
+    @Test(groups = "slow")
     public void testOverlyLongPhoneNumber() throws AccountApiException {
-        final Account account = createTestAccount(1, "12345678901234567890123456");
-        accountDao.create(account, internalCallContext);
+        final AccountModelDao account = createTestAccount(1, "12345678901234567890123456");
+        try {
+            accountDao.create(account, internalCallContext);
+            Assert.fail();
+        } catch (RuntimeException e) {
+            Assert.assertTrue(e.getCause() instanceof SQLException);
+        }
     }
 
     @Test(groups = "slow")
     public void testGetById() throws AccountApiException {
-        Account account = createTestAccount(1);
+        AccountModelDao account = createTestAccount(1);
         final UUID id = account.getId();
         final String key = account.getExternalKey();
         final String name = account.getName();
@@ -163,7 +147,7 @@ public class TestAccountDao extends AccountDaoTestBase {
 
     @Test(groups = "slow")
     public void testTags() throws EntityPersistenceException, TagApiException {
-        final Account account = createTestAccount(1);
+        final AccountModelDao account = createTestAccount(1);
         final TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", false);
         final TagDefinitionSqlDao tagDefinitionDao = dbi.onDemand(TagDefinitionSqlDao.class);
         tagDefinitionDao.create(definition, internalCallContext);
@@ -184,7 +168,7 @@ public class TestAccountDao extends AccountDaoTestBase {
 
     @Test(groups = "slow")
     public void testGetIdFromKey() throws AccountApiException {
-        final Account account = createTestAccount(1);
+        final AccountModelDao account = createTestAccount(1);
         accountDao.create(account, internalCallContext);
 
         try {
@@ -203,25 +187,26 @@ public class TestAccountDao extends AccountDaoTestBase {
 
     @Test(groups = "slow")
     public void testUpdate() throws Exception {
-        final Account account = createTestAccount(1);
+        final AccountModelDao account = createTestAccount(1);
         accountDao.create(account, internalCallContext);
 
-        final AccountData accountData = new MockAccountBuilder(account).migrated(false)
-                                                                       .isNotifiedForInvoices(false)
-                                                                       .timeZone(DateTimeZone.forID("Australia/Darwin"))
-                                                                       .locale("FR-CA")
-                                                                       .build();
+        final AccountData accountData = new MockAccountBuilder(new DefaultAccount(account)).migrated(false)
+                                                                                           .isNotifiedForInvoices(false)
+                                                                                           .timeZone(DateTimeZone.forID("Australia/Darwin"))
+                                                                                           .locale("FR-CA")
+                                                                                           .build();
 
-        final Account updatedAccount = new DefaultAccount(account.getId(), accountData);
+        final AccountModelDao updatedAccount = new AccountModelDao(account.getId(), accountData);
         accountDao.update(updatedAccount, internalCallContext);
 
-        final Account savedAccount = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
+        final AccountModelDao savedAccount = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
 
         assertNotNull(savedAccount);
         assertEquals(savedAccount.getName(), updatedAccount.getName());
         assertEquals(savedAccount.getEmail(), updatedAccount.getEmail());
         assertEquals(savedAccount.getPaymentMethodId(), updatedAccount.getPaymentMethodId());
-        assertEquals(savedAccount.getBillCycleDay(), updatedAccount.getBillCycleDay());
+        assertEquals(savedAccount.getBillingCycleDayLocal(), updatedAccount.getBillingCycleDayLocal());
+        assertEquals(savedAccount.getBillingCycleDayUTC(), updatedAccount.getBillingCycleDayUTC());
         assertEquals(savedAccount.getFirstNameLength(), updatedAccount.getFirstNameLength());
         assertEquals(savedAccount.getTimeZone(), updatedAccount.getTimeZone());
         assertEquals(savedAccount.getLocale(), updatedAccount.getLocale());
@@ -236,19 +221,19 @@ public class TestAccountDao extends AccountDaoTestBase {
 
     @Test(groups = "slow")
     public void testUpdatePaymentMethod() throws Exception {
-        final Account account = createTestAccount(1);
+        final AccountModelDao account = createTestAccount(1);
         accountDao.create(account, internalCallContext);
 
         final UUID newPaymentMethodId = UUID.randomUUID();
         accountDao.updatePaymentMethod(account.getId(), newPaymentMethodId, internalCallContext);
 
-        final Account newAccount = accountDao.getById(account.getId(), internalCallContext);
+        final AccountModelDao newAccount = accountDao.getById(account.getId(), internalCallContext);
         assertEquals(newAccount.getPaymentMethodId(), newPaymentMethodId);
 
         // And then set it to null
         accountDao.updatePaymentMethod(account.getId(), null, internalCallContext);
 
-        final Account newAccountWithPMNull = accountDao.getById(account.getId(), internalCallContext);
+        final AccountModelDao newAccountWithPMNull = accountDao.getById(account.getId(), internalCallContext);
         assertNull(newAccountWithPMNull.getPaymentMethodId());
 
     }
@@ -260,7 +245,7 @@ public class TestAccountDao extends AccountDaoTestBase {
                                                           "John Smith", 4, Currency.USD, new DefaultBillCycleDay(15), null,
                                                           DateTimeZone.forID("America/Cambridge_Bay"), "EN-CA",
                                                           null, null, null, null, null, null, null, null, false, false);
-        accountDao.create(account, internalCallContext);
+        accountDao.create(new AccountModelDao(accountId, account), internalCallContext);
 
         final String address1 = "123 address 1";
         final String address2 = "456 address 2";
@@ -277,9 +262,9 @@ public class TestAccountDao extends AccountDaoTestBase {
                                                                  address1, address2, companyName, city, stateOrProvince, country,
                                                                  postalCode, phone, false, false);
 
-        accountDao.update(updatedAccount, internalCallContext);
+        accountDao.update(new AccountModelDao(accountId, updatedAccount), internalCallContext);
 
-        final Account savedAccount = accountDao.getById(accountId, internalCallContext);
+        final AccountModelDao savedAccount = accountDao.getById(accountId, internalCallContext);
 
         assertNotNull(savedAccount);
         assertEquals(savedAccount.getId(), accountId);
@@ -293,132 +278,72 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(savedAccount.getPhone(), phone);
     }
 
-    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
-    public void testShouldntBeAbleToUpdateExternalKey() throws Exception {
-        final Account account = createTestAccount();
-        accountDao.create(account, internalCallContext);
-
-        final MutableAccountData otherAccount = account.toMutableAccountData();
-        otherAccount.setExternalKey(UUID.randomUUID().toString());
-
-        accountDao.update(new DefaultAccount(account.getId(), otherAccount), internalCallContext);
-    }
-
-    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
-    public void testShouldntBeAbleToUpdateCurrency() throws Exception {
-        final Account account = createTestAccount();
-        accountDao.create(account, internalCallContext);
-
-        final MutableAccountData otherAccount = account.toMutableAccountData();
-        otherAccount.setCurrency(Currency.GBP);
-
-        accountDao.update(new DefaultAccount(account.getId(), otherAccount), internalCallContext);
-    }
-
-    @Test(groups = "slow", expectedExceptions = IllegalArgumentException.class)
-    public void testShouldntBeAbleToUpdateBillCycleDay() throws Exception {
-        final Account account = createTestAccount();
-        accountDao.create(account, internalCallContext);
-
-        final MutableAccountData otherAccount = account.toMutableAccountData();
-        otherAccount.setBillCycleDay(new BillCycleDay() {
-            @Override
-            public int getDayOfMonthUTC() {
-                return account.getBillCycleDay().getDayOfMonthUTC() + 2;
-            }
-
-            @Override
-            public int getDayOfMonthLocal() {
-                return account.getBillCycleDay().getDayOfMonthLocal() + 2;
-            }
-        });
-
-        accountDao.update(new DefaultAccount(account.getId(), otherAccount), internalCallContext);
-    }
-
     @Test(groups = "slow")
     public void testShouldBeAbleToUpdateSomeFields() throws Exception {
-        final Account account = createTestAccount();
+        final AccountModelDao account = createTestAccount();
         accountDao.create(account, internalCallContext);
 
-        final MutableAccountData otherAccount = account.toMutableAccountData();
+        final MutableAccountData otherAccount = new DefaultAccount(account).toMutableAccountData();
         otherAccount.setAddress1(UUID.randomUUID().toString());
         otherAccount.setEmail(UUID.randomUUID().toString());
 
-        final DefaultAccount newAccount = new DefaultAccount(account.getId(), otherAccount);
-        accountDao.update(newAccount, internalCallContext);
-
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext), newAccount);
-    }
-
-    @Test(groups = "slow")
-    public void testShouldBeAbleToPassNullForSomeFieldsToAvoidUpdate() throws Exception {
-        final Account account = createTestAccount();
-        accountDao.create(account, internalCallContext);
-
-        // Update the address and leave other fields null
-        final MutableAccountData mutableAccountData = new DefaultMutableAccountData(null, null, null, 0, null, null, null,
-                                                                                    null, null, null, null, null, null, null,
-                                                                                    null, null, null, null, false, false);
-        final String newAddress1 = UUID.randomUUID().toString();
-        mutableAccountData.setAddress1(newAddress1);
-
-        final DefaultAccount newAccount = new DefaultAccount(account.getId(), mutableAccountData);
+        final AccountModelDao newAccount = new AccountModelDao(account.getId(), otherAccount);
         accountDao.update(newAccount, internalCallContext);
 
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext).getAddress1(), newAddress1);
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext).getAddress2(), account.getAddress2());
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext).getCurrency(), account.getCurrency());
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext).getExternalKey(), account.getExternalKey());
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext).getBillCycleDay(), account.getBillCycleDay());
+        final AccountModelDao retrievedAccount = accountDao.getById(account.getId(), internalCallContext);
+        Assert.assertEquals(retrievedAccount.getAddress1(), newAccount.getAddress1());
+        Assert.assertEquals(retrievedAccount.getEmail(), newAccount.getEmail());
     }
 
     @Test(groups = "slow")
     public void testShouldBeAbleToHandleOtherBCDClass() throws Exception {
-        final Account account = createTestAccount();
+        final AccountModelDao account = createTestAccount();
         accountDao.create(account, internalCallContext);
 
-        final MutableAccountData otherAccount = account.toMutableAccountData();
+        final MutableAccountData otherAccount = new DefaultAccount(account).toMutableAccountData();
         otherAccount.setAddress1(UUID.randomUUID().toString());
         otherAccount.setEmail(UUID.randomUUID().toString());
         // Same BCD, but not .equals method
         otherAccount.setBillCycleDay(new BillCycleDay() {
             @Override
             public int getDayOfMonthUTC() {
-                return account.getBillCycleDay().getDayOfMonthUTC();
+                return account.getBillingCycleDayUTC();
             }
 
             @Override
             public int getDayOfMonthLocal() {
-                return account.getBillCycleDay().getDayOfMonthLocal();
+                return account.getBillingCycleDayLocal();
             }
         });
 
-        final DefaultAccount newAccount = new DefaultAccount(account.getId(), otherAccount);
+        final AccountModelDao newAccount = new AccountModelDao(account.getId(), otherAccount);
         accountDao.update(newAccount, internalCallContext);
 
-        final Account newFetchedAccount = accountDao.getById(account.getId(), internalCallContext);
+        final AccountModelDao newFetchedAccount = accountDao.getById(account.getId(), internalCallContext);
         Assert.assertEquals(newFetchedAccount.getAddress1(), newAccount.getAddress1());
         Assert.assertEquals(newFetchedAccount.getEmail(), newAccount.getEmail());
         // Same BCD
-        Assert.assertEquals(newFetchedAccount.getBillCycleDay(), account.getBillCycleDay());
+        Assert.assertEquals(newFetchedAccount.getBillingCycleDayUTC(), account.getBillingCycleDayUTC());
+        Assert.assertEquals(newFetchedAccount.getBillingCycleDayLocal(), account.getBillingCycleDayLocal());
     }
 
     @Test(groups = "slow")
     public void testShouldBeAbleToHandleBCDOfZeroZero() throws Exception {
-        final Account account = createTestAccount(0);
+        final AccountModelDao account = createTestAccount(0);
         accountDao.create(account, internalCallContext);
-        final Account fetchedAccount = accountDao.getById(account.getId(), internalCallContext);
+        final AccountModelDao fetchedAccount = accountDao.getById(account.getId(), internalCallContext);
 
-        final MutableAccountData otherAccount = account.toMutableAccountData();
+        final MutableAccountData otherAccount = new DefaultAccount(fetchedAccount).toMutableAccountData();
         // Set BCD to null
         otherAccount.setBillCycleDay(null);
 
-        final DefaultAccount newAccount = new DefaultAccount(account.getId(), otherAccount);
+        final AccountModelDao newAccount = new AccountModelDao(account.getId(), otherAccount);
         accountDao.update(newAccount, internalCallContext);
 
         // Same BCD (zero/zero)
-        Assert.assertEquals(accountDao.getById(account.getId(), internalCallContext), fetchedAccount);
+        final AccountModelDao retrievedAccount = accountDao.getById(account.getId(), internalCallContext);
+        Assert.assertEquals(retrievedAccount.getBillingCycleDayUTC(), fetchedAccount.getBillingCycleDayUTC());
+        Assert.assertEquals(retrievedAccount.getBillingCycleDayLocal(), fetchedAccount.getBillingCycleDayLocal());
     }
 
     @Test(groups = "slow")
@@ -430,13 +355,18 @@ public class TestAccountDao extends AccountDaoTestBase {
         accountEmailDao.create(email, internalCallContext);
         Assert.assertEquals(accountEmailDao.getByAccountId(accountId, internalCallContext).size(), 1);
 
-        accountEmailDao.create(email, internalCallContext);
-        Assert.assertEquals(accountEmailDao.getByAccountId(accountId, internalCallContext).size(), 1);
+        try {
+            accountEmailDao.create(email, internalCallContext);
+            Assert.fail();
+        } catch (TransactionFailedException e) {
+            Assert.assertTrue(e.getCause() instanceof AccountApiException);
+            Assert.assertEquals(((AccountApiException) e.getCause()).getCode(), ErrorCode.ACCOUNT_EMAIL_ALREADY_EXISTS.getCode());
+        }
     }
 
     @Test(groups = "slow")
     public void testAccountEmail() throws AccountApiException {
-        List<AccountEmail> emails = new ArrayList<AccountEmail>();
+        List<AccountEmail> emails;
 
         // generate random account id
         final UUID accountId = UUID.randomUUID();
@@ -447,30 +377,16 @@ public class TestAccountDao extends AccountDaoTestBase {
         emails = accountEmailDao.getByAccountId(accountId, internalCallContext);
         assertEquals(emails.size(), 1);
 
-        // verify that history and audit contain one entry
-        verifyAccountEmailAuditAndHistoryCount(accountId, 1);
-
-        // update e-mail
-        final AccountEmail updatedEmail = new DefaultAccountEmail(email, "test2@gmail.com");
-        emails.clear();
-        emails.add(updatedEmail);
-        accountEmailDao.create(updatedEmail, internalCallContext);
-        emails = accountEmailDao.getByAccountId(accountId, internalCallContext);
-        assertEquals(emails.size(), 1);
-
-        // verify that history and audit contain three entries
-        // two inserts and one delete
-        verifyAccountEmailAuditAndHistoryCount(accountId, 3);
+        // verify that audit contains one entry
+        final AuditDao audit = new DefaultAuditDao(dbi);
+        final List<AuditLog> auditLogs = audit.getAuditLogsForId(TableName.ACCOUNT_EMAIL, email.getId(), AuditLevel.FULL, internalCallContext);
+        assertEquals(auditLogs.size(), 1);
 
         // delete e-mail
         accountEmailDao.delete(email, internalCallContext);
-        accountEmailDao.delete(updatedEmail, internalCallContext);
 
         emails = accountEmailDao.getByAccountId(accountId, internalCallContext);
         assertEquals(emails.size(), 0);
-
-        // verify that history and audit contain four entries
-        verifyAccountEmailAuditAndHistoryCount(accountId, 4);
     }
 
     @Test(groups = "slow")
@@ -506,32 +422,5 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(thirdEmails.size(), 1);
         assertEquals(thirdEmails.get(0).getAccountId(), accountId);
         assertEquals(thirdEmails.get(0).getEmail(), email2);
-
-        // Verify that history and audit contain three entries (2 inserts and one delete)
-        verifyAccountEmailAuditAndHistoryCount(accountId, 3);
-    }
-
-    private void verifyAccountEmailAuditAndHistoryCount(final UUID accountId, final int expectedCount) {
-        final Handle handle = dbi.open();
-
-        // verify audit
-        StringBuilder sb = new StringBuilder();
-        sb.append("select * from audit_log a ");
-        sb.append("inner join account_email_history aeh on a.record_id = aeh.history_record_id ");
-        sb.append("where a.table_name = 'account_email_history' ");
-        sb.append(String.format("and aeh.account_id='%s'", accountId.toString()));
-        List<Map<String, Object>> result = handle.select(sb.toString());
-        assertEquals(result.size(), expectedCount);
-
-        // ***** NOT IDEAL
-        // ... but this works after the email record has been deleted; will likely fail when multiple emails exist for the same account
-        // verify history table
-        sb = new StringBuilder();
-        sb.append("select * from account_email_history aeh ");
-        sb.append(String.format("where aeh.account_id='%s'", accountId.toString()));
-        result = handle.select(sb.toString());
-        assertEquals(result.size(), expectedCount);
-
-        handle.close();
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index 7a243cc..06af0da 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -33,6 +33,7 @@ import org.testng.annotations.Test;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
+import com.ning.billing.account.dao.AccountModelDao;
 import com.ning.billing.analytics.AnalyticsTestModule;
 import com.ning.billing.analytics.AnalyticsTestSuiteWithEmbeddedDB;
 import com.ning.billing.analytics.MockDuration;
@@ -219,7 +220,7 @@ public class TestAnalyticsService extends AnalyticsTestSuiteWithEmbeddedDB {
     }
 
     private void createAccountCreationEvent(final Account account) {
-        accountCreationNotification = new DefaultAccountCreationEvent(account, null, 1L, 1L);
+        accountCreationNotification = new DefaultAccountCreationEvent(new AccountModelDao(account.getId(), account), null, 1L, 1L);
     }
 
     private void createInvoiceAndPaymentCreationEvents(final Account account) {
diff --git a/util/src/main/java/com/ning/billing/util/dao/DateTimeZoneArgumentFactory.java b/util/src/main/java/com/ning/billing/util/dao/DateTimeZoneArgumentFactory.java
new file mode 100644
index 0000000..97fe381
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/DateTimeZoneArgumentFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2012 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.dao;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.joda.time.DateTimeZone;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.Argument;
+import org.skife.jdbi.v2.tweak.ArgumentFactory;
+
+public class DateTimeZoneArgumentFactory implements ArgumentFactory<DateTimeZone> {
+
+    @Override
+    public boolean accepts(final Class<?> expectedType, final Object value, final StatementContext ctx) {
+        return value instanceof DateTimeZone;
+    }
+
+    @Override
+    public Argument build(final Class<?> expectedType, final DateTimeZone value, final StatementContext ctx) {
+        return new DateTimeZoneArgument(value);
+    }
+
+    public class DateTimeZoneArgument implements Argument {
+
+        private final DateTimeZone value;
+
+        public DateTimeZoneArgument(final DateTimeZone value) {
+            this.value = value;
+        }
+
+        @Override
+        public void apply(final int position, final PreparedStatement statement, final StatementContext ctx) throws SQLException {
+            if (value != null) {
+                statement.setString(position, value.toString());
+            } else {
+                statement.setNull(position, Types.VARCHAR);
+            }
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("DateTimeZoneArgument");
+            sb.append("{value=").append(value);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
index 2a1c085..1356796 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntityDaoBase.java
@@ -24,7 +24,6 @@ import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.entity.Entity;
-import com.ning.billing.util.entity.EntityPersistenceException;
 
 public abstract class EntityDaoBase<T extends Entity, U extends BillingExceptionBase> implements EntityDao<T, U> {
 
@@ -56,7 +55,7 @@ public abstract class EntityDaoBase<T extends Entity, U extends BillingException
     }
 
     protected void postBusEventFromTransaction(T entity, T savedEntity, ChangeType changeType, final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory, final InternalCallContext context)
-        throws BillingExceptionBase {
+            throws BillingExceptionBase {
     }
 
     protected abstract U generateAlreadyExistsException(final T entity, final InternalCallContext context);
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
index b360462..c914ba7 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDao.java
@@ -29,7 +29,6 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import com.ning.billing.util.audit.ChangeType;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
-import com.ning.billing.util.callcontext.InternalTenantContextBinder;
 import com.ning.billing.util.dao.AuditSqlDao;
 import com.ning.billing.util.dao.HistorySqlDao;
 import com.ning.billing.util.entity.Entity;
@@ -56,7 +55,7 @@ public interface EntitySqlDao<T extends Entity> extends AuditSqlDao, HistorySqlD
                             @BindBean final InternalTenantContext context);
 
     @SqlQuery
-    public Long getHistoryRecordId(@Bind("recordId") final Long recordId,
+    public Long getHistoryRecordId(@Bind("targetRecordId") final Long targetRecordId,
                                    @BindBean final InternalTenantContext context);
 
     @SqlQuery
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
index fbf6a1c..9ba0b85 100644
--- a/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/EntitySqlDaoWrapperInvocationHandler.java
@@ -73,10 +73,12 @@ public class EntitySqlDaoWrapperInvocationHandler<T extends EntitySqlDao<U>, U e
                     final StatementContext statementContext = ((StatementException) t.getCause()).getStatementContext();
                     if (statementContext != null) {
                         final PreparedStatement statement = statementContext.getStatement();
-                        // Note: we rely on the JDBC driver to have a sane toString() method...
-                        errorDuringTransaction(t.getCause().getCause(), method, statement.toString());
-                        // Never reached
-                        return null;
+                        if (statement != null) {
+                            // Note: we rely on the JDBC driver to have a sane toString() method...
+                            errorDuringTransaction(t.getCause().getCause(), method, statement.toString());
+                            // Never reached
+                            return null;
+                        }
                     }
                 }
                 errorDuringTransaction(t.getCause().getCause(), method);
diff --git a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
index 1fca412..06d7657 100644
--- a/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/entity/dao/EntitySqlDao.sql.stg
@@ -159,11 +159,11 @@ where <idField("t.")> = :id
 ;
 >>
 
-getHistoryRecordId(recordId) ::= <<
+getHistoryRecordId(targetRecordId) ::= <<
 select
   max(<recordIdField("t.")>)
-from <tableName()> t
-where <recordIdField("t.")> = :recordId
+from <historyTableName()> t
+where <targetRecordIdField("t.")> = :targetRecordId
 <AND_CHECK_TENANT("t.")>
 ;
 >>
diff --git a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
index 6c827f7..c0c7661 100644
--- a/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
+++ b/util/src/test/java/com/ning/billing/dbi/DBIProvider.java
@@ -20,10 +20,10 @@ import java.util.concurrent.TimeUnit;
 
 import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.sqlobject.customizers.RegisterArgumentFactory;
 import org.skife.jdbi.v2.tweak.transactions.SerializableTransactionRunner;
 
 import com.ning.billing.util.dao.DateTimeArgumentFactory;
+import com.ning.billing.util.dao.DateTimeZoneArgumentFactory;
 import com.ning.billing.util.dao.EnumArgumentFactory;
 import com.ning.billing.util.dao.UUIDArgumentFactory;
 
@@ -65,6 +65,7 @@ public class DBIProvider implements Provider<IDBI> {
         final BoneCPDataSource ds = new BoneCPDataSource(dbConfig);
         final DBI dbi = new DBI(ds);
         dbi.registerArgumentFactory(new UUIDArgumentFactory());
+        dbi.registerArgumentFactory(new DateTimeZoneArgumentFactory());
         dbi.registerArgumentFactory(new DateTimeArgumentFactory());
         dbi.registerArgumentFactory(new EnumArgumentFactory());
 
diff --git a/util/src/test/java/com/ning/billing/util/dao/TestStringTemplateInheritance.java b/util/src/test/java/com/ning/billing/util/dao/TestStringTemplateInheritance.java
index 62ed6c5..5513d73 100644
--- a/util/src/test/java/com/ning/billing/util/dao/TestStringTemplateInheritance.java
+++ b/util/src/test/java/com/ning/billing/util/dao/TestStringTemplateInheritance.java
@@ -94,8 +94,8 @@ public class TestStringTemplateInheritance extends UtilTestSuite {
                                                                               ";");
         Assert.assertEquals(kombucha.getInstanceOf("getHistoryRecordId").toString(), "select\n" +
                                                                                      "  max(t.record_id)\n" +
-                                                                                     "from kombucha t\n" +
-                                                                                     "where t.record_id = :recordId\n" +
+                                                                                     "from kombucha_history t\n" +
+                                                                                     "where t.target_record_id = :targetRecordId\n" +
                                                                                      "and t.tenant_record_id = :tenantRecordId\n" +
                                                                                      ";");
         Assert.assertEquals(kombucha.getInstanceOf("get").toString(), "select\n" +