killbill-memoizeit

Merging with integration

5/18/2012 5:37:05 PM

Changes

account/src/main/java/com/ning/billing/account/api/user/AccountBuilder.java 184(+0 -184)

account/src/test/java/com/ning/billing/account/glue/AccountModuleWithEmbeddedDb.java 55(+0 -55)

payment/pom.xml 12(+12 -0)

util/src/main/java/com/ning/billing/util/customfield/CustomizableEntityBase.java 65(+0 -65)

util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldAuditSqlDao.sql.stg 17(+0 -17)

util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldHistorySqlDao.sql.stg 18(+0 -18)

util/src/main/resources/com/ning/billing/util/tag/dao/TagAuditSqlDao.sql.stg 21(+0 -21)

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 496fb9b..54cfd9c 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
@@ -21,15 +21,13 @@ import java.util.UUID;
 
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.entity.ExtendedEntityBase;
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.junction.api.BlockingState;
 
-import javax.annotation.Nullable;
-
 public class DefaultAccount extends ExtendedEntityBase implements Account {
     private final String externalKey;
 	private final String email;
@@ -50,42 +48,24 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
 	private final String phone;
     private final boolean isMigrated;
     private final boolean isNotifiedForInvoices;
-    private final String updatedBy;
-    private final DateTime updatedDate;
-    
-    
-	//intended for creation and migration
-	public DefaultAccount(final String createdBy, final DateTime createdDate,
-                          final String updatedBy, final DateTime updatedDate,
-                          final AccountData data) {
-		this(UUID.randomUUID(), createdBy, createdDate, updatedBy, updatedDate, data);
-	}
 
     public DefaultAccount(final AccountData data) {
-		this(UUID.randomUUID(), null, null, null, null, data);
-	}
-
-    public DefaultAccount(final UUID id, final AccountData data) {
-		this(id, null, null, null, null, data);
+		this(UUID.randomUUID(), data);
 	}
 
 	/**
 	 * This call is used to update an existing account
-	 *  
+	 *
 	 * @param id UUID id of the existing account to update
 	 * @param data AccountData new data for the existing account
 	 */
-	public DefaultAccount(final UUID id, @Nullable final String createdBy, @Nullable final DateTime createdDate,
-                          @Nullable final String updatedBy, @Nullable final DateTime updatedDate,
-                          final AccountData data) {
+	public DefaultAccount(final UUID id, final AccountData data) {
 		this(id, data.getExternalKey(), data.getEmail(), data.getName(), data.getFirstNameLength(),
 				data.getCurrency(), data.getBillCycleDay(), data.getPaymentProviderName(),
 				data.getTimeZone(), data.getLocale(),
 				data.getAddress1(), data.getAddress2(), data.getCompanyName(),
 				data.getCity(), data.getStateOrProvince(), data.getCountry(),
-				data.getPostalCode(), data.getPhone(), data.isMigrated(), data.isNotifiedForInvoices(),
-                createdBy, createdDate,
-                updatedBy, updatedDate);
+				data.getPostalCode(), data.getPhone(), data.isMigrated(), data.isNotifiedForInvoices());
 	}
 
 	/*
@@ -98,11 +78,8 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
                           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 isMigrated, final boolean isNotifiedForInvoices,
-                          final String createdBy, final DateTime createdDate,
-                          final String updatedBy, final DateTime updatedDate) {
-
-		super(id, createdBy, createdDate);
+                          final boolean isMigrated, final boolean isNotifiedForInvoices) {
+		super(id);
 		this.externalKey = externalKey;
 		this.email = email;
 		this.name = name;
@@ -122,8 +99,6 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
 		this.phone = phone;
         this.isMigrated = isMigrated;
         this.isNotifiedForInvoices = isNotifiedForInvoices;
-        this.updatedBy = updatedBy;
-        this.updatedDate = updatedDate;
 	}
 
     @Override
@@ -142,8 +117,8 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
     }
 
     @Override
-	public String getObjectName() {
-		return ObjectType;
+	public ObjectType getObjectType() {
+		return ObjectType.ACCOUNT;
 	}
 
 	@Override
@@ -237,16 +212,6 @@ public class DefaultAccount extends ExtendedEntityBase implements Account {
     }
 
     @Override
-    public String getUpdatedBy() {
-        return updatedBy;
-    }
-
-    @Override
-    public DateTime getUpdatedDate() {
-        return updatedDate;
-    }
-
-    @Override
 	public String getPhone() {
 		return phone;
 	}
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 dd9323d..d511b26 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
@@ -17,7 +17,6 @@
 package com.ning.billing.account.api;
 
 import com.ning.billing.util.entity.UpdatableEntityBase;
-import org.joda.time.DateTime;
 
 import java.util.UUID;
 
@@ -32,12 +31,11 @@ public class DefaultAccountEmail extends UpdatableEntityBase implements AccountE
     }
 
     public DefaultAccountEmail(AccountEmail source, String newEmail) {
-        this(source.getId(), source.getAccountId(), newEmail,
-             source.getCreatedBy(), source.getCreatedDate(), source.getUpdatedBy(), source.getUpdatedDate());
+        this(source.getId(), source.getAccountId(), newEmail);
     }
 
-    public DefaultAccountEmail(UUID id, UUID accountId, String email, String createdBy, DateTime createdDate, String updatedBy, DateTime updatedDate) {
-        super(id, createdBy, createdDate, updatedBy, updatedDate);
+    public DefaultAccountEmail(UUID id, UUID accountId, String email) {
+        super(id);
         this.accountId = accountId;
         this.email = email;
     }
@@ -51,4 +49,21 @@ public class DefaultAccountEmail extends UpdatableEntityBase implements AccountE
     public String getEmail() {
         return email;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DefaultAccountEmail that = (DefaultAccountEmail) o;
+
+        if (!id.equals(that.id)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
 }
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 e8df191..c28e25b 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,7 @@ package com.ning.billing.account.api.user;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.account.dao.AccountEmailDao;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
@@ -39,12 +40,14 @@ import com.ning.billing.util.tag.TagDefinition;
 
 public class DefaultAccountUserApi implements AccountUserApi {
     private final CallContextFactory factory;
-    private final AccountDao dao;
+    private final AccountDao accountDao;
+    private final AccountEmailDao accountEmailDao;
 
     @Inject
-    public DefaultAccountUserApi(final CallContextFactory factory, final AccountDao dao) {
+    public DefaultAccountUserApi(final CallContextFactory factory, final AccountDao accountDao, final AccountEmailDao accountEmailDao) {
         this.factory = factory;
-        this.dao = dao;
+        this.accountDao = accountDao;
+        this.accountEmailDao = accountEmailDao;
     }
 
     @Override
@@ -55,7 +58,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         account.addTagsFromDefinitions(tagDefinitions);
 
         try {
-            dao.create(account, context);
+            accountDao.create(account, context);
         } catch (EntityPersistenceException e) {
             throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
         }
@@ -65,7 +68,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public Account getAccountByKey(final String key) throws AccountApiException {
-        Account account = dao.getAccountByKey(key);
+        Account account = accountDao.getAccountByKey(key);
         if(account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_KEY, key);
         }
@@ -74,7 +77,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public Account getAccountById(final UUID id) throws AccountApiException {
-        Account account = dao.getById(id.toString());
+        Account account = accountDao.getById(id);
         if(account == null) {
             throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, id);
         }
@@ -83,18 +86,18 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public List<Account> getAccounts() {
-        return dao.get();
+        return accountDao.get();
     }
 
     @Override
     public UUID getIdFromKey(final String externalKey) throws AccountApiException {
-        return dao.getIdFromKey(externalKey);
+        return accountDao.getIdFromKey(externalKey);
     }
 
     @Override
     public void updateAccount(final Account account, final CallContext context) throws AccountApiException {
         try {
-            dao.update(account, context);
+            accountDao.update(account, context);
         } catch (EntityPersistenceException e) {
             throw new AccountApiException(e, ErrorCode.ACCOUNT_UPDATE_FAILED);
         }
@@ -106,7 +109,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         Account account = new DefaultAccount(accountId, accountData);
 
         try {
-            dao.update(account, context);
+            accountDao.update(account, context);
         } catch (EntityPersistenceException e) {
             throw new AccountApiException(e, e.getCode(), e.getMessage());
         }
@@ -133,7 +136,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         account.addTagsFromDefinitions(tagDefinitions);
 
         try {
-            dao.create(account, migrationContext);
+            accountDao.create(account, migrationContext);
         } catch (EntityPersistenceException e) {
             throw new AccountApiException(e, ErrorCode.ACCOUNT_CREATION_FAILED);
         }
@@ -143,11 +146,11 @@ public class DefaultAccountUserApi implements AccountUserApi {
 
     @Override
     public List<AccountEmail> getEmails(final UUID accountId) {
-        return dao.getEmails(accountId);
+        return accountEmailDao.getEmails(accountId);
     }
 
     @Override
     public void saveEmails(final UUID accountId, final List<AccountEmail> newEmails, final CallContext context) {
-        dao.saveEmails(accountId, newEmails, context);
+        accountEmailDao.saveEmails(accountId, newEmails, context);
     }
 }
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 00f785f..67474ab 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
@@ -22,9 +22,7 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.entity.UpdatableEntityDao;
-
-import javax.annotation.Nullable;
+import com.ning.billing.util.entity.dao.UpdatableEntityDao;
 
 public interface AccountDao extends UpdatableEntityDao<Account> {
     public Account getAccountByKey(String key);
@@ -36,8 +34,4 @@ public interface AccountDao extends UpdatableEntityDao<Account> {
      * @throws AccountApiException when externalKey is null
      */
     public UUID getIdFromKey(String externalKey) throws AccountApiException;
-
-    public List<AccountEmail> getEmails(UUID accountId);
-
-    public void saveEmails(UUID accountId, List<AccountEmail> emails, CallContext context);
 }
\ No newline at end of file
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
new file mode 100644
index 0000000..01344b3
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailHistoryBinder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.account.api.AccountEmail;
+import com.ning.billing.util.dao.EntityHistory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(AccountEmailHistoryBinder.AccountEmailHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface AccountEmailHistoryBinder {
+    public static class AccountEmailHistoryBinderFactory implements BinderFactory {
+        @Override
+        public Binder<AccountEmailHistoryBinder, EntityHistory<AccountEmail>> build(Annotation annotation) {
+            return new Binder<AccountEmailHistoryBinder, EntityHistory<AccountEmail>>() {
+                @Override
+                public void bind(SQLStatement q, AccountEmailHistoryBinder bind, EntityHistory<AccountEmail> history) {
+                    q.bind("recordId", history.getValue());
+                    q.bind("changeType", history.getChangeType().toString());
+
+                    AccountEmail accountEmail = history.getEntity();
+                    q.bind("id", accountEmail.getId().toString());
+                    q.bind("accountId", accountEmail.getAccountId().toString());
+                    q.bind("email", accountEmail.getEmail());
+                }
+            };
+        }
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java b/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
index 9444941..9a46344 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountEmailMapper.java
@@ -34,11 +34,6 @@ public class AccountEmailMapper extends MapperBase implements ResultSetMapper<Ac
         UUID accountId = UUID.fromString(result.getString("account_id"));
         String email = result.getString("email");
 
-        String createdBy = result.getString("created_by");
-        DateTime createdDate = getDate(result, "created_date");
-        String updatedBy = result.getString("updated_by");
-        DateTime updatedDate = getDate(result, "updated_date");
-
-        return new DefaultAccountEmail(id, accountId, email, createdBy, createdDate, updatedBy, updatedDate);
+        return new DefaultAccountEmail(id, accountId, email);
     }
 }
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 1902154..15f405e 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
@@ -17,15 +17,14 @@
 package com.ning.billing.account.dao;
 
 import com.ning.billing.account.api.AccountEmail;
-import com.ning.billing.util.ChangeType;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.dao.ChangeTypeBinder;
-import com.ning.billing.util.entity.UpdatableEntityDao;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.ObjectTypeBinder;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
-import org.skife.jdbi.v2.sqlobject.SqlQuery;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -35,39 +34,66 @@ import java.util.List;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(AccountEmailMapper.class)
-public interface AccountEmailSqlDao extends UpdatableEntityDao<AccountEmail>, Transactional<AccountEmailSqlDao>, Transmogrifier {
+public interface AccountEmailSqlDao extends UpdatableEntityCollectionSqlDao<AccountEmail>, Transactional<AccountEmailSqlDao>, Transmogrifier {
     @Override
-    @SqlUpdate
-    public void create(@AccountEmailBinder final AccountEmail accountEmail,
-                       @CallContextBinder final CallContext context);
-
-    @SqlBatch(transactional = false)
-    public void create(@AccountEmailBinder final List<AccountEmail> accountEmailList,
-                       @CallContextBinder final CallContext context);
+    @SqlBatch(transactional=false)
+    public void insertFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @AccountEmailBinder final List<AccountEmail> entities,
+                                      @CallContextBinder final CallContext context);
 
     @Override
-    @SqlUpdate
-    public void update(@AccountEmailBinder final AccountEmail accountEmail,
-                       @CallContextBinder final CallContext context);
-
-    @SqlBatch(transactional = false)
-    public void update(@AccountEmailBinder final List<AccountEmail> accountEmailList,
-                       @CallContextBinder final CallContext context);
-
-    @SqlUpdate
-    public void delete(@AccountEmailBinder final AccountEmail accountEmail,
-                       @CallContextBinder final CallContext context);
+    @SqlBatch(transactional=false)
+    public void updateFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @AccountEmailBinder final List<AccountEmail> entities,
+                                      @CallContextBinder final CallContext context);
 
-    @SqlBatch(transactional = false)
-    public void delete(@AccountEmailBinder final List<AccountEmail> accountEmailList,
-                       @CallContextBinder final CallContext context);
+    @Override
+    @SqlBatch(transactional=false)
+    public void deleteFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @AccountEmailBinder final List<AccountEmail> entities,
+                                      @CallContextBinder final CallContext context);
 
+    @Override
     @SqlBatch(transactional=false)
-    public void insertAccountEmailHistoryFromTransaction(@Bind("historyRecordId") final List<String> historyRecordIdList,
-                                                         @AccountEmailBinder final List<AccountEmail> accountEmail,
-                                                         @ChangeTypeBinder final ChangeType changeType,
-                                                         @CallContextBinder final CallContext context);
+    public void addHistoryFromTransaction(@Bind("objectId") final String objectId,
+                                               @ObjectTypeBinder final ObjectType objectType,
+                                               @AccountEmailHistoryBinder final List<EntityHistory<AccountEmail>> entities,
+                                               @CallContextBinder final CallContext context);
+//    @Override
+//    @SqlUpdate
+//    public void create(@AccountEmailBinder final AccountEmail accountEmail,
+//                       @CallContextBinder final CallContext context);
+
+//    @SqlBatch(transactional = false)
+//    public void create(@AccountEmailBinder final List<AccountEmail> accountEmailList,
+//                       @CallContextBinder final CallContext context);
 
-    @SqlQuery
-    public List<AccountEmail> getByAccountId(@Bind("accountId") final String accountId);
+//    @Override
+//    @SqlUpdate
+//    public void update(@AccountEmailBinder final AccountEmail accountEmail,
+//                       @CallContextBinder final CallContext context);
+//
+//    @SqlBatch(transactional = false)
+//    public void update(@AccountEmailBinder final List<AccountEmail> accountEmailList,
+//                       @CallContextBinder final CallContext context);
+//
+//    @SqlUpdate
+//    public void delete(@AccountEmailBinder final AccountEmail accountEmail,
+//                       @CallContextBinder final CallContext context);
+//
+//    @SqlBatch(transactional = false)
+//    public void delete(@AccountEmailBinder final List<AccountEmail> accountEmailList,
+//                       @CallContextBinder final CallContext context);
+//
+//    @SqlBatch(transactional=false)
+//    public void insertAccountEmailHistoryFromTransaction(@Bind("historyRecordId") final List<String> historyRecordIdList,
+//                                                         @AccountEmailBinder final List<AccountEmail> accountEmail,
+//                                                         @ChangeTypeBinder final ChangeType changeType,
+//                                                         @CallContextBinder final CallContext context);
+//
+//    @SqlQuery
+//    public List<AccountEmail> getByAccountId(@Bind("accountId") final String accountId);
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
new file mode 100644
index 0000000..66cba44
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountHistoryBinder.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.account.api.Account;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.dao.EntityHistory;
+import org.joda.time.DateTimeZone;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(AccountHistoryBinder.AccountHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface AccountHistoryBinder {
+    public static class AccountHistoryBinderFactory implements BinderFactory {
+        @Override
+        public Binder<AccountHistoryBinder, EntityHistory<Account>> build(Annotation annotation) {
+            return new Binder<AccountHistoryBinder, EntityHistory<Account>>() {
+                @Override
+                public void bind(SQLStatement q, AccountHistoryBinder bind, EntityHistory<Account> history) {
+                    q.bind("recordId", history.getValue());
+                    q.bind("changeType", history.getChangeType().toString());
+
+                    Account account = history.getEntity();
+                    q.bind("id", account.getId().toString());
+                    q.bind("externalKey", account.getExternalKey());
+                    q.bind("email", account.getEmail());
+                    q.bind("name", account.getName());
+                    q.bind("firstNameLength", account.getFirstNameLength());
+                    Currency currency = account.getCurrency();
+                    q.bind("currency", (currency == null) ? null : currency.toString());
+                    q.bind("billingCycleDay", account.getBillCycleDay());
+                    q.bind("paymentProviderName", account.getPaymentProviderName());
+                    DateTimeZone timeZone = account.getTimeZone();
+                    q.bind("timeZone", (timeZone == null) ? null : timeZone.toString());
+                    q.bind("locale", account.getLocale());
+                    q.bind("address1", account.getAddress1());
+                    q.bind("address2", account.getAddress2());
+                    q.bind("companyName", account.getCompanyName());
+                    q.bind("city", account.getCity());
+                    q.bind("stateOrProvince", account.getStateOrProvince());
+                    q.bind("country", account.getCountry());
+                    q.bind("postalCode", account.getPostalCode());
+                    q.bind("phone", account.getPhone());
+                    q.bind("migrated", account.isMigrated());
+                    q.bind("isNotifiedForInvoices", account.isNotifiedForInvoices());
+                }
+            };
+        }
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/dao/AccountMapper.java b/account/src/main/java/com/ning/billing/account/dao/AccountMapper.java
index af8be67..1a62c19 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AccountMapper.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AccountMapper.java
@@ -17,7 +17,7 @@
 package com.ning.billing.account.dao;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.user.AccountBuilder;
+import com.ning.billing.account.api.DefaultAccount;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.dao.MapperBase;
 import org.joda.time.DateTime;
@@ -58,27 +58,12 @@ public class AccountMapper extends MapperBase implements ResultSetMapper<Account
         String country = result.getString("country");
         String phone = result.getString("phone");
 
-        Boolean migrated = result.getBoolean("migrated");
+        Boolean isMigrated = result.getBoolean("migrated");
         Boolean isNotifiedForInvoices = result.getBoolean("is_notified_for_invoices");
 
-        String createdBy = result.getString("created_by");
-        DateTime createdDate = getDate(result, "created_date");
-        String updatedBy = result.getString("updated_by");
-        DateTime updatedDate = getDate(result, "updated_date");
-
-        return new AccountBuilder(id).externalKey(externalKey).email(email)
-                                     .name(name).firstNameLength(firstNameLength)
-                                     .phone(phone).currency(currency)
-                                     .billingCycleDay(billingCycleDay)
-                                     .paymentProviderName(paymentProviderName)
-                                     .timeZone(timeZone).locale(locale)
-                                     .address1(address1).address2(address2)
-                                     .companyName(companyName)
-                                     .city(city).stateOrProvince(stateOrProvince)
-                                     .postalCode(postalCode).country(country)
-                                     .migrated(migrated).isNotifiedForInvoices(isNotifiedForInvoices)
-                                     .createdBy(createdBy).createdDate(createdDate)
-                                     .updatedBy(updatedBy).updatedDate(updatedDate)
-                                     .build();
+        return new DefaultAccount(id, externalKey, email, name,firstNameLength, currency,
+                billingCycleDay, paymentProviderName, timeZone, locale,
+                address1, address2, companyName, city, stateOrProvince, country, postalCode, phone,
+                isMigrated, isNotifiedForInvoices);
     }
 }
\ No newline at end of file
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 298ed72..8ed05ee 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
@@ -18,11 +18,15 @@ package com.ning.billing.account.dao;
 
 import java.util.UUID;
 
+import com.ning.billing.account.api.Account;
 import com.ning.billing.util.ChangeType;
+import com.ning.billing.util.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.dao.ChangeTypeBinder;
-import com.ning.billing.util.entity.UpdatableEntityDao;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.UuidMapper;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
@@ -31,12 +35,9 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 
-import com.ning.billing.account.api.Account;
-import com.ning.billing.util.UuidMapper;
-
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper({UuidMapper.class, AccountMapper.class})
-public interface AccountSqlDao extends UpdatableEntityDao<Account>, Transactional<AccountSqlDao>, Transmogrifier {
+public interface AccountSqlDao extends UpdatableEntitySqlDao<Account>, Transactional<AccountSqlDao>, Transmogrifier {
     @SqlQuery
     public Account getAccountByKey(@Bind("externalKey") final String key);
 
@@ -51,9 +52,8 @@ public interface AccountSqlDao extends UpdatableEntityDao<Account>, Transactiona
     @SqlUpdate
     public void update(@AccountBinder Account account, @CallContextBinder final CallContext context);
 
+    @Override
     @SqlUpdate
-    public void insertAccountHistoryFromTransaction(@AccountBinder final Account account,
-                                                    @Bind("historyRecordId") final String historyRecordId,
-                                                    @ChangeTypeBinder ChangeType changeType,
-                                                    @CallContextBinder CallContext context);
+    public void insertHistoryFromTransaction(@AccountHistoryBinder final EntityHistory<Account> account,
+                                            @CallContextBinder final CallContext context);
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
index 4fcc49e..6d52d10 100644
--- a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountDao.java
@@ -17,15 +17,16 @@
 package com.ning.billing.account.dao;
 
 import java.sql.DataTruncation;
-import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.tag.dao.TagDao;
 import org.skife.jdbi.v2.IDBI;
@@ -40,28 +41,18 @@ import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountChangeEvent;
 import com.ning.billing.account.api.AccountCreationEvent;
-import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
-import com.ning.billing.util.dao.AuditedDaoBase;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
 import com.ning.billing.util.tag.Tag;
 
-
-
-    
-
-public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
-
+public class AuditedAccountDao implements AccountDao {
     private final static Logger log = LoggerFactory.getLogger(AuditedAccountDao.class);
     
-    private static final String ACCOUNT_EMAIL_HISTORY_TABLE = "account_email_history";
-
     private final AccountSqlDao accountSqlDao;
-    private final AccountEmailSqlDao accountEmailSqlDao;
     private final TagDao tagDao;
     private final CustomFieldDao customFieldDao;
     private final Bus eventBus;
@@ -70,7 +61,6 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
     public AuditedAccountDao(IDBI dbi, Bus eventBus, TagDao tagDao, CustomFieldDao customFieldDao) {
         this.eventBus = eventBus;
         this.accountSqlDao = dbi.onDemand(AccountSqlDao.class);
-        this.accountEmailSqlDao = dbi.onDemand(AccountEmailSqlDao.class);
         this.tagDao = tagDao;
         this.customFieldDao = customFieldDao;
     }
@@ -99,11 +89,11 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
     }
 
     @Override
-    public Account getById(final String id) {
+    public Account getById(final UUID id) {
         return accountSqlDao.inTransaction(new Transaction<Account, AccountSqlDao>() {
             @Override
             public Account inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws Exception {
-                Account account = accountSqlDao.getById(id);
+                Account account = accountSqlDao.getById(id.toString());
                 if (account != null) {
                     setCustomFieldsFromWithinTransaction(account, accountSqlDao);
                     setTagsFromWithinTransaction(account, accountSqlDao);
@@ -141,13 +131,16 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
                         throw new AccountApiException(ErrorCode.ACCOUNT_ALREADY_EXISTS, key);
                     }
                     transactionalDao.create(account, context);
-                    UUID historyId = UUID.randomUUID();
 
-                    accountSqlDao.insertAccountHistoryFromTransaction(account, historyId.toString(), ChangeType.INSERT, context);
+                    // insert history
+                    Long recordId = accountSqlDao.getRecordId(account.getId().toString());
+                    EntityHistory<Account> history = new EntityHistory<Account>(account.getId(), recordId, account, ChangeType.INSERT);
+                    accountSqlDao.insertHistoryFromTransaction(history, context);
 
-                    AuditSqlDao auditDao = accountSqlDao.become(AuditSqlDao.class);
-                    auditDao.insertAuditFromTransaction("account_history", historyId.toString(),
-                                                         ChangeType.INSERT, context);
+                    // insert audit
+                    Long historyRecordId = accountSqlDao.getHistoryRecordId(recordId);
+                    EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.INSERT);
+                    accountSqlDao.insertAuditFromTransaction(audit, context);
 
                     saveTagsFromWithinTransaction(account, transactionalDao, context);
                     saveCustomFieldsFromWithinTransaction(account, transactionalDao, context);
@@ -190,12 +183,13 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
 
                     transactional.update(account, context);
 
-                    UUID historyId = UUID.randomUUID();
+                    Long recordId = accountSqlDao.getRecordId(account.getId().toString());
+                    EntityHistory<Account> history = new EntityHistory<Account>(account.getId(), recordId, account, ChangeType.INSERT);
+                    accountSqlDao.insertHistoryFromTransaction(history, context);
 
-                    accountSqlDao.insertAccountHistoryFromTransaction(account, historyId.toString(), ChangeType.UPDATE, context);
-
-                    AuditSqlDao auditDao = accountSqlDao.become(AuditSqlDao.class);
-                    auditDao.insertAuditFromTransaction("account_history" ,historyId.toString(), ChangeType.INSERT, context);
+                    Long historyRecordId = accountSqlDao.getHistoryRecordId(recordId);
+                    EntityAudit audit = new EntityAudit(TableName.ACCOUNT_HISTORY, historyRecordId, ChangeType.INSERT);
+                    accountSqlDao.insertAuditFromTransaction(audit, context);
 
                     saveTagsFromWithinTransaction(account, transactional, context);
                     saveCustomFieldsFromWithinTransaction(account, transactional, context);
@@ -221,71 +215,13 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
     }
 
     @Override
-    public List<AccountEmail> getEmails(final UUID accountId) {
-        return accountEmailSqlDao.getByAccountId(accountId.toString());
-    }
-
-    @Override
-    public void saveEmails(final UUID accountId, final List<AccountEmail> emails, final CallContext context) {
-        final List<AccountEmail> existingEmails = accountEmailSqlDao.getByAccountId(accountId.toString());
-        final List<AccountEmail> updatedEmails = new ArrayList<AccountEmail>();
-
-        Iterator<AccountEmail> existingEmailIterator = existingEmails.iterator();
-        while (existingEmailIterator.hasNext()) {
-            AccountEmail existingEmail = existingEmailIterator.next();
-
-            Iterator<AccountEmail> newEmailIterator = emails.iterator();
-            while (newEmailIterator.hasNext()) {
-                AccountEmail newEmail = newEmailIterator.next();
-                if (newEmail.getId().equals(existingEmail.getId())) {
-                    // check equality; if not equal, add to updated
-                    if (!newEmail.equals(existingEmail)) {
-                        updatedEmails.add(newEmail);
-                    }
-
-                    // remove from both
-                    newEmailIterator.remove();
-                    existingEmailIterator.remove();
-                }
-            }
-        }
-
-        // remaining emails in newEmail are inserts; remaining emails in existingEmail are deletes
-        accountEmailSqlDao.inTransaction(new Transaction<Void, AccountEmailSqlDao>() {
-            @Override
-            public Void inTransaction(AccountEmailSqlDao dao, TransactionStatus transactionStatus) throws Exception {
-                dao.create(emails, context);
-                dao.update(updatedEmails, context);
-                dao.delete(existingEmails, context);
-
-                List<String> insertHistoryIdList = getIdList(emails.size());
-                List<String> updateHistoryIdList = getIdList(updatedEmails.size());
-                List<String> deleteHistoryIdList = getIdList(existingEmails.size());
-
-                // insert histories
-                dao.insertAccountEmailHistoryFromTransaction(insertHistoryIdList, emails, ChangeType.INSERT, context);
-                dao.insertAccountEmailHistoryFromTransaction(updateHistoryIdList, updatedEmails, ChangeType.UPDATE, context);
-                dao.insertAccountEmailHistoryFromTransaction(deleteHistoryIdList, existingEmails, ChangeType.DELETE, context);
-
-                // insert audits
-                AuditSqlDao auditSqlDao = dao.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction(ACCOUNT_EMAIL_HISTORY_TABLE, insertHistoryIdList, ChangeType.INSERT, context);
-                auditSqlDao.insertAuditFromTransaction(ACCOUNT_EMAIL_HISTORY_TABLE, updateHistoryIdList, ChangeType.UPDATE, context);
-                auditSqlDao.insertAuditFromTransaction(ACCOUNT_EMAIL_HISTORY_TABLE, deleteHistoryIdList, ChangeType.DELETE, context);
-
-                return null;
-            }
-        });
-    }
-
-    @Override
     public void test() {
         accountSqlDao.test();
     }
 
     private void setCustomFieldsFromWithinTransaction(final Account account, final AccountSqlDao transactionalDao) {
         CustomFieldSqlDao customFieldSqlDao = transactionalDao.become(CustomFieldSqlDao.class);
-        List<CustomField> fields = customFieldSqlDao.load(account.getId().toString(), account.getObjectName());
+        List<CustomField> fields = customFieldSqlDao.load(account.getId().toString(), account.getObjectType());
 
         account.clearFields();
         if (fields != null) {
@@ -294,7 +230,7 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
     }
 
     private void setTagsFromWithinTransaction(final Account account, final AccountSqlDao transactionalDao) {
-        List<Tag> tags = tagDao.loadTagsFromTransaction(transactionalDao, account.getId(), Account.ObjectType);
+        List<Tag> tags = tagDao.loadEntitiesFromTransaction(transactionalDao, account.getId(), ObjectType.ACCOUNT);
         account.clearTags();
 
         if (tags != null) {
@@ -304,13 +240,11 @@ public class AuditedAccountDao extends AuditedDaoBase implements AccountDao {
 
     private void saveTagsFromWithinTransaction(final Account account, final AccountSqlDao transactionalDao,
                                                final CallContext context) {
-        tagDao.saveTagsFromTransaction(transactionalDao, account.getId(), account.getObjectName(), account.getTagList(), context);
+        tagDao.saveEntitiesFromTransaction(transactionalDao, account.getId(), account.getObjectType(), account.getTagList(), context);
     }
 
     private void saveCustomFieldsFromWithinTransaction(final Account account, final AccountSqlDao transactionalDao,
                                                        final CallContext context) {
-        customFieldDao.saveFields(transactionalDao, account.getId(), account.getObjectName(), account.getFieldList(), context);
+        customFieldDao.saveEntitiesFromTransaction(transactionalDao, account.getId(), account.getObjectType(), account.getFieldList(), context);
     }
-
-
 }
diff --git a/account/src/main/java/com/ning/billing/account/dao/AuditedAccountEmailDao.java b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountEmailDao.java
new file mode 100644
index 0000000..e51c194
--- /dev/null
+++ b/account/src/main/java/com/ning/billing/account/dao/AuditedAccountEmailDao.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2010-2011 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 com.google.inject.Inject;
+import com.ning.billing.account.api.AccountEmail;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.AuditedCollectionDaoBase;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
+import java.util.List;
+import java.util.UUID;
+
+public class AuditedAccountEmailDao extends AuditedCollectionDaoBase<AccountEmail> implements AccountEmailDao {
+    private final AccountEmailSqlDao accountEmailSqlDao;
+
+    @Inject
+    public AuditedAccountEmailDao(IDBI dbi) {
+        this.accountEmailSqlDao = dbi.onDemand(AccountEmailSqlDao.class);
+    }
+
+    @Override
+    public List<AccountEmail> getEmails(final UUID accountId) {
+        return super.loadEntities(accountId, ObjectType.ACCOUNT_EMAIL);
+    }
+
+    @Override
+    public void saveEmails(final UUID accountId, final List<AccountEmail> emails, final CallContext context) {
+        super.saveEntitiesFromTransaction(accountEmailSqlDao, accountId, ObjectType.ACCOUNT_EMAIL, emails, context);
+    }
+
+    public void test() {
+        accountEmailSqlDao.test();
+    }
+
+//    @Override
+//    public List<AccountEmail> getEmails(final UUID accountId) {
+//        return accountEmailSqlDao.load(accountId.toString(), null);
+//        //return accountEmailSqlDao.getByAccountId(accountId.toString());
+//    }
+
+//    @Override
+//    public void saveEmails(final UUID accountId, final List<AccountEmail> emails, final CallContext context) {
+//        final List<AccountEmail> existingEmails = accountEmailSqlDao.getByAccountId(accountId.toString());
+//        final List<AccountEmail> updatedEmails = new ArrayList<AccountEmail>();
+//
+//        Iterator<AccountEmail> existingEmailIterator = existingEmails.iterator();
+//        while (existingEmailIterator.hasNext()) {
+//            AccountEmail existingEmail = existingEmailIterator.next();
+//
+//            Iterator<AccountEmail> newEmailIterator = emails.iterator();
+//            while (newEmailIterator.hasNext()) {
+//                AccountEmail newEmail = newEmailIterator.next();
+//                if (newEmail.getId().equals(existingEmail.getId())) {
+//                    // check equality; if not equal, add to updated
+//                    if (!newEmail.equals(existingEmail)) {
+//                        updatedEmails.add(newEmail);
+//                    }
+//
+//                    // remove from both
+//                    newEmailIterator.remove();
+//                    existingEmailIterator.remove();
+//                }
+//            }
+//        }
+//
+//        // remaining emails in newEmail are inserts; remaining emails in existingEmail are deletes
+//        accountEmailSqlDao.inTransaction(new Transaction<Void, AccountEmailSqlDao>() {
+//            @Override
+//            public Void inTransaction(AccountEmailSqlDao dao, TransactionStatus transactionStatus) throws Exception {
+//                dao.create(emails, context);
+//                dao.update(updatedEmails, context);
+//                dao.delete(existingEmails, context);
+//
+//                List<String> insertHistoryIdList = getIdList(emails.size());
+//                List<String> updateHistoryIdList = getIdList(updatedEmails.size());
+//                List<String> deleteHistoryIdList = getIdList(existingEmails.size());
+//
+//                // insert histories
+//                dao.insertAccountEmailHistoryFromTransaction(insertHistoryIdList, emails, ChangeType.INSERT, context);
+//                dao.insertAccountEmailHistoryFromTransaction(updateHistoryIdList, updatedEmails, ChangeType.UPDATE, context);
+//                dao.insertAccountEmailHistoryFromTransaction(deleteHistoryIdList, existingEmails, ChangeType.DELETE, context);
+//
+//                // insert audits
+//                auditSqlDao.insertAuditFromTransaction(TableName.ACCOUNT_EMAIL_HISTORY, insertHistoryIdList, ChangeType.INSERT, context);
+//                auditSqlDao.insertAuditFromTransaction(TableName.ACCOUNT_EMAIL_HISTORY, updateHistoryIdList, ChangeType.UPDATE, context);
+//                auditSqlDao.insertAuditFromTransaction(TableName.ACCOUNT_EMAIL_HISTORY, deleteHistoryIdList, ChangeType.DELETE, context);
+//
+//                return null;
+//            }
+//        });
+//    }
+//
+//    private List<String> getIdList(int size) {
+//        List<String> results = new ArrayList<String>();
+//        for (int i = 0; i < size; i++) {
+//            results.add(UUID.randomUUID().toString());
+//        }
+//        return results;
+//    }
+
+    @Override
+    protected TableName getTableName() {
+        return TableName.ACCOUNT_EMAIL_HISTORY;
+    }
+
+    @Override
+    protected UpdatableEntityCollectionSqlDao<AccountEmail> transmogrifyDao(Transmogrifier transactionalDao) {
+        return transactionalDao.become(AccountEmailSqlDao.class);
+    }
+
+    @Override
+    protected UpdatableEntityCollectionSqlDao<AccountEmail> getSqlDao() {
+        return accountEmailSqlDao;
+    }
+}
diff --git a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
index e3009e8..956d878 100644
--- a/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
+++ b/account/src/main/java/com/ning/billing/account/glue/AccountModule.java
@@ -23,15 +23,17 @@ import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.account.api.DefaultAccountService;
 import com.ning.billing.account.api.user.DefaultAccountUserApi;
 import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.AuditedAccountDao;
+import com.ning.billing.account.dao.AuditedAccountEmailDao;
 import com.ning.billing.util.glue.RealImplementation;
 
 public class AccountModule extends AbstractModule {
-
     private void installConfig() {
     }
 
     protected void installAccountDao() {
+        bind(AccountEmailDao.class).to(AuditedAccountEmailDao.class).asEagerSingleton();
         bind(AccountDao.class).to(AuditedAccountDao.class).asEagerSingleton();
     }
 
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 d287c08..3f981a4 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
@@ -10,25 +10,46 @@ fields(prefix) ::= <<
     <prefix>updated_date
 >>
 
-create() ::= <<
+insertFromTransaction() ::= <<
     INSERT INTO account_emails(<fields()>)
-    VALUES
-    (:id, :accountId, :email, :userName, :createdDate, :userName, :updatedDate);
+    VALUES (:id, :accountId, :email, :userName, :createdDate, :userName, :updatedDate);
 >>
 
-update() ::= <<
+updateFromTransaction() ::= <<
     UPDATE account_emails
-    SET email = :email, updated_by = :userName, updated_date = :updatedDate;
+    SET email = :email, updated_by = :userName, updated_date = :updatedDate
+    WHERE id = :id;
 >>
 
-delete() ::= <<
+deleteFromTransaction() ::= <<
     DELETE FROM account_emails
     WHERE id = :id;
 >>
 
-insertAccountEmailHistoryFromTransaction() ::= <<
-    INSERT INTO account_email_history(history_record_id, id, account_id, email, change_type, updated_by, date)
-    VALUES (:historyRecordId, :id, :accountId, :email, :changeType, :userName, :updatedDate);
+addHistoryFromTransaction() ::= <<
+    INSERT INTO account_email_history(record_id, id, account_id, email, change_type, updated_by, date)
+    VALUES (:recordId, :id, :accountId, :email, :changeType, :userName, :updatedDate);
+>>
+
+load() ::= <<
+    SELECT <fields()> FROM account_emails WHERE account_id = :objectId;
+>>
+
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM account_emails
+    WHERE account_id = :objectId;
+>>
+
+getMaxHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM account_email_history;
+>>
+
+getHistoryRecordIds() ::= <<
+    SELECT history_record_id, record_id
+    FROM account_email_history
+    WHERE history_record_id > :maxHistoryRecordId;
 >>
 
 getById() ::= <<
@@ -43,6 +64,22 @@ getByAccountId() ::= <<
     SELECT <fields()> FROM account_emails WHERE account_id = :accountId;
 >>
 
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
     SELECT 1 FROM account_emails;
 >>
\ No newline at end of file
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 6bd5e79..fda1503 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
@@ -48,14 +48,49 @@ update() ::= <<
     WHERE id = :id;
 >>
 
-insertAccountHistoryFromTransaction() ::= <<
-    INSERT INTO account_history
-    (history_record_id, id, external_key, email, name, first_name_length, currency,
-    billing_cycle_day, payment_provider_name, time_zone, locale,
-    address1, address2, company_name, city, state_or_province,
-    country, postal_code, phone, migrated, is_notified_for_invoices, change_type, updated_by, date)
+historyFields() ::= <<
+    record_id,
+    id,
+    external_key,
+    email,
+    name,
+    first_name_length,
+    currency,
+    billing_cycle_day,
+    payment_provider_name,
+    time_zone,
+    locale,
+    address1,
+    address2,
+    company_name,
+    city,
+    state_or_province,
+    country,
+    postal_code,
+    phone,
+    migrated,
+    is_notified_for_invoices,
+    change_type,
+    updated_by,
+    date
+>>
+
+getRecordId() ::= <<
+    SELECT record_id
+    FROM accounts
+    WHERE id = :id;
+>>
+
+getHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM account_history
+    WHERE record_id = :recordId;
+>>
+
+insertHistoryFromTransaction() ::= <<
+    INSERT INTO account_history(<historyFields()>)
     VALUES
-    (:historyRecordId, :id, :externalKey, :email, :name, :firstNameLength, :currency,
+    (:recordId, :id, :externalKey, :email, :name, :firstNameLength, :currency,
      :billingCycleDay, :paymentProviderName, :timeZone, :locale,
      :address1, :address2, :companyName, :city, :stateOrProvince,
      :country, :postalCode, :phone, :migrated, :isNotifiedForInvoices, :changeType, :userName, :createdDate);
@@ -84,6 +119,22 @@ getIdFromKey() ::= <<
     WHERE external_key = :externalKey;
 >>
 
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
     SELECT 1 FROM accounts;
 >>
diff --git a/account/src/main/resources/com/ning/billing/account/ddl.sql b/account/src/main/resources/com/ning/billing/account/ddl.sql
index 266215d..5fe7c90 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -1,5 +1,6 @@
 DROP TABLE IF EXISTS accounts;
 CREATE TABLE accounts (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
     external_key varchar(128) NULL,
     email varchar(50) NOT NULL,
@@ -24,14 +25,16 @@ CREATE TABLE accounts (
     created_by varchar(50) NOT NULL,
     updated_date datetime DEFAULT NULL,
     updated_by varchar(50) DEFAULT NULL,
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX accounts_id ON accounts(id);
 CREATE UNIQUE INDEX accounts_external_key ON accounts(external_key);
 CREATE UNIQUE INDEX accounts_email ON accounts(email);
 
 DROP TABLE IF EXISTS account_history;
 CREATE TABLE account_history (
-    history_record_id char(36) NOT NULL,
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
     id char(36) NOT NULL,
     external_key varchar(128) NULL,
     email varchar(50) NOT NULL,
@@ -54,12 +57,14 @@ CREATE TABLE account_history (
     is_notified_for_invoices boolean NOT NULL,
     change_type char(6) NOT NULL,
     updated_by varchar(50) NOT NULL,
-    date datetime NOT NULL
+    date datetime NOT NULL,
+    PRIMARY KEY(history_record_id)
 ) ENGINE=innodb;
-CREATE INDEX account_id ON account_history(id);
+CREATE INDEX account_history_record_id ON account_history(record_id);
 
 DROP TABLE IF EXISTS account_emails;
 CREATE TABLE account_emails (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
     account_id char(36) NOT NULL,
     email varchar(50) NOT NULL,
@@ -67,13 +72,16 @@ CREATE TABLE account_emails (
     created_date datetime NOT NULL,
     updated_by varchar(50) NOT NULL,
     updated_date datetime NOT NULL,
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX account_email_id ON account_emails(id);
 CREATE INDEX account_email_account_id ON account_emails(account_id);
+CREATE UNIQUE INDEX account_email_account_id_email ON account_emails(account_id, email);
 
 DROP TABLE IF EXISTS account_email_history;
 CREATE TABLE account_email_history (
-    history_record_id char(36) NOT NULL,
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
     id char(36) NOT NULL,
     account_id char(36) NOT NULL,
     email varchar(50) NOT NULL,
@@ -81,4 +89,5 @@ CREATE TABLE account_email_history (
     updated_by varchar(50) NOT NULL,
     date datetime NOT NULL,
     PRIMARY KEY(history_record_id)
-) ENGINE=innodb;
\ No newline at end of file
+) ENGINE=innodb;
+CREATE INDEX account_email_record_id ON account_email_history(record_id);
\ No newline at end of file
diff --git a/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java b/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
index 9396541..f916278 100644
--- a/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
+++ b/account/src/test/java/com/ning/billing/account/api/MockAccountUserApi.java
@@ -51,10 +51,9 @@ public class MockAccountUserApi implements AccountUserApi {
                                  final String phone) {
 
 		Account result = new DefaultAccount(id, externalKey, email, name,
-				firstNameLength, currency, billCycleDay, paymentProviderName,
-				timeZone, locale, address1, address2, companyName, city,
-				stateOrProvince, country, postalCode, phone, false, false,
-                null, null, null, null);
+                                firstNameLength, currency, billCycleDay, paymentProviderName,
+                                timeZone, locale, address1, address2, companyName, city,
+                                stateOrProvince, country, postalCode, phone, false, false);
 		accounts.add(result);
 		return result;
 	}
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 edc1a09..9eb462f 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
@@ -20,11 +20,19 @@ import static org.testng.Assert.fail;
 
 import java.io.IOException;
 
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.bus.Bus;
+import com.ning.billing.util.bus.InMemoryBus;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
+import com.ning.billing.util.tag.dao.AuditedTagDao;
+import com.ning.billing.util.tag.dao.TagDao;
 import org.apache.commons.io.IOUtils;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
@@ -33,18 +41,15 @@ import org.skife.jdbi.v2.TransactionStatus;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
-import com.ning.billing.account.glue.AccountModuleWithEmbeddedDb;
-import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.BusService;
 import org.testng.annotations.BeforeMethod;
 
 public abstract class AccountDaoTestBase {
-    protected AccountModuleWithEmbeddedDb module;
+    private final MysqlTestingHelper helper = new MysqlTestingHelper();
+
     protected AccountDao accountDao;
+    protected AccountEmailDao accountEmailDao;
     protected IDBI dbi;
 
     protected CallContext context;
@@ -53,26 +58,30 @@ public abstract class AccountDaoTestBase {
     protected void setup() throws IOException {
         // Health check test to make sure MySQL is setup properly
         try {
-            module = new AccountModuleWithEmbeddedDb();
             final String accountDdl = IOUtils.toString(AccountSqlDao.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
             final String utilDdl = IOUtils.toString(AccountSqlDao.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
 
-            module.startDb();
-            module.initDb(accountDdl);
-            module.initDb(utilDdl);
+            helper.startMysql();
+            helper.initDb(accountDdl);
+            helper.initDb(utilDdl);
 
-            final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module);
-            dbi = injector.getInstance(IDBI.class);
+            dbi = helper.getDBI();
 
-            accountDao = injector.getInstance(AccountDao.class);
-            accountDao.test();
+            Bus bus = new InMemoryBus();
+            BusService busService = new DefaultBusService(bus);
+            ((DefaultBusService) busService).startBus();
 
-            Clock clock = injector.getInstance(Clock.class);
-            context = new DefaultCallContextFactory(clock).createCallContext("Account Dao Tests", CallOrigin.TEST, UserType.TEST);
+            TagDao tagDao = new AuditedTagDao(dbi);
+            CustomFieldDao customFieldDao = new AuditedCustomFieldDao(dbi);
 
+            accountDao = new AuditedAccountDao(dbi, bus, tagDao, customFieldDao);
+            accountDao.test();
 
-            BusService busService = injector.getInstance(BusService.class);
-            ((DefaultBusService) busService).startBus();
+            accountEmailDao = new AuditedAccountEmailDao(dbi);
+            accountEmailDao.test();
+
+            Clock clock = new ClockMock();
+            context = new DefaultCallContextFactory(clock).createCallContext("Account Dao Tests", CallOrigin.TEST, UserType.TEST);
         }
         catch (Throwable t) {
             fail(t.toString());
@@ -82,7 +91,7 @@ public abstract class AccountDaoTestBase {
     @AfterClass(alwaysRun = true)
     public void stopMysql()
     {
-        module.stopDb();
+        helper.stopMysql();
     }
 
     @BeforeMethod(alwaysRun = true)
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 6c8b169..907447d 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
@@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.AccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountChangeEvent;
 import com.ning.billing.account.api.user.DefaultAccountCreationEvent;
@@ -34,7 +33,7 @@ import com.ning.billing.util.bus.Bus.EventBusException;
 
 public class MockAccountDao implements AccountDao {
     private final Bus eventBus;
-    private final Map<String, Account> accounts = new ConcurrentHashMap<String, Account>();
+    private final Map<UUID, Account> accounts = new ConcurrentHashMap<UUID, Account>();
 
     @Inject
     public MockAccountDao(Bus eventBus) {
@@ -43,7 +42,7 @@ public class MockAccountDao implements AccountDao {
 
     @Override
     public void create(Account account, CallContext context) {
-        accounts.put(account.getId().toString(), account);
+        accounts.put(account.getId(), account);
 
         try {
             eventBus.post(new DefaultAccountCreationEvent(account, null));
@@ -54,7 +53,7 @@ public class MockAccountDao implements AccountDao {
     }
 
     @Override
-    public Account getById(String id) {
+    public Account getById(UUID id) {
         return accounts.get(id);
     }
 
@@ -84,18 +83,8 @@ public class MockAccountDao implements AccountDao {
     }
 
     @Override
-    public List<AccountEmail> getEmails(UUID accountId) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void saveEmails(UUID accountId, List<AccountEmail> emails, CallContext context) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public void update(Account account, CallContext context) {
-        Account currentAccount = accounts.put(account.getId().toString(), account);
+        Account currentAccount = accounts.put(account.getId(), account);
 
         AccountChangeEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), null, currentAccount, account);
         if (changeEvent.hasChanges()) {
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 9fd4e22..26a5fdc 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
@@ -29,7 +29,6 @@ import java.util.UUID;
 import com.ning.billing.account.api.AccountEmail;
 import com.ning.billing.account.api.DefaultAccountEmail;
 import com.ning.billing.util.entity.EntityPersistenceException;
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.skife.jdbi.v2.Handle;
 import org.testng.annotations.Test;
@@ -63,7 +62,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         return new DefaultAccount(UUID.randomUUID(), thisKey, thisEmail, name, firstNameLength, Currency.USD,
                 billCycleDay, null, timeZone, locale,
                 null, null, null, null, null, null, null, // add null address fields
-                phone, false, false, "test", DateTime.now(), "test", DateTime.now());
+                phone, false, false);
     }
 
     @Test
@@ -76,7 +75,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
-        r = accountDao.getById(r.getId().toString());
+        r = accountDao.getById(r.getId());
         assertNotNull(r);
         assertEquals(r.getExternalKey(), a.getExternalKey());
 
@@ -112,7 +111,7 @@ public class TestAccountDao extends AccountDaoTestBase {
 
         accountDao.create(account, context);
 
-        account = accountDao.getById(id.toString());
+        account = accountDao.getById(id);
         assertNotNull(account);
         assertEquals(account.getId(), id);
         assertEquals(account.getExternalKey(), key);
@@ -139,7 +138,7 @@ public class TestAccountDao extends AccountDaoTestBase {
     @Test
     public void testTags() throws EntityPersistenceException {
         Account account = createTestAccount(1);
-        TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only");
+        TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", false);
         TagDefinitionSqlDao tagDescriptionDao = dbi.onDemand(TagDefinitionSqlDao.class);
         tagDescriptionDao.create(definition, context);
 
@@ -147,7 +146,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         assertEquals(account.getTagList().size(), 1);
         accountDao.create(account, context);
 
-        Account thisAccount = accountDao.getById(account.getId().toString());
+        Account thisAccount = accountDao.getById(account.getId());
         List<Tag> tagList = thisAccount.getTagList();
         assertEquals(tagList.size(), 1);
         Tag tag = tagList.get(0);
@@ -273,7 +272,7 @@ public class TestAccountDao extends AccountDaoTestBase {
             }
         };
 
-        Account updatedAccount = new DefaultAccount(account.getId(), null, null, null, null, accountData);
+        Account updatedAccount = new DefaultAccount(account.getId(), accountData);
         accountDao.update(updatedAccount, context);
 
         Account savedAccount = accountDao.getAccountByKey(account.getExternalKey());
@@ -301,8 +300,7 @@ public class TestAccountDao extends AccountDaoTestBase {
         DefaultAccount account = new DefaultAccount(accountId, "extKey123456", "myemail123456@glam.com",
                                                     "John Smith", 4, Currency.USD, 15, null,
                                                     DateTimeZone.forID("America/Cambridge_Bay"), "EN-CA",
-                                                    null, null, null, null, null, null, null, null, false, false,
-                                                    null, null, null, null);
+                                                    null, null, null, null, null, null, null, null, false, false);
         accountDao.create(account, context);
 
         String address1 = "123 address 1";
@@ -318,11 +316,11 @@ public class TestAccountDao extends AccountDaoTestBase {
                                                     "John Smith", 4, Currency.USD, 15, null,
                                                     DateTimeZone.forID("America/Cambridge_Bay"), "EN-CA",
                                                     address1, address2, companyName, city, stateOrProvince, country,
-                                                    postalCode, phone, false, false, null, null, null, null);
+                                                    postalCode, phone, false, false);
 
         accountDao.update(updatedAccount, context);
 
-        Account savedAccount = accountDao.getById(accountId.toString());
+        Account savedAccount = accountDao.getById(accountId);
 
         assertNotNull(savedAccount);
         assertEquals(savedAccount.getId(), accountId);
@@ -345,18 +343,18 @@ public class TestAccountDao extends AccountDaoTestBase {
                                                     DateTimeZone.forID("America/Cambridge_Bay"), "EN-CA",
                                                     "123 address 1", "456 address 2", null, "Cambridge Bay",
                                                     "Nunavut", "Canada", "X0B 0C0", "18001112222",
-                                                    false, false, null, null, null, null);
+                                                    false, false);
         accountDao.create(account, context);
 
         DefaultAccount updatedAccount = new DefaultAccount(accountId, "extKey654321", "myemail654321@glam.com",
                                                     "John Smith", 4, Currency.USD, 15, null,
                                                     DateTimeZone.forID("America/Cambridge_Bay"), "EN-CA",
                                                     null, null, null, null, null, null, null, null,
-                                                    false, false, null, null, null, null);
+                                                    false, false);
 
         accountDao.update(updatedAccount, context);
 
-        Account savedAccount = accountDao.getById(accountId.toString());
+        Account savedAccount = accountDao.getById(accountId);
 
         assertNotNull(savedAccount);
         assertEquals(savedAccount.getId(), accountId);
@@ -378,13 +376,13 @@ public class TestAccountDao extends AccountDaoTestBase {
         DefaultAccount account = new DefaultAccount(accountId, originalExternalKey, "myemail1337@glam.com",
                                                     "John Smith", 4, Currency.USD, 15, null,
                                                     null, null, null, null, null, null, null, null, null, null,
-                                                    false, false, null, null, null, null);
+                                                    false, false);
         accountDao.create(account, context);
 
         DefaultAccount updatedAccount = new DefaultAccount(accountId, "extKey1338", "myemail1337@glam.com",
                                                     "John Smith", 4, Currency.USD, 15, null,
                                                     null, null, null, null, null, null, null, null, null, null,
-                                                    false, false, null, null, null, null);
+                                                    false, false);
         accountDao.update(updatedAccount, context);
     }
 
@@ -398,8 +396,8 @@ public class TestAccountDao extends AccountDaoTestBase {
         // add a new e-mail
         final AccountEmail email = new DefaultAccountEmail(accountId, "test@gmail.com");
         emails.add(email);
-        accountDao.saveEmails(accountId, emails, context);
-        emails = accountDao.getEmails(accountId);
+        accountEmailDao.saveEmails(accountId, emails, context);
+        emails = accountEmailDao.getEmails(accountId);
         assertEquals(emails.size(), 1);
 
         // verify that history and audit contain one entry
@@ -409,16 +407,16 @@ public class TestAccountDao extends AccountDaoTestBase {
         AccountEmail updatedEmail = new DefaultAccountEmail(email, "test2@gmail.com");
         emails.clear();
         emails.add(updatedEmail);
-        accountDao.saveEmails(accountId, emails, context);
-        emails = accountDao.getEmails(accountId);
+        accountEmailDao.saveEmails(accountId, emails, context);
+        emails = accountEmailDao.getEmails(accountId);
         assertEquals(emails.size(), 1);
 
         // verify that history and audit contain two entries
         verifyAccountEmailAuditAndHistoryCount(accountId, 2);
 
         // delete e-mail
-        accountDao.saveEmails(accountId, new ArrayList<AccountEmail>(), context);
-        emails = accountDao.getEmails(accountId);
+        accountEmailDao.saveEmails(accountId, new ArrayList<AccountEmail>(), context);
+        emails = accountEmailDao.getEmails(accountId);
         assertEquals(emails.size(), 0);
 
         // verify that history and audit contain three entries
@@ -437,10 +435,12 @@ public class TestAccountDao extends AccountDaoTestBase {
         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 ");
-        sb.append(String.format("where account_id='%s'", accountId.toString()));
+        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);
 
diff --git a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
index 74fe321..8700cfa 100644
--- a/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
+++ b/account/src/test/java/com/ning/billing/account/glue/AccountModuleWithMocks.java
@@ -17,8 +17,12 @@
 package com.ning.billing.account.glue;
 
 import com.ning.billing.account.dao.AccountDao;
+import com.ning.billing.account.dao.AccountEmailDao;
 import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.util.clock.MockClockModule;
+import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.customfield.dao.CustomFieldDao;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.FieldStoreModule;
 import com.ning.billing.util.tag.MockTagStoreModuleMemory;
@@ -27,6 +31,8 @@ public class AccountModuleWithMocks extends AccountModule {
     @Override
     protected void installAccountDao() {
         bind(MockAccountDao.class).asEagerSingleton();
+        AccountEmailDao accountEmailDao = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountEmailDao.class);
+        bind(AccountEmailDao.class).toInstance(accountEmailDao);
         bind(AccountDao.class).to(MockAccountDao.class);
     }
 
@@ -35,7 +41,5 @@ public class AccountModuleWithMocks extends AccountModule {
         super.configure();
         install(new MockClockModule());
         install(new CallContextModule());
-        install(new MockTagStoreModuleMemory());
-        install(new FieldStoreModule());
     }
 }
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
index 8d107ef..e692eb7 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessAccountRecorder.java
@@ -87,7 +87,7 @@ public class BusinessAccountRecorder {
      */
     public void accountUpdated(final PaymentInfoEvent paymentInfo) {
         try {
-            final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+            final PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getId());
             if (paymentAttempt == null) {
                 return;
             }
@@ -155,56 +155,46 @@ public class BusinessAccountRecorder {
     }
 
     private void updateBusinessAccountFromAccount(final Account account, final BusinessAccount bac) {
-
-        try {
-            DateTime lastInvoiceDate = null;
-            BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
-            String lastPaymentStatus = null;
-            String paymentMethod = null;
-            String creditCardType = null;
-            String billingAddressCountry = null;
-
-            // Retrieve invoices information
-            final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
-            if (invoices != null && invoices.size() > 0) {
-                final List<String> invoiceIds = new ArrayList<String>();
-                for (final Invoice invoice : invoices) {
-                    invoiceIds.add(invoice.getId().toString());
-                    totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
-
-                    if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
-                        lastInvoiceDate = invoice.getInvoiceDate();
-                    }
-                }
-
-                // Retrieve payments information for these invoices
-                DateTime lastPaymentDate = null;
-                final List<PaymentInfoEvent> payments = paymentApi.getPaymentInfo(invoiceIds);
-                if (payments != null) {
-                    for (final PaymentInfoEvent payment : payments) {
-                        // Use the last payment method/type/country as the default one for the account
-                        if (lastPaymentDate == null || payment.getCreatedDate().isAfter(lastPaymentDate)) {
-                            lastPaymentDate = payment.getCreatedDate();
-
-                            lastPaymentStatus = payment.getStatus();
-                            paymentMethod = payment.getPaymentMethod();
-                            creditCardType = payment.getCardType();
-                            billingAddressCountry = payment.getCardCountry();
-                        }
-                    }
+        DateTime lastInvoiceDate = null;
+        BigDecimal totalInvoiceBalance = BigDecimal.ZERO;
+        String lastPaymentStatus = null;
+        String paymentMethod = null;
+        String creditCardType = null;
+        String billingAddressCountry = null;
+
+        // Retrieve invoices information
+        final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId());
+        if (invoices != null && invoices.size() > 0) {
+            final List<String> invoiceIds = new ArrayList<String>();
+            for (final Invoice invoice : invoices) {
+                invoiceIds.add(invoice.getId().toString());
+                totalInvoiceBalance = totalInvoiceBalance.add(invoice.getBalance());
+
+                if (lastInvoiceDate == null || invoice.getInvoiceDate().isAfter(lastInvoiceDate)) {
+                    lastInvoiceDate = invoice.getInvoiceDate();
                 }
             }
 
-            bac.setLastPaymentStatus(lastPaymentStatus);
-            bac.setPaymentMethod(paymentMethod);
-            bac.setCreditCardType(creditCardType);
-            bac.setBillingAddressCountry(billingAddressCountry);
-            bac.setLastInvoiceDate(lastInvoiceDate);
-            bac.setTotalInvoiceBalance(totalInvoiceBalance);
-
-            bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
-        } catch (PaymentApiException e) {
-            log.error("Failed to update Business account", e);
+            // Retrieve payments information for these invoices
+            try {
+                final PaymentInfoEvent payment = paymentApi.getLastPaymentInfo(invoiceIds);
+
+                lastPaymentStatus = payment.getStatus();
+                paymentMethod = payment.getPaymentMethod();
+                creditCardType = payment.getCardType();
+                billingAddressCountry = payment.getCardCountry();
+
+                bac.setLastPaymentStatus(lastPaymentStatus);
+                bac.setPaymentMethod(paymentMethod);
+                bac.setCreditCardType(creditCardType);
+                bac.setBillingAddressCountry(billingAddressCountry);
+                bac.setLastInvoiceDate(lastInvoiceDate);
+                bac.setTotalInvoiceBalance(totalInvoiceBalance);
+
+                bac.setBalance(invoiceUserApi.getAccountBalance(account.getId()));
+            } catch (PaymentApiException ex) {
+                // TODO: handle this exception
+            }
         }
     }
 }
diff --git a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
index 441b064..8b00dff 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/BusinessSubscription.java
@@ -88,7 +88,7 @@ public class BusinessSubscription
      * want the phase start date).
      *
      * @param subscription Subscription to use as a model
-     * @param currency     Account currency
+     * @param currency     ACCOUNT currency
      */
     BusinessSubscription(final Subscription subscription, final Currency currency, Catalog catalog)
     {
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountBinder.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountBinder.java
index 6478536..b9da3fa 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountBinder.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountBinder.java
@@ -50,12 +50,12 @@ public @interface BusinessAccountBinder
                     final DateTime dateTimeNow = new DateTime(DateTimeZone.UTC);
 
                     if (account.getCreatedDt() != null) {
-                        q.bind("created_dt", account.getCreatedDt().getMillis());
+                        q.bind("created_date", account.getCreatedDt().getMillis());
                     }
                     else {
-                        q.bind("created_dt", dateTimeNow.getMillis());
+                        q.bind("created_date", dateTimeNow.getMillis());
                     }
-                    q.bind("updated_dt", dateTimeNow.getMillis());
+                    q.bind("updated_date", dateTimeNow.getMillis());
 
                     q.bind("account_key", account.getKey());
                     q.bind("balance", account.getRoundedBalance());
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountDao.sql.stg
index 55f03e8..10f27b8 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountDao.sql.stg
@@ -3,8 +3,8 @@ group BusinessAccount;
 getAccount(account_key) ::= <<
   select
     account_key
-  , created_dt
-  , updated_dt
+  , created_date
+  , updated_date
   , balance
   , tags
   , last_invoice_date
@@ -22,8 +22,8 @@ getAccount(account_key) ::= <<
 createAccount() ::= <<
   insert into bac(
     account_key
-  , created_dt
-  , updated_dt
+  , created_date
+  , updated_date
   , balance
   , tags
   , last_invoice_date
@@ -34,8 +34,8 @@ createAccount() ::= <<
   , billing_address_country
   ) values (
     :account_key
-  , :created_dt
-  , :updated_dt
+  , :created_date
+  , :updated_date
   , :balance
   , :tags
   , :last_invoice_date
@@ -49,7 +49,7 @@ createAccount() ::= <<
 
 saveAccount() ::= <<
   update bac set
-    updated_dt=:updated_dt
+    updated_date=:updated_date
   , balance=:balance
   , tags=:tags
   , last_invoice_date=:last_invoice_date
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
index 6489b12..7240236 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
+++ b/analytics/src/main/resources/com/ning/billing/analytics/ddl.sql
@@ -40,8 +40,8 @@ create index bst_key_index on bst (event_key, requested_timestamp asc);
 drop table if exists bac;
 create table bac (
   account_key varchar(50) not null
-, created_dt bigint not null
-, updated_dt bigint not null
+, created_date bigint not null
+, updated_date bigint not null
 , balance numeric(10, 4) default 0
 , tags varchar(500) default null
 , last_invoice_date bigint default null
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 b567464..1477dfa 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
@@ -26,13 +26,13 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
 import com.ning.billing.util.tag.TagDefinition;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -79,7 +79,6 @@ import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.DefaultInvoice;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
-import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentAttempt;
@@ -107,8 +106,8 @@ public class TestAnalyticsService {
     private static final String KEY = "12345";
     private static final String ACCOUNT_KEY = "pierre-12345";
     private static final Currency ACCOUNT_CURRENCY = Currency.EUR;
-    private static final DefaultTagDefinition TAG_ONE = new DefaultTagDefinition("batch20", "something");
-    private static final DefaultTagDefinition TAG_TWO = new DefaultTagDefinition("awesome", "something");
+    private static final DefaultTagDefinition TAG_ONE = new DefaultTagDefinition("batch20", "something", false);
+    private static final DefaultTagDefinition TAG_TWO = new DefaultTagDefinition("awesome", "something", false);
     private static final BigDecimal INVOICE_AMOUNT = BigDecimal.valueOf(1243.11);
     private static final String PAYMENT_METHOD = "Paypal";
     private static final String CARD_COUNTRY = "France";
@@ -266,7 +265,7 @@ public class TestAnalyticsService {
         final DefaultInvoice invoice = new DefaultInvoice(account.getId(), clock.getUTCNow(), clock.getUTCNow(), ACCOUNT_CURRENCY);
         final FixedPriceInvoiceItem invoiceItem = new FixedPriceInvoiceItem(
                 UUID.randomUUID(), invoice.getId(), account.getId(), UUID.randomUUID(), UUID.randomUUID(), "somePlan", "somePhase", clock.getUTCNow(), clock.getUTCNow().plusDays(1),
-                INVOICE_AMOUNT, ACCOUNT_CURRENCY, context.getUserName(), clock.getUTCNow());
+                INVOICE_AMOUNT, ACCOUNT_CURRENCY);
         invoice.addInvoiceItem(invoiceItem);
 
         invoiceDao.create(invoice, context);
@@ -278,12 +277,12 @@ public class TestAnalyticsService {
         invoiceCreationNotification = new DefaultInvoiceCreationEvent(invoice.getId(), account.getId(),
                 INVOICE_AMOUNT, ACCOUNT_CURRENCY, clock.getUTCNow(), null);
 
-        paymentInfoNotification = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
-        final PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice.getId(), account.getId(), BigDecimal.TEN,
-                ACCOUNT_CURRENCY, clock.getUTCNow(), clock.getUTCNow(), paymentInfoNotification.getPaymentId(), 1);
+        paymentInfoNotification = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID()).setPaymentMethod(PAYMENT_METHOD).setCardCountry(CARD_COUNTRY).build();
+        final PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice.getId(), account.getId(), BigDecimal.TEN,
+                ACCOUNT_CURRENCY, clock.getUTCNow(), clock.getUTCNow(), paymentInfoNotification.getId(), 1, null, null);
         paymentDao.createPaymentAttempt(paymentAttempt, context);
         paymentDao.savePaymentInfo(paymentInfoNotification, context);
-        Assert.assertEquals(paymentDao.getPaymentInfo(Arrays.asList(invoice.getId().toString())).size(), 1);
+        Assert.assertEquals(paymentDao.getPaymentInfoList(Arrays.asList(invoice.getId().toString())).size(), 1);
     }
 
     @AfterClass(groups = "slow")
diff --git a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
index 3e24a39..d8c856d 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/dao/TestAnalyticsDao.java
@@ -355,7 +355,7 @@ public class TestAnalyticsDao
         Assert.assertEquals("PayPal", account.getPaymentMethod());
         Assert.assertTrue(account.getUpdatedDt().compareTo(previousUpdatedDt) > 0);
 
-        // Account not found
+        // ACCOUNT not found
         Assert.assertNull(businessAccountDao.getAccount("Doesn't exist"));
     }
 }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
index 02dbb08..03a7767 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockAccount.java
@@ -19,8 +19,8 @@ package com.ning.billing.analytics;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.account.api.Account;
@@ -152,16 +152,6 @@ public class MockAccount implements Account
     }
 
     @Override
-    public String getCreatedBy() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public DateTime getCreatedDate() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public String getFieldValue(String fieldName) {
         throw new UnsupportedOperationException();
     }
@@ -202,7 +192,7 @@ public class MockAccount implements Account
     }
 
     @Override
-    public String getObjectName() {
+    public ObjectType getObjectType() {
         throw new UnsupportedOperationException();
     }
 
@@ -257,16 +247,6 @@ public class MockAccount implements Account
     }
 
     @Override
-    public String getUpdatedBy() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public DateTime getUpdatedDate() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public MutableAccountData toMutableAccountData() {
         throw new UnsupportedOperationException();
     }
diff --git a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
index cb786a0..1a72707 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/MockSubscription.java
@@ -19,6 +19,7 @@ package com.ning.billing.analytics;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -74,16 +75,6 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public String getCreatedBy() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public DateTime getCreatedDate() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public UUID getBundleId()
     {
         return BUNDLE_ID;
@@ -203,7 +194,7 @@ public class MockSubscription implements Subscription
     }
 
     @Override
-    public String getObjectName() {
+    public ObjectType getObjectType() {
         throw new UnsupportedOperationException();
     }
 
diff --git a/api/src/main/java/com/ning/billing/account/api/Account.java b/api/src/main/java/com/ning/billing/account/api/Account.java
index 6f2453e..1f7000d 100644
--- a/api/src/main/java/com/ning/billing/account/api/Account.java
+++ b/api/src/main/java/com/ning/billing/account/api/Account.java
@@ -21,8 +21,6 @@ import com.ning.billing.util.customfield.Customizable;
 import com.ning.billing.util.entity.UpdatableEntity;
 import com.ning.billing.util.tag.Taggable;
 
-public interface Account extends AccountData, Customizable, UpdatableEntity, Taggable, Blockable{ 
-    public static String ObjectType = "account";
-    
+public interface Account extends AccountData, Customizable, UpdatableEntity, Taggable, Blockable {
     public MutableAccountData toMutableAccountData(); 
 }
diff --git a/api/src/main/java/com/ning/billing/config/EntitlementConfig.java b/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
index c73530f..12418c6 100644
--- a/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
+++ b/api/src/main/java/com/ning/billing/config/EntitlementConfig.java
@@ -24,19 +24,9 @@ import com.google.common.annotations.VisibleForTesting;
 public interface EntitlementConfig extends NotificationConfig, KillbillConfig  {
 
 	@Override
-    @Config("killbill.entitlement.dao.claim.time")
-    @Default("60000")
-    public long getDaoClaimTimeMs();
-
-	@Override
-    @Config("killbill.entitlement.dao.ready.max")
-    @Default("10")
-    public int getDaoMaxReadyEvents();
-
-	@Override
     @Config("killbill.entitlement.engine.notifications.sleep")
     @Default("500")
-    public long getNotificationSleepTimeMs();
+    public long getSleepTimeMs();    
 
 	@Override
     @Config("killbill.notifications.off")
diff --git a/api/src/main/java/com/ning/billing/config/InvoiceConfig.java b/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
index 18972eb..407f4d3 100644
--- a/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
+++ b/api/src/main/java/com/ning/billing/config/InvoiceConfig.java
@@ -21,22 +21,12 @@ import org.skife.config.Default;
 
 public interface InvoiceConfig extends NotificationConfig, KillbillConfig  {
 
-	@Override
-    @Config("killbill.invoice.dao.claim.time")
-    @Default("60000")
-    public long getDaoClaimTimeMs();
-
-	@Override	
-    @Config("killbill.invoice.dao.ready.max")
-    @Default("10")
-    public int getDaoMaxReadyEvents();
-
-	@Override
+    @Override    
     @Config("killbill.invoice.engine.notifications.sleep")
     @Default("500")
-    public long getNotificationSleepTimeMs();
+    public long getSleepTimeMs();
 
-	@Override
+    @Override
     @Config("killbill.notifications.off")
     @Default("false")
     public boolean isNotificationProcessingOff();
diff --git a/api/src/main/java/com/ning/billing/config/NotificationConfig.java b/api/src/main/java/com/ning/billing/config/NotificationConfig.java
index 82f68b6..630a2d6 100644
--- a/api/src/main/java/com/ning/billing/config/NotificationConfig.java
+++ b/api/src/main/java/com/ning/billing/config/NotificationConfig.java
@@ -17,13 +17,6 @@
 package com.ning.billing.config;
 
 
-public interface NotificationConfig {
-
-    public long getDaoClaimTimeMs();
-
-    public int getDaoMaxReadyEvents();
-
-    public long getNotificationSleepTimeMs();
-
+public interface NotificationConfig extends PersistentQueueConfig {
     public boolean isNotificationProcessingOff();
 }
diff --git a/api/src/main/java/com/ning/billing/config/PaymentConfig.java b/api/src/main/java/com/ning/billing/config/PaymentConfig.java
index 599232c..f606039 100644
--- a/api/src/main/java/com/ning/billing/config/PaymentConfig.java
+++ b/api/src/main/java/com/ning/billing/config/PaymentConfig.java
@@ -35,19 +35,9 @@ public interface PaymentConfig extends NotificationConfig, KillbillConfig  {
     public List<Integer> getPaymentRetryDays();
 
 	@Override
-    @Config("killbill.payment.dao.claim.time")
-    @Default("60000")
-    public long getDaoClaimTimeMs();
-
-	@Override
-    @Config("killbill.payment.dao.ready.max")
-    @Default("10")
-    public int getDaoMaxReadyEvents();
-
-	@Override
     @Config("killbill.payment.engine.notifications.sleep")
     @Default("500")
-    public long getNotificationSleepTimeMs();
+    public long getSleepTimeMs();
 
 	@Override
     @Config("killbill.payment.engine.events.off")
diff --git a/api/src/main/java/com/ning/billing/config/PersistentQueueConfig.java b/api/src/main/java/com/ning/billing/config/PersistentQueueConfig.java
new file mode 100644
index 0000000..c7e1515
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/config/PersistentQueueConfig.java
@@ -0,0 +1,20 @@
+/* 
+ * Copyright 2010-2011 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.config;
+
+public interface PersistentQueueConfig {
+    public long getSleepTimeMs();
+}
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
index 7a5d7b7..fddb5e9 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionBundle.java
@@ -18,18 +18,17 @@ package com.ning.billing.entitlement.api.user;
 
 import java.util.UUID;
 
+import com.ning.billing.util.entity.Entity;
 import org.joda.time.DateTime;
 
 import com.ning.billing.junction.api.Blockable;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.overdue.OverdueState;
 
-public interface SubscriptionBundle extends Blockable {
+public interface SubscriptionBundle extends Blockable, Entity {
 
     public UUID getAccountId();
 
-    public UUID getId();
-
     public DateTime getStartDate();
 
     public String getKey();
diff --git a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
index 0cf30ab..cfa172a 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
@@ -25,8 +25,6 @@ import java.util.List;
 import java.util.UUID;
 
 public interface Invoice extends ExtendedEntity {
-    public static String ObjectType = "invoice";
-
     boolean addInvoiceItem(InvoiceItem item);
 
     boolean addInvoiceItems(List<InvoiceItem> items);
diff --git a/api/src/main/java/com/ning/billing/payment/api/Either.java b/api/src/main/java/com/ning/billing/payment/api/Either.java
index 25ce8f8..c71c5b1 100644
--- a/api/src/main/java/com/ning/billing/payment/api/Either.java
+++ b/api/src/main/java/com/ning/billing/payment/api/Either.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.payment.api;
 
+import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonValue;
 
 public abstract class Either<T, V> {
@@ -29,9 +30,12 @@ public abstract class Either<T, V> {
     private Either() {
     }
 
+    @JsonIgnore
     public boolean isLeft() {
         return false;
     }
+
+    @JsonIgnore
     public boolean isRight() {
         return false;
     }
@@ -49,6 +53,7 @@ public abstract class Either<T, V> {
             this.value = value;
         }
         @Override
+        @JsonIgnore
         public boolean isLeft() {
             return true;
         }
@@ -66,6 +71,7 @@ public abstract class Either<T, V> {
             this.value = value;
         }
         @Override
+        @JsonIgnore
         public boolean isRight() {
             return true;
         }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index c7b5965..b1bef23 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -65,10 +65,13 @@ public interface PaymentApi {
     public void updatePaymentProviderAccountContact(String accountKey, CallContext context)
         throws PaymentApiException;
 
-    public PaymentAttempt getPaymentAttemptForPaymentId(final String id)
+    public PaymentAttempt getPaymentAttemptForPaymentId(final UUID id)
         throws PaymentApiException;
 
-    public List<PaymentInfoEvent> getPaymentInfo(final List<String> invoiceIds)
+    public List<PaymentInfoEvent> getPaymentInfoList(final List<String> invoiceIds)
+        throws PaymentApiException;
+
+    public PaymentInfoEvent getLastPaymentInfo(final List<String> invoiceIds)
         throws PaymentApiException;
 
     public List<PaymentAttempt> getPaymentAttemptsForInvoiceId(final String invoiceId)
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
index 15ac4ee..a424fc6 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentAttempt.java
@@ -16,281 +16,31 @@
 
 package com.ning.billing.payment.api;
 
-import java.math.BigDecimal;
-import java.util.UUID;
-
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-
-import com.google.common.base.Objects;
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.Invoice;
-
-public class PaymentAttempt {
-    private final UUID paymentAttemptId;
-    private final UUID invoiceId;
-    private final UUID accountId;
-    private final BigDecimal amount;
-    private final Currency currency;
-    private final String paymentId;
-    private final DateTime invoiceDate;
-    private final DateTime paymentAttemptDate;
-    private final Integer retryCount;
-    private final DateTime createdDate;
-    private final DateTime updatedDate;
-
-    public PaymentAttempt(UUID paymentAttemptId,
-                          UUID invoiceId,
-                          UUID accountId,
-                          BigDecimal amount,
-                          Currency currency,
-                          DateTime invoiceDate,
-                          DateTime paymentAttemptDate,
-                          String paymentId,
-                          Integer retryCount,
-                          DateTime createdDate,
-                          DateTime updatedDate) {
-        this.paymentAttemptId = paymentAttemptId;
-        this.invoiceId = invoiceId;
-        this.accountId = accountId;
-        this.amount = amount;
-        this.currency = currency;
-        this.invoiceDate = invoiceDate;
-        this.paymentAttemptDate = paymentAttemptDate == null ? new DateTime(DateTimeZone.UTC) : paymentAttemptDate;
-        this.paymentId = paymentId;
-        this.retryCount = retryCount == null ? 0 : retryCount;
-        this.createdDate = createdDate;
-        this.updatedDate = updatedDate;
-    }
-
-    public PaymentAttempt(UUID paymentAttemptId,
-                          UUID invoiceId,
-                          UUID accountId,
-                          BigDecimal amount,
-                          Currency currency,
-                          DateTime invoiceDate,
-                          DateTime paymentAttemptDate,
-                          String paymentId,
-                          Integer retryCount) {
-        this(paymentAttemptId,
-             invoiceId,
-             accountId,
-             amount,
-             currency,
-             invoiceDate,
-             paymentAttemptDate,
-             paymentId,
-             retryCount,
-             null,
-             null);
-    }
-
-    public PaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, BigDecimal amount, Currency currency, DateTime invoiceDate, DateTime paymentAttemptDate) {
-        this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null, null);
-    }
-
-    public PaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, DateTime invoiceDate, DateTime paymentAttemptDate) {
-        this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null, null);
-    }
-
-    public PaymentAttempt(UUID paymentAttemptId, Invoice invoice) {
-        this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null, null, null);
-    }
-
-    public DateTime getInvoiceDate() {
-        return invoiceDate;
-    }
-
-    public UUID getPaymentAttemptId() {
-        return paymentAttemptId;
-    }
-
-    public String getPaymentId() {
-        return paymentId;
-    }
-
-    public DateTime getPaymentAttemptDate() {
-        return paymentAttemptDate;
-    }
-
-    public UUID getInvoiceId() {
-        return invoiceId;
-    }
-
-    public UUID getAccountId() {
-        return accountId;
-    }
-
-    public DateTime getCreatedDate() {
-        return createdDate;
-    }
-
-    public DateTime getUpdatedDate() {
-        return updatedDate;
-    }
-
-    public BigDecimal getAmount() {
-        return amount;
-    }
-
-    public Currency getCurrency() {
-        return currency;
-    }
-
-    public Integer getRetryCount() {
-        return retryCount;
-    }
-
-    @Override
-    public String toString() {
-        return "PaymentAttempt [paymentAttemptId=" + paymentAttemptId + ", invoiceId=" + invoiceId + ", accountId=" + accountId + ", amount=" + amount + ", currency=" + currency + ", paymentId=" + paymentId + ", invoiceDate=" + invoiceDate + ", paymentAttemptDate=" + paymentAttemptDate + ", retryCount=" + retryCount + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
-    }
-
-    public Builder cloner() {
-        return new Builder(this);
-    }
-
-    public static class Builder {
-        private UUID paymentAttemptId;
-        private UUID invoiceId;
-        private UUID accountId;
-        private BigDecimal amount;
-        private Currency currency;
-        private DateTime invoiceDate;
-        private DateTime paymentAttemptDate;
-        private String paymentId;
-        private Integer retryCount;
-        private DateTime createdDate;
-        private DateTime updatedDate;
-
-        public Builder() {
-        }
-
-        public Builder(PaymentAttempt src) {
-            this.paymentAttemptId = src.paymentAttemptId;
-            this.invoiceId = src.invoiceId;
-            this.accountId = src.accountId;
-            this.amount = src.amount;
-            this.currency = src.currency;
-            this.invoiceDate = src.invoiceDate;
-            this.paymentAttemptDate = src.paymentAttemptDate;
-            this.paymentId = src.paymentId;
-            this.retryCount = src.retryCount;
-            this.createdDate = src.createdDate;
-            this.updatedDate = src.updatedDate;
-        }
-
-        public Builder setPaymentAttemptId(UUID paymentAttemptId) {
-            this.paymentAttemptId = paymentAttemptId;
-            return this;
-        }
-
-        public Builder setInvoiceId(UUID invoiceId) {
-            this.invoiceId = invoiceId;
-            return this;
-        }
-
-        public Builder setAccountId(UUID accountId) {
-            this.accountId = accountId;
-            return this;
-        }
-
-        public Builder setAmount(BigDecimal amount) {
-            this.amount = amount;
-            return this;
-        }
-
-        public Builder setCurrency(Currency currency) {
-            this.currency = currency;
-            return this;
-        }
-
-        public Builder setCreatedDate(DateTime createdDate) {
-            this.createdDate = createdDate;
-            return this;
-        }
-
-        public Builder setUpdatedDate(DateTime updatedDate) {
-            this.updatedDate = updatedDate;
-            return this;
-        }
-
-        public Builder setInvoiceDate(DateTime invoiceDate) {
-            this.invoiceDate = invoiceDate;
-            return this;
-        }
+import com.ning.billing.util.entity.Entity;
+import org.joda.time.DateTime;
 
-        public Builder setPaymentAttemptDate(DateTime paymentAttemptDate) {
-            this.paymentAttemptDate = paymentAttemptDate;
-            return this;
-        }
+import java.math.BigDecimal;
+import java.util.UUID;
 
-        public Builder setPaymentId(String paymentId) {
-            this.paymentId = paymentId;
-            return this;
-        }
+public interface PaymentAttempt extends Entity {
+    DateTime getInvoiceDate();
 
-        public Builder setRetryCount(Integer retryCount) {
-            this.retryCount = retryCount;
-            return this;
-        }
+    UUID getPaymentId();
 
-        public PaymentAttempt build() {
-            return new PaymentAttempt(paymentAttemptId,
-                                      invoiceId,
-                                      accountId,
-                                      amount,
-                                      currency,
-                                      invoiceDate,
-                                      paymentAttemptDate,
-                                      paymentId,
-                                      retryCount,
-                                      createdDate,
-                                      updatedDate);
-        }
+    DateTime getPaymentAttemptDate();
 
-    }
+    UUID getInvoiceId();
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(paymentAttemptId,
-                                invoiceId,
-                                accountId,
-                                amount,
-                                currency,
-                                invoiceDate,
-                                paymentAttemptDate,
-                                paymentId,
-                                retryCount,
-                                createdDate,
-                                updatedDate);
-    }
+    UUID getAccountId();
 
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+    BigDecimal getAmount();
 
-        final PaymentAttempt that = (PaymentAttempt) o;
+    Currency getCurrency();
 
-        if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) return false;
-        if (amount != null ? !(amount.compareTo(that.amount) == 0) : that.amount != null) return false;
-        if (createdDate != null ? !(getUnixTimestamp(createdDate) == getUnixTimestamp(that.createdDate)) : that.createdDate != null) return false;
-        if (currency != that.currency) return false;
-        if (invoiceDate != null ? !(getUnixTimestamp(invoiceDate) == getUnixTimestamp(that.invoiceDate)) : that.invoiceDate != null) return false;
-        if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) return false;
-        if (paymentAttemptDate != null ? !(getUnixTimestamp(paymentAttemptDate) == getUnixTimestamp(that.paymentAttemptDate)) : that.paymentAttemptDate != null)
-            return false;
-        if (paymentAttemptId != null ? !paymentAttemptId.equals(that.paymentAttemptId) : that.paymentAttemptId != null)
-            return false;
-        if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) return false;
-        if (retryCount != null ? !retryCount.equals(that.retryCount) : that.retryCount != null) return false;
-        if (updatedDate != null ? !(getUnixTimestamp(updatedDate) == getUnixTimestamp(that.updatedDate)) : that.updatedDate != null) return false;
+    Integer getRetryCount();
 
-        return true;
-    }
+    DateTime getCreatedDate();
 
-    private static long getUnixTimestamp(final DateTime dateTime) {
-        return dateTime.getMillis() / 1000;
-    }
+    DateTime getUpdatedDate();
 }
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
index a93b3bb..c4cabb9 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentInfoEvent.java
@@ -16,20 +16,17 @@
 package com.ning.billing.payment.api;
 
 import java.math.BigDecimal;
+
+import com.ning.billing.util.entity.Entity;
 import org.joda.time.DateTime;
 
 import com.ning.billing.util.bus.BusEvent;
 
-public interface PaymentInfoEvent extends BusEvent {
-
-    public String getPaymentId();
-
+public interface PaymentInfoEvent extends Entity, BusEvent {
     public BigDecimal getAmount();
 
     public String getBankIdentificationNumber();
 
-    public DateTime getCreatedDate();
-
     public DateTime getEffectiveDate();
 
     public String getPaymentNumber();
@@ -49,6 +46,4 @@ public interface PaymentInfoEvent extends BusEvent {
     public String getStatus();
 
     public String getType();
-
-    public DateTime getUpdatedDate();
 }
diff --git a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
index 5d05bb0..2ecd93d 100644
--- a/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
+++ b/api/src/main/java/com/ning/billing/util/api/TagUserApi.java
@@ -17,13 +17,15 @@
 package com.ning.billing.util.api;
 
 import java.util.List;
+import java.util.UUID;
 
 import com.ning.billing.util.callcontext.CallContext;
-import org.joda.time.DateTime;
 
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
 
+// TODO: add ability to create, update and remove tags
 public interface TagUserApi {
     /***
      *
@@ -33,13 +35,13 @@ public interface TagUserApi {
 
     /***
      *
-     * @param name Identifies the definition.
+     * @param definitionName Identifies the definition.
      * @param description Describes the use of the definition.
      * @param context The call context, for auditing purposes
      * @return the newly created tag definition
      * @throws TagDefinitionApiException
      */
-    public TagDefinition create(String name, String description, CallContext context) throws TagDefinitionApiException;
+    public TagDefinition create(String definitionName, String description, CallContext context) throws TagDefinitionApiException;
 
     /***
      *
@@ -64,18 +66,12 @@ public interface TagUserApi {
      * @throws TagDefinitionApiException
 	 */
 	public TagDefinition getTagDefinition(String name) throws TagDefinitionApiException;
-	
-	/**
-	 * @param controlTagName
-	 * @throws TagDefinitionApiException
-	 */
-	public Tag createControlTag(String controlTagName) throws TagDefinitionApiException;
-	
-	
-	/**
-	 * @param tagDefinitionName
-	 * @return
-	 */
-	public Tag createDescriptiveTag(String tagDefinitionName) throws TagDefinitionApiException;
-	
+
+	public List<Tag> createControlTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions) throws TagDefinitionApiException;
+
+    public Tag createControlTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition) throws TagDefinitionApiException;
+
+	public List<Tag> createDescriptiveTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions) throws TagDefinitionApiException;
+
+	public Tag createDescriptiveTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition) throws TagDefinitionApiException;
 }
diff --git a/api/src/main/java/com/ning/billing/util/customfield/Customizable.java b/api/src/main/java/com/ning/billing/util/customfield/Customizable.java
index daf549c..e43ed82 100644
--- a/api/src/main/java/com/ning/billing/util/customfield/Customizable.java
+++ b/api/src/main/java/com/ning/billing/util/customfield/Customizable.java
@@ -19,6 +19,7 @@ package com.ning.billing.util.customfield;
 import java.util.List;
 
 import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.entity.Entity;
 
 public interface Customizable {
@@ -38,5 +39,5 @@ public interface Customizable {
 
     public void clearPersistedFields(CallContext context);
 
-    public String getObjectName();
+    public ObjectType getObjectType();
 }
diff --git a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
new file mode 100644
index 0000000..18d987c
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 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;
+
+public enum ObjectType {
+    ACCOUNT("account"),
+    ACCOUNT_EMAIL("account email"),
+    BUNDLE("subscription bundle"),
+    INVOICE("invoice"),
+    RECURRING_INVOICE_ITEM("recurring_invoice_item"),
+    SUBSCRIPTION("subscription");
+
+    private final String objectName;
+    ObjectType(String objectName) {
+        this.objectName = objectName;
+    }
+
+    public String getObjectName() {
+        return objectName;
+    }
+}
diff --git a/api/src/main/java/com/ning/billing/util/entity/Entity.java b/api/src/main/java/com/ning/billing/util/entity/Entity.java
index 3369538..f363534 100644
--- a/api/src/main/java/com/ning/billing/util/entity/Entity.java
+++ b/api/src/main/java/com/ning/billing/util/entity/Entity.java
@@ -16,12 +16,8 @@
 
 package com.ning.billing.util.entity;
 
-import org.joda.time.DateTime;
-
 import java.util.UUID;
 
-public interface Entity<T> {
+public interface Entity {
     public UUID getId();
-    public String getCreatedBy();
-    public DateTime getCreatedDate();
 }
diff --git a/api/src/main/java/com/ning/billing/util/entity/UpdatableEntity.java b/api/src/main/java/com/ning/billing/util/entity/UpdatableEntity.java
index c860ddb..758d7dc 100644
--- a/api/src/main/java/com/ning/billing/util/entity/UpdatableEntity.java
+++ b/api/src/main/java/com/ning/billing/util/entity/UpdatableEntity.java
@@ -16,9 +16,5 @@
 
 package com.ning.billing.util.entity;
 
-import org.joda.time.DateTime;
-
 public interface UpdatableEntity extends Entity {
-    public String getUpdatedBy();
-    public DateTime getUpdatedDate();
 }
diff --git a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
index 408e09d..d35e011 100644
--- a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
+++ b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
@@ -18,8 +18,11 @@ package com.ning.billing.util.tag;
 
 import com.ning.billing.util.entity.Entity;
 
+// TODO: needs to surface created date, created by, isControlTag
 public interface TagDefinition extends Entity {
     String getName();
 
     String getDescription();
+
+    Boolean isControlTag();
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
index 3bb0bc6..4f9fb3d 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/overdue/TestOverdueIntegration.java
@@ -40,7 +40,7 @@ import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.api.TestApiListener.NextEvent;
-import com.ning.billing.beatrix.integration.MockModule;
+import com.ning.billing.beatrix.integration.BeatrixModule;
 import com.ning.billing.beatrix.integration.TestIntegrationBase;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -61,7 +61,7 @@ import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.config.XMLLoader;
 
 @Test(groups = "slow")
-@Guice(modules = {MockModule.class})
+@Guice(modules = {BeatrixModule.class})
 public class TestOverdueIntegration extends TestIntegrationBase {
     private final String configXml =  
             "<overdueConfig>" +
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java
index 538f3dd..d444776 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/PaymentTestModule.java
@@ -16,15 +16,15 @@
 
 package com.ning.billing.beatrix.integration.payment;
 
+import com.ning.billing.account.dao.MockAccountDao;
+import com.ning.billing.invoice.dao.MockInvoiceDao;
 import org.apache.commons.collections.MapUtils;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.inject.Provider;
 import com.ning.billing.account.dao.AccountDao;
-import com.ning.billing.account.dao.MockAccountDao;
 import com.ning.billing.config.PaymentConfig;
 import com.ning.billing.invoice.dao.InvoiceDao;
-import com.ning.billing.invoice.dao.MockInvoiceDao;
 import com.ning.billing.junction.api.BillingApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.payment.dao.MockPaymentDao;
@@ -45,7 +45,6 @@ public class PaymentTestModule extends PaymentModule {
 
 	}
 
-
     public PaymentTestModule() {
         super(MapUtils.toProperties(ImmutableMap.of("killbill.payment.provider.default", "my-mock",
                 "killbill.payment.engine.events.off", "false")));
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java
index 24c8042..753b966 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestHelper.java
@@ -19,6 +19,7 @@ package com.ning.billing.beatrix.integration.payment;
 import java.math.BigDecimal;
 import java.util.UUID;
 
+import com.ning.billing.mock.BrainDeadProxyFactory;
 import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -26,7 +27,6 @@ import org.joda.time.DateTimeZone;
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.account.api.user.AccountBuilder;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
@@ -49,42 +49,44 @@ public class TestHelper {
     public TestHelper(CallContextFactory factory, AccountUserApi accountUserApi, InvoiceTestApi invoiceTestApi) {
         this.accountUserApi = accountUserApi;
         this.invoiceTestApi = invoiceTestApi;
-        context = factory.createCallContext("Princess Buttercup", CallOrigin.TEST, UserType.TEST);
+        context = factory.createCallContext("Payment Test", CallOrigin.TEST, UserType.TEST);
     }
 
     // These helper methods can be overridden in a plugin implementation
     public Account createTestCreditCardAccount() throws EntityPersistenceException {
-        final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
-        final String externalKey = RandomStringUtils.randomAlphanumeric(10);
-        final Account account = new AccountBuilder(UUID.randomUUID()).name(name)
-                                                                     .firstNameLength(name.length())
-                                                                     .externalKey(externalKey)
-                                                                     .phone("123-456-7890")
-                                                                     .email("ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com")
-                                                                     .currency(Currency.USD)
-                                                                     .billingCycleDay(1)
-                                                                     .build();
+        String email = "ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com";
+        final Account account = createTestAccount(email);
+
         ((ZombieControl)accountUserApi).addResult("getAccountById", account);
         ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
         return account;
     }
 
     public Account createTestPayPalAccount() throws EntityPersistenceException {
-        final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
-        final String externalKey = RandomStringUtils.randomAlphanumeric(10);
-        final Account account = new AccountBuilder(UUID.randomUUID()).name(name)
-                                                                     .firstNameLength(name.length())
-                                                                     .externalKey(externalKey)
-                                                                     .phone("123-456-7890")
-                                                                     .email("ppuser@example.com")
-                                                                     .currency(Currency.USD)
-                                                                     .billingCycleDay(1)
-                                                                     .build();
+        final Account account = createTestAccount("ppuser@example.com");
         ((ZombieControl)accountUserApi).addResult("getAccountById", account);
         ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
         return account;
     }
 
+    private Account createTestAccount(String email) {
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ZombieControl zombie = (ZombieControl) account;
+        zombie.addResult("getId", UUID.randomUUID());
+        String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
+        zombie.addResult("getName", name);
+        zombie.addResult("getFirstNameLength", 10);
+        String externalKey = RandomStringUtils.randomAlphanumeric(10);
+        zombie.addResult("getExternalKey", externalKey);
+        zombie.addResult("getPhone", "123-456-7890");
+        zombie.addResult("getEmail", email);
+        zombie.addResult("getCurrency", Currency.USD);
+        zombie.addResult("getBillCycleDay", 1);
+        zombie.addResult("getPaymentProviderName", "");
+
+        return account;
+    }
+
     public Invoice createTestInvoice(Account account,
                                      DateTime targetDate,
                                      Currency currency,
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestNotifyInvoicePaymentApi.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestNotifyInvoicePaymentApi.java
index d7febde..2b72204 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestNotifyInvoicePaymentApi.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestNotifyInvoicePaymentApi.java
@@ -20,6 +20,7 @@ import static org.testng.Assert.assertNotNull;
 
 import java.util.UUID;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
@@ -40,7 +41,6 @@ import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.mock.glue.MockJunctionModule;
 import com.ning.billing.payment.RequestProcessor;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
 import com.ning.billing.util.callcontext.CallContext;
@@ -85,16 +85,16 @@ public class TestNotifyInvoicePaymentApi {
         final Account account = testHelper.createTestCreditCardAccount();
         final Invoice invoice = testHelper.createTestInvoice(account);
 
-        PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
+        PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice);
 
         invoicePaymentApi.notifyOfPaymentAttempt(invoice.getId(),
                                      invoice.getBalance(),
                                      invoice.getCurrency(),
-                                     paymentAttempt.getPaymentAttemptId(),
+                                     paymentAttempt.getId(),
                                      paymentAttempt.getPaymentAttemptDate(),
                                      context);
 
-        InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getPaymentAttemptId());
+        InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getId());
 
         assertNotNull(invoicePayment);
     }
@@ -104,13 +104,13 @@ public class TestNotifyInvoicePaymentApi {
         final Account account = testHelper.createTestCreditCardAccount();
         final Invoice invoice = testHelper.createTestInvoice(account);
 
-        PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
+        PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice);
         invoicePaymentApi.notifyOfPaymentAttempt(invoice.getId(),
-                                                 paymentAttempt.getPaymentAttemptId(),
+                                                 paymentAttempt.getId(),
                                                  paymentAttempt.getPaymentAttemptDate(),
                                                  context);
 
-        InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getPaymentAttemptId());
+        InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getId());
 
         assertNotNull(invoicePayment);
     }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java
index 32a7157..9ac8a6b 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/payment/TestPaymentInvoiceIntegration.java
@@ -104,7 +104,7 @@ public class TestPaymentInvoiceIntegration {
                                                  new MockJunctionModule(),
                                                  new AbstractModule()
                                             
-                                                  {
+                                                 {
                                                     @Override
                                                     protected void configure() {
                                                         bind(IDBI.class).toInstance(dbi);
@@ -147,10 +147,10 @@ public class TestPaymentInvoiceIntegration {
         assertTrue(paymentInfoReceiver.getErrors().isEmpty());
 
         List<PaymentInfoEvent> payments = paymentInfoReceiver.getProcessedPayments();
-        PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(payments.get(0).getPaymentId());
+        PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(payments.get(0).getId());
         Assert.assertNotNull(paymentAttempt);
 
-        Invoice invoiceForPayment = invoicePaymentApi.getInvoiceForPaymentAttemptId(paymentAttempt.getPaymentAttemptId());
+        Invoice invoiceForPayment = invoicePaymentApi.getInvoiceForPaymentAttemptId(paymentAttempt.getId());
 
         Assert.assertNotNull(invoiceForPayment);
         Assert.assertEquals(invoiceForPayment.getId(), invoice.getId());
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index c936a52..51f5820 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -45,7 +45,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.invoice.api.Invoice;
 
 @Test(groups = "slow")
-@Guice(modules = {MockModule.class})
+@Guice(modules = {BeatrixModule.class})
 public class TestIntegration extends TestIntegrationBase {
     @Test(groups = "slow", enabled = true)
     public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 54b17a3..78e37d0 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -30,10 +30,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.TransactionCallback;
-import org.skife.jdbi.v2.TransactionStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -49,7 +46,6 @@ import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.api.TestApiListener;
 import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
-import com.ning.billing.catalog.DefaultCatalogService;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.EntitlementService;
@@ -58,7 +54,6 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceService;
@@ -85,7 +80,8 @@ public class TestIntegrationBase implements TestListenerStatus {
     protected static final Logger log = LoggerFactory.getLogger(TestIntegration.class);
     protected static long AT_LEAST_ONE_MONTH_MS =  31L * 24L * 3600L * 1000L;
 
-    protected static final long DELAY = 20000; //MDW Note fixed test by increasing the delay from 10000
+
+    protected static final long DELAY = 5000;
 
     @Inject
     protected IDBI dbi;
@@ -300,7 +296,7 @@ public class TestIntegrationBase implements TestListenerStatus {
             }
             @Override
             public String getPaymentProviderName() {
-                return MockModule.PLUGIN_NAME;
+                return BeatrixModule.PLUGIN_NAME;
             }
 
             @Override
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
index 2203f41..fe6f8a8 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -50,7 +50,7 @@ import com.ning.billing.entitlement.api.user.SubscriptionEvents;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 
 @Test(groups = "slow")
-@Guice(modules = {MockModule.class})
+@Guice(modules = {BeatrixModule.class})
 public class TestRepairIntegration extends TestIntegrationBase {
 
     
diff --git a/beatrix/src/test/resources/resource.properties b/beatrix/src/test/resources/resource.properties
index d63334b..a2c4ec1 100644
--- a/beatrix/src/test/resources/resource.properties
+++ b/beatrix/src/test/resources/resource.properties
@@ -1,7 +1,11 @@
 killbill.catalog.uri=file:src/test/resources/catalogSample.xml
 killbill.entitlement.dao.claim.time=60000
 killbill.entitlement.dao.ready.max=1
-killbill.entitlement.engine.notifications.sleep=500
+killbill.payment.engine.notifications.sleep=100
+killbill.invoice.engine.notifications.sleep=100
+killbill.entitlement.engine.notifications.sleep=100
+killbill.billing.util.persistent.bus.sleep=100
+killbill.billing.util.persistent.bus.nbThreads=1
 user.timezone=UTC
 
 
diff --git a/catalog/src/test/java/com/ning/billing/catalog/TestPlanPhase.java b/catalog/src/test/java/com/ning/billing/catalog/TestPlanPhase.java
index e25ac82..bee4e3d 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/TestPlanPhase.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/TestPlanPhase.java
@@ -58,23 +58,23 @@ public class TestPlanPhase {
 		DefaultPlanPhase ppDiscount = MockPlanPhase.create1USDMonthlyEvergreen().setPhaseType(PhaseType.DISCOUNT).setPlan(p);
 		DefaultPlanPhase ppTrial = MockPlanPhase.create30DayTrial().setPhaseType(PhaseType.TRIAL).setPlan(p);
 		DefaultPlanPhase ppEvergreen = MockPlanPhase.create1USDMonthlyEvergreen().setPhaseType(PhaseType.EVERGREEN).setPlan(p);
-		DefaultPlanPhase ppFixedterm = MockPlanPhase.create1USDMonthlyEvergreen().setPhaseType(PhaseType.FIXEDTERM).setPlan(p);
+		DefaultPlanPhase ppFixedTerm = MockPlanPhase.create1USDMonthlyEvergreen().setPhaseType(PhaseType.FIXEDTERM).setPlan(p);
 		
 		String ppnDiscount = DefaultPlanPhase.phaseName(p.getName(), ppDiscount.getPhaseType());
 		String ppnTrial = DefaultPlanPhase.phaseName(p.getName(), ppTrial.getPhaseType());
 		String ppnEvergreen = DefaultPlanPhase.phaseName(p.getName(), ppEvergreen.getPhaseType());
-		String ppnFixedterm = DefaultPlanPhase.phaseName(p.getName(), ppFixedterm.getPhaseType());
+		String ppnFixedTerm = DefaultPlanPhase.phaseName(p.getName(), ppFixedTerm.getPhaseType());
 		
 		Assert.assertEquals(ppnTrial, planNameExt + "trial");
 		Assert.assertEquals(ppnEvergreen, planNameExt + "evergreen");
-		Assert.assertEquals(ppnFixedterm, planNameExt + "fixedterm");
+		Assert.assertEquals(ppnFixedTerm, planNameExt + "fixedterm");
 		Assert.assertEquals(ppnDiscount, planNameExt + "discount");
 		
 		
 		Assert.assertEquals(DefaultPlanPhase.planName(ppnDiscount),planName);
 		Assert.assertEquals(DefaultPlanPhase.planName(ppnTrial),planName);
 		Assert.assertEquals(DefaultPlanPhase.planName(ppnEvergreen), planName);
-		Assert.assertEquals(DefaultPlanPhase.planName(ppnFixedterm), planName);
+		Assert.assertEquals(DefaultPlanPhase.planName(ppnFixedTerm), planName);
 		
 		
 		
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
index ae3cde0..0e44528 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/PlanAligner.java
@@ -21,7 +21,6 @@ import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.*;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.DefaultClock;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
index 1c3cfc5..21b97f8 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
@@ -19,28 +19,20 @@ package com.ning.billing.entitlement.api.billing;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
-import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallContextFactory;
 
 public class DefaultChargeThruApi implements ChargeThruApi {
-
-    private static final Logger log = LoggerFactory.getLogger(DefaultChargeThruApi.class);
-
     private final EntitlementDao entitlementDao;
     private final SubscriptionFactory subscriptionFactory;
   
-
     @Inject
-    public DefaultChargeThruApi(final CallContextFactory factory, final SubscriptionFactory subscriptionFactory, final EntitlementDao dao, final AccountUserApi accountApi) {
+    public DefaultChargeThruApi(final SubscriptionFactory subscriptionFactory, final EntitlementDao dao) {
         super();
         this.subscriptionFactory = subscriptionFactory;
         this.entitlementDao = dao;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
index ab01dff..9f73725 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultEntitlementTimelineApi.java
@@ -18,11 +18,9 @@ package com.ning.billing.entitlement.api.timeline;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.UUID;
@@ -34,27 +32,18 @@ import com.google.inject.name.Named;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
-import com.ning.billing.catalog.api.CatalogUserApi;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionBundleData;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
 import com.ning.billing.entitlement.events.EntitlementEvent;
-import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
-import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
 import com.ning.billing.util.callcontext.CallContext;
 
@@ -350,7 +339,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             if (firstBPDeletedTime != null && 
                     ! cur.getEffectiveDate().isBefore(firstBPDeletedTime) &&
                     ! foundDeletedEvent) {
-                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_MISSING_AO_DELETE_EVENT, cur.getId(), data.getId());                
+                throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_MISSING_AO_DELETE_EVENT, cur.getId(), data.getId());
             }
 
             if (nbDeleted == 0) {
@@ -404,7 +393,7 @@ public class DefaultEntitlementTimelineApi implements EntitlementTimelineApi {
             }
             @Override
             public String getExternalKey() {
-                return null;
+                return externalKey;
             }
         };
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
index 315550d..4080326 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/DefaultSubscriptionTimeline.java
@@ -32,7 +32,6 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.events.phase.PhaseEvent;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
index 75574d3..7f526d4 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/timeline/SubscriptionDataRepair.java
@@ -17,11 +17,9 @@ package com.ning.billing.entitlement.api.timeline;
 
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 
 import org.joda.time.DateTime;
-import org.omg.CORBA.Request;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
@@ -35,10 +33,8 @@ import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionApiService;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.entitlement.api.user.SubscriptionEvent;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
 import com.ning.billing.entitlement.api.user.SubscriptionTransitionData;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
index b8745fe..7d92852 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultEntitlementUserApi.java
@@ -24,7 +24,6 @@ import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
-import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Catalog;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.CatalogService;
@@ -32,7 +31,6 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
-import com.ning.billing.catalog.api.Product;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
index 0f2db75..44ed086 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionApiService.java
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.api.user;
 
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
 
 import org.joda.time.DateTime;
@@ -37,7 +36,6 @@ import com.ning.billing.catalog.api.PlanSpecifier;
 import com.ning.billing.catalog.api.PriceList;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.Product;
-import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.alignment.PlanAligner;
 import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.SubscriptionApiService;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
index eb59d38..37a94f6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/DefaultSubscriptionFactory.java
@@ -21,7 +21,6 @@ import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionApiService;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
-import com.ning.billing.entitlement.api.timeline.SubscriptionDataRepair;
 import com.ning.billing.entitlement.events.EntitlementEvent;
 import com.ning.billing.entitlement.exceptions.EntitlementError;
 import com.ning.billing.util.clock.Clock;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index 0bc6bb9..815410a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -24,7 +24,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.dao.ObjectType;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -94,7 +94,7 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
 
     public SubscriptionData(SubscriptionBuilder builder,
             @Nullable SubscriptionApiService apiService, @Nullable Clock clock) {
-        super(builder.getId(), null, null);
+        super(builder.getId());
         this.apiService = apiService;
         this.clock = clock;
         this.bundleId = builder.getBundleId();
@@ -107,8 +107,8 @@ public class SubscriptionData extends ExtendedEntityBase implements Subscription
     }
 
     @Override
-    public String getObjectName() {
-        return "Subscription";
+    public ObjectType getObjectType() {
+        return ObjectType.SUBSCRIPTION;
     }
 
     @Override
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index c8f82a2..344f47e 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -30,8 +30,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 
-import com.google.inject.name.Named;
-
 
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.Product;
@@ -135,21 +133,15 @@ public class Engine implements EventListener, EntitlementService {
                 }
             },
             new NotificationConfig() {
+                
                 @Override
-                public boolean isNotificationProcessingOff() {
-                    return config.isNotificationProcessingOff();
-                }
-                @Override
-                public long getNotificationSleepTimeMs() {
-                    return config.getNotificationSleepTimeMs();
-                }
-                @Override
-                public int getDaoMaxReadyEvents() {
-                    return config.getDaoMaxReadyEvents();
+                public long getSleepTimeMs() {
+                    return config.getSleepTimeMs();
                 }
+                
                 @Override
-                public long getDaoClaimTimeMs() {
-                    return config.getDaoClaimTimeMs();
+                public boolean isNotificationProcessingOff() {
+                    return config.isNotificationProcessingOff();
                 }
             });
         } catch (NotificationQueueAlreadyExists e) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
index 5af5294..b6becbb 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/BundleSqlDao.java
@@ -22,6 +22,8 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -45,14 +47,15 @@ import com.ning.billing.util.dao.MapperBase;
 
 
 @ExternalizedSqlViaStringTemplate3()
-public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Transmogrifier {
+public interface BundleSqlDao extends Transactional<BundleSqlDao>, EntitySqlDao<SubscriptionBundle>,
+                                      AuditSqlDao, CloseMe, Transmogrifier {
 
     @SqlUpdate
     public void insertBundle(@Bind(binder = SubscriptionBundleBinder.class) SubscriptionBundleData bundle,
                              @CallContextBinder final CallContext context);
 
     @SqlUpdate
-    public void updateBundleLastSysTime(@Bind("id") String id, @Bind("last_sys_update_dt") Date lastSysUpdate);
+    public void updateBundleLastSysTime(@Bind("id") String id, @Bind("lastSysUpdateDate") Date lastSysUpdate);
     
     @SqlQuery
     @Mapper(ISubscriptionBundleSqlMapper.class)
@@ -60,20 +63,20 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Tran
 
     @SqlQuery
     @Mapper(ISubscriptionBundleSqlMapper.class)
-    public SubscriptionBundle getBundleFromKey(@Bind("external_key") String externalKey);
+    public SubscriptionBundle getBundleFromKey(@Bind("externalKey") String externalKey);
 
     @SqlQuery
     @Mapper(ISubscriptionBundleSqlMapper.class)
-    public List<SubscriptionBundle> getBundleFromAccount(@Bind("account_id") String accountId);
+    public List<SubscriptionBundle> getBundleFromAccount(@Bind("accountId") String accountId);
 
     public static class SubscriptionBundleBinder extends BinderBase implements Binder<Bind, SubscriptionBundleData> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, SubscriptionBundleData bundle) {
             stmt.bind("id", bundle.getId().toString());
-            stmt.bind("start_dt", getDate(bundle.getStartDate()));
-            stmt.bind("external_key", bundle.getKey());
-            stmt.bind("account_id", bundle.getAccountId().toString());
-            stmt.bind("last_sys_update_dt", getDate(bundle.getLastSysUpdateTime()));            
+            stmt.bind("startDate", getDate(bundle.getStartDate()));
+            stmt.bind("externalKey", bundle.getKey());
+            stmt.bind("accountId", bundle.getAccountId().toString());
+            stmt.bind("lastSysUpdateDate", getDate(bundle.getLastSysUpdateTime()));
         }
     }
 
@@ -85,8 +88,8 @@ public interface BundleSqlDao extends Transactional<BundleSqlDao>, CloseMe, Tran
             UUID id = UUID.fromString(r.getString("id"));
             String key = r.getString("external_key");
             UUID accountId = UUID.fromString(r.getString("account_id"));
-            DateTime startDate = getDate(r, "start_dt");
-            DateTime lastSysUpdateDate = getDate(r, "last_sys_update_dt");
+            DateTime startDate = getDate(r, "start_date");
+            DateTime lastSysUpdateDate = getDate(r, "last_sys_update_date");
             SubscriptionBundleData bundle = new SubscriptionBundleData(id, key, accountId, startDate, lastSysUpdateDate);
             return bundle;
         }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index fd897f6..5e95c88 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -43,7 +43,7 @@ public interface EntitlementDao {
 
     public Subscription getSubscriptionFromId(final SubscriptionFactory factory, final UUID subscriptionId);
 
-    // Account retrieval
+    // ACCOUNT retrieval
     public UUID getAccountIdFromSubscriptionId(final UUID subscriptionId);
 
     // Subscription retrieval
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
index 92c37db..a43117d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.java
@@ -20,6 +20,7 @@ import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.api.user.DefaultSubscriptionFactory.SubscriptionBuilder;
+import com.ning.billing.util.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.dao.BinderBase;
@@ -45,7 +46,7 @@ import java.util.List;
 import java.util.UUID;
 
 @ExternalizedSqlViaStringTemplate3()
-public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, CloseMe, Transmogrifier {
+public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, AuditSqlDao, CloseMe, Transmogrifier {
 	@SqlUpdate
     public void insertSubscription(@Bind(binder = SubscriptionBinder.class) SubscriptionData sub,
                                    @CallContextBinder final CallContext context);
@@ -56,32 +57,32 @@ public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, C
 
     @SqlQuery
     @Mapper(SubscriptionMapper.class)
-    public List<Subscription> getSubscriptionsFromBundleId(@Bind("bundle_id") String bundleId);
+    public List<Subscription> getSubscriptionsFromBundleId(@Bind("bundleId") String bundleId);
 
     @SqlUpdate
-    public void updateChargedThroughDate(@Bind("id") String id, @Bind("ctd_dt") Date ctd,
-                                   @CallContextBinder final CallContext context);
+    public void updateChargedThroughDate(@Bind("id") String id, @Bind("chargedThroughDate") Date chargedThroughDate,
+                                        @CallContextBinder final CallContext context);
 
-    @SqlUpdate void updateActiveVersion(@Bind("id") String id, @Bind("active_version") long activeVersion,
+    @SqlUpdate void updateActiveVersion(@Bind("id") String id, @Bind("activeVersion") long activeVersion,
             @CallContextBinder final CallContext context);
     
     @SqlUpdate
-    public void updateForRepair(@Bind("id") String id, @Bind("active_version") long activeVersion,
-            @Bind("start_dt") Date startDate,
-            @Bind("bundle_start_dt") Date bundleStartDate,
+    public void updateForRepair(@Bind("id") String id, @Bind("activeVersion") long activeVersion,
+            @Bind("startDate") Date startDate,
+            @Bind("bundleStartDate") Date bundleStartDate,
             @CallContextBinder final CallContext context);
 
     public static class SubscriptionBinder extends BinderBase implements Binder<Bind, SubscriptionData> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, SubscriptionData sub) {
             stmt.bind("id", sub.getId().toString());
-            stmt.bind("bundle_id", sub.getBundleId().toString());
+            stmt.bind("bundleId", sub.getBundleId().toString());
             stmt.bind("category", sub.getCategory().toString());
-            stmt.bind("start_dt", getDate(sub.getStartDate()));
-            stmt.bind("bundle_start_dt", getDate(sub.getBundleStartDate()));
-            stmt.bind("active_version", sub.getActiveVersion());
-            stmt.bind("ctd_dt", getDate(sub.getChargedThroughDate()));
-            stmt.bind("ptd_dt", getDate(sub.getPaidThroughDate()));
+            stmt.bind("startDate", getDate(sub.getStartDate()));
+            stmt.bind("bundleStartDate", getDate(sub.getBundleStartDate()));
+            stmt.bind("activeVersion", sub.getActiveVersion());
+            stmt.bind("chargedThroughDate", getDate(sub.getChargedThroughDate()));
+            stmt.bind("paidThroughDate", getDate(sub.getPaidThroughDate()));
         }
     }
 
@@ -93,10 +94,10 @@ public interface SubscriptionSqlDao extends Transactional<SubscriptionSqlDao>, C
             UUID id = UUID.fromString(r.getString("id"));
             UUID bundleId = UUID.fromString(r.getString("bundle_id"));
             ProductCategory category = ProductCategory.valueOf(r.getString("category"));
-            DateTime bundleStartDate = getDate(r, "bundle_start_dt");
-            DateTime startDate = getDate(r, "start_dt");
-            DateTime ctd = getDate(r, "ctd_dt");
-            DateTime ptd = getDate(r, "ptd_dt");
+            DateTime bundleStartDate = getDate(r, "bundle_start_date");
+            DateTime startDate = getDate(r, "start_date");
+            DateTime ctd = getDate(r, "charged_through_date");
+            DateTime ptd = getDate(r, "paid_through_date");
             long activeVersion = r.getLong("active_version");
 
             return new SubscriptionData(new SubscriptionBuilder()
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/EntitlementEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/EntitlementEvent.java
index d3895c0..8e7688b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/EntitlementEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/EntitlementEvent.java
@@ -16,12 +16,13 @@
 
 package com.ning.billing.entitlement.events;
 
+import com.ning.billing.util.entity.Entity;
 import org.joda.time.DateTime;
 
 import java.util.UUID;
 
 
-public interface EntitlementEvent extends Comparable<EntitlementEvent> {
+public interface EntitlementEvent extends Comparable<EntitlementEvent>, Entity {
 
     public enum EventType {
         API_USER,
@@ -32,8 +33,6 @@ public interface EntitlementEvent extends Comparable<EntitlementEvent> {
 
     public long getTotalOrdering();
 
-    public UUID getId();
-
     public long getActiveVersion();
 
     public void setActiveVersion(long activeVersion);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
index 5861e5d..4afc75d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/EventBase.java
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.events;
 
 import com.ning.billing.entitlement.events.user.ApiEvent;
-import com.ning.billing.entitlement.exceptions.EntitlementError;
 import org.joda.time.DateTime;
 
 import java.util.UUID;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
index 47546ea..23f7b2b 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/phase/PhaseEventData.java
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.events.phase;
 
 
-import com.ning.billing.entitlement.alignment.TimedPhase;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.events.EventBase;
 import org.joda.time.DateTime;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
index c68da2b..d2ea706 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/events/user/ApiEventBase.java
@@ -17,7 +17,6 @@
 package com.ning.billing.entitlement.events.user;
 
 import com.ning.billing.entitlement.events.EventBase;
-import org.joda.time.DateTime;
 
 import java.util.UUID;
 
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java b/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
index 6a477c7..a809c9f 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/glue/DefaultEntitlementModule.java
@@ -42,7 +42,7 @@ import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.engine.addon.AddonUtils;
 import com.ning.billing.entitlement.engine.core.Engine;
 import com.ning.billing.entitlement.engine.dao.EntitlementDao;
-import com.ning.billing.entitlement.engine.dao.EntitlementSqlDao;
+import com.ning.billing.entitlement.engine.dao.AuditedEntitlementDao;
 import com.ning.billing.entitlement.engine.dao.RepairEntitlementDao;
 import com.ning.billing.glue.EntitlementModule;
 import com.ning.billing.util.glue.RealImplementation;
@@ -57,7 +57,7 @@ public class DefaultEntitlementModule extends AbstractModule implements Entitlem
     }
 
     protected void installEntitlementDao() {
-        bind(EntitlementDao.class).to(EntitlementSqlDao.class).asEagerSingleton();
+        bind(EntitlementDao.class).to(AuditedEntitlementDao.class).asEagerSingleton();
         bind(EntitlementDao.class).annotatedWith(Names.named(REPAIR_NAMED)).to(RepairEntitlementDao.class);
         bind(RepairEntitlementLifecycleDao.class).annotatedWith(Names.named(REPAIR_NAMED)).to(RepairEntitlementDao.class);
         bind(RepairEntitlementDao.class).asEagerSingleton();
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
index 2064310..f86f170 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
@@ -1,16 +1,16 @@
 DROP TABLE IF EXISTS events;
 DROP TABLE IF EXISTS entitlement_events;
 CREATE TABLE entitlement_events (
-    id int(11) unsigned NOT NULL AUTO_INCREMENT,
-    event_id char(36) NOT NULL,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
     event_type varchar(9) NOT NULL,
     user_type varchar(25) DEFAULT NULL,
-    requested_dt datetime NOT NULL,
-    effective_dt datetime NOT NULL,
+    requested_date datetime NOT NULL,
+    effective_date datetime NOT NULL,
     subscription_id char(36) NOT NULL,
     plan_name varchar(64) DEFAULT NULL,
     phase_name varchar(128) DEFAULT NULL,
-    plist_name varchar(64) DEFAULT NULL,
+    price_list_name varchar(64) DEFAULT NULL,
     user_token char(36),
     current_version int(11) DEFAULT 1,
     is_active bool DEFAULT 1,
@@ -18,34 +18,39 @@ CREATE TABLE entitlement_events (
     created_date datetime NOT NULL,
     updated_by varchar(50) NOT NULL,
     updated_date datetime NOT NULL,
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
-CREATE INDEX idx_ent_1 ON entitlement_events(subscription_id,is_active,effective_dt);
-CREATE INDEX idx_ent_2 ON entitlement_events(subscription_id,effective_dt,created_date,requested_dt,id);
+CREATE UNIQUE INDEX entitlement_events_id ON entitlement_events(id);
+CREATE INDEX idx_ent_1 ON entitlement_events(subscription_id,is_active,effective_date);
+CREATE INDEX idx_ent_2 ON entitlement_events(subscription_id,effective_date,created_date,requested_date,id);
 
 DROP TABLE IF EXISTS subscriptions;
 CREATE TABLE subscriptions (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
     bundle_id char(36) NOT NULL,
     category varchar(32) NOT NULL,
-    start_dt datetime NOT NULL,
-    bundle_start_dt datetime NOT NULL,
+    start_date datetime NOT NULL,
+    bundle_start_date datetime NOT NULL,
     active_version int(11) DEFAULT 1,
-    ctd_dt datetime DEFAULT NULL,
-    ptd_dt datetime DEFAULT NULL,
+    charged_through_date datetime DEFAULT NULL,
+    paid_through_date datetime DEFAULT NULL,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
     updated_by varchar(50) NOT NULL,
     updated_date datetime NOT NULL,
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX subscriptions_id ON subscriptions(id);
 
 DROP TABLE IF EXISTS bundles;
 CREATE TABLE bundles (
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
-    start_dt datetime, /*NOT NULL*/
+    start_date datetime, /*NOT NULL*/
     external_key varchar(64) NOT NULL,
     account_id char(36) NOT NULL,
-    last_sys_update_dt datetime,
-    PRIMARY KEY(id)
+    last_sys_update_date datetime,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+ CREATE UNIQUE INDEX bundles_id ON bundles(id);
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
index 184604d..2b0467d 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/BundleSqlDao.sql.stg
@@ -1,66 +1,68 @@
 group BundleSqlDao;
 
+fields(prefix) ::= <<
+    <prefix>id,
+    <prefix>start_date,
+    <prefix>external_key,
+    <prefix>account_id,
+    <prefix>last_sys_update_date
+>>
+
 insertBundle() ::= <<
-    insert into bundles (
-      id
-      , start_dt
-      , external_key
-      , account_id
-      , last_sys_update_dt
-    ) values (
-      :id
-      , :start_dt
-      , :external_key
-      , :account_id
-      , :last_sys_update_dt
-    );
+    insert into bundles (<fields()>)
+    values (:id, :startDate, :externalKey, :accountId, :lastSysUpdateDate);
 >>
 
-updateBundleLastSysTime(id, last_sys_update_dt)  ::= <<
+updateBundleLastSysTime()  ::= <<
     update bundles
     set
-        last_sys_update_dt = :last_sys_update_dt
+        last_sys_update_date = :lastSysUpdateDate
     where id = :id
     ;
 >>
 
-getBundleFromId(id) ::= <<
-    select
-      id
-      , start_dt
-      , external_key
-      , account_id
-      , last_sys_update_dt
+getBundleFromId() ::= <<
+    select <fields()>
     from bundles
     where
       id = :id
     ;
 >>
 
-getBundleFromKey(external_key) ::= <<
-    select
-      id
-      , start_dt
-      , external_key
-      , account_id
-      , last_sys_update_dt
+getBundleFromKey() ::= <<
+    select <fields()>
     from bundles
     where
-      external_key = :external_key
+      external_key = :externalKey
     ;
 >>
 
-
-getBundleFromAccount(account_id) ::= <<
-    select
-      id
-      , start_dt
-      , external_key
-      , account_id
-      , last_sys_update_dt
+getBundleFromAccount() ::= <<
+    select <fields()>
     from bundles
     where
-      account_id = :account_id
+      account_id = :accountId
     ;
 >>
 
+getRecordId() ::= <<
+    SELECT record_id
+    FROM bundles
+    WHERE id = :id;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
\ No newline at end of file
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
index 804f6ae..1b16b00 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/engine/dao/SubscriptionSqlDao.sql.stg
@@ -5,24 +5,24 @@ insertSubscription() ::= <<
         id
       , bundle_id
       , category
-      , start_dt
-      , bundle_start_dt
+      , start_date
+      , bundle_start_date
       , active_version
-      , ctd_dt
-      , ptd_dt
+      , charged_through_date
+      , paid_through_date
       , created_by
       , created_date
       , updated_by
       , updated_date
     ) values (
         :id
-      , :bundle_id
+      , :bundleId
       , :category
-      , :start_dt
-      , :bundle_start_dt
-      , :active_version
-      , :ctd_dt
-      , :ptd_dt
+      , :startDate
+      , :bundleStartDate
+      , :activeVersion
+      , :chargedThroughDate
+      , :paidThroughDate
       , :userName
       , :createdDate
       , :userName
@@ -30,40 +30,40 @@ insertSubscription() ::= <<
     );
 >>
 
-getSubscriptionFromId(id) ::= <<
+getSubscriptionFromId() ::= <<
     select
         id
       , bundle_id
       , category
-      , start_dt
-      , bundle_start_dt
+      , start_date
+      , bundle_start_date
       , active_version
-      , ctd_dt
-      , ptd_dt    
+      , charged_through_date
+      , paid_through_date    
     from subscriptions
     where id = :id
     ;
 >>
 
-getSubscriptionsFromBundleId(bundle_id) ::= <<
+getSubscriptionsFromBundleId() ::= <<
     select
       id
       , bundle_id
       , category
-      , start_dt
-      , bundle_start_dt
+      , start_date
+      , bundle_start_date
       , active_version
-      , ctd_dt
-      , ptd_dt    
+      , charged_through_date
+      , paid_through_date    
     from subscriptions
-    where bundle_id = :bundle_id
+    where bundle_id = :bundleId
     ;
 >>
 
 updateChargedThroughDate() ::= <<
     update subscriptions
     set
-      ctd_dt = :ctd_dt
+      charged_through_date = :chargedThroughDate
       , updated_by = :userName
       , updated_date = :updatedDate
     where id = :id
@@ -73,7 +73,7 @@ updateChargedThroughDate() ::= <<
 updateActiveVersion() ::= <<
     update subscriptions
     set
-      active_version = :active_version
+      active_version = :activeVersion
       , updated_by = :userName
       , updated_date = :updatedDate
     where id = :id
@@ -83,11 +83,33 @@ updateActiveVersion() ::= <<
 updateForRepair() ::= <<
     update subscriptions
     set
-      active_version = :active_version
-      , start_dt = :start_dt
-      , bundle_start_dt = :bundle_start_dt
+      active_version = :activeVersion
+      , start_date = :startDate
+      , bundle_start_date = :bundleStartDate
       , updated_by = :userName
       , updated_date = :updatedDate
     where id = :id
     ;
 >>
+
+getRecordId() ::= <<
+    SELECT record_id
+    FROM subscriptions
+    WHERE id = :id;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
index e1f6c28..2681a0b 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/migration/TestMigration.java
@@ -32,7 +32,6 @@ import org.testng.Assert;
 
 import com.ning.billing.api.TestApiListener.NextEvent;
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
@@ -45,7 +44,6 @@ import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.Entitl
 import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
-import org.testng.annotations.Test;
 
 public abstract class TestMigration extends TestApiBase {
     public void testSingleBasePlan() {
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
index fce7e8a..d56e8c4 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
@@ -21,14 +21,12 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.Interval;
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.inject.Guice;
@@ -37,7 +35,6 @@ import com.google.inject.Stage;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.api.TestApiListener.NextEvent;
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
@@ -45,9 +42,6 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
@@ -131,14 +125,15 @@ public class TestRepairBP extends TestApiBaseRepair {
         assertListenerStatus();
     }
     
-    @Test(groups={"slow"})
+    //TODO MDW: Temporary disable need to look at this with Stephane
+    @Test(groups={"slow"}, enabled = false)
     public void testBPRepairWithCancellationOnstart() throws Exception {
 
         log.info("Starting testBPRepairWithCancellationOnstart");
         
         String baseProduct = "Shotgun";
         DateTime startDate = clock.getUTCNow();
-        
+         
         // CREATE BP
         Subscription baseSubscription = createSubscription(baseProduct, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, startDate);
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
index ec75a30..d7fd642 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
@@ -32,7 +32,6 @@ import com.google.inject.Injector;
 import com.google.inject.Stage;
 import com.ning.billing.api.TestApiListener.NextEvent;
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
@@ -40,8 +39,6 @@ import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.ExistingEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
index 7421b48..54fda89 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithError.java
@@ -34,20 +34,15 @@ import com.google.inject.Stage;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.api.TestApiListener.NextEvent;
 import com.ning.billing.catalog.api.BillingPeriod;
-import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.catalog.api.PhaseType;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.EntitlementRepairException;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.DeletedEvent;
 import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline.NewEvent;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
 import com.ning.billing.entitlement.glue.MockEngineModuleMemory;
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
index 3851eb2..d52c55a 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoSql.java
@@ -32,7 +32,7 @@ import com.ning.billing.util.clock.Clock;
 
 import com.ning.billing.util.notificationq.NotificationQueueService;
 
-public class MockEntitlementDaoSql extends EntitlementSqlDao implements MockEntitlementDao {
+public class MockEntitlementDaoSql extends AuditedEntitlementDao implements MockEntitlementDao {
 
     private final ResetSqlDao resetDao;
 
diff --git a/entitlement/src/test/resources/entitlement.properties b/entitlement/src/test/resources/entitlement.properties
index af1c3fc..58f4f95 100644
--- a/entitlement/src/test/resources/entitlement.properties
+++ b/entitlement/src/test/resources/entitlement.properties
@@ -1,6 +1,8 @@
 killbill.catalog.uri=file:src/test/resources/testInput.xml
 killbill.entitlement.dao.claim.time=60000
 killbill.entitlement.dao.ready.max=1
-killbill.entitlement.engine.notifications.sleep=500
+killbill.entitlement.engine.notifications.sleep=100
+killbill.billing.util.persistent.bus.sleep=100
+killbill.billing.util.persistent.bus.nbThreads=1
 user.timezone=UTC
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/migration/MigrationInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/api/migration/MigrationInvoice.java
index 84877eb..6627982 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/migration/MigrationInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/migration/MigrationInvoice.java
@@ -24,6 +24,6 @@ import java.util.UUID;
 
 public class MigrationInvoice extends DefaultInvoice {
     public MigrationInvoice(UUID accountId, DateTime invoiceDate, DateTime targetDate, Currency currency) {
-        super(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, true, null, null);
+        super(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, true);
     }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index fb30979..5178a29 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -18,10 +18,7 @@ package com.ning.billing.invoice.dao;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
@@ -29,51 +26,38 @@ import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.inject.Inject;
 import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
-import com.ning.billing.invoice.api.user.DefaultInvoiceCreationEvent;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
-import com.ning.billing.junction.api.BillingApi;
 import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
-import com.ning.billing.util.bus.Bus;
-import com.ning.billing.util.bus.Bus.EventBusException;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.dao.TagDao;
 
 public class DefaultInvoiceDao implements InvoiceDao {
-    private final static Logger log = LoggerFactory.getLogger(DefaultInvoiceDao.class);
-
     private final InvoiceSqlDao invoiceSqlDao;
     private final InvoicePaymentSqlDao invoicePaymentSqlDao;
-    private final BillingApi billingApi;
     private final TagDao tagDao;
 
-    private final Bus eventBus;
-
 	private final NextBillingDatePoster nextBillingDatePoster;
 
     @Inject
-    public DefaultInvoiceDao(final IDBI dbi, final Bus eventBus,
-                             final BillingApi entitlementBillingApi,
+    public DefaultInvoiceDao(final IDBI dbi,
                              final NextBillingDatePoster nextBillingDatePoster,
                              final TagDao tagDao) {
         this.invoiceSqlDao = dbi.onDemand(InvoiceSqlDao.class);
         this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
-        this.eventBus = eventBus;
-        this.billingApi = entitlementBillingApi;
         this.nextBillingDatePoster = nextBillingDatePoster;
         this.tagDao = tagDao;
     }
@@ -161,51 +145,49 @@ public class DefaultInvoiceDao implements InvoiceDao {
                 Invoice currentInvoice = transactional.getById(invoice.getId().toString());
 
                 if (currentInvoice == null) {
+                    List<EntityAudit> audits = new ArrayList<EntityAudit>();
+
                     transactional.create(invoice, context);
+                    Long recordId = transactional.getRecordId(invoice.getId().toString());
+                    audits.add(new EntityAudit(TableName.INVOICES, recordId, ChangeType.INSERT));
+
+                    List<Long> recordIdList;
 
                     List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
                     RecurringInvoiceItemSqlDao recurringInvoiceItemDao = transactional.become(RecurringInvoiceItemSqlDao.class);
                     recurringInvoiceItemDao.batchCreateFromTransaction(recurringInvoiceItems, context);
+                    recordIdList = recurringInvoiceItemDao.getRecordIds(invoice.getId().toString());
+                    audits.addAll(createAudits(TableName.RECURRING_INVOICE_ITEMS, recordIdList));
 
                     notifyOfFutureBillingEvents(transactional, recurringInvoiceItems);
 
                     List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
                     FixedPriceInvoiceItemSqlDao fixedPriceInvoiceItemDao = transactional.become(FixedPriceInvoiceItemSqlDao.class);
                     fixedPriceInvoiceItemDao.batchCreateFromTransaction(fixedPriceInvoiceItems, context);
+                    recordIdList = fixedPriceInvoiceItemDao.getRecordIds(invoice.getId().toString());
+                    audits.addAll(createAudits(TableName.FIXED_INVOICE_ITEMS, recordIdList));
 
                     List<InvoicePayment> invoicePayments = invoice.getPayments();
                     InvoicePaymentSqlDao invoicePaymentSqlDao = transactional.become(InvoicePaymentSqlDao.class);
                     invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
+                    recordIdList = invoicePaymentSqlDao.getRecordIds(invoice.getId().toString());
+                    audits.addAll(createAudits(TableName.INVOICE_PAYMENTS, recordIdList));
 
-                    AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                    auditSqlDao.insertAuditFromTransaction("invoices", invoice.getId().toString(), ChangeType.INSERT, context);
-                    auditSqlDao.insertAuditFromTransaction("recurring_invoice_items", getIdsFromInvoiceItems(recurringInvoiceItems), ChangeType.INSERT, context);
-                    auditSqlDao.insertAuditFromTransaction("fixed_invoice_items", getIdsFromInvoiceItems(fixedPriceInvoiceItems), ChangeType.INSERT, context);
-                    auditSqlDao.insertAuditFromTransaction("invoice_payments", getIdsFromInvoicePayments(invoicePayments), ChangeType.INSERT, context);
+                    transactional.insertAuditFromTransaction(audits, context);
                 }
+
                 return null;
             }
         });
     }
 
-    private List<String> getIdsFromInvoiceItems(List<InvoiceItem> invoiceItems) {
-        List<String> ids = new ArrayList<String>();
-
-        for (InvoiceItem item : invoiceItems) {
-            ids.add(item.getId().toString());
-        }
-
-        return ids;
-    }
-
-    private List<String> getIdsFromInvoicePayments(List<InvoicePayment> invoicePayments) {
-        List<String> ids = new ArrayList<String>();
-
-        for (InvoicePayment payment : invoicePayments) {
-            ids.add(payment.getId().toString());
+    private List<EntityAudit> createAudits(TableName tableName, List<Long> recordIdList) {
+        List<EntityAudit> entityAuditList = new ArrayList<EntityAudit>();
+        for (Long recordId : recordIdList) {
+            entityAuditList.add(new EntityAudit(tableName, recordId, ChangeType.INSERT));
         }
 
-        return ids;
+        return entityAuditList;
     }
 
     @Override
@@ -234,9 +216,10 @@ public class DefaultInvoiceDao implements InvoiceDao {
             public Void inTransaction(InvoicePaymentSqlDao transactional, TransactionStatus status) throws Exception {
                 transactional.notifyOfPaymentAttempt(invoicePayment, context);
 
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
                 String invoicePaymentId = invoicePayment.getId().toString();
-                auditSqlDao.insertAuditFromTransaction("invoice_payments", invoicePaymentId, ChangeType.INSERT, context);
+                Long recordId = transactional.getRecordId(invoicePaymentId);
+                EntityAudit audit = new EntityAudit(TableName.INVOICE_PAYMENTS, recordId, ChangeType.INSERT);
+                transactional.insertAuditFromTransaction(audit, context);
 
                 return null;
             }
@@ -269,12 +252,12 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     @Override
     public void addControlTag(ControlTagType controlTagType, UUID invoiceId, CallContext context) {
-        tagDao.addTag(controlTagType.toString(), invoiceId, Invoice.ObjectType, context);
+        tagDao.addTag(controlTagType.toString(), invoiceId, ObjectType.INVOICE, context);
     }
 
     @Override
     public void removeControlTag(ControlTagType controlTagType, UUID invoiceId, CallContext context) {
-        tagDao.removeTag(controlTagType.toString(), invoiceId, Invoice.ObjectType, context);
+        tagDao.removeTag(controlTagType.toString(), invoiceId, ObjectType.INVOICE, context);
     }
 
     @Override
@@ -332,7 +315,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
     }
 
     private void getTagsWithinTransaction(final Invoice invoice, final Transmogrifier dao) {
-        List<Tag> tags = tagDao.loadTagsFromTransaction(dao, invoice.getId(), Invoice.ObjectType);
+        List<Tag> tags = tagDao.loadEntitiesFromTransaction(dao, invoice.getId(), ObjectType.INVOICE);
         invoice.addTags(tags);
     }
 
@@ -345,7 +328,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
     private void getFieldsWithinTransaction(final Invoice invoice, final InvoiceSqlDao invoiceSqlDao) {
         CustomFieldSqlDao customFieldSqlDao = invoiceSqlDao.become(CustomFieldSqlDao.class);
         String invoiceId = invoice.getId().toString();
-        List<CustomField> customFields = customFieldSqlDao.load(invoiceId, Invoice.ObjectType);
+        List<CustomField> customFields = customFieldSqlDao.load(invoiceId, ObjectType.INVOICE);
         invoice.setFields(customFields);
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
index b89c68b..d4fa5ee 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.java
@@ -27,6 +27,7 @@ import java.sql.SQLException;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -46,11 +47,13 @@ import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper(FixedPriceInvoiceItemSqlDao.FixedPriceInvoiceItemMapper.class)
-public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
+public interface FixedPriceInvoiceItemSqlDao extends EntitySqlDao<InvoiceItem> {
+    @SqlQuery
+    List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
     @SqlQuery
     List<InvoiceItem> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId);
 
@@ -109,11 +112,9 @@ public interface FixedPriceInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             DateTime endDate = new DateTime(result.getTimestamp("end_date"));
             BigDecimal amount = result.getBigDecimal("amount");
             Currency currency = Currency.valueOf(result.getString("currency"));
-            String createdBy = result.getString("created_by");
-            DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
 
             return new FixedPriceInvoiceItem(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
-                                            startDate, endDate, amount, currency, createdBy, createdDate);
+                                            startDate, endDate, amount, currency);
         }
     }
 }
\ No newline at end of file
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index c51d65d..a11c8e0 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -28,9 +28,11 @@ import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -51,7 +53,10 @@ import com.ning.billing.invoice.api.InvoicePayment;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(InvoicePaymentSqlDao.InvoicePaymentMapper.class)
-public interface InvoicePaymentSqlDao extends Transactional<InvoicePaymentSqlDao>, Transmogrifier {
+public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Transactional<InvoicePaymentSqlDao>, AuditSqlDao, Transmogrifier {
+    @SqlQuery
+    List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+    
     @SqlQuery
     public InvoicePayment getByPaymentAttemptId(@Bind("paymentAttempt") final String paymentAttemptId);
 
@@ -81,15 +86,13 @@ public interface InvoicePaymentSqlDao extends Transactional<InvoicePaymentSqlDao
     public static class InvoicePaymentMapper extends MapperBase implements ResultSetMapper<InvoicePayment> {
         @Override
         public InvoicePayment map(int index, ResultSet result, StatementContext context) throws SQLException {
-            final UUID id = UUID.fromString(result.getString("id"));
-            final UUID paymentAttemptId = UUID.fromString(result.getString("payment_attempt_id"));
-            final UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
+            final UUID id = getUUID(result, "id");
+            final UUID paymentAttemptId = getUUID(result, "payment_attempt_id");
+            final UUID invoiceId = getUUID(result, "invoice_id");
             final DateTime paymentAttemptDate = getDate(result, "payment_attempt_date");
             final BigDecimal amount = result.getBigDecimal("amount");
             final String currencyString = result.getString("currency");
             final Currency currency = (currencyString == null) ? null : Currency.valueOf(currencyString);
-            final String createdBy = result.getString("created_by");
-            final DateTime createdDate = getDate(result, "created_date");
 
             return new InvoicePayment() {
                 @Override
@@ -116,14 +119,6 @@ public interface InvoicePaymentSqlDao extends Transactional<InvoicePaymentSqlDao
                 public Currency getCurrency() {
                     return currency;
                 }
-                @Override
-                public String getCreatedBy() {
-                    return createdBy;
-                }
-                @Override
-                public DateTime getCreatedDate() {
-                    return createdDate ;
-                }
             };
         }
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index dc8e303..af611bc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -20,9 +20,10 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.model.DefaultInvoice;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.UuidMapper;
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.dao.UuidMapper;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -53,7 +54,7 @@ import java.util.UUID;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper(InvoiceSqlDao.InvoiceMapper.class)
-public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<InvoiceSqlDao>, Transmogrifier, CloseMe {
+public interface InvoiceSqlDao extends EntitySqlDao<Invoice>, AuditSqlDao, Transactional<InvoiceSqlDao>, Transmogrifier, CloseMe {
     @Override
     @SqlUpdate
     void create(@InvoiceBinder Invoice invoice, @CallContextBinder final CallContext context);
@@ -117,10 +118,8 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
             DateTime targetDate = new DateTime(result.getTimestamp("target_date"));
             Currency currency = Currency.valueOf(result.getString("currency"));
             boolean isMigrationInvoice = result.getBoolean("migrated");
-            String createdBy = result.getString("created_by");
-            DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
 
-            return new DefaultInvoice(id, accountId, invoiceNumber, invoiceDate, targetDate, currency, isMigrationInvoice, createdBy, createdDate);
+            return new DefaultInvoice(id, accountId, invoiceNumber, invoiceDate, targetDate, currency, isMigrationInvoice);
         }
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
index 46c5153..4daa560 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.java
@@ -27,6 +27,7 @@ import java.sql.SQLException;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.MapperBase;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -46,11 +47,14 @@ import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 
 @ExternalizedSqlViaStringTemplate3()
 @RegisterMapper(RecurringInvoiceItemSqlDao.RecurringInvoiceItemMapper.class)
-public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
+public interface RecurringInvoiceItemSqlDao extends EntitySqlDao<InvoiceItem> {
+    @SqlQuery
+    List<Long> getRecordIds(@Bind("invoiceId") final String invoiceId);
+
     @SqlQuery
     List<InvoiceItem> getInvoiceItemsByInvoice(@Bind("invoiceId") final String invoiceId);
 
@@ -96,28 +100,25 @@ public interface RecurringInvoiceItemSqlDao extends EntityDao<InvoiceItem> {
         }
     }
 
-    public static class RecurringInvoiceItemMapper implements ResultSetMapper<InvoiceItem> {
+    public static class RecurringInvoiceItemMapper extends MapperBase implements ResultSetMapper<InvoiceItem> {
         @Override
         public InvoiceItem map(int index, ResultSet result, StatementContext context) throws SQLException {
-            UUID id = UUID.fromString(result.getString("id"));
-            UUID invoiceId = UUID.fromString(result.getString("invoice_id"));
-            UUID accountId = UUID.fromString(result.getString("account_id"));
-            UUID subscriptionId = result.getString("subscription_id") == null ? null : UUID.fromString(result.getString("subscription_id"));
-            UUID bundleId = result.getString("bundle_id") == null ? null : UUID.fromString(result.getString("bundle_id"));
+            UUID id = getUUID(result, "id");
+            UUID invoiceId = getUUID(result, "invoice_id");
+            UUID accountId = getUUID(result, "account_id");
+            UUID subscriptionId = getUUID(result, "subscription_id");
+            UUID bundleId = getUUID(result, "bundle_id");
             String planName = result.getString("plan_name");
             String phaseName = result.getString("phase_name");
-            DateTime startDate = new DateTime(result.getTimestamp("start_date"));
-            DateTime endDate = new DateTime(result.getTimestamp("end_date"));
+            DateTime startDate = getDate(result, "start_date");
+            DateTime endDate = getDate(result, "end_date");
             BigDecimal amount = result.getBigDecimal("amount");
             BigDecimal rate = result.getBigDecimal("rate");
             Currency currency = Currency.valueOf(result.getString("currency"));
-            String reversedItemString = result.getString("reversed_item_id");
-            UUID reversedItemId = (reversedItemString == null) ? null : UUID.fromString(reversedItemString);
-            String createdBy = result.getString("created_by");
-            DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
+            UUID reversedItemId = getUUID(result, "reversed_item_id");
 
             return new RecurringInvoiceItem(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate,
-                    amount, rate, currency, reversedItemId, createdBy, createdDate);
+                    amount, rate, currency, reversedItemId);
 
         }
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
index 58c4a49..ac800a7 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/CreditInvoiceItem.java
@@ -20,18 +20,16 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoiceItem;
 import org.joda.time.DateTime;
 
-import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.util.UUID;
 
 public class CreditInvoiceItem extends InvoiceItemBase {
     public CreditInvoiceItem(UUID invoiceId, UUID accountId, DateTime date, BigDecimal amount, Currency currency) {
-        this(UUID.randomUUID(), invoiceId, accountId, date, amount, currency, null, null);
+        this(UUID.randomUUID(), invoiceId, accountId, date, amount, currency);
     }
 
-    public CreditInvoiceItem(UUID id, UUID invoiceId, UUID accountId, DateTime date, BigDecimal amount, Currency currency,
-                             @Nullable String createdBy, @Nullable DateTime createdDate) {
-        super(id, invoiceId, accountId, null, null, null, null, date, date, amount, currency, createdBy, createdDate);
+    public CreditInvoiceItem(UUID id, UUID invoiceId, UUID accountId, DateTime date, BigDecimal amount, Currency currency) {
+        super(id, invoiceId, accountId, null, null, null, null, date, date, amount, currency);
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 1467415..8f38437 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.entity.ExtendedEntityBase;
 import org.joda.time.DateTime;
 
@@ -45,13 +46,13 @@ public class DefaultInvoice extends ExtendedEntityBase implements Invoice {
 
     // used to create a new invoice
     public DefaultInvoice(UUID accountId, DateTime invoiceDate, DateTime targetDate, Currency currency) {
-        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false, null, null);
+        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false);
     }
 
     // used to hydrate invoice from persistence layer
     public DefaultInvoice(UUID invoiceId, UUID accountId, @Nullable Integer invoiceNumber, DateTime invoiceDate,
-                          DateTime targetDate, Currency currency, boolean isMigrationInvoice, @Nullable String createdBy, @Nullable DateTime createdDate) {
-        super(invoiceId, createdBy, createdDate);
+                          DateTime targetDate, Currency currency, boolean isMigrationInvoice) {
+        super(invoiceId);
         this.accountId = accountId;
         this.invoiceNumber = invoiceNumber;
         this.invoiceDate = invoiceDate;
@@ -112,11 +113,6 @@ public class DefaultInvoice extends ExtendedEntityBase implements Invoice {
     }
 
     @Override
-    public UUID getId() {
-        return id;
-    }
-
-    @Override
     public UUID getAccountId() {
         return accountId;
     }
@@ -196,11 +192,7 @@ public class DefaultInvoice extends ExtendedEntityBase implements Invoice {
         }
 
         DateTime lastPaymentAttempt = getLastPaymentAttempt();
-        if (lastPaymentAttempt == null) {
-            return true;
-        }
-
-        return !lastPaymentAttempt.plusDays(numberOfDays).isAfter(targetDate);
+        return (lastPaymentAttempt == null) || lastPaymentAttempt.plusDays(numberOfDays).isAfter(targetDate);
     }
 
     @Override
@@ -209,8 +201,8 @@ public class DefaultInvoice extends ExtendedEntityBase implements Invoice {
     }
 
     @Override
-    public String getObjectName() {
-        return Invoice.ObjectType;
+    public ObjectType getObjectType() {
+        return ObjectType.INVOICE;
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
index 22eb5e6..ba02039 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
@@ -33,18 +33,17 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment 
     private final Currency currency;
 
     public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate) {
-        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null, null, null);
+        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null);
     }
 
     public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
                                  final BigDecimal amount, final Currency currency) {
-        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency, null, null);
+        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency);
     }
 
     public DefaultInvoicePayment(final UUID id, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
-                                 @Nullable final BigDecimal amount, @Nullable final Currency currency,
-                                 @Nullable final String createdBy, @Nullable final DateTime createdDate) {
-        super(id, createdBy, createdDate);
+                                 @Nullable final BigDecimal amount, @Nullable final Currency currency) {
+        super(id);
         this.paymentAttemptId = paymentAttemptId;
         this.amount = amount;
         this.invoiceId = invoiceId;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
index 72566df..b5a79ab 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
@@ -32,9 +32,8 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
     }
 
     public FixedPriceInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
-                                 DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
-                                 String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
+                                 DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
index f659807..5ccaa8c 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
@@ -40,14 +40,13 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
     public InvoiceItemBase(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
             DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
         this(UUID.randomUUID(), invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
-                startDate, endDate, amount, currency, null, null);
+                startDate, endDate, amount, currency);
     }
 
-
-    public InvoiceItemBase(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId, @Nullable UUID subscriptionId, String planName, String phaseName,
-            DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
-            @Nullable String createdBy, @Nullable DateTime createdDate) {
-        super(id, createdBy, createdDate);
+    public InvoiceItemBase(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId,
+                           @Nullable UUID subscriptionId, String planName, String phaseName,
+                           DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency) {
+        super(id);
         this.invoiceId = invoiceId;
         this.accountId = accountId;
         this.subscriptionId = subscriptionId;
@@ -60,15 +59,6 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
         this.currency = currency;
     }
 
-    public DateTime getCreatedDate() {
-        return createdDate;
-    }
-
-    @Override
-    public UUID getId() {
-        return id;
-    }
-
     @Override
     public UUID getInvoiceId() {
         return invoiceId;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
index 6fd9608..bc813fc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
@@ -46,22 +46,22 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
         this.reversedItemId = reversedItemId;
     }
 
-    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId,
+                                String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
-                                Currency currency,
-                                String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
+                                Currency currency) {
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
         this.rate = rate;
         this.reversedItemId = null;
     }
 
-    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
+    public RecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId,
+                                String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
-                                Currency currency, UUID reversedItemId,
-                                String createdBy, DateTime createdDate) {
-        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate);
+                                Currency currency, UUID reversedItemId) {
+        super(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency);
         this.rate = rate;
         this.reversedItemId = reversedItemId;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
index 28d15a8..d61e206 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/notification/DefaultNextBillingDateNotifier.java
@@ -86,21 +86,15 @@ public class DefaultNextBillingDateNotifier implements  NextBillingDateNotifier 
                 }
             },
             new NotificationConfig() {
+                
                 @Override
-                public boolean isNotificationProcessingOff() {
-                    return config.isNotificationProcessingOff();
-                }
-                @Override
-                public long getNotificationSleepTimeMs() {
-                    return config.getNotificationSleepTimeMs();
+                public long getSleepTimeMs() {
+                    return config.getSleepTimeMs();
                 }
+                
                 @Override
-                public int getDaoMaxReadyEvents() {
-                    return config.getDaoMaxReadyEvents();
-                }
-                @Override
-                public long getDaoClaimTimeMs() {
-                    return config.getDaoClaimTimeMs();
+                public boolean isNotificationProcessingOff() {
+                    return config.isNotificationProcessingOff();
                 }
             });
         } catch (NotificationQueueAlreadyExists e) {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index 2fad805..92d1a63 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -38,6 +38,7 @@ import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.invoice.api.formatters.InvoiceFormatter;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.template.translation.TranslatorConfig;
 import com.ning.billing.util.tag.Tag;
@@ -215,8 +216,8 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
     }
 
     @Override
-    public String getObjectName() {
-        return invoice.getObjectName();
+    public ObjectType getObjectType() {
+        return invoice.getObjectType();
     }
 
     @Override
@@ -225,16 +226,6 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
     }
 
     @Override
-    public String getCreatedBy() {
-        return invoice.getCreatedBy();
-    }
-
-    @Override
-    public DateTime getCreatedDate() {
-        return invoice.getCreatedDate();
-    }
-
-    @Override
     public List<Tag> getTagList() {
         return invoice.getTagList();
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index cc072d9..f1a2e8d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -123,14 +123,4 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
     public UUID getId() {
         return item.getId();
     }
-
-    @Override
-    public String getCreatedBy() {
-        return item.getCreatedBy();
-    }
-
-    @Override
-    public DateTime getCreatedDate() {
-        return item.getCreatedDate();
-    }
 }
\ No newline at end of file
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
index 659d876..d7aed8c 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
@@ -53,6 +53,28 @@ batchCreateFromTransaction() ::= <<
          :startDate, :endDate, :amount, :currency, :userName, :createdDate);
 >>
 
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM fixed_invoice_items
+    WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
   SELECT 1
   FROM fixed_invoice_items;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index a673b81..6967da0 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -49,6 +49,34 @@ getInvoicePayment() ::= <<
     WHERE payment_id = :payment_id;
 >>
 
+getRecordId() ::= <<
+    SELECT record_id
+    FROM invoice_payments
+    WHERE id = :id;
+>>
+
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM invoice_payments
+    WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
   SELECT 1 FROM invoice_payments;
 >>
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 27f8dff..d7a11b9 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -1,18 +1,6 @@
 group InvoiceDao;
 
-invoiceFetchFields(prefix) ::= <<
-    <prefix>invoice_number,
-    <prefix>id,
-    <prefix>account_id,
-    <prefix>invoice_date,
-    <prefix>target_date,
-    <prefix>currency,
-  	<prefix>migrated,
-    <prefix>created_by,
-    <prefix>created_date
->>
-
-invoiceSetFields(prefix) ::= <<
+invoiceFields(prefix) ::= <<
     <prefix>id,
     <prefix>account_id,
     <prefix>invoice_date,
@@ -24,42 +12,42 @@ invoiceSetFields(prefix) ::= <<
 >>
 
 get() ::= <<
-  SELECT <invoiceFetchFields()>
+  SELECT record_id as invoice_number, <invoiceFields()>
   FROM invoices
   ORDER BY target_date ASC;
 >>
 
 getInvoicesByAccount() ::= <<
-  SELECT <invoiceFetchFields()>
+  SELECT record_id as invoice_number, <invoiceFields()>
   FROM invoices
   WHERE account_id = :accountId AND migrated = 'FALSE'
   ORDER BY target_date ASC;
 >>
 
 getAllInvoicesByAccount() ::= <<
-  SELECT <invoiceFetchFields()>
+  SELECT record_id as invoice_number, <invoiceFields()>
   FROM invoices
   WHERE account_id = :accountId
   ORDER BY target_date ASC;
 >>
 
 getInvoicesByAccountAfterDate() ::= <<
-  SELECT <invoiceFetchFields()>
+  SELECT record_id as invoice_number, <invoiceFields()>
   FROM invoices
   WHERE account_id = :accountId AND target_date >= :fromDate AND migrated = 'FALSE'
   ORDER BY target_date ASC;
 >>
 
 getInvoicesBySubscription() ::= <<
-  SELECT <invoiceFetchFields("i.")>
+  SELECT record_id as invoice_number, <invoiceFields("i.")>
   FROM invoices i
   LEFT JOIN recurring_invoice_items rii ON i.id = rii.invoice_id
   WHERE rii.subscription_id = :subscriptionId  AND migrated = 'FALSE'
-  GROUP BY <invoiceFetchFields("i.")>;
+  GROUP BY record_id as invoice_number, <invoiceFields("i.")>;
 >>
 
 getById() ::= <<
-  SELECT <invoiceFetchFields()>
+  SELECT record_id as invoice_number, <invoiceFields()>
   FROM invoices
   WHERE id = :id;
 >>
@@ -75,7 +63,7 @@ getAccountBalance() ::= <<
 >>
 
 create() ::= <<
-  INSERT INTO invoices(<invoiceSetFields()>)
+  INSERT INTO invoices(<invoiceFields()>)
   VALUES (:id, :accountId, :invoiceDate, :targetDate, :currency, :migrated, :userName, :createdDate);
 >>
 
@@ -87,7 +75,7 @@ getInvoiceIdByPaymentAttemptId() ::= <<
 >>
 
 getUnpaidInvoicesByAccountId() ::= <<
-  SELECT <invoiceFetchFields("i.")>
+  SELECT record_id as invoice_number, <invoiceFields("i.")>
   FROM invoices i
   LEFT JOIN invoice_payment_summary ips ON i.id = ips.invoice_id
   LEFT JOIN invoice_item_summary iis ON i.id = iis.invoice_id
@@ -98,6 +86,28 @@ getUnpaidInvoicesByAccountId() ::= <<
   ORDER BY i.target_date ASC;
 >>
 
+getRecordId() ::= <<
+    SELECT record_id
+    FROM invoices
+    WHERE id = :id;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
   SELECT 1
   FROM invoices;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
index 7573ef3..8afb199 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
@@ -55,6 +55,28 @@ batchCreateFromTransaction() ::= <<
          :amount, :rate, :currency, :reversedItemId, :userName, :createdDate);
 >>
 
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM recurring_invoice_items
+    WHERE invoice_id = :invoiceId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
   SELECT 1
   FROM recurring_invoice_items;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index d04806a..8bda35c 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -1,43 +1,47 @@
 DROP TABLE IF EXISTS invoice_items;
 DROP TABLE IF EXISTS recurring_invoice_items;
 CREATE TABLE recurring_invoice_items (
-  id char(36) NOT NULL,
-  invoice_id char(36) NOT NULL,
-  account_id char(36) NOT NULL,
-  bundle_id char(36),
-  subscription_id char(36),
-  plan_name varchar(50) NOT NULL,
-  phase_name varchar(50) NOT NULL,
-  start_date datetime NOT NULL,
-  end_date datetime NOT NULL,
-  amount numeric(10,4) NULL,
-  rate numeric(10,4) NULL,
-  currency char(3) NOT NULL,
-  reversed_item_id char(36),
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    invoice_id char(36) NOT NULL,
+    account_id char(36) NOT NULL,
+    bundle_id char(36),
+    subscription_id char(36),
+    plan_name varchar(50) NOT NULL,
+    phase_name varchar(50) NOT NULL,
+    start_date datetime NOT NULL,
+    end_date datetime NOT NULL,
+    amount numeric(10,4) NULL,
+    rate numeric(10,4) NULL,
+    currency char(3) NOT NULL,
+    reversed_item_id char(36),
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX recurring_invoice_items_id ON recurring_invoice_items(id);
 CREATE INDEX recurring_invoice_items_subscription_id ON recurring_invoice_items(subscription_id ASC);
 CREATE INDEX recurring_invoice_items_invoice_id ON recurring_invoice_items(invoice_id ASC);
 
 DROP TABLE IF EXISTS fixed_invoice_items;
 CREATE TABLE fixed_invoice_items (
-  id char(36) NOT NULL,
-  invoice_id char(36) NOT NULL,
-  account_id char(36) NOT NULL,
-  bundle_id char(36),
-  subscription_id char(36),
-  plan_name varchar(50) NOT NULL,
-  phase_name varchar(50) NOT NULL,
-  start_date datetime NOT NULL,
-  end_date datetime NOT NULL,
-  amount numeric(10,4) NULL,
-  currency char(3) NOT NULL,
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    invoice_id char(36) NOT NULL,
+    account_id char(36) NOT NULL,
+    bundle_id char(36),
+    subscription_id char(36),
+    plan_name varchar(50) NOT NULL,
+    phase_name varchar(50) NOT NULL,
+    start_date datetime NOT NULL,
+    end_date datetime NOT NULL,
+    amount numeric(10,4) NULL,
+    currency char(3) NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX fixed_invoice_items_id ON fixed_invoice_items(id);
 CREATE INDEX fixed_invoice_items_subscription_id ON fixed_invoice_items(subscription_id ASC);
 CREATE INDEX fixed_invoice_items_invoice_id ON fixed_invoice_items(invoice_id ASC);
 
@@ -45,33 +49,34 @@ DROP TABLE IF EXISTS invoice_locking;
 
 DROP TABLE IF EXISTS invoices;
 CREATE TABLE invoices (
-  invoice_number int NOT NULL AUTO_INCREMENT,
-  id char(36) NOT NULL,
-  account_id char(36) NOT NULL,
-  invoice_date datetime NOT NULL,
-  target_date datetime NOT NULL,
-  currency char(3) NOT NULL,
-  migrated bool NOT NULL,
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(invoice_number)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    account_id char(36) NOT NULL,
+    invoice_date datetime NOT NULL,
+    target_date datetime NOT NULL,
+    currency char(3) NOT NULL,
+    migrated bool NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
-CREATE INDEX invoices_invoice_number ON invoices(invoice_number ASC);
-CREATE INDEX invoices_id ON invoices(id ASC);
+CREATE UNIQUE INDEX invoices_id ON invoices(id);
 CREATE INDEX invoices_account_id ON invoices(account_id ASC);
 
 DROP TABLE IF EXISTS invoice_payments;
 CREATE TABLE invoice_payments (
-  id char(36) NOT NULL,
-  invoice_id char(36) NOT NULL,
-  payment_attempt_id char(36) COLLATE utf8_bin NOT NULL,
-  payment_attempt_date datetime,
-  amount numeric(10,4),
-  currency char(3),
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(invoice_id, payment_attempt_id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    invoice_id char(36) NOT NULL,
+    payment_attempt_id char(36) COLLATE utf8_bin NOT NULL,
+    payment_attempt_date datetime,
+    amount numeric(10,4),
+    currency char(3),
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX invoice_payments_id ON invoice_payments(id);
 CREATE UNIQUE INDEX invoice_payments_unique ON invoice_payments(invoice_id, payment_attempt_id);
 
 DROP VIEW IF EXISTS invoice_payment_summary;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index a7b0f09..efedbaf 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -239,7 +239,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
 	}
 
 
-	// Account balance should reflect total of migration and non-migration invoices
+	// ACCOUNT balance should reflect total of migration and non-migration invoices
 	@Test(groups={"slow"},enabled=true)
 	public void testBalance(){
 		Invoice migrationInvoice = invoiceDao.getById(migrationInvoiceId);
@@ -247,7 +247,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoicingTestBase {
 		BigDecimal balanceOfAllInvoices = migrationInvoice.getBalance().add(regularInvoice.getBalance());
 
 		BigDecimal accountBalance = invoiceUserApi.getAccountBalance(accountId);
-		System.out.println("Account balance: " + accountBalance + " should equal the Balance Of All Invoices: " + balanceOfAllInvoices);
+		System.out.println("ACCOUNT balance: " + accountBalance + " should equal the Balance Of All Invoices: " + balanceOfAllInvoices);
 		Assert.assertEquals(accountBalance.compareTo(balanceOfAllInvoices), 0);
 
 
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 08354db..91dbf7d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -55,11 +55,7 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
 
     private final InvoiceConfig invoiceConfig = new InvoiceConfig() {
         @Override
-        public long getDaoClaimTimeMs() {throw new UnsupportedOperationException();}
-        @Override
-        public int getDaoMaxReadyEvents() {throw new UnsupportedOperationException();}
-        @Override
-        public long getNotificationSleepTimeMs() {throw new UnsupportedOperationException();}
+        public long getSleepTimeMs() {throw new UnsupportedOperationException();}
         @Override
         public boolean isNotificationProcessingOff() {throw new UnsupportedOperationException();}
         @Override
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
index bd43d0a..521d83d 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithMocks.java
@@ -52,11 +52,4 @@ public class InvoiceModuleWithMocks extends DefaultInvoiceModule {
     public void installInvoiceMigrationApi() {
 
     }
-
-    @Override
-    public void configure() {
-        super.configure();
-
-        install(new FieldStoreModule());
-    }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 49fca25..6c3dd65 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -22,13 +22,11 @@ import static org.testng.Assert.assertNull;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import org.joda.time.DateTime;
 import org.testng.annotations.Test;
@@ -70,17 +68,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         Clock clock = new DefaultClock();
         InvoiceConfig invoiceConfig = new InvoiceConfig() {
             @Override
-            public long getDaoClaimTimeMs() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public int getDaoMaxReadyEvents() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public long getNotificationSleepTimeMs() {
+            public long getSleepTimeMs() {
                 throw new UnsupportedOperationException();
             }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
index 2b7e409..82645a5 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJson.java
@@ -191,14 +191,14 @@ public class AccountJson extends AccountJsonSimple {
     }
 
     @JsonCreator
-    public AccountJson(@JsonProperty("account_id") String acountId,
+    public AccountJson(@JsonProperty("accountId") String accountId,
             @JsonProperty("name") String name,
-            @JsonProperty("first_name_length") Integer length,
+            @JsonProperty("firstNameLength") Integer length,
             @JsonProperty("external_key") String externalKey,
             @JsonProperty("email") String email,
-            @JsonProperty("billing_day") Integer billCycleDay,
+            @JsonProperty("billingDay") Integer billCycleDay,
             @JsonProperty("currency") String currency,
-            @JsonProperty("payment_provider") String paymentProvider,
+            @JsonProperty("paymentProvider") String paymentProvider,
             @JsonProperty("timezone") String timeZone,
             @JsonProperty("address1") String address1,
             @JsonProperty("address2") String address2,
@@ -206,7 +206,7 @@ public class AccountJson extends AccountJsonSimple {
             @JsonProperty("state") String state,
             @JsonProperty("country") String country,
             @JsonProperty("phone") String phone) {
-        super(acountId, externalKey);
+        super(accountId, externalKey);
         this.name = name;
         this.length = length;
         this.email = email;
@@ -279,7 +279,7 @@ public class AccountJson extends AccountJsonSimple {
 		final int prime = 31;
 		int result = 1;
 		result = prime * result
-				+ ((acountId == null) ? 0 : acountId.hashCode());
+				+ ((accountId == null) ? 0 : accountId.hashCode());
 		result = prime * result
 				+ ((address1 == null) ? 0 : address1.hashCode());
 		result = prime * result
@@ -392,10 +392,10 @@ public class AccountJson extends AccountJsonSimple {
 			return false;
 		} else {
 			AccountJson other = (AccountJson) obj;
-			if (acountId == null) {
-				if (other.acountId != null)
+			if (accountId == null) {
+				if (other.accountId != null)
 					return false;
-			} else if (!acountId.equals(other.acountId))
+			} else if (!accountId.equals(other.accountId))
 				return false;
 		}
 		return true;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJsonSimple.java
index 548635e..d7e1b2d 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountJsonSimple.java
@@ -22,25 +22,25 @@ import org.codehaus.jackson.map.annotate.JsonView;
 public class AccountJsonSimple {
 
     @JsonView(BundleTimelineViews.Base.class)
-    protected final String acountId;
+    protected final String accountId;
     
     @JsonView(BundleTimelineViews.Base.class)
     protected final String externalKey;
     
     public AccountJsonSimple() {
-        this.acountId = null;
+        this.accountId = null;
         this.externalKey = null;
     }
 
     @JsonCreator
-    public AccountJsonSimple(@JsonProperty("account_id") String acountId,
-            @JsonProperty("external_key") String externalKey) {
-        this.acountId = acountId;
+    public AccountJsonSimple(@JsonProperty("accountId") String accountId,
+            @JsonProperty("externalKey") String externalKey) {
+        this.accountId = accountId;
         this.externalKey = externalKey;
     }
 
-    public String getAcountId() {
-        return acountId;
+    public String getAccountId() {
+        return accountId;
     }
 
     public String getExternalKey() {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 4521257..881745a 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -16,29 +16,29 @@
 package com.ning.billing.jaxrs.json;
 
 import java.math.BigDecimal;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 import org.codehaus.jackson.annotate.JsonCreator;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonView;
-import org.joda.time.DateTime;
 
 import com.ning.billing.account.api.Account;
-import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.entitlement.api.timeline.BundleTimeline;
 import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class AccountTimelineJson {
 
     @JsonView(BundleTimelineViews.ReadTimeline.class)
-    private final List<PaymentJson> payments;
+    private final List<PaymentJsonWithBundleKeys> payments;
 
     @JsonView(BundleTimelineViews.ReadTimeline.class)
-    private final List<InvoiceJson> invoices;
+    private final List<InvoiceJsonWithBundleKeys> invoices;
     
     @JsonView(BundleTimelineViews.ReadTimeline.class)
     private final AccountJsonSimple account;
@@ -49,31 +49,67 @@ public class AccountTimelineJson {
     @JsonCreator
     public AccountTimelineJson(@JsonProperty("account") AccountJsonSimple account,
             @JsonProperty("bundles") List<BundleJsonWithSubscriptions> bundles,
-            @JsonProperty("invoices") List<InvoiceJson> invoices,            
-            @JsonProperty("payments") List<PaymentJson> payments) {
+            @JsonProperty("invoices") List<InvoiceJsonWithBundleKeys> invoices,            
+            @JsonProperty("payments") List<PaymentJsonWithBundleKeys> payments) {
         this.account = account;
         this.bundles = bundles;
         this.invoices = invoices;
         this.payments = payments;
     }
     
+    private String getBundleExternalKey(UUID invoiceId,  List<Invoice> invoices, List<BundleTimeline> bundles) {
+        for (Invoice cur : invoices) {
+            if (cur.getId().equals(invoiceId)) {
+                return getBundleExternalKey(cur, bundles);
+            }
+        }
+        return null;
+    }
+    
+    private String getBundleExternalKey(Invoice invoice, List<BundleTimeline> bundles) {
+        Set<UUID> b = new HashSet<UUID>();
+        for (final InvoiceItem cur : invoice.getInvoiceItems()) {
+            b.add(cur.getBundleId());
+        }
+        boolean first = true;
+        StringBuilder tmp = new StringBuilder();
+        for (final UUID cur : b) {
+            for (final BundleTimeline bt : bundles) {
+                if (bt.getBundleId().equals(cur)) {
+                    if (!first) {
+                        tmp.append(",");
+                    }
+                    tmp.append(bt.getExternalKey());
+                    first = false;
+                    break;
+                }
+            }
+        }
+        return tmp.toString();
+    }
+    
     public AccountTimelineJson(Account account, List<Invoice> invoices, List<PaymentAttempt> payments, List<BundleTimeline> bundles) {
         this.account = new AccountJsonSimple(account.getId().toString(), account.getExternalKey());
         this.bundles = new LinkedList<BundleJsonWithSubscriptions>();
         for (BundleTimeline cur : bundles) {
             this.bundles.add(new BundleJsonWithSubscriptions(account.getId(), cur));            
         }
-        this.invoices = new LinkedList<InvoiceJson>();
+        this.invoices = new LinkedList<InvoiceJsonWithBundleKeys>();
         for (Invoice cur : invoices) {
-            this.invoices.add(new InvoiceJson(cur.getTotalAmount(), cur.getId().toString(), cur.getInvoiceDate(), Integer.toString(cur.getInvoiceNumber()), cur.getBalance()));
+            this.invoices.add(new InvoiceJsonWithBundleKeys(cur.getTotalAmount(), cur.getId().toString(), cur.getInvoiceDate(), cur.getTargetDate(),
+                    Integer.toString(cur.getInvoiceNumber()), cur.getBalance(),
+                    getBundleExternalKey(cur, bundles)));
         }
-        this.payments = new LinkedList<PaymentJson>();
+        this.payments = new LinkedList<PaymentJsonWithBundleKeys>();
         for (PaymentAttempt cur : payments) {
+            
+
             String status = cur.getPaymentId() != null ? "Success" : "Failed";
             BigDecimal paidAmount = cur.getPaymentId() != null ? cur.getAmount() : BigDecimal.ZERO;
             
-            this.payments.add(new PaymentJson(cur.getAmount(), paidAmount, cur.getInvoiceId().toString(), cur.getPaymentId(), cur.getCreatedDate(), cur.getUpdatedDate(),
-                    cur.getRetryCount(), cur.getCurrency().toString(), status));
+            this.payments.add(new PaymentJsonWithBundleKeys(cur.getAmount(), paidAmount, cur.getInvoiceId(), cur.getPaymentId(), cur.getCreatedDate(), cur.getUpdatedDate(),
+                    cur.getRetryCount(), cur.getCurrency().toString(), status,
+                    getBundleExternalKey(cur.getInvoiceId(), invoices, bundles)));
           }
     }
     
@@ -84,11 +120,11 @@ public class AccountTimelineJson {
         this.payments = null;
     }
 
-    public List<PaymentJson> getPayments() {
+    public List<PaymentJsonWithBundleKeys> getPayments() {
         return payments;
     }
 
-    public List<InvoiceJson> getInvoices() {
+    public List<InvoiceJsonWithBundleKeys> getInvoices() {
         return invoices;
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
index 9f8f7b6..c1221b8 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonNoSubsciptions.java
@@ -16,16 +16,12 @@
 
 package com.ning.billing.jaxrs.json;
 
-import java.util.LinkedList;
 import java.util.List;
-import java.util.UUID;
 
 import org.codehaus.jackson.annotate.JsonCreator;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonView;
 
-import com.ning.billing.entitlement.api.timeline.BundleTimeline;
-import com.ning.billing.entitlement.api.timeline.SubscriptionTimeline;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 
 public class BundleJsonNoSubsciptions  extends BundleJsonSimple {
@@ -35,9 +31,9 @@ public class BundleJsonNoSubsciptions  extends BundleJsonSimple {
 
 
     @JsonCreator
-    public BundleJsonNoSubsciptions(@JsonProperty("bundle_id") String bundleId,
-            @JsonProperty("account_id") String accountId,
-            @JsonProperty("external_key") String externalKey,
+    public BundleJsonNoSubsciptions(@JsonProperty("bundleId") String bundleId,
+            @JsonProperty("accountId") String accountId,
+            @JsonProperty("externalKey") String externalKey,
             @JsonProperty("subscriptions") List<SubscriptionJsonWithEvents> subscriptions) {
         super(bundleId, externalKey);
         this.accountId = accountId;
@@ -49,7 +45,7 @@ public class BundleJsonNoSubsciptions  extends BundleJsonSimple {
 
     
     public BundleJsonNoSubsciptions(SubscriptionBundle bundle) {
-        super(bundle.getId().toString(), bundle.getKey());        
+        super(bundle.getId().toString(), bundle.getKey());
         this.accountId = bundle.getAccountId().toString();
     }
     
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonSimple.java
index 3053f0d..8c2d836 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonSimple.java
@@ -16,6 +16,7 @@
 package com.ning.billing.jaxrs.json;
 
 import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.map.annotate.JsonView;
 
 public class BundleJsonSimple {
@@ -27,7 +28,8 @@ public class BundleJsonSimple {
     protected final String externalKey;
 
     @JsonCreator
-    public BundleJsonSimple(String bundleId, String externalKey) {
+    public BundleJsonSimple(@JsonProperty("bundleId") String bundleId,
+            @JsonProperty("externalKey") String externalKey) {
         super();
         this.bundleId = bundleId;
         this.externalKey = externalKey;
@@ -38,10 +40,12 @@ public class BundleJsonSimple {
         this.externalKey = null;
     }
 
+    @JsonProperty("bundleId")
     public String getBundleId() {
         return bundleId;
     }
 
+    @JsonProperty("externalKey")
     public String getExternalKey() {
         return externalKey;
     }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
index dd2c788..fa45cdd 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleJsonWithSubscriptions.java
@@ -33,13 +33,14 @@ public class BundleJsonWithSubscriptions extends BundleJsonSimple {
     private final List<SubscriptionJsonWithEvents> subscriptions;
 
     @JsonCreator
-    public BundleJsonWithSubscriptions(@JsonProperty("bundle_id") String bundleId,
-            @JsonProperty("external_key") String externalKey,
+    public BundleJsonWithSubscriptions(@JsonProperty("bundleId") String bundleId,
+            @JsonProperty("externalKey") String externalKey,
             @JsonProperty("subscriptions") List<SubscriptionJsonWithEvents> subscriptions) {
         super(bundleId, externalKey);
         this.subscriptions = subscriptions;
     }
 
+    @JsonProperty("subscriptions")
     public List<SubscriptionJsonWithEvents> getSubscriptions() {
         return subscriptions;
     }
@@ -53,7 +54,7 @@ public class BundleJsonWithSubscriptions extends BundleJsonSimple {
     }
     
     public BundleJsonWithSubscriptions(SubscriptionBundle bundle) {
-        super(bundle.getId().toString(), bundle.getKey());        
+        super(bundle.getId().toString(), bundle.getKey());
         this.subscriptions = null;
     }
     
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
index 64a416c..099d837 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/BundleTimelineJson.java
@@ -31,20 +31,20 @@ public class BundleTimelineJson {
     private final BundleJsonWithSubscriptions bundle;
 
     @JsonView(BundleTimelineViews.ReadTimeline.class)
-    private final List<PaymentJson> payments;
+    private final List<PaymentJsonSimple> payments;
 
     @JsonView(BundleTimelineViews.ReadTimeline.class)
-    private final List<InvoiceJson> invoices;
+    private final List<InvoiceJsonSimple> invoices;
 
     @JsonView(BundleTimelineViews.WriteTimeline.class)
     private final String resonForChange;
 
     @JsonCreator
-    public BundleTimelineJson(@JsonProperty("view_id") String viewId,
+    public BundleTimelineJson(@JsonProperty("viewId") String viewId,
             @JsonProperty("bundle") BundleJsonWithSubscriptions bundle,
-            @JsonProperty("payments") List<PaymentJson> payments,
-            @JsonProperty("invoices") List<InvoiceJson> invoices,
-            @JsonProperty("reason_for_change") String reason) {
+            @JsonProperty("payments") List<PaymentJsonSimple> payments,
+            @JsonProperty("invoices") List<InvoiceJsonSimple> invoices,
+            @JsonProperty("reasonForChange") String reason) {
         this.viewId = viewId;
         this.bundle = bundle;
         this.payments = payments;
@@ -60,11 +60,11 @@ public class BundleTimelineJson {
         return bundle;
     }
 
-    public List<PaymentJson> getPayments() {
+    public List<PaymentJsonSimple> getPayments() {
         return payments;
     }
 
-    public List<InvoiceJson> getInvoices() {
+    public List<InvoiceJsonSimple> getInvoices() {
         return invoices;
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java
new file mode 100644
index 0000000..cc15072
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithBundleKeys.java
@@ -0,0 +1,57 @@
+package com.ning.billing.jaxrs.json;
+import java.math.BigDecimal;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+import com.ning.billing.invoice.api.Invoice;
+
+/* 
+ * Copyright 2010-2011 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.
+ */
+
+public class InvoiceJsonWithBundleKeys extends InvoiceJsonSimple {
+    
+    
+    private final String bundleKeys;
+
+
+    public InvoiceJsonWithBundleKeys() {
+        super();
+        this.bundleKeys = null;
+    }
+    
+    @JsonCreator
+    public InvoiceJsonWithBundleKeys(@JsonProperty("amount") BigDecimal amount,
+            @JsonProperty("invoiceId") String invoiceId,
+            @JsonProperty("invoiceDate") DateTime invoiceDate,
+            @JsonProperty("targetDate") DateTime targetDate,            
+            @JsonProperty("invoiceNumber") String invoiceNumber,
+            @JsonProperty("balance") BigDecimal balance,
+            @JsonProperty("externalBundleKeys") String bundleKeys) {
+        super(amount, invoiceId, invoiceDate, targetDate, invoiceNumber, balance);
+        this.bundleKeys = bundleKeys;
+    }
+
+    public InvoiceJsonWithBundleKeys(Invoice input, String bundleKeys) {
+        super(input);
+        this.bundleKeys = bundleKeys;
+    }
+
+    public String getBundleKeys() {
+        return bundleKeys;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java
new file mode 100644
index 0000000..e322a59
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonWithBundleKeys.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 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.jaxrs.json;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.joda.time.DateTime;
+
+public class PaymentJsonWithBundleKeys extends PaymentJsonSimple {
+
+    private final String bundleKeys;
+    
+    public PaymentJsonWithBundleKeys() {
+        super();
+        this.bundleKeys = null;
+    }
+
+    @JsonCreator
+    public PaymentJsonWithBundleKeys(@JsonProperty("amount") BigDecimal amount,
+            @JsonProperty("paidAmount") BigDecimal paidAmount,
+            @JsonProperty("invoiceId") UUID invoiceId,
+            @JsonProperty("paymentId") UUID paymentId,
+            @JsonProperty("requestedDt") DateTime requestedDate,
+            @JsonProperty("effectiveDt") DateTime effectiveDate,
+            @JsonProperty("retryCount") Integer retryCount,
+            @JsonProperty("currency") String currency,            
+            @JsonProperty("status") String status,
+            @JsonProperty("externalBundleKeys") String bundleKeys) {
+        super(amount, paidAmount, invoiceId, paymentId, requestedDate, effectiveDate, retryCount, currency, status);
+        this.bundleKeys = bundleKeys;
+    }
+    
+    public String getBundleKeys() {
+        return bundleKeys;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
index 2ec1c44..95a5e09 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonNoEvents.java
@@ -57,14 +57,14 @@ public class SubscriptionJsonNoEvents extends SubscriptionJsonSimple {
 
 
     @JsonCreator
-    public SubscriptionJsonNoEvents(@JsonProperty("subscription_id") String subscriptionId,
-            @JsonProperty("bundle_id") String bundleId,
-            @JsonProperty("start_date") DateTime startDate,
-            @JsonProperty("product_name") String productName,
-            @JsonProperty("product_category") String productCategory,
-            @JsonProperty("billing_period") String billingPeriod,
-            @JsonProperty("price_list") String priceList,
-            @JsonProperty("charged_through_date") DateTime chargedThroughDate) {
+    public SubscriptionJsonNoEvents(@JsonProperty("subscriptionId") String subscriptionId,
+            @JsonProperty("bundleId") String bundleId,
+            @JsonProperty("startDate") DateTime startDate,
+            @JsonProperty("productName") String productName,
+            @JsonProperty("productCategory") String productCategory,
+            @JsonProperty("billingPeriod") String billingPeriod,
+            @JsonProperty("priceList") String priceList,
+            @JsonProperty("chargedThroughDate") DateTime chargedThroughDate) {
         super(subscriptionId);
         this.bundleId = bundleId;
         this.startDate = startDate;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
index ebb86e4..5fb782e 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonSimple.java
@@ -29,7 +29,7 @@ public class SubscriptionJsonSimple {
     }
 
     @JsonCreator
-    public SubscriptionJsonSimple(@JsonProperty("subscription_id") String subscriptionId) {
+    public SubscriptionJsonSimple(@JsonProperty("subscriptionId") String subscriptionId) {
         this.subscriptionId = subscriptionId;
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
index 2f798df..be5ba2c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/SubscriptionJsonWithEvents.java
@@ -58,13 +58,13 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
         }
  
         @JsonCreator
-        public SubscriptionReadEventJson(@JsonProperty("event_id") String eventId,
-                @JsonProperty("billing_period") String billingPeriod,
-                @JsonProperty("requested_dt") DateTime requestedDate,
-                @JsonProperty("effective_dt") DateTime effectiveDate,
+        public SubscriptionReadEventJson(@JsonProperty("eventId") String eventId,
+                @JsonProperty("billingPeriod") String billingPeriod,
+                @JsonProperty("requestedDt") DateTime requestedDate,
+                @JsonProperty("effectiveDt") DateTime effectiveDate,
                 @JsonProperty("product") String product,
-                @JsonProperty("price_list") String priceList,
-                @JsonProperty("event_type") String eventType,
+                @JsonProperty("priceList") String priceList,
+                @JsonProperty("eventType") String eventType,
                 @JsonProperty("phase") String phase) {
             super(billingPeriod, requestedDate, product, priceList, eventType, phase);
             this.eventId = eventId;
@@ -97,8 +97,8 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
         @JsonCreator
         public SubscriptionDeletedEventJson(@JsonProperty("event_id") String eventId,
                 @JsonProperty("billing_period") String billingPeriod,
-                @JsonProperty("requested_dt") DateTime requestedDate,
-                @JsonProperty("effective_dt") DateTime effectiveDate,
+                @JsonProperty("requested_date") DateTime requestedDate,
+                @JsonProperty("effective_date") DateTime effectiveDate,
                 @JsonProperty("product") String product,
                 @JsonProperty("price_list") String priceList,
                 @JsonProperty("event_type") String eventType,
@@ -112,7 +112,7 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
     public static class SubscriptionNewEventJson extends SubscriptionBaseEventJson {
         @JsonCreator
         public SubscriptionNewEventJson(@JsonProperty("billing_period") String billingPeriod,
-                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("requested_date") DateTime requestedDate,
                 @JsonProperty("product") String product,
                 @JsonProperty("price_list") String priceList,
                 @JsonProperty("event_type") String eventType,
@@ -165,7 +165,7 @@ public class SubscriptionJsonWithEvents extends SubscriptionJsonSimple {
         
         @JsonCreator
         public SubscriptionBaseEventJson(@JsonProperty("billing_period") String billingPeriod,
-                @JsonProperty("requested_dt") DateTime requestedDate,
+                @JsonProperty("requested_date") DateTime requestedDate,
                 @JsonProperty("product") String product,
                 @JsonProperty("price_list") String priceList,
                 @JsonProperty("event_type") String eventType,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index 07502cc..b8db3f8 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -69,7 +69,6 @@ import com.ning.billing.jaxrs.util.TagHelper;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.customfield.CustomField;
@@ -244,6 +243,7 @@ public class AccountResource implements BaseJaxrsResource {
             Account account = accountApi.getAccountById(UUID.fromString(accountId));
            
             List<Invoice> invoices = invoiceApi.getInvoicesByAccount(account.getId());
+
             List<PaymentAttempt> payments = new LinkedList<PaymentAttempt>();
 
             if (invoices.size() > 0) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index 5cc35bd..fd2ec57 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -43,29 +43,22 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 import com.google.inject.Inject;
-import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.account.api.AccountUserApi;
-import com.ning.billing.entitlement.api.timeline.EntitlementTimelineApi;
-import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceUserApi;
-import com.ning.billing.jaxrs.json.AccountJson;
-import com.ning.billing.jaxrs.json.InvoiceJson;
+
+import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
 import com.ning.billing.jaxrs.util.Context;
 import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
-import com.ning.billing.jaxrs.util.TagHelper;
-import com.ning.billing.payment.api.PaymentApi;
-import com.ning.billing.util.api.TagUserApi;
-
 
 
 @Path(BaseJaxrsResource.INVOICES_PATH)
 public class InvoiceResource implements BaseJaxrsResource {
 
 
-    private static final Logger log = LoggerFactory.getLogger(AccountResource.class);
+    private static final Logger log = LoggerFactory.getLogger(InvoiceResource.class);
 
     private final DateTimeFormatter DATE_TIME_FORMATTER = ISODateTimeFormat.dateTime();
     
@@ -93,9 +86,9 @@ public class InvoiceResource implements BaseJaxrsResource {
             Preconditions.checkNotNull(accountId, "% query parameter must be specified", QUERY_ACCOUNT_ID);
             accountApi.getAccountById(UUID.fromString(accountId));
             List<Invoice> invoices = invoiceApi.getInvoicesByAccount(UUID.fromString(accountId));
-            List<InvoiceJson> result = new LinkedList<InvoiceJson>();
+            List<InvoiceJsonSimple> result = new LinkedList<InvoiceJsonSimple>();
             for (Invoice cur : invoices) {
-                result.add(new InvoiceJson(cur));
+                result.add(new InvoiceJsonSimple(cur));
             }
             return Response.status(Status.OK).entity(result).build();
         } catch (AccountApiException e) {
@@ -110,14 +103,14 @@ public class InvoiceResource implements BaseJaxrsResource {
     @Produces(APPLICATION_JSON)
     public Response getInvoice(@PathParam("invoiceId") String invoiceId) {
         Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId));
-        InvoiceJson json = new InvoiceJson(invoice);
+        InvoiceJsonSimple json = new InvoiceJsonSimple(invoice);
         return Response.status(Status.OK).entity(json).build();
     }
 
     @POST
     @Consumes(APPLICATION_JSON)
     @Produces(APPLICATION_JSON)
-    public Response createFutureInvoice(final InvoiceJson invoice,
+    public Response createFutureInvoice(final InvoiceJsonSimple invoice,
             @QueryParam(QUERY_ACCOUNT_ID) final String accountId,
             @QueryParam(QUERY_TARGET_DATE) final String targetDate,
             @QueryParam(QUERY_DRY_RUN) @DefaultValue("false") final Boolean dryRun,
@@ -136,7 +129,7 @@ public class InvoiceResource implements BaseJaxrsResource {
             Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRun.booleanValue(),
                     context.createContext(createdBy, reason, comment));
             if (dryRun) {
-                return Response.status(Status.OK).entity(new InvoiceJson(generatedInvoice)).build();
+                return Response.status(Status.OK).entity(new InvoiceJsonSimple(generatedInvoice)).build();
             } else {
                return uriBuilder.buildResponse(InvoiceResource.class, "getInvoice", generatedInvoice.getId());
             }
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index c2f5391..2988f5a 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -28,7 +28,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
-import com.ning.billing.jaxrs.json.PaymentJson;
+import com.ning.billing.jaxrs.json.PaymentJsonSimple;
 
 
 @Path("/1.0/payment")
@@ -53,7 +53,7 @@ public class PaymentResource {
     @Produces(APPLICATION_JSON)
     @Consumes(APPLICATION_JSON)
     @Path("/{invoiceId:\\w+-\\w+-\\w+-\\w+-\\w+}")
-    public Response createInstantPayment(PaymentJson payment,
+    public Response createInstantPayment(PaymentJsonSimple payment,
             @PathParam("invoiceId") String invoiceId,
             @QueryParam("last4CC") String last4CC,
             @QueryParam("nameOnCC") String nameOnCC) {
diff --git a/junction/src/main/java/com/ning/billing/junction/block/DefaultBlockingChecker.java b/junction/src/main/java/com/ning/billing/junction/block/DefaultBlockingChecker.java
index 38f8bb7..8becce5 100644
--- a/junction/src/main/java/com/ning/billing/junction/block/DefaultBlockingChecker.java
+++ b/junction/src/main/java/com/ning/billing/junction/block/DefaultBlockingChecker.java
@@ -65,7 +65,7 @@ public class DefaultBlockingChecker implements BlockingChecker {
 
     private static final Object TYPE_SUBSCRIPTION = "Subscription";
     private static final Object TYPE_BUNDLE = "Bundle";
-    private static final Object TYPE_ACCOUNT = "Account";
+    private static final Object TYPE_ACCOUNT = "ACCOUNT";
 
     private static final Object ACTION_CHANGE = "Change";
     private static final Object ACTION_ENTITLEMENT = "Entitlement";
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingAccount.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingAccount.java
index 30347a4..83b9aaf 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingAccount.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingAccount.java
@@ -19,8 +19,8 @@ package com.ning.billing.junction.plumbing.api;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
-import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.account.api.Account;
@@ -52,31 +52,15 @@ public class BlockingAccount implements Account {
         return account.hasTag(tagDefinition);
     }
 
-    public String getUpdatedBy() {
-        return account.getUpdatedBy();
-    }
-
     public UUID getId() {
         return account.getId();
     }
 
-    public String getCreatedBy() {
-        return account.getCreatedBy();
-    }
-
     @Override
     public boolean hasTag(ControlTagType controlTagType) {
         return account.hasTag(controlTagType);
     }
 
-    public DateTime getUpdatedDate() {
-        return account.getUpdatedDate();
-    }
-
-    public DateTime getCreatedDate() {
-        return account.getCreatedDate();
-    }
-
     public void addTag(TagDefinition definition) {
         account.addTag(definition);
     }
@@ -205,8 +189,8 @@ public class BlockingAccount implements Account {
         return account.getStateOrProvince();
     }
 
-    public String getObjectName() {
-        return account.getObjectName();
+    public ObjectType getObjectType() {
+        return account.getObjectType();
     }
 
     public String getPostalCode() {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
index bc38db9..3de3305 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/api/BlockingSubscription.java
@@ -19,6 +19,7 @@ package com.ning.billing.junction.plumbing.api;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import org.joda.time.DateTime;
 
@@ -67,18 +68,10 @@ public class BlockingSubscription implements Subscription {
         return subscription.getId();
     }
 
-    public String getCreatedBy() {
-        return subscription.getCreatedBy();
-    }
-
     public boolean hasTag(ControlTagType controlTagType) {
         return subscription.hasTag(controlTagType);
     }
 
-    public DateTime getCreatedDate() {
-        return subscription.getCreatedDate();
-    }
-
     public void addTag(TagDefinition definition) {
         subscription.addTag(definition);
     }
@@ -140,8 +133,8 @@ public class BlockingSubscription implements Subscription {
         subscription.clearPersistedFields(context);
     }
 
-    public String getObjectName() {
-        return subscription.getObjectName();
+    public ObjectType getObjectType() {
+        return subscription.getObjectType();
     }
 
     public boolean cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index 3f14062..8f88049 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -22,7 +22,6 @@ import java.util.TreeSet;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/junction/src/main/resources/com/ning/billing/junction/ddl.sql b/junction/src/main/resources/com/ning/billing/junction/ddl.sql
index 656ce70..92b3437 100644
--- a/junction/src/main/resources/com/ning/billing/junction/ddl.sql
+++ b/junction/src/main/resources/com/ning/billing/junction/ddl.sql
@@ -1,13 +1,15 @@
 
 DROP TABLE IF EXISTS blocking_states;
 CREATE TABLE blocking_states (
-  id char(36) NOT NULL,
-  type varchar(20) NOT NULL,
-  state varchar(50) NOT NULL,  
-  service varchar(20) NOT NULL,    
-  block_change bool NOT NULL,
-  block_entitlement bool NOT NULL,
-  block_billing bool NOT NULL,
-  created_date datetime NOT NULL
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    type varchar(20) NOT NULL,
+    state varchar(50) NOT NULL,
+    service varchar(20) NOT NULL,
+    block_change bool NOT NULL,
+    block_entitlement bool NOT NULL,
+    block_billing bool NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
-CREATE INDEX blocking_states_by_id ON blocking_states (id);
\ No newline at end of file
+CREATE INDEX blocking_states_id ON blocking_states(id);
\ No newline at end of file
diff --git a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
index 78ca164..c6241d8 100644
--- a/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/api/blocking/TestBlockingApi.java
@@ -27,12 +27,10 @@ import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
-import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.junction.MockModule;
diff --git a/junction/src/test/java/com/ning/billing/junction/blocking/TestBlockingChecker.java b/junction/src/test/java/com/ning/billing/junction/blocking/TestBlockingChecker.java
index 0753924..0bff4da 100644
--- a/junction/src/test/java/com/ning/billing/junction/blocking/TestBlockingChecker.java
+++ b/junction/src/test/java/com/ning/billing/junction/blocking/TestBlockingChecker.java
@@ -215,7 +215,7 @@ public class TestBlockingChecker {
         }
         
         
-        //BLOCKED Account
+        //BLOCKED ACCOUNT
         setStateSubscription(false, false, false);
         setStateBundle(false, false, false);
         setStateAccount(true, false, false);
@@ -293,7 +293,7 @@ public class TestBlockingChecker {
         }
         
         
-        //BLOCKED Account
+        //BLOCKED ACCOUNT
         setStateSubscription(false, false, false);
         setStateBundle(false, false, false);
         setStateAccount(true, false, false);
@@ -338,7 +338,7 @@ public class TestBlockingChecker {
         checker.checkBlockedEntitlement(account);
         checker.checkBlockedBilling(account);
 
-        //BLOCKED Account
+        //BLOCKED ACCOUNT
         setStateSubscription(false, false, false);
         setStateBundle(false, false, false);
         setStateAccount(true, false, false);
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
index 2780249..8c85596 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/MockSubscription.java
@@ -19,6 +19,7 @@ package com.ning.billing.junction.plumbing.billing;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.BillingPeriod;
@@ -50,18 +51,10 @@ public class MockSubscription implements Subscription {
         return sub.getId();
     }
 
-    public String getCreatedBy() {
-        return sub.getCreatedBy();
-    }
-
     public boolean hasTag(TagDefinition tagDefinition) {
         return sub.hasTag(tagDefinition);
     }
 
-    public DateTime getCreatedDate() {
-        return sub.getCreatedDate();
-    }
-
     public String getFieldValue(String fieldName) {
         return sub.getFieldValue(fieldName);
     }
@@ -126,12 +119,13 @@ public class MockSubscription implements Subscription {
         sub.clearPersistedFields(context);
     }
 
-    public boolean cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException {
-        return sub.cancel(requestedDate, eot, context);
+    @Override
+    public ObjectType getObjectType() {
+        return sub.getObjectType();
     }
 
-    public String getObjectName() {
-        return sub.getObjectName();
+    public boolean cancel(DateTime requestedDate, boolean eot, CallContext context) throws EntitlementUserApiException {
+        return sub.cancel(requestedDate, eot, context);
     }
 
     public boolean uncancel(CallContext context) throws EntitlementUserApiException {
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
index 65ebcb3..85e239f 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestDefaultEntitlementBillingApi.java
@@ -250,7 +250,7 @@ public class TestDefaultEntitlementBillingApi {
 		checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
 	}
 
-    @Test(enabled=true, groups="fast")
+    @Test(enabled=false, groups="fast")
 	public void testBillingEventsAnnual() throws CatalogApiException {
 		DateTime now = clock.getUTCNow();
 		DateTime then = now.minusDays(1);
@@ -317,7 +317,7 @@ public class TestDefaultEntitlementBillingApi {
 		checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
 	}
 
-    @Test(enabled=true, groups="fast")
+    @Test(enabled=false, groups="fast")
 	public void testBillingEventsAddOn() throws CatalogApiException {
 		DateTime now = clock.getUTCNow();
 		DateTime then = now.minusDays(1);
diff --git a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
index b39411a..9f45075 100644
--- a/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
+++ b/overdue/src/main/java/com/ning/billing/ovedue/notification/DefaultOverdueCheckNotifier.java
@@ -76,16 +76,8 @@ public class DefaultOverdueCheckNotifier implements  OverdueCheckNotifier {
                     return config.isNotificationProcessingOff();
                 }
                 @Override
-                public long getNotificationSleepTimeMs() {
-                    return config.getNotificationSleepTimeMs();
-                }
-                @Override
-                public int getDaoMaxReadyEvents() {
-                    return config.getDaoMaxReadyEvents();
-                }
-                @Override
-                public long getDaoClaimTimeMs() {
-                    return config.getDaoClaimTimeMs();
+                public long getSleepTimeMs() {
+                    return config.getSleepTimeMs();
                 }
             });
         } catch (NotificationQueueAlreadyExists e) {
diff --git a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
index f208813..4039a51 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/listener/OverdueListener.java
@@ -45,15 +45,15 @@ public class OverdueListener {
     public void handlePaymentInfoEvent(final PaymentInfoEvent event) {
         log.info(String.format("Received PaymentInfo event %s", event.toString()));
         try {
-            String paymentId = event.getPaymentId();
+            UUID paymentId = event.getId();
             PaymentAttempt attempt = paymentApi.getPaymentAttemptForPaymentId(paymentId);
             UUID accountId = attempt.getAccountId();
             dispatcher.processOverdueForAccount(accountId);
         } catch (PaymentApiException e) {
-            log.error("Payment exception encountered when trying process Overdue against payement: " + event.getPaymentId(), e);
+            log.error("Payment exception encountered when trying process Overdue against payement: " + event.getId(), e);
         }
     }
-
+ 
     @Subscribe
     public void handlePaymentErrorEvent(final PaymentErrorEvent event) {
         log.info(String.format("Received PaymentError event %s", event.toString()));
diff --git a/overdue/src/main/java/com/ning/billing/overdue/OverdueProperties.java b/overdue/src/main/java/com/ning/billing/overdue/OverdueProperties.java
index e3cfd36..0f6b010 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/OverdueProperties.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/OverdueProperties.java
@@ -26,19 +26,9 @@ import com.ning.billing.config.NotificationConfig;
 public interface OverdueProperties extends NotificationConfig, KillbillConfig  {
 
     @Override
-    @Config("killbill.overdue.dao.claim.time")
-    @Default("60000")
-    public long getDaoClaimTimeMs();
-
-    @Override   
-    @Config("killbill.overdue.dao.ready.max")
-    @Default("10")
-    public int getDaoMaxReadyEvents();
-
-    @Override
     @Config("killbill.overdue.engine.notifications.sleep")
     @Default("500")
-    public long getNotificationSleepTimeMs();
+    public long getSleepTimeMs();
 
     @Override
     @Config("killbill.notifications.off")
diff --git a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
index ada0f15..e019e01 100644
--- a/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
+++ b/overdue/src/main/java/com/ning/billing/overdue/service/DefaultOverdueService.java
@@ -94,7 +94,7 @@ public class DefaultOverdueService implements ExtendedOverdueService {
                 overdueConfig = new OverdueConfig();
             } catch (IllegalArgumentException e) {
                 overdueConfig = new OverdueConfig();
-            }catch (Exception e) {
+            } catch (Exception e) {
                 throw new ServiceException(e);
             }
             

payment/pom.xml 12(+12 -0)

diff --git a/payment/pom.xml b/payment/pom.xml
index 9df551f..e4933be 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -34,6 +34,18 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-account</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ning.billing</groupId>
+            <artifactId>killbill-invoice</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <scope>provided</scope>
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index a670ab3..e38e2d9 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -22,8 +22,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
-
 import org.apache.commons.lang.StringUtils;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
@@ -209,10 +207,10 @@ public class DefaultPaymentApi implements PaymentApi {
 
                     } else {
                         
-                        PaymentAttempt newPaymentAttempt = new PaymentAttempt.Builder(paymentAttempt)
-                        .setRetryCount(paymentAttempt.getRetryCount() + 1)
-                        .setPaymentAttemptId(UUID.randomUUID())
-                        .build();
+                        PaymentAttempt newPaymentAttempt = new DefaultPaymentAttempt.Builder(paymentAttempt)
+                                                                                    .setRetryCount(paymentAttempt.getRetryCount() + 1)
+                                                                                    .setPaymentAttemptId(UUID.randomUUID())
+                                                                                    .build();
 
                         paymentDao.createPaymentAttempt(newPaymentAttempt, context);
                         Either<PaymentErrorEvent, PaymentInfoEvent> result =  processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
@@ -296,18 +294,18 @@ public class DefaultPaymentApi implements PaymentApi {
 
                 if (paymentMethodInfo instanceof CreditCardPaymentMethodInfo) {
                     CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethodInfo;
-                    paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getPaymentId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry(), context);
+                    paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry(), context);
                 }
                 else if (paymentMethodInfo instanceof PaypalPaymentMethodInfo) {
                     PaypalPaymentMethodInfo paypalPaymentMethodInfo = (PaypalPaymentMethodInfo)paymentMethodInfo;
-                    paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getPaymentId(), null, null, context);
+                    paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getId(), null, null, context);
                 }
             } else {
                 log.info(paymentMethodInfoOrError.getLeft().getMessage());
             }
 
-            if (paymentInfo.getPaymentId() != null) {
-                paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getPaymentAttemptId(), paymentInfo.getPaymentId(), context);
+            if (paymentInfo.getId() != null) {
+                paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getId(), paymentInfo.getId(), context);
             }
             postPaymentEvent(paymentInfo, account.getId());
        }
@@ -317,7 +315,7 @@ public class DefaultPaymentApi implements PaymentApi {
                 paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
                         //                                                                         paymentInfo.getRefundAmount(), TODO
                         paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency(),
-                                paymentAttempt.getPaymentAttemptId(),
+                                paymentAttempt.getId(),
                                 paymentAttempt.getPaymentAttemptDate(),
                                 context);
 
@@ -394,7 +392,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public PaymentAttempt getPaymentAttemptForPaymentId(String id) {
+    public PaymentAttempt getPaymentAttemptForPaymentId(UUID id) {
         return paymentDao.getPaymentAttemptForPaymentId(id);
     }
 
@@ -415,8 +413,13 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
-        return paymentDao.getPaymentInfo(invoiceIds);
+    public List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds) {
+        return paymentDao.getPaymentInfoList(invoiceIds);
+    }
+
+    @Override
+    public PaymentInfoEvent getLastPaymentInfo(List<String> invoiceIds) {
+        return paymentDao.getLastPaymentInfo(invoiceIds);
     }
 
     @Override
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java
new file mode 100644
index 0000000..681f0ca
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentAttempt.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2010-2011 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.payment.api;
+
+import java.math.BigDecimal;
+import java.util.UUID;
+
+import com.ning.billing.util.entity.EntityBase;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.google.common.base.Objects;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.Invoice;
+
+public class DefaultPaymentAttempt extends EntityBase implements PaymentAttempt  {
+    private final UUID invoiceId;
+    private final UUID accountId;
+    private final BigDecimal amount;
+    private final Currency currency;
+    private final UUID paymentId;
+    private final DateTime invoiceDate;
+    private final DateTime paymentAttemptDate;
+    private final Integer retryCount;
+    private final DateTime createdDate;
+    private final DateTime updatedDate;
+
+    public DefaultPaymentAttempt(UUID id,
+                          UUID invoiceId,
+                          UUID accountId,
+                          BigDecimal amount,
+                          Currency currency,
+                          DateTime invoiceDate,
+                          DateTime paymentAttemptDate,
+                          UUID paymentId,
+                          Integer retryCount,
+                          DateTime createdDate, DateTime updatedDate) {
+        super(id);
+        this.invoiceId = invoiceId;
+        this.accountId = accountId;
+        this.amount = amount;
+        this.currency = currency;
+        this.invoiceDate = invoiceDate;
+        this.paymentAttemptDate = paymentAttemptDate == null ? new DateTime(DateTimeZone.UTC) : paymentAttemptDate;
+        this.paymentId = paymentId;
+        this.retryCount = retryCount == null ? 0 : retryCount;
+        this.createdDate = createdDate;
+        this.updatedDate = updatedDate;
+    }
+
+    public DefaultPaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, BigDecimal amount, Currency currency, DateTime invoiceDate, DateTime paymentAttemptDate) {
+        this(paymentAttemptId, invoiceId, accountId, amount, currency, invoiceDate, paymentAttemptDate, null, null, null, null);
+    }
+
+    public DefaultPaymentAttempt(UUID paymentAttemptId, UUID invoiceId, UUID accountId, DateTime invoiceDate, DateTime paymentAttemptDate) {
+        this(paymentAttemptId, invoiceId, accountId, null, null, invoiceDate, paymentAttemptDate, null, null, null, null);
+    }
+
+    public DefaultPaymentAttempt(UUID paymentAttemptId, Invoice invoice) {
+        this(paymentAttemptId, invoice.getId(), invoice.getAccountId(), invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(), null, null, null, null, null);
+    }
+
+    @Override public DateTime getInvoiceDate() {
+        return invoiceDate;
+    }
+
+    @Override public UUID getId() {
+        return id;
+    }
+
+    @Override public UUID getPaymentId() {
+        return paymentId;
+    }
+
+    @Override public DateTime getPaymentAttemptDate() {
+        return paymentAttemptDate;
+    }
+
+    @Override public UUID getInvoiceId() {
+        return invoiceId;
+    }
+
+    @Override public UUID getAccountId() {
+        return accountId;
+    }
+
+    @Override public BigDecimal getAmount() {
+        return amount;
+    }
+
+    @Override public Currency getCurrency() {
+        return currency;
+    }
+
+    @Override public Integer getRetryCount() {
+        return retryCount;
+    }
+
+    @Override public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    @Override public DateTime getUpdatedDate() {
+        return updatedDate;
+    }
+
+    @Override
+    public String toString() {
+        return "PaymentAttempt [paymentAttemptId=" + id + ", invoiceId=" + invoiceId + ", accountId=" + accountId + ", amount=" + amount + ", currency=" + currency + ", paymentId=" + paymentId + ", invoiceDate=" + invoiceDate + ", paymentAttemptDate=" + paymentAttemptDate + ", retryCount=" + retryCount + "]";
+    }
+
+    public Builder cloner() {
+        return new Builder(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(id,
+                                invoiceId,
+                                accountId,
+                                amount,
+                                currency,
+                                invoiceDate,
+                                paymentAttemptDate,
+                                paymentId,
+                                retryCount,
+                                createdDate, updatedDate);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final PaymentAttempt that = (PaymentAttempt) o;
+
+        if (accountId != null ? !accountId.equals(that.getAccountId()) : that.getAccountId() != null) return false;
+        if (amount != null ? !(amount.compareTo(that.getAmount()) == 0) : that.getAmount() != null) return false;
+        if (currency != that.getCurrency()) return false;
+        if (invoiceDate == null ? that.getInvoiceDate() != null : invoiceDate.compareTo(that.getInvoiceDate()) != 0) return false;
+        if (invoiceId != null ? !invoiceId.equals(that.getInvoiceId()) : that.getInvoiceId() != null) return false;
+        if (paymentAttemptDate == null ? that.getPaymentAttemptDate() != null : paymentAttemptDate.compareTo(that.getPaymentAttemptDate()) != 0) return false;
+        if (id != null ? !id.equals(that.getId()) : that.getId() != null)
+            return false;
+        if (paymentId != null ? !paymentId.equals(that.getPaymentId()) : that.getPaymentId() != null) return false;
+        if (retryCount != null ? !retryCount.equals(that.getRetryCount()) : that.getRetryCount() != null) return false;
+        if (createdDate.compareTo(that.getCreatedDate()) != 0) return false;
+        if (updatedDate.compareTo(that.getUpdatedDate()) != 0) return false;
+
+        return true;
+    }
+
+    public static class Builder {
+        private UUID id;
+        private UUID invoiceId;
+        private UUID accountId;
+        private BigDecimal amount;
+        private Currency currency;
+        private DateTime invoiceDate;
+        private DateTime paymentAttemptDate;
+        private UUID paymentId;
+        private Integer retryCount;
+        private DateTime createdDate;
+        private DateTime updatedDate;
+
+        public Builder() {
+        }
+
+        public Builder(PaymentAttempt src) {
+            this.id = src.getId();
+            this.invoiceId = src.getInvoiceId();
+            this.accountId = src.getAccountId();
+            this.amount = src.getAmount();
+            this.currency = src.getCurrency();
+            this.invoiceDate = src.getInvoiceDate();
+            this.paymentAttemptDate = src.getPaymentAttemptDate();
+            this.paymentId = src.getPaymentId();
+            this.retryCount = src.getRetryCount();
+            this.createdDate = src.getCreatedDate();
+            this.updatedDate = src.getUpdatedDate();
+        }
+
+        public Builder setPaymentAttemptId(UUID paymentAttemptId) {
+            this.id = paymentAttemptId;
+            return this;
+        }
+
+        public Builder setInvoiceId(UUID invoiceId) {
+            this.invoiceId = invoiceId;
+            return this;
+        }
+
+        public Builder setAccountId(UUID accountId) {
+            this.accountId = accountId;
+            return this;
+        }
+
+        public Builder setAmount(BigDecimal amount) {
+            this.amount = amount;
+            return this;
+        }
+
+        public Builder setCurrency(Currency currency) {
+            this.currency = currency;
+            return this;
+        }
+
+        public Builder setInvoiceDate(DateTime invoiceDate) {
+            this.invoiceDate = invoiceDate;
+            return this;
+        }
+
+        public Builder setPaymentAttemptDate(DateTime paymentAttemptDate) {
+            this.paymentAttemptDate = paymentAttemptDate;
+            return this;
+        }
+
+        public Builder setPaymentId(UUID paymentId) {
+            this.paymentId = paymentId;
+            return this;
+        }
+
+        public Builder setRetryCount(Integer retryCount) {
+            this.retryCount = retryCount;
+            return this;
+        }
+
+        public Builder setCreatedDate(DateTime createdDate) {
+            this.createdDate = createdDate;
+            return this;
+        }
+
+        public Builder setUpdateDate(DateTime updateDate) {
+            this.updatedDate = updateDate;
+            return this;
+        }
+
+        public PaymentAttempt build() {
+            return new DefaultPaymentAttempt(id,
+                                      invoiceId,
+                                      accountId,
+                                      amount,
+                                      currency,
+                                      invoiceDate,
+                                      paymentAttemptDate,
+                                      paymentId,
+                                      retryCount,
+                                      createdDate, updatedDate);
+        }
+    }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
index e592294..02b7299 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentInfoEvent.java
@@ -19,20 +19,15 @@ package com.ning.billing.payment.api;
 import java.math.BigDecimal;
 import java.util.UUID;
 
+import com.ning.billing.util.entity.EntityBase;
 import org.codehaus.jackson.annotate.JsonCreator;
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 
 import com.google.common.base.Objects;
-import com.ning.billing.util.bus.BusEvent;
-import com.ning.billing.util.bus.BusEvent.BusEventType;
 
-public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
-	
-
-    private final String paymentId;
+public class DefaultPaymentInfoEvent extends EntityBase implements PaymentInfoEvent {
     private final BigDecimal amount;
     private final BigDecimal refundAmount;
     private final String paymentNumber;
@@ -46,11 +41,9 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
     private final String cardCountry;
 	private final UUID userToken;
     private final DateTime effectiveDate;
-    private final DateTime createdDate;
-    private final DateTime updatedDate;
 
     @JsonCreator
-    public DefaultPaymentInfoEvent(@JsonProperty("paymentId") String paymentId,
+    public DefaultPaymentInfoEvent(@JsonProperty("id") UUID id,
                        @JsonProperty("amount") BigDecimal amount,
                        @JsonProperty("refundAmount") BigDecimal refundAmount,
                        @JsonProperty("bankIdentificationNumber") String bankIdentificationNumber,
@@ -63,10 +56,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
                        @JsonProperty("cardType") String cardType,
                        @JsonProperty("cardCountry") String cardCountry,
                        @JsonProperty("userToken") UUID userToken,
-                       @JsonProperty("effectiveDate") DateTime effectiveDate,
-                       @JsonProperty("createdDate") DateTime createdDate,
-                       @JsonProperty("updatedDate") DateTime updatedDate) {
-        this.paymentId = paymentId;
+                       @JsonProperty("effectiveDate") DateTime effectiveDate) {
+        super(id);
         this.amount = amount;
         this.refundAmount = refundAmount;
         this.bankIdentificationNumber = bankIdentificationNumber;
@@ -80,12 +71,10 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
         this.cardCountry = cardCountry;
         this.userToken = userToken;
         this.effectiveDate = effectiveDate;
-        this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
-        this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
     }
 
     public DefaultPaymentInfoEvent(DefaultPaymentInfoEvent src) {
-        this(src.paymentId,
+        this(src.id,
              src.amount,
              src.refundAmount,
              src.bankIdentificationNumber,
@@ -98,9 +87,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
              src.cardType,
              src.cardCountry,
              src.userToken,
-             src.effectiveDate,
-             src.createdDate,
-             src.updatedDate);
+             src.effectiveDate);
     }
     
     @JsonIgnore
@@ -119,11 +106,6 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
     }
 
     @Override
-    public String getPaymentId() {
-        return paymentId;
-    }
-
-    @Override
     public BigDecimal getAmount() {
         return amount;
     }
@@ -134,11 +116,6 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
     }
 
     @Override
-    public DateTime getCreatedDate() {
-        return createdDate;
-    }
-
-    @Override
     public DateTime getEffectiveDate() {
         return effectiveDate;
     }
@@ -188,13 +165,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
         return type;
     }
 
-    @Override
-    public DateTime getUpdatedDate() {
-        return updatedDate;
-    }
-
     public static class Builder {
-        private String paymentId;
+        private UUID id;
         private BigDecimal amount;
         private BigDecimal refundAmount;
         private String paymentNumber;
@@ -208,14 +180,12 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
         private String cardCountry;
         private UUID userToken;
         private DateTime effectiveDate;
-        private DateTime createdDate;
-        private DateTime updatedDate;
 
         public Builder() {
         }
 
         public Builder(DefaultPaymentInfoEvent src) {
-            this.paymentId = src.paymentId;
+            this.id = src.id;
             this.amount = src.amount;
             this.refundAmount = src.refundAmount;
             this.paymentNumber = src.paymentNumber;
@@ -229,12 +199,10 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
             this.cardType = src.cardType;
             this.cardCountry = src.cardCountry;
             this.userToken = src.userToken;
-            this.createdDate = src.createdDate;
-            this.updatedDate = src.updatedDate;
         }
 
-        public Builder setPaymentId(String paymentId) {
-            this.paymentId = paymentId;
+        public Builder setId(UUID id) {
+            this.id = id;
             return this;
         }
 
@@ -253,11 +221,6 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
             return this;
         }
 
-        public Builder setCreatedDate(DateTime createdDate) {
-            this.createdDate = createdDate;
-            return this;
-        }
-
         public Builder setEffectiveDate(DateTime effectiveDate) {
             this.effectiveDate = effectiveDate;
             return this;
@@ -308,13 +271,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
             return this;
         }
 
-        public Builder setUpdatedDate(DateTime updatedDate) {
-            this.updatedDate = updatedDate;
-            return this;
-        }
-
         public PaymentInfoEvent build() {
-            return new DefaultPaymentInfoEvent(paymentId,
+            return new DefaultPaymentInfoEvent(id,
                                    amount,
                                    refundAmount,
                                    bankIdentificationNumber,
@@ -327,15 +285,13 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
                                    cardType,
                                    cardCountry,
                                    userToken,
-                                   effectiveDate,
-                                   createdDate,
-                                   updatedDate);
+                                   effectiveDate);
         }
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(paymentId,
+        return Objects.hashCode(id,
                                 amount,
                                 refundAmount,
                                 bankIdentificationNumber,
@@ -347,9 +303,7 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
                                 paymentMethod,
                                 cardType,
                                 cardCountry,
-                                effectiveDate,
-                                createdDate,
-                                updatedDate);
+                                effectiveDate);
     }
 
     @Override
@@ -364,10 +318,8 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
             return false;
         if (cardCountry != null ? !cardCountry.equals(that.cardCountry) : that.cardCountry != null) return false;
         if (cardType != null ? !cardType.equals(that.cardType) : that.cardType != null) return false;
-        if (createdDate != null ? !(getUnixTimestamp(createdDate) == getUnixTimestamp(that.createdDate)) : that.createdDate != null) return false;
-        if (effectiveDate != null ? !(getUnixTimestamp(effectiveDate) == getUnixTimestamp(that.effectiveDate)) : that.effectiveDate != null)
-            return false;
-        if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) return false;
+        if (effectiveDate == null ? that.effectiveDate != null : effectiveDate.compareTo(that.effectiveDate) != 0) return false;
+        if (id != null ? !id.equals(that.id) : that.id != null) return false;
         if (paymentMethod != null ? !paymentMethod.equals(that.paymentMethod) : that.paymentMethod != null)
             return false;
         if (paymentMethodId != null ? !paymentMethodId.equals(that.paymentMethodId) : that.paymentMethodId != null)
@@ -378,17 +330,12 @@ public class DefaultPaymentInfoEvent implements PaymentInfoEvent {
         if (refundAmount != null ? !refundAmount.equals(that.refundAmount) : that.refundAmount != null) return false;
         if (status != null ? !status.equals(that.status) : that.status != null) return false;
         if (type != null ? !type.equals(that.type) : that.type != null) return false;
-        if (updatedDate != null ? !(getUnixTimestamp(updatedDate) == getUnixTimestamp(that.updatedDate)) : that.updatedDate != null) return false;
 
         return true;
     }
 
     @Override
     public String toString() {
-        return "PaymentInfo [paymentId=" + paymentId + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", paymentMethodId=" + paymentMethodId + ", paymentMethod=" + paymentMethod + ", cardType=" + cardType + ", cardCountry=" + cardCountry + ", effectiveDate=" + effectiveDate + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
-    }
-
-    private static long getUnixTimestamp(final DateTime dateTime) {
-        return dateTime.getMillis() / 1000;
+        return "PaymentInfo [id=" + id + ", amount=" + amount + ", refundAmount=" + refundAmount + ", paymentNumber=" + paymentNumber + ", bankIdentificationNumber=" + bankIdentificationNumber + ", status=" + status + ", type=" + type + ", referenceId=" + referenceId + ", paymentMethodId=" + paymentMethodId + ", paymentMethod=" + paymentMethod + ", cardType=" + cardType + ", cardCountry=" + cardCountry + ", effectiveDate=" + effectiveDate + "]";
     }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index a21a90c..39201ac 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -19,10 +19,12 @@ package com.ning.billing.payment.dao;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
 import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
-import org.apache.commons.lang.Validate;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.TableName;
 import org.skife.jdbi.v2.IDBI;
 
 import com.google.common.collect.ImmutableList;
@@ -34,35 +36,40 @@ import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
 
 public class AuditedPaymentDao implements PaymentDao {
-    private final PaymentSqlDao sqlDao;
+    private final PaymentSqlDao paymentSqlDao;
+    private final PaymentAttemptSqlDao paymentAttemptSqlDao;
 
     @Inject
     public AuditedPaymentDao(IDBI dbi) {
-        this.sqlDao = dbi.onDemand(PaymentSqlDao.class);
+        this.paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
+        this.paymentAttemptSqlDao = dbi.onDemand(PaymentAttemptSqlDao.class);
     }
 
     @Override
-    public PaymentAttempt getPaymentAttemptForPaymentId(String paymentId) {
-        return sqlDao.getPaymentAttemptForPaymentId(paymentId);
+    public PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId) {
+        return paymentAttemptSqlDao.getPaymentAttemptForPaymentId(paymentId.toString());
     }
 
     @Override
     public List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId) {
-        return sqlDao.getPaymentAttemptsForInvoiceId(invoiceId);
+        return paymentAttemptSqlDao.getPaymentAttemptsForInvoiceId(invoiceId);
     }
 
     @Override
     public PaymentAttempt createPaymentAttempt(final PaymentAttempt paymentAttempt, final CallContext context) {
-        return sqlDao.inTransaction(new Transaction<PaymentAttempt, PaymentSqlDao>() {
+        return paymentAttemptSqlDao.inTransaction(new Transaction<PaymentAttempt, PaymentAttemptSqlDao>() {
             @Override
-            public PaymentAttempt inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
+            public PaymentAttempt inTransaction(PaymentAttemptSqlDao transactional, TransactionStatus status) throws Exception {
                 transactional.insertPaymentAttempt(paymentAttempt, context);
-                PaymentAttempt savedPaymentAttempt = transactional.getPaymentAttemptById(paymentAttempt.getPaymentAttemptId().toString());
-                UUID historyRecordId = UUID.randomUUID();
-                transactional.insertPaymentAttemptHistory(historyRecordId.toString(), paymentAttempt, context);
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction("payment_attempt", historyRecordId.toString(),
-                                                       ChangeType.INSERT, context);
+                PaymentAttempt savedPaymentAttempt = transactional.getPaymentAttemptById(paymentAttempt.getId().toString());
+
+                Long recordId = transactional.getRecordId(paymentAttempt.getId().toString());
+                EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttempt.getId(), recordId, paymentAttempt, ChangeType.INSERT);
+                transactional.insertHistoryFromTransaction(history, context);
+
+                Long historyRecordId = transactional.getHistoryRecordId(recordId);
+                EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.INSERT);
+                transactional.insertAuditFromTransaction(audit, context);
                 return savedPaymentAttempt;
             }
         });
@@ -70,16 +77,19 @@ public class AuditedPaymentDao implements PaymentDao {
 
     @Override
     public PaymentAttempt createPaymentAttempt(final Invoice invoice, final CallContext context) {
-        return sqlDao.inTransaction(new Transaction<PaymentAttempt, PaymentSqlDao>() {
+        return paymentAttemptSqlDao.inTransaction(new Transaction<PaymentAttempt, PaymentAttemptSqlDao>() {
             @Override
-            public PaymentAttempt inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
-                final PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
+            public PaymentAttempt inTransaction(PaymentAttemptSqlDao transactional, TransactionStatus status) throws Exception {
+                final PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice);
                 transactional.insertPaymentAttempt(paymentAttempt, context);
-                UUID historyRecordId = UUID.randomUUID();
-                transactional.insertPaymentAttemptHistory(historyRecordId.toString(), paymentAttempt, context);
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction("payment_attempt", historyRecordId.toString(),
-                                                       ChangeType.INSERT, context);
+
+                Long recordId = transactional.getRecordId(paymentAttempt.getId().toString());
+                EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttempt.getId(), recordId, paymentAttempt, ChangeType.INSERT);
+                transactional.insertHistoryFromTransaction(history, context);
+
+                Long historyRecordId = transactional.getHistoryRecordId(recordId);
+                EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.INSERT);
+                transactional.insertAuditFromTransaction(audit, context);
 
                 return paymentAttempt;
             }
@@ -88,15 +98,17 @@ public class AuditedPaymentDao implements PaymentDao {
 
     @Override
     public void savePaymentInfo(final PaymentInfoEvent info, final CallContext context) {
-        sqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
+        paymentSqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
             @Override
             public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
                 transactional.insertPaymentInfo(info, context);
-                UUID historyRecordId = UUID.randomUUID();
-                transactional.insertPaymentInfoHistory(historyRecordId.toString(), info, context);
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction("payment", historyRecordId.toString(),
-                                                       ChangeType.INSERT, context);
+                Long recordId = transactional.getRecordId(info.getId().toString());
+                EntityHistory<PaymentInfoEvent> history = new EntityHistory<PaymentInfoEvent>(info.getId(), recordId, info, ChangeType.INSERT);
+                transactional.insertHistoryFromTransaction(history, context);
+
+                Long historyRecordId = transactional.getHistoryRecordId(recordId);
+                EntityAudit audit = new EntityAudit(TableName.PAYMENTS, historyRecordId, ChangeType.INSERT);
+                transactional.insertAuditFromTransaction(audit, context);
 
                 return null;
             }
@@ -104,17 +116,19 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updatePaymentAttemptWithPaymentId(final UUID paymentAttemptId, final String paymentId, final CallContext context) {
-        sqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
+    public void updatePaymentAttemptWithPaymentId(final UUID paymentAttemptId, final UUID id, final CallContext context) {
+        paymentAttemptSqlDao.inTransaction(new Transaction<Void, PaymentAttemptSqlDao>() {
             @Override
-            public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
-                transactional.updatePaymentAttemptWithPaymentId(paymentAttemptId.toString(), paymentId, context);
+            public Void inTransaction(PaymentAttemptSqlDao transactional, TransactionStatus status) throws Exception {
+                transactional.updatePaymentAttemptWithPaymentId(paymentAttemptId.toString(), id.toString(), context);
                 PaymentAttempt paymentAttempt = transactional.getPaymentAttemptById(paymentAttemptId.toString());
-                UUID historyRecordId = UUID.randomUUID();
-                transactional.insertPaymentAttemptHistory(historyRecordId.toString(), paymentAttempt, context);
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction("payment_attempt", historyRecordId.toString(),
-                                                       ChangeType.UPDATE, context);
+                Long recordId = transactional.getRecordId(paymentAttemptId.toString());
+                EntityHistory<PaymentAttempt> history = new EntityHistory<PaymentAttempt>(paymentAttemptId, recordId, paymentAttempt, ChangeType.UPDATE);
+                transactional.insertHistoryFromTransaction(history, context);
+
+                Long historyRecordId = transactional.getHistoryRecordId(recordId);
+                EntityAudit audit = new EntityAudit(TableName.PAYMENT_ATTEMPTS, historyRecordId, ChangeType.UPDATE);
+                transactional.insertAuditFromTransaction(audit, context);
 
                 return null;
             }
@@ -122,18 +136,21 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updatePaymentInfo(final String type, final String paymentId, final String cardType,
+    public void updatePaymentInfo(final String type, final UUID paymentId, final String cardType,
                                   final String cardCountry, final CallContext context) {
-        sqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
+        paymentSqlDao.inTransaction(new Transaction<Void, PaymentSqlDao>() {
             @Override
             public Void inTransaction(PaymentSqlDao transactional, TransactionStatus status) throws Exception {
-                transactional.updatePaymentInfo(type, paymentId, cardType, cardCountry, context);
-                PaymentInfoEvent paymentInfo = transactional.getPaymentInfo(paymentId);
-                UUID historyRecordId = UUID.randomUUID();
-                transactional.insertPaymentInfoHistory(historyRecordId.toString(), paymentInfo, context);
-                AuditSqlDao auditSqlDao = transactional.become(AuditSqlDao.class);
-                auditSqlDao.insertAuditFromTransaction("payments", historyRecordId.toString(),
-                                                       ChangeType.UPDATE, context);
+                transactional.updatePaymentInfo(type, paymentId.toString(), cardType, cardCountry, context);
+                PaymentInfoEvent paymentInfo = transactional.getPaymentInfo(paymentId.toString());
+
+                Long recordId = transactional.getRecordId(paymentId.toString());
+                EntityHistory<PaymentInfoEvent> history = new EntityHistory<PaymentInfoEvent>(paymentInfo.getId(), recordId, paymentInfo, ChangeType.UPDATE);
+                transactional.insertHistoryFromTransaction(history, context);
+
+                Long historyRecordId = transactional.getHistoryRecordId(recordId);
+                EntityAudit audit = new EntityAudit(TableName.PAYMENT_HISTORY, historyRecordId, ChangeType.UPDATE);
+                transactional.insertAuditFromTransaction(audit, context);
 
                 return null;
             }
@@ -141,11 +158,20 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
-    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
+    public List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds) {
         if (invoiceIds == null || invoiceIds.size() == 0) {
             return ImmutableList.<PaymentInfoEvent>of();
         } else {
-            return sqlDao.getPaymentInfos(invoiceIds);
+            return paymentSqlDao.getPaymentInfoList(invoiceIds);
+        }
+    }
+
+    @Override
+    public PaymentInfoEvent getLastPaymentInfo(List<String> invoiceIds) {
+        if (invoiceIds == null || invoiceIds.size() == 0) {
+            return null;
+        } else {
+            return paymentSqlDao.getLastPaymentInfo(invoiceIds);
         }
     }
 
@@ -154,18 +180,18 @@ public class AuditedPaymentDao implements PaymentDao {
         if (invoiceIds == null || invoiceIds.size() == 0) {
             return ImmutableList.<PaymentAttempt>of();
         } else {
-            return sqlDao.getPaymentAttemptsForInvoiceIds(invoiceIds);
+            return paymentAttemptSqlDao.getPaymentAttemptsForInvoiceIds(invoiceIds);
         }
     }
 
     @Override
     public PaymentAttempt getPaymentAttemptById(UUID paymentAttemptId) {
-        return sqlDao.getPaymentAttemptById(paymentAttemptId.toString());
+        return paymentAttemptSqlDao.getPaymentAttemptById(paymentAttemptId.toString());
     }
 
     @Override
     public PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptIdStr) {
-        return sqlDao.getPaymentInfoForPaymentAttemptId(paymentAttemptIdStr);
+        return paymentSqlDao.getPaymentInfoForPaymentAttemptId(paymentAttemptIdStr);
     }
 
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
new file mode 100644
index 0000000..569ef40
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptHistoryBinder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-2011 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.payment.dao;
+
+import com.ning.billing.payment.api.PaymentAttempt;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(PaymentAttemptHistoryBinder.PaymentAttemptHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PaymentAttemptHistoryBinder {
+    public static class PaymentAttemptHistoryBinderFactory extends BinderBase implements BinderFactory {
+        @Override
+        public Binder<PaymentAttemptHistoryBinder, EntityHistory<PaymentAttempt>> build(Annotation annotation) {
+            return new Binder<PaymentAttemptHistoryBinder, EntityHistory<PaymentAttempt>>() {
+                @Override
+                public void bind(SQLStatement q, PaymentAttemptHistoryBinder bind, EntityHistory<PaymentAttempt> history) {
+                    q.bind("recordId", history.getValue());
+                    q.bind("changeType", history.getChangeType().toString());
+
+                    PaymentAttempt paymentAttempt = history.getEntity();
+                    q.bind("id", paymentAttempt.getId().toString());
+                    q.bind("invoiceId", paymentAttempt.getInvoiceId().toString());
+                    q.bind("accountId", paymentAttempt.getAccountId().toString());
+                    q.bind("amount", paymentAttempt.getAmount());
+                    q.bind("currency", paymentAttempt.getCurrency().toString());
+                    q.bind("invoiceDate", getDate(paymentAttempt.getInvoiceDate()));
+                    q.bind("paymentAttemptDate", getDate(paymentAttempt.getPaymentAttemptDate()));
+                    q.bind("paymentId", paymentAttempt.getPaymentId() == null ? null : paymentAttempt.getPaymentId().toString());
+                    q.bind("retryCount", paymentAttempt.getRetryCount());
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
new file mode 100644
index 0000000..a1fed90
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptSqlDao.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2010-2011 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.payment.dao;
+
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
+import com.ning.billing.payment.api.PaymentAttempt;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+import org.skife.jdbi.v2.unstable.BindIn;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.UUID;
+
+@ExternalizedSqlViaStringTemplate3()
+@RegisterMapper(PaymentAttemptSqlDao.PaymentAttemptMapper.class)
+public interface PaymentAttemptSqlDao extends Transactional<PaymentAttemptSqlDao>, UpdatableEntitySqlDao<PaymentAttempt>, CloseMe {
+    @SqlUpdate
+    void insertPaymentAttempt(@Bind(binder = PaymentAttemptBinder.class) PaymentAttempt paymentAttempt,
+                              @CallContextBinder CallContext context);
+
+    @SqlQuery
+    PaymentAttempt getPaymentAttemptForPaymentId(@Bind("paymentId") String paymentId);
+
+    @SqlQuery
+    PaymentAttempt getPaymentAttemptById(@Bind("id") String paymentAttemptId);
+
+    @SqlQuery
+    List<PaymentAttempt> getPaymentAttemptsForInvoiceId(@Bind("invoiceId") String invoiceId);
+
+    @SqlQuery
+    List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(@BindIn("invoiceIds") List<String> invoiceIds);
+
+
+    @SqlUpdate
+    void updatePaymentAttemptWithPaymentId(@Bind("id") String paymentAttemptId,
+                                           @Bind("payment_id") String paymentId,
+                                           @CallContextBinder CallContext context);
+
+    @SqlUpdate
+    void updatePaymentAttemptWithRetryInfo(@Bind("id") String paymentAttemptId,
+                                           @Bind("retry_count") int retryCount,
+                                           @CallContextBinder CallContext context);
+    
+    @Override
+    @SqlUpdate
+    public void insertHistoryFromTransaction(@PaymentAttemptHistoryBinder final EntityHistory<PaymentAttempt> account,
+                                            @CallContextBinder final CallContext context);
+
+    public static class PaymentAttemptMapper extends MapperBase implements ResultSetMapper<PaymentAttempt> {
+        @Override
+        public PaymentAttempt map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
+
+            UUID paymentAttemptId = getUUID(rs, "id");
+            UUID invoiceId = getUUID(rs, "invoice_id");
+            UUID accountId = getUUID(rs, "account_id");
+            BigDecimal amount = rs.getBigDecimal("amount");
+            Currency currency = Currency.valueOf(rs.getString("currency"));
+            DateTime invoiceDate = getDate(rs, "invoice_date");
+            DateTime paymentAttemptDate = getDate(rs, "payment_attempt_date");
+            UUID paymentId = getUUID(rs, "payment_id");
+            Integer retryCount = rs.getInt("retry_count");
+            DateTime createdDate = getDate(rs, "created_date");
+            DateTime updatedDate = getDate(rs, "updated_date");
+
+            return new DefaultPaymentAttempt(paymentAttemptId,
+                                      invoiceId,
+                                      accountId,
+                                      amount,
+                                      currency,
+                                      invoiceDate,
+                                      paymentAttemptDate,
+                                      paymentId,
+                                      retryCount,
+                                      createdDate, updatedDate);
+        }
+    }
+
+    public static final class PaymentAttemptBinder extends BinderBase implements Binder<Bind, PaymentAttempt> {
+        @Override
+        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentAttempt paymentAttempt) {
+            stmt.bind("id", paymentAttempt.getId().toString());
+            stmt.bind("invoiceId", paymentAttempt.getInvoiceId().toString());
+            stmt.bind("accountId", paymentAttempt.getAccountId().toString());
+            stmt.bind("amount", paymentAttempt.getAmount());
+            stmt.bind("currency", paymentAttempt.getCurrency().toString());
+            stmt.bind("invoiceDate", getDate(paymentAttempt.getInvoiceDate()));
+            stmt.bind("paymentAttemptDate", getDate(paymentAttempt.getPaymentAttemptDate()));
+            stmt.bind("paymentId", paymentAttempt.getPaymentId() == null ? null : paymentAttempt.getPaymentId().toString());
+            stmt.bind("retryCount", paymentAttempt.getRetryCount());
+        }
+    }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
index 8c07824..581ed71 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentDao.java
@@ -31,16 +31,18 @@ public interface PaymentDao {
 
     void savePaymentInfo(PaymentInfoEvent right, CallContext context);
 
-    PaymentAttempt getPaymentAttemptForPaymentId(String paymentId);
+    PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId);
     List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds);
 
-    void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context);
+    void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, UUID paymentId, CallContext context);
 
     List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
 
-    void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context);
+    void updatePaymentInfo(String paymentMethodType, UUID paymentId, String cardType, String cardCountry, CallContext context);
 
-    List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds);
+    List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds);
+
+    PaymentInfoEvent getLastPaymentInfo(List<String> invoiceIds);
 
     PaymentAttempt getPaymentAttemptById(UUID paymentAttemptId);
     PaymentInfoEvent getPaymentInfoForPaymentAttemptId(String paymentAttemptId);
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
new file mode 100644
index 0000000..2ec9fc7
--- /dev/null
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentHistoryBinder.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2011 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.payment.dao;
+
+import com.ning.billing.payment.api.PaymentInfoEvent;
+import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(PaymentHistoryBinder.PaymentHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PaymentHistoryBinder {
+    public static class PaymentHistoryBinderFactory extends BinderBase implements BinderFactory {
+        @Override
+        public Binder<PaymentHistoryBinder, EntityHistory<PaymentInfoEvent>> build(Annotation annotation) {
+            return new Binder<PaymentHistoryBinder, EntityHistory<PaymentInfoEvent>>() {
+                @Override
+                public void bind(SQLStatement q, PaymentHistoryBinder bind, EntityHistory<PaymentInfoEvent> history) {
+                    q.bind("recordId", history.getValue());
+                    q.bind("changeType", history.getChangeType().toString());
+
+                    PaymentInfoEvent paymentInfo = history.getEntity();
+                    q.bind("id", paymentInfo.getId().toString());
+                    q.bind("amount", paymentInfo.getAmount());
+                    q.bind("refund_amount", paymentInfo.getRefundAmount());
+                    q.bind("payment_number", paymentInfo.getPaymentNumber());
+                    q.bind("bank_identification_number", paymentInfo.getBankIdentificationNumber());
+                    q.bind("status", paymentInfo.getStatus());
+                    q.bind("payment_type", paymentInfo.getType());
+                    q.bind("reference_id", paymentInfo.getReferenceId());
+                    q.bind("payment_method_id", paymentInfo.getPaymentMethodId());
+                    q.bind("payment_method", paymentInfo.getPaymentMethod());
+                    q.bind("card_type", paymentInfo.getCardType());
+                    q.bind("card_country", paymentInfo.getCardCountry());
+                    q.bind("effective_date", getDate(paymentInfo.getEffectiveDate()));
+                }
+            };
+        }
+    }
+}
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
index b7b861a..bdd9829 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentSqlDao.java
@@ -25,7 +25,9 @@ import java.util.UUID;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.dao.BinderBase;
+import com.ning.billing.util.dao.EntityHistory;
 import com.ning.billing.util.dao.MapperBase;
+import com.ning.billing.util.entity.dao.UpdatableEntitySqlDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
@@ -36,126 +38,48 @@ import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.mixins.CloseMe;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 import org.skife.jdbi.v2.unstable.BindIn;
 
-import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.payment.api.DefaultPaymentInfoEvent;
-import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 
 @ExternalizedSqlViaStringTemplate3()
-@RegisterMapper({PaymentSqlDao.PaymentAttemptMapper.class, PaymentSqlDao.PaymentInfoMapper.class})
-public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Transmogrifier {
-    @SqlUpdate
-    void insertPaymentAttempt(@Bind(binder = PaymentAttemptBinder.class) PaymentAttempt paymentAttempt,
-                              @CallContextBinder CallContext context);
-
-    @SqlUpdate
-    void insertPaymentAttemptHistory(@Bind("historyRecordId") final String historyRecordId,
-                                     @Bind(binder = PaymentAttemptBinder.class) final PaymentAttempt paymentAttempt,
-                                     @CallContextBinder final CallContext context);
-
-    @SqlQuery
-    PaymentAttempt getPaymentAttemptForPaymentId(@Bind("payment_id") String paymentId);
-
-    @SqlQuery
-    PaymentAttempt getPaymentAttemptById(@Bind("payment_attempt_id") String paymentAttemptId);
-
-    @SqlQuery
-    List<PaymentAttempt> getPaymentAttemptsForInvoiceId(@Bind("invoice_id") String invoiceId);
-
-    @SqlQuery
-    List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(@BindIn("invoiceIds") List<String> invoiceIds);
-
+@RegisterMapper(PaymentSqlDao.PaymentInfoMapper.class)
+public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEntitySqlDao<PaymentInfoEvent>, CloseMe {
     @SqlQuery
     PaymentInfoEvent getPaymentInfoForPaymentAttemptId(@Bind("payment_attempt_id") String paymentAttemptId);
 
     @SqlUpdate
-    void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
-                                           @Bind("payment_id") String paymentId,
-                                           @CallContextBinder CallContext context);
-
-    @SqlUpdate
-    void updatePaymentAttemptWithRetryInfo(@Bind("payment_attempt_id") String paymentAttemptId,
-                                           @Bind("retry_count") int retryCount,
-                                           @CallContextBinder CallContext context);
-
-    @SqlUpdate
     void updatePaymentInfo(@Bind("payment_method") String paymentMethod,
-                           @Bind("payment_id") String paymentId,
+                           @Bind("id") String paymentId,
                            @Bind("card_type") String cardType,
                            @Bind("card_country") String cardCountry,
                            @CallContextBinder CallContext context);
 
     @SqlQuery
-    List<PaymentInfoEvent> getPaymentInfos(@BindIn("invoiceIds") final List<String> invoiceIds);
+    List<PaymentInfoEvent> getPaymentInfoList(@BindIn("invoiceIds") final List<String> invoiceIds);
+
+    @SqlQuery
+    PaymentInfoEvent getLastPaymentInfo(@BindIn("invoiceIds") final List<String> invoiceIds);
 
     @SqlUpdate
     void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) final PaymentInfoEvent paymentInfo,
                            @CallContextBinder final CallContext context);
 
-    @SqlUpdate
-    void insertPaymentInfoHistory(@Bind("historyRecordId") final String historyRecordId,
-                                  @Bind(binder = PaymentInfoBinder.class) final PaymentInfoEvent paymentInfo,
-                                  @CallContextBinder final CallContext context);
-
     @SqlQuery
-    PaymentInfoEvent getPaymentInfo(@Bind("paymentId") final String paymentId);
-
-    public static final class PaymentAttemptBinder extends BinderBase implements Binder<Bind, PaymentAttempt> {
-        @Override
-        public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentAttempt paymentAttempt) {
-            stmt.bind("payment_attempt_id", paymentAttempt.getPaymentAttemptId() == null ? null : paymentAttempt.getPaymentAttemptId().toString());
-            stmt.bind("invoice_id", paymentAttempt.getInvoiceId().toString());
-            stmt.bind("account_id", paymentAttempt.getAccountId().toString());
-            stmt.bind("amount", paymentAttempt.getAmount());
-            stmt.bind("currency", paymentAttempt.getCurrency().toString());
-            stmt.bind("invoice_dt", getDate(paymentAttempt.getInvoiceDate()));
-            stmt.bind("payment_attempt_dt", getDate(paymentAttempt.getPaymentAttemptDate()));
-            stmt.bind("payment_id", paymentAttempt.getPaymentId());
-            stmt.bind("retry_count", paymentAttempt.getRetryCount());
-            stmt.bind("created_dt", getDate(paymentAttempt.getCreatedDate()));
-            stmt.bind("updated_dt", getDate(paymentAttempt.getUpdatedDate()));
-        }
-    }
+    PaymentInfoEvent getPaymentInfo(@Bind("id") final String paymentId);
 
-    public static class PaymentAttemptMapper extends MapperBase implements ResultSetMapper<PaymentAttempt> {
-        @Override
-        public PaymentAttempt map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
-
-            UUID paymentAttemptId = UUID.fromString(rs.getString("payment_attempt_id"));
-            UUID invoiceId = UUID.fromString(rs.getString("invoice_id"));
-            UUID accountId = UUID.fromString(rs.getString("account_id"));
-            BigDecimal amount = rs.getBigDecimal("amount");
-            Currency currency = Currency.valueOf(rs.getString("currency"));
-            DateTime invoiceDate = getDate(rs, "invoice_dt");
-            DateTime paymentAttemptDate = getDate(rs, "payment_attempt_dt");
-            String paymentId = rs.getString("payment_id");
-            Integer retryCount = rs.getInt("retry_count");
-            DateTime createdDate = getDate(rs, "created_dt");
-            DateTime updatedDate = getDate(rs, "updated_dt");
-
-            return new PaymentAttempt(paymentAttemptId,
-                                      invoiceId,
-                                      accountId,
-                                      amount,
-                                      currency,
-                                      invoiceDate,
-                                      paymentAttemptDate,
-                                      paymentId,
-                                      retryCount,
-                                      createdDate,
-                                      updatedDate);
-        }
-    }
+    @Override
+    @SqlUpdate
+    public void insertHistoryFromTransaction(@PaymentHistoryBinder final EntityHistory<PaymentInfoEvent> account,
+                                            @CallContextBinder final CallContext context);
 
     public static final class PaymentInfoBinder extends BinderBase implements Binder<Bind, PaymentInfoEvent> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, PaymentInfoEvent paymentInfo) {
-            stmt.bind("payment_id", paymentInfo.getPaymentId().toString());
+            stmt.bind("id", paymentInfo.getId().toString());
             stmt.bind("amount", paymentInfo.getAmount());
             stmt.bind("refund_amount", paymentInfo.getRefundAmount());
             stmt.bind("payment_number", paymentInfo.getPaymentNumber());
@@ -167,17 +91,14 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
             stmt.bind("payment_method", paymentInfo.getPaymentMethod());
             stmt.bind("card_type", paymentInfo.getCardType());
             stmt.bind("card_country", paymentInfo.getCardCountry());
-            stmt.bind("effective_dt", getDate(paymentInfo.getEffectiveDate()));
-            stmt.bind("created_dt", getDate(paymentInfo.getCreatedDate()));
-            stmt.bind("updated_dt", getDate(paymentInfo.getUpdatedDate()));
+            stmt.bind("effective_date", getDate(paymentInfo.getEffectiveDate()));
         }
     }
 
     public static class PaymentInfoMapper extends MapperBase implements ResultSetMapper<PaymentInfoEvent> {
         @Override
         public PaymentInfoEvent map(int index, ResultSet rs, StatementContext ctx) throws SQLException {
-
-            String paymentId = rs.getString("payment_id");
+            UUID id = getUUID(rs, "id");
             BigDecimal amount = rs.getBigDecimal("amount");
             BigDecimal refundAmount = rs.getBigDecimal("refund_amount");
             String paymentNumber = rs.getString("payment_number");
@@ -189,13 +110,11 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
             String paymentMethod = rs.getString("payment_method");
             String cardType = rs.getString("card_type");
             String cardCountry = rs.getString("card_country");            
-            DateTime effectiveDate = getDate(rs, "effective_dt");
-            DateTime createdDate = getDate(rs, "created_dt");
-            DateTime updatedDate = getDate(rs, "updated_dt");
+            DateTime effectiveDate = getDate(rs, "effective_date");
 
             UUID userToken = null; //rs.getString("user_token") != null ? UUID.fromString(rs.getString("user_token")) : null;
             
-            return new DefaultPaymentInfoEvent(paymentId,
+            return new DefaultPaymentInfoEvent(id,
                                    amount,
                                    refundAmount,
                                    bankIdentificationNumber,
@@ -208,9 +127,7 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, CloseMe, Tr
                                    cardType,
                                    cardCountry,
                                    userToken,
-                                   effectiveDate,
-                                   createdDate,
-                                   updatedDate);
+                                   effectiveDate);
         }
     }
 
diff --git a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
index be654bb..5e73fc5 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/NoOpPaymentProviderPlugin.java
@@ -51,10 +51,9 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
             return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("unknown", "test error", account.getId(), invoice.getId(), null));
         }
         PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder()
-                                             .setPaymentId(UUID.randomUUID().toString())
+                                             .setId(UUID.randomUUID())
                                              .setAmount(invoice.getBalance())
                                              .setStatus("Processed")
-                                             .setCreatedDate(new DateTime(DateTimeZone.UTC))
                                              .setEffectiveDate(new DateTime(DateTimeZone.UTC))
                                              .setType("Electronic")
                                              .build();
@@ -69,7 +68,7 @@ public class NoOpPaymentProviderPlugin implements PaymentProviderPlugin {
     @Override
     public Either<PaymentErrorEvent, String> createPaymentProviderAccount(Account account) {
         return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("unsupported",
-                                            "Account creation not supported in this plugin",
+                                            "ACCOUNT creation not supported in this plugin",
                                             account.getId(),
                                             null, null));
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
index 508fe21..528da58 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -65,8 +65,6 @@ public class RequestProcessor {
  
     @Subscribe
     public void receiveInvoice(InvoiceCreationEvent event) {
-
-
         log.info("Received invoice creation notification for account {} and invoice {}", event.getAccountId(), event.getInvoiceId());
         PaymentErrorEvent errorEvent = null;
         try {
diff --git a/payment/src/main/java/com/ning/billing/payment/RetryService.java b/payment/src/main/java/com/ning/billing/payment/RetryService.java
index f754d36..2f61db4 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -98,7 +98,7 @@ public class RetryService implements KillbillService {
     }
 
     public void scheduleRetry(PaymentAttempt paymentAttempt, DateTime timeOfRetry) {
-        final String id = paymentAttempt.getPaymentAttemptId().toString();
+        final String id = paymentAttempt.getId().toString();
 
         NotificationKey key = new NotificationKey() {
             @Override
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
new file mode 100644
index 0000000..15302fe
--- /dev/null
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
@@ -0,0 +1,106 @@
+group paymentAttemptSqlDao;
+
+paymentAttemptFields(prefix) ::= <<
+    <prefix>id,
+    <prefix>invoice_id,
+    <prefix>account_id,
+    <prefix>amount,
+    <prefix>currency,
+    <prefix>payment_id,
+    <prefix>payment_attempt_date,
+    <prefix>invoice_date,
+    <prefix>retry_count,
+    <prefix>created_by,
+    <prefix>created_date,
+    <prefix>updated_by,
+    <prefix>updated_date
+>>
+
+insertPaymentAttempt() ::= <<
+    INSERT INTO payment_attempts (<paymentAttemptFields()>)
+    VALUES (:id, :invoiceId, :accountId, :amount, :currency, :paymentId,
+            :paymentAttemptDate, :invoiceDate, :retryCount, :userName, :createdDate, :userName, :createdDate);
+>>
+
+getPaymentAttemptForPaymentId() ::= <<
+    SELECT <paymentAttemptFields()>
+      FROM payment_attempts
+     WHERE payment_id = :paymentId;
+>>
+
+getPaymentAttemptById() ::= <<
+    SELECT <paymentAttemptFields()>
+      FROM payment_attempts
+     WHERE id = :id;
+>>
+
+getPaymentAttemptsForInvoiceIds(invoiceIds) ::= <<
+    SELECT <paymentAttemptFields()>
+      FROM payment_attempts
+     WHERE invoice_id in (<invoiceIds>);
+>>
+
+getPaymentAttemptsForInvoiceId() ::= <<
+    SELECT <paymentAttemptFields()>
+      FROM payment_attempts
+     WHERE invoice_id = :invoiceId;
+>>
+
+updatePaymentAttemptWithPaymentId() ::= <<
+    UPDATE payment_attempts
+       SET payment_id = :payment_id,
+           updated_by = :userName,
+           updated_date = :updatedDate
+     WHERE id = :id;
+>>
+
+historyFields(prefix) ::= <<
+    record_id,
+    id,
+    account_id,
+    invoice_id,
+    amount,
+    currency,
+    payment_attempt_date,
+    payment_id,
+    retry_count,
+    invoice_date,
+    created_by,
+    created_date,
+    updated_by,
+    updated_date
+>>
+
+insertHistoryFromTransaction() ::= <<
+    INSERT INTO payment_attempt_history (<historyFields()>)
+    VALUES (:recordId, :id, :accountId, :invoiceId, :amount, :currency, :paymentAttemptDate, :paymentId,
+            :retryCount, :invoiceDate, :userName, :createdDate, :userName, :updatedDate);
+>>
+
+getRecordId() ::= <<
+    SELECT record_id
+    FROM payment_attempts
+    WHERE id = :id;
+>>
+
+getHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM payment_attempt_history
+    WHERE record_id = :recordId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
index 87c8d8f..3f125ab 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -1,23 +1,7 @@
 group PaymentSqlDao;
 
-paymentAttemptFields(prefix) ::= <<
-    <prefix>payment_attempt_id,
-    <prefix>invoice_id,
-    <prefix>account_id,
-    <prefix>amount,
-    <prefix>currency,
-    <prefix>payment_id,
-    <prefix>payment_attempt_dt,
-    <prefix>invoice_dt,
-    <prefix>retry_count,
-    <prefix>created_by,
-    <prefix>created_dt,
-    <prefix>updated_by,
-    <prefix>updated_dt
->>
-
 paymentInfoFields(prefix) ::= <<
-    <prefix>payment_id,
+    <prefix>id,
     <prefix>amount,
     <prefix>refund_amount,
     <prefix>bank_identification_number,
@@ -29,69 +13,18 @@ paymentInfoFields(prefix) ::= <<
     <prefix>payment_method,
     <prefix>card_type,
     <prefix>card_country,
-    <prefix>effective_dt,
+    <prefix>effective_date,
     <prefix>created_by,
-    <prefix>created_dt,
+    <prefix>created_date,
     <prefix>updated_by,
-    <prefix>updated_dt
->>
-
-insertPaymentAttempt() ::= <<
-    INSERT INTO payment_attempts (<paymentAttemptFields()>)
-    VALUES (:payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id,
-            :payment_attempt_dt, :invoice_dt, :retry_count, :userName, :createdDate, :userName, :createdDate);
->>
-
-insertPaymentAttemptHistory() ::= <<
-    INSERT INTO payment_attempt_history (history_record_id, <paymentAttemptFields()>)
-    VALUES (:historyRecordId, :payment_attempt_id, :invoice_id, :account_id, :amount, :currency, :payment_id,
-            :payment_attempt_dt, :invoice_dt, :retry_count, :userName, :createdDate, :userName, :createdDate);
->>
-
-getPaymentAttemptForPaymentId() ::= <<
-    SELECT <paymentAttemptFields()>
-      FROM payment_attempts
-     WHERE payment_id = :payment_id
->>
-
-getPaymentAttemptById() ::= <<
-    SELECT <paymentAttemptFields()>
-      FROM payment_attempts
-     WHERE payment_attempt_id = :payment_attempt_id
->>
-
-getPaymentAttemptsForInvoiceIds(invoiceIds) ::= <<
-    SELECT <paymentAttemptFields()>
-      FROM payment_attempts
-     WHERE invoice_id in (<invoiceIds>)
->>
-
-getPaymentAttemptsForInvoiceId() ::= <<
-    SELECT <paymentAttemptFields()>
-      FROM payment_attempts
-     WHERE invoice_id = :invoice_id
->>
-
-updatePaymentAttemptWithPaymentId() ::= <<
-    UPDATE payment_attempts
-       SET payment_id = :payment_id,
-           updated_by = :userName,
-           updated_dt = :updatedDate
-     WHERE payment_attempt_id = :payment_attempt_id
+    <prefix>updated_date
 >>
 
 insertPaymentInfo() ::= <<
     INSERT INTO payments (<paymentInfoFields()>)
-    VALUES (:payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number,
+    VALUES (:id, :amount, :refund_amount, :bank_identification_number, :payment_number,
     :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
-    :card_country, :effective_dt, :userName, :createdDate, :userName, :createdDate);
->>
-
-insertPaymentInfoHistory() ::= <<
-    INSERT INTO payment_history (history_record_id, <paymentInfoFields()>)
-    VALUES (:historyRecordId, :payment_id, :amount, :refund_amount, :bank_identification_number, :payment_number,
-    :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
-    :card_country, :effective_dt, :userName, :createdDate, :userName, :createdDate);
+    :card_country, :effective_date, :userName, :createdDate, :userName, :createdDate);
 >>
 
 updatePaymentInfo() ::= <<
@@ -100,26 +33,92 @@ updatePaymentInfo() ::= <<
            card_type = :card_type,
            card_country = :card_country,
            updated_by = :userName,
-           updated_dt = :updatedDate
-     WHERE payment_id = :payment_id
+           updated_date = :updatedDate
+     WHERE id = :id
 >>
 
-getPaymentInfos(invoiceIds) ::= <<
+getPaymentInfoList(invoiceIds) ::= <<
     SELECT <paymentInfoFields("p.")>
       FROM payments p, payment_attempts pa
-     WHERE pa.invoice_id in (<invoiceIds>)
-       AND pa.payment_id = p.payment_id
+    WHERE pa.invoice_id in (<invoiceIds>)
+       AND pa.payment_id = p.id
+>>
+
+getLastPaymentInfo(invoiceIds) ::= <<
+    SELECT <paymentInfoFields("p.")>
+    FROM payments p, payment_attempts pa
+    WHERE pa.invoice_id in (<invoiceIds>)
+    AND pa.payment_id = p.id
+    ORDER BY p.created_date DESC
+    LIMIT 1;
 >>
 
 getPaymentInfoForPaymentAttemptId() ::= <<
     SELECT <paymentInfoFields("p.")>
       FROM payments p, payment_attempts pa
-     WHERE pa.payment_attempt_id = :payment_attempt_id
-       AND pa.payment_id = p.payment_id
+    WHERE pa.payment_attempt_id = :payment_attempt_id
+       AND pa.payment_id = p.id
 >>
 
 getPaymentInfo() ::= <<
     SELECT <paymentInfoFields()>
     FROM payments
-    WHERE payment_id = :paymentId
+    WHERE id = :id
+>>
+
+historyFields(prefix) ::= <<
+    record_id,
+    id,
+    amount,
+    refund_amount,
+    payment_number,
+    bank_identification_number,
+    status,
+    reference_id,
+    payment_type,
+    payment_method_id,
+    payment_method,
+    card_type,
+    card_country,
+    effective_date,
+    created_by,
+    created_date,
+    updated_by,
+    updated_date
+>>
+
+insertHistoryFromTransaction() ::= <<
+    INSERT INTO payment_history (<historyFields()>)
+    VALUES (:recordId, :id, :amount, :refund_amount, :bank_identification_number, :payment_number,
+    :payment_type, :status, :reference_id, :payment_method_id, :payment_method, :card_type,
+    :card_country, :effective_date, :userName, :createdDate, :userName, :updatedDate);
+>>
+
+getRecordId() ::= <<
+    SELECT record_id
+    FROM payments
+    WHERE id = :id;
+>>
+
+getHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM payment_history
+    WHERE record_id = :recordId;
 >>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
diff --git a/payment/src/main/resources/com/ning/billing/payment/ddl.sql b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
index 3a344f9..c77945f 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -1,81 +1,90 @@
 DROP TABLE IF EXISTS payment_attempts;
 CREATE TABLE payment_attempts (
-      payment_attempt_id char(36) COLLATE utf8_bin NOT NULL,
-      account_id char(36) COLLATE utf8_bin NOT NULL,
-      invoice_id char(36) COLLATE utf8_bin NOT NULL,
-      amount decimal(8,2),
-      currency char(3),
-      payment_attempt_dt datetime NOT NULL,
-      payment_id varchar(36) COLLATE utf8_bin,
-      retry_count tinyint,
-      invoice_dt datetime NOT NULL,
-      created_by varchar(50) NOT NULL,
-      created_dt datetime NOT NULL,
-      updated_by varchar(50) NOT NULL,
-      updated_dt datetime NOT NULL,
-      PRIMARY KEY (payment_attempt_id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    account_id char(36) COLLATE utf8_bin NOT NULL,
+    invoice_id char(36) COLLATE utf8_bin NOT NULL,
+    amount decimal(8,2),
+    currency char(3),
+    payment_attempt_date datetime NOT NULL,
+    payment_id varchar(36) COLLATE utf8_bin,
+    retry_count tinyint,
+    invoice_date datetime NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    PRIMARY KEY (record_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE UNIQUE INDEX payment_attempts_id ON payment_attempts(id);
+CREATE INDEX payment_attempts_account_id_invoice_id ON payment_attempts(account_id, invoice_id);
 
 DROP TABLE IF EXISTS payment_attempt_history;
 CREATE TABLE payment_attempt_history (
-      history_record_id char(36) NOT NULL,
-      payment_attempt_id char(36) COLLATE utf8_bin NOT NULL,
-      account_id char(36) COLLATE utf8_bin NOT NULL,
-      invoice_id char(36) COLLATE utf8_bin NOT NULL,
-      amount decimal(8,2),
-      currency char(3),
-      payment_attempt_dt datetime NOT NULL,
-      payment_id varchar(36) COLLATE utf8_bin,
-      retry_count tinyint,
-      invoice_dt datetime NOT NULL,
-      created_by varchar(50) NOT NULL,
-      created_dt datetime NOT NULL,
-      updated_by varchar(50) NOT NULL,
-      updated_dt datetime NOT NULL,
-      PRIMARY KEY (history_record_id)
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
+    id char(36) NOT NULL,
+    account_id char(36) COLLATE utf8_bin NOT NULL,
+    invoice_id char(36) COLLATE utf8_bin NOT NULL,
+    amount decimal(8,2),
+    currency char(3),
+    payment_attempt_date datetime NOT NULL,
+    payment_id varchar(36) COLLATE utf8_bin,
+    retry_count tinyint,
+    invoice_date datetime NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    PRIMARY KEY (history_record_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE INDEX payment_attempt_history_record_id ON payment_attempt_history(record_id);
 
 DROP TABLE IF EXISTS payments; 
 CREATE TABLE payments (
-      payment_id varchar(36) COLLATE utf8_bin NOT NULL,
-      amount decimal(8,2),
-      refund_amount decimal(8,2),
-      payment_number varchar(36) COLLATE utf8_bin,
-      bank_identification_number varchar(36) COLLATE utf8_bin,
-      status varchar(20) COLLATE utf8_bin,
-      reference_id varchar(36) COLLATE utf8_bin,
-      payment_type varchar(20) COLLATE utf8_bin,
-      payment_method_id varchar(36) COLLATE utf8_bin,
-      payment_method varchar(20) COLLATE utf8_bin,
-      card_type varchar(20) COLLATE utf8_bin,
-      card_country varchar(50) COLLATE utf8_bin,
-      effective_dt datetime,
-      created_by varchar(50) NOT NULL,
-      created_dt datetime NOT NULL,
-      updated_by varchar(50) NOT NULL,
-      updated_dt datetime NOT NULL,
-      PRIMARY KEY (payment_id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    amount decimal(8,2),
+    refund_amount decimal(8,2),
+    payment_number varchar(36) COLLATE utf8_bin,
+    bank_identification_number varchar(36) COLLATE utf8_bin,
+    status varchar(20) COLLATE utf8_bin,
+    reference_id varchar(36) COLLATE utf8_bin,
+    payment_type varchar(20) COLLATE utf8_bin,
+    payment_method_id varchar(36) COLLATE utf8_bin,
+    payment_method varchar(20) COLLATE utf8_bin,
+    card_type varchar(20) COLLATE utf8_bin,
+    card_country varchar(50) COLLATE utf8_bin,
+    effective_date datetime,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    PRIMARY KEY (record_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE UNIQUE INDEX payments_id ON payments(id);
 
 DROP TABLE IF EXISTS payment_history;
 CREATE TABLE payment_history (
-      history_record_id char(36) NOT NULL,
-      payment_id varchar(36) COLLATE utf8_bin NOT NULL,
-      amount decimal(8,2),
-      refund_amount decimal(8,2),
-      payment_number varchar(36) COLLATE utf8_bin,
-      bank_identification_number varchar(36) COLLATE utf8_bin,
-      status varchar(20) COLLATE utf8_bin,
-      reference_id varchar(36) COLLATE utf8_bin,
-      payment_type varchar(20) COLLATE utf8_bin,
-      payment_method_id varchar(36) COLLATE utf8_bin,
-      payment_method varchar(20) COLLATE utf8_bin,
-      card_type varchar(20) COLLATE utf8_bin,
-      card_country varchar(50) COLLATE utf8_bin,
-      effective_dt datetime,
-      created_by varchar(50) NOT NULL,
-      created_dt datetime NOT NULL,
-      updated_by varchar(50) NOT NULL,
-      updated_dt datetime NOT NULL,
-      PRIMARY KEY (history_record_id)
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
+    id char(36) NOT NULL,
+    amount decimal(8,2),
+    refund_amount decimal(8,2),
+    payment_number varchar(36) COLLATE utf8_bin,
+    bank_identification_number varchar(36) COLLATE utf8_bin,
+    status varchar(20) COLLATE utf8_bin,
+    reference_id varchar(36) COLLATE utf8_bin,
+    payment_type varchar(20) COLLATE utf8_bin,
+    payment_method_id varchar(36) COLLATE utf8_bin,
+    payment_method varchar(20) COLLATE utf8_bin,
+    card_type varchar(20) COLLATE utf8_bin,
+    card_country varchar(50) COLLATE utf8_bin,
+    effective_date datetime,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    PRIMARY KEY (history_record_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE INDEX payment_history_record_id ON payment_history(record_id);
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java b/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
index 14a5dba..198e986 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestEventJson.java
@@ -49,13 +49,13 @@ public class TestEventJson {
     
     @Test(groups= {"fast"})
     public void testPaymentInfoEvent() throws Exception {
-        PaymentInfoEvent e = new DefaultPaymentInfoEvent(UUID.randomUUID().toString(), new BigDecimal(12), new BigDecimal(12.9), "BNP", "eeert", "success",
-                "credit", "ref", "paypal", "paypal", "", "", UUID.randomUUID(), new DateTime(), new DateTime(), new DateTime());
+        PaymentInfoEvent e = new DefaultPaymentInfoEvent(UUID.randomUUID(), new BigDecimal(12), new BigDecimal(12.9), "BNP", "eeert", "success",
+                "credit", "ref", "paypal", "paypal", "", "", UUID.randomUUID(), new DateTime());
         
         String json = mapper.writeValueAsString(e);
 
-        Class<?> claz = Class.forName(DefaultPaymentInfoEvent.class.getName());
-        Object obj =  mapper.readValue(json, claz);
+        Class<?> clazz = Class.forName(DefaultPaymentInfoEvent.class.getName());
+        Object obj =  mapper.readValue(json, clazz);
         Assert.assertTrue(obj.equals(e));
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 85aa07b..c7f925b 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -36,13 +36,11 @@ import org.testng.annotations.Test;
 
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.mock.MockAccountBuilder;
 import com.ning.billing.payment.MockRecurringInvoiceItem;
 import com.ning.billing.payment.TestHelper;
 import com.ning.billing.util.bus.Bus;
@@ -52,7 +50,6 @@ import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.DefaultCallContext;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.entity.EntityPersistenceException;
 
 public abstract class TestPaymentApi {
     @Inject
@@ -108,30 +105,30 @@ public abstract class TestPaymentApi {
 
         PaymentInfoEvent paymentInfo = results.get(0);
 
-        assertNotNull(paymentInfo.getPaymentId());
+        assertNotNull(paymentInfo.getId());
         assertTrue(paymentInfo.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
         assertNotNull(paymentInfo.getPaymentNumber());
         assertFalse(paymentInfo.getStatus().equals("Error"));
 
-        PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getPaymentId());
+        PaymentAttempt paymentAttempt = paymentApi.getPaymentAttemptForPaymentId(paymentInfo.getId());
         assertNotNull(paymentAttempt);
-        assertNotNull(paymentAttempt.getPaymentAttemptId());
+        assertNotNull(paymentAttempt.getId());
         assertEquals(paymentAttempt.getInvoiceId(), invoice.getId());
         assertTrue(paymentAttempt.getAmount().compareTo(amount.setScale(2, RoundingMode.HALF_EVEN)) == 0);
         assertEquals(paymentAttempt.getCurrency(), Currency.USD);
-        assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getPaymentId());
+        assertEquals(paymentAttempt.getPaymentId(), paymentInfo.getId());
         DateTime nowTruncated = now.withMillisOfSecond(0).withSecondOfMinute(0);
         DateTime paymentAttemptDateTruncated = paymentAttempt.getPaymentAttemptDate().withMillisOfSecond(0).withSecondOfMinute(0);
         assertEquals(paymentAttemptDateTruncated.compareTo(nowTruncated), 0);
 
-        List<PaymentInfoEvent> paymentInfos = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
+        List<PaymentInfoEvent> paymentInfos = paymentApi.getPaymentInfoList(Arrays.asList(invoice.getId().toString()));
         assertNotNull(paymentInfos);
         assertTrue(paymentInfos.size() > 0);
 
         PaymentInfoEvent paymentInfoFromGet = paymentInfos.get(0);
         assertEquals(paymentInfo.getAmount(), paymentInfoFromGet.getAmount());
         assertEquals(paymentInfo.getRefundAmount(), paymentInfoFromGet.getRefundAmount());
-        assertEquals(paymentInfo.getPaymentId(), paymentInfoFromGet.getPaymentId());
+        assertEquals(paymentInfo.getId(), paymentInfoFromGet.getId());
         assertEquals(paymentInfo.getPaymentNumber(), paymentInfoFromGet.getPaymentNumber());
         assertEquals(paymentInfo.getStatus(), paymentInfoFromGet.getStatus());
         assertEquals(paymentInfo.getBankIdentificationNumber(), paymentInfoFromGet.getBankIdentificationNumber());
@@ -159,8 +156,7 @@ public abstract class TestPaymentApi {
 
         PaymentMethodInfo paymentMethodInfo = paymentApi.getPaymentMethod(accountKey, paymentMethodId);
 
-        PaymentProviderAccount accountResult = paymentApi.getPaymentProviderAccount(accountKey);
-        return accountResult;
+        return paymentApi.getPaymentProviderAccount(accountKey);
     }
 
     @Test(enabled=true)
@@ -175,20 +171,18 @@ public abstract class TestPaymentApi {
         final Account account = testHelper.createTestPayPalAccount();
         paymentApi.createPaymentProviderAccount(account, context);
 
-        String newName = "Tester " + RandomStringUtils.randomAlphanumeric(10);
-        String newNumber = "888-888-" + RandomStringUtils.randomNumeric(4);
-
-        final Account accountToUpdate = new MockAccountBuilder(account.getId())
-                                                                  .name(newName)
-                                                                  .firstNameLength(newName.length())
-                                                                  .externalKey(account.getExternalKey())
-                                                                  .phone(newNumber)
-                                                                  .email(account.getEmail())
-                                                                  .currency(account.getCurrency())
-                                                                  .billingCycleDay(account.getBillCycleDay())
-                                                                  .build();
-
-        paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
+        Account updatedAccount = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ZombieControl zombieAccount = (ZombieControl) updatedAccount;
+        zombieAccount.addResult("getId", account.getId());
+        zombieAccount.addResult("getName", "Tester " + RandomStringUtils.randomAlphanumeric(10));
+        zombieAccount.addResult("getFirstNameLength", 6);
+        zombieAccount.addResult("getExternalKey", account.getExternalKey());
+        zombieAccount.addResult("getPhone", "888-888-" + RandomStringUtils.randomNumeric(4));
+        zombieAccount.addResult("getEmail", account.getEmail());
+        zombieAccount.addResult("getCurrency", account.getCurrency());
+        zombieAccount.addResult("getBillCycleDay", account.getBillCycleDay());
+
+        paymentApi.updatePaymentProviderAccountContact(updatedAccount.getExternalKey(), context);
     }
 
     @Test(enabled=true)
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
index cad55f0..3f90466 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/MockPaymentDao.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
 import com.ning.billing.util.callcontext.CallContext;
 import org.apache.commons.collections.CollectionUtils;
 
@@ -34,11 +35,11 @@ import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 
 public class MockPaymentDao implements PaymentDao {
-    private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
+    private final Map<UUID, PaymentInfoEvent> payments = new ConcurrentHashMap<UUID, PaymentInfoEvent>();
     private final Map<UUID, PaymentAttempt> paymentAttempts = new ConcurrentHashMap<UUID, PaymentAttempt>();
 
     @Override
-    public PaymentAttempt getPaymentAttemptForPaymentId(String paymentId) {
+    public PaymentAttempt getPaymentAttemptForPaymentId(UUID paymentId) {
         for (PaymentAttempt paymentAttempt : paymentAttempts.values()) {
             if (paymentId.equals(paymentAttempt.getPaymentId())) {
                 return paymentAttempt;
@@ -49,39 +50,39 @@ public class MockPaymentDao implements PaymentDao {
 
     @Override
     public PaymentAttempt createPaymentAttempt(Invoice invoice, CallContext context) {
-        PaymentAttempt updatedPaymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice.getId(), invoice.getAccountId(),
+        PaymentAttempt updatedPaymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice.getId(), invoice.getAccountId(),
                 invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(),
-                null, null, null, context.getCreatedDate(), context.getUpdatedDate());
+                null, null, null, null, null);
 
-        paymentAttempts.put(updatedPaymentAttempt.getPaymentAttemptId(), updatedPaymentAttempt);
+        paymentAttempts.put(updatedPaymentAttempt.getId(), updatedPaymentAttempt);
         return updatedPaymentAttempt;
     }
 
     @Override
     public PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt, CallContext context) {
-        PaymentAttempt updatedPaymentAttempt = new PaymentAttempt(paymentAttempt.getPaymentAttemptId(),
+        PaymentAttempt updatedPaymentAttempt = new DefaultPaymentAttempt(paymentAttempt.getId(),
                 paymentAttempt.getInvoiceId(),
                 paymentAttempt.getAccountId(), paymentAttempt.getAmount(), paymentAttempt.getCurrency(),
                 paymentAttempt.getInvoiceDate(), paymentAttempt.getPaymentAttemptDate(),
                 paymentAttempt.getPaymentId(), paymentAttempt.getRetryCount(),
-                context.getCreatedDate(), context.getUpdatedDate());
+                paymentAttempt.getCreatedDate(), paymentAttempt.getUpdatedDate());
 
-        paymentAttempts.put(updatedPaymentAttempt.getPaymentAttemptId(), updatedPaymentAttempt);
+        paymentAttempts.put(updatedPaymentAttempt.getId(), updatedPaymentAttempt);
         return updatedPaymentAttempt;
     }
 
     @Override
     public void savePaymentInfo(PaymentInfoEvent paymentInfo, CallContext context) {
-        payments.put(paymentInfo.getPaymentId(), paymentInfo);
+        payments.put(paymentInfo.getId(), paymentInfo);
     }
 
     @Override
-    public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context) {
+    public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, UUID paymentId, CallContext context) {
         PaymentAttempt existingPaymentAttempt = paymentAttempts.get(paymentAttemptId);
 
         if (existingPaymentAttempt != null) {
-            paymentAttempts.put(existingPaymentAttempt.getPaymentAttemptId(),
-                                existingPaymentAttempt.cloner().setPaymentId(paymentId).build());
+            paymentAttempts.put(existingPaymentAttempt.getId(),
+                                ((DefaultPaymentAttempt) existingPaymentAttempt).cloner().setPaymentId(paymentId).build());
         }
     }
 
@@ -97,21 +98,20 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context) {
+    public void updatePaymentInfo(String paymentMethodType, UUID paymentId, String cardType, String cardCountry, CallContext context) {
         DefaultPaymentInfoEvent existingPayment = (DefaultPaymentInfoEvent) payments.get(paymentId);
         if (existingPayment != null) {
             PaymentInfoEvent payment = existingPayment.cloner()
                     .setPaymentMethod(paymentMethodType)
                     .setCardType(cardType)
                     .setCardCountry(cardCountry)
-                    .setUpdatedDate(context.getUpdatedDate())
                     .build();
             payments.put(paymentId, payment);
         }
     }
 
     @Override
-    public List<PaymentInfoEvent> getPaymentInfo(List<String> invoiceIds) {
+    public List<PaymentInfoEvent> getPaymentInfoList(List<String> invoiceIds) {
         List<PaymentAttempt> attempts = getPaymentAttemptsForInvoiceIds(invoiceIds);
         List<PaymentInfoEvent> paymentsToReturn = new ArrayList<PaymentInfoEvent>(invoiceIds.size());
 
@@ -119,7 +119,7 @@ public class MockPaymentDao implements PaymentDao {
             paymentsToReturn.addAll(Collections2.filter(payments.values(), new Predicate<PaymentInfoEvent>() {
                 @Override
                 public boolean apply(PaymentInfoEvent input) {
-                    return input.getPaymentId().equals(attempt.getPaymentId());
+                    return input.getId().equals(attempt.getPaymentId());
                 }
             }));
         }
@@ -127,6 +127,20 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
+    public PaymentInfoEvent getLastPaymentInfo(List<String> invoiceIds) {
+        List<PaymentInfoEvent> payments = getPaymentInfoList(invoiceIds);
+        PaymentInfoEvent lastPayment = null;
+
+        for (PaymentInfoEvent payment : payments) {
+            if ((lastPayment == null) || (payment.getEffectiveDate().isAfter(lastPayment.getEffectiveDate()))) {
+                lastPayment = payment;
+            }
+        }
+
+        return lastPayment;
+    }
+
+    @Override
     public List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds) {
         List<PaymentAttempt> paymentAttempts = new ArrayList<PaymentAttempt>(invoiceIds.size());
         for (String invoiceId : invoiceIds) {
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 902db05..40b92ef 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -21,12 +21,12 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.DefaultCallContext;
 import com.ning.billing.util.callcontext.TestCallContext;
 import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.DefaultClock;
 import org.testng.Assert;
@@ -44,7 +44,7 @@ public abstract class TestPaymentDao {
 
     @Test
     public void testCreatePayment() {
-        PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+        PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
                 .setAmount(BigDecimal.TEN)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -60,7 +60,7 @@ public abstract class TestPaymentDao {
 
     @Test
     public void testUpdatePaymentInfo() {
-        PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+        PaymentInfoEvent paymentInfo = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
                 .setAmount(BigDecimal.TEN)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -68,20 +68,18 @@ public abstract class TestPaymentDao {
                 .setPaymentMethodId("12345")
                 .setReferenceId("12345")
                 .setType("Electronic")
-                .setCreatedDate(new DefaultClock().getUTCNow())
-                .setUpdatedDate(new DefaultClock().getUTCNow())
                 .setEffectiveDate(new DefaultClock().getUTCNow())
                 .build();
 
         CallContext context = new TestCallContext("PaymentTests");
         paymentDao.savePaymentInfo(paymentInfo, context);
-        paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US", context);
+        paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getId(), "Visa", "US", context);
     }
 
     @Test
     public void testUpdatePaymentAttempt() {
-        PaymentAttempt paymentAttempt = new PaymentAttempt.Builder().setPaymentAttemptId(UUID.randomUUID())
-                .setPaymentId(UUID.randomUUID().toString())
+        PaymentAttempt paymentAttempt = new DefaultPaymentAttempt.Builder().setPaymentAttemptId(UUID.randomUUID())
+                .setPaymentId(UUID.randomUUID())
                 .setInvoiceId(UUID.randomUUID())
                 .setAccountId(UUID.randomUUID())
                 .setAmount(BigDecimal.TEN)
@@ -97,14 +95,14 @@ public abstract class TestPaymentDao {
         final UUID invoiceId = UUID.randomUUID();
         final UUID paymentAttemptId = UUID.randomUUID();
         final UUID accountId = UUID.randomUUID();
-        final String paymentId = UUID.randomUUID().toString();
+        final UUID paymentId = UUID.randomUUID();
         final BigDecimal invoiceAmount = BigDecimal.TEN;
 
         // Move the clock backwards to test the updated_date field (see below)
         ClockMock clock = new ClockMock();
         CallContext thisContext = new DefaultCallContext("Payment Tests", CallOrigin.TEST, UserType.TEST, clock);
 
-        PaymentAttempt originalPaymentAttempt = new PaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, clock.getUTCNow(), clock.getUTCNow(), paymentId, 0);
+        PaymentAttempt originalPaymentAttempt = new DefaultPaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, clock.getUTCNow(), clock.getUTCNow(), paymentId, 0, null, null);
         PaymentAttempt attempt = paymentDao.createPaymentAttempt(originalPaymentAttempt, thisContext);
 
         List<PaymentAttempt> attemptsFromGet = paymentDao.getPaymentAttemptsForInvoiceId(invoiceId.toString());
@@ -115,11 +113,11 @@ public abstract class TestPaymentDao {
 
         Assert.assertEquals(attempt, attempt3);
 
-        PaymentAttempt attempt4 = paymentDao.getPaymentAttemptById(attempt3.getPaymentAttemptId());
+        PaymentAttempt attempt4 = paymentDao.getPaymentAttemptById(attempt3.getId());
 
         Assert.assertEquals(attempt3, attempt4);
 
-        PaymentInfoEvent originalPaymentInfo = new DefaultPaymentInfoEvent.Builder().setPaymentId(paymentId)
+        PaymentInfoEvent originalPaymentInfo = new DefaultPaymentInfoEvent.Builder().setId(paymentId)
                 .setAmount(invoiceAmount)
                 .setStatus("Processed")
                 .setBankIdentificationNumber("1234")
@@ -127,19 +125,18 @@ public abstract class TestPaymentDao {
                 .setPaymentMethodId("12345")
                 .setReferenceId("12345")
                 .setType("Electronic")
-                .setCreatedDate(clock.getUTCNow())
-                .setUpdatedDate(clock.getUTCNow())
                 .setEffectiveDate(clock.getUTCNow())
                 .build();
 
         paymentDao.savePaymentInfo(originalPaymentInfo, thisContext);
-        PaymentInfoEvent paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
+        PaymentInfoEvent paymentInfo = paymentDao.getPaymentInfoList(Arrays.asList(invoiceId.toString())).get(0);
         Assert.assertEquals(paymentInfo, originalPaymentInfo);
 
         clock.setDeltaFromReality(60 * 60 * 1000); // move clock forward one hour
-        paymentDao.updatePaymentInfo(originalPaymentInfo.getPaymentMethod(), originalPaymentInfo.getPaymentId(), originalPaymentInfo.getCardType(), originalPaymentInfo.getCardCountry(), thisContext);
-        paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
-        Assert.assertEquals(paymentInfo.getCreatedDate().compareTo(attempt.getCreatedDate()), 0);
-        Assert.assertTrue(paymentInfo.getUpdatedDate().isAfter(originalPaymentInfo.getUpdatedDate()));
+        paymentDao.updatePaymentInfo(originalPaymentInfo.getPaymentMethod(), originalPaymentInfo.getId(), originalPaymentInfo.getCardType(), originalPaymentInfo.getCardCountry(), thisContext);
+        paymentInfo = paymentDao.getPaymentInfoList(Arrays.asList(invoiceId.toString())).get(0);
+        // TODO: replace these asserts
+//        Assert.assertEquals(paymentInfo.getCreatedDate().compareTo(attempt.getCreatedDate()), 0);
+//        Assert.assertTrue(paymentInfo.getUpdatedDate().isAfter(originalPaymentInfo.getUpdatedDate()));
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
index 6da3323..20c0446 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockInvoice.java
@@ -23,6 +23,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
+import com.ning.billing.util.dao.ObjectType;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
@@ -45,13 +46,13 @@ public class MockInvoice extends ExtendedEntityBase implements Invoice {
 
     // used to create a new invoice
     public MockInvoice(UUID accountId, DateTime invoiceDate, DateTime targetDate, Currency currency) {
-        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false, null, null);
+        this(UUID.randomUUID(), accountId, null, invoiceDate, targetDate, currency, false);
     }
 
     // used to hydrate invoice from persistence layer
     public MockInvoice(UUID invoiceId, UUID accountId, @Nullable Integer invoiceNumber, DateTime invoiceDate,
-                          DateTime targetDate, Currency currency, boolean isMigrationInvoice, @Nullable String createdBy, @Nullable DateTime createdDate) {
-        super(invoiceId, createdBy, createdDate);
+                          DateTime targetDate, Currency currency, boolean isMigrationInvoice) {
+        super(invoiceId);
         this.accountId = accountId;
         this.invoiceNumber = invoiceNumber;
         this.invoiceDate = invoiceDate;
@@ -214,8 +215,8 @@ public class MockInvoice extends ExtendedEntityBase implements Invoice {
     }
 
     @Override
-    public String getObjectName() {
-        return Invoice.ObjectType;
+    public ObjectType getObjectType() {
+        return ObjectType.RECURRING_INVOICE_ITEM;
     }
 
     @Override
diff --git a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
index 40a927f..93c90fa 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
@@ -62,30 +62,28 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem 
     public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
-                                Currency currency,
-                                String createdBy, DateTime createdDate) {
-        this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate, rate, null);
+                                Currency currency) {
+        this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, rate, null);
 
     }
 
     public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
                                 DateTime startDate, DateTime endDate,
                                 BigDecimal amount, BigDecimal rate,
-                                Currency currency, UUID reversedItemId,
-                                String createdBy, DateTime createdDate) {
-        this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, createdBy, createdDate, rate, reversedItemId);
+                                Currency currency, UUID reversedItemId) {
+        this(id, invoiceId, accountId, bundleId, subscriptionId, planName, phaseName, startDate, endDate, amount, currency, rate, reversedItemId);
     }
     public MockRecurringInvoiceItem(UUID invoiceId, UUID accountId, UUID bundleId, UUID subscriptionId, String planName, String phaseName,
             DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency, BigDecimal rate, UUID reversedItemId){
         this(UUID.randomUUID(), invoiceId, accountId, bundleId, subscriptionId, planName, phaseName,
-                startDate, endDate, amount, currency, null, null, rate, reversedItemId);
+                startDate, endDate, amount, currency, rate, reversedItemId);
     }
 
 
     public MockRecurringInvoiceItem(UUID id, UUID invoiceId, UUID accountId, @Nullable UUID bundleId, @Nullable UUID subscriptionId, String planName, String phaseName,
             DateTime startDate, DateTime endDate, BigDecimal amount, Currency currency,
-            @Nullable String createdBy, @Nullable DateTime createdDate, BigDecimal rate, UUID reversedItemId) {
-        super(id, createdBy, createdDate);
+            BigDecimal rate, UUID reversedItemId) {
+        super(id);
         this.invoiceId = invoiceId;
         this.accountId = accountId;
         this.subscriptionId = subscriptionId;
@@ -98,11 +96,6 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem 
         this.currency = currency;
         this.rate = rate;
         this.reversedItemId = reversedItemId;
-
-    }
-
-    public DateTime getCreatedDate() {
-        return createdDate;
     }
 
     @Override
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
index f1176f7..d9d2c77 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/MockPaymentProviderPlugin.java
@@ -45,7 +45,7 @@ import com.ning.billing.util.clock.Clock;
 public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
     private final AtomicBoolean makeNextInvoiceFail = new AtomicBoolean(false);
     private final AtomicBoolean makeAllInvoicesFail = new AtomicBoolean(false);
-    private final Map<String, PaymentInfoEvent> payments = new ConcurrentHashMap<String, PaymentInfoEvent>();
+    private final Map<UUID, PaymentInfoEvent> payments = new ConcurrentHashMap<UUID, PaymentInfoEvent>();
     private final Map<String, PaymentProviderAccount> accounts = new ConcurrentHashMap<String, PaymentProviderAccount>();
     private final Map<String, PaymentMethodInfo> paymentMethods = new ConcurrentHashMap<String, PaymentMethodInfo>();
     private final Clock clock;
@@ -69,17 +69,16 @@ public class MockPaymentProviderPlugin implements PaymentProviderPlugin {
             return Either.left((PaymentErrorEvent) new DefaultPaymentErrorEvent("unknown", "test error", account.getId(), invoice.getId(), null));
         }
         else {
-            PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder().setPaymentId(UUID.randomUUID().toString())
+            PaymentInfoEvent payment = new DefaultPaymentInfoEvent.Builder().setId(UUID.randomUUID())
                                                  .setAmount(invoice.getBalance())
                                                  .setStatus("Processed")
                                                  .setBankIdentificationNumber("1234")
-                                                 .setCreatedDate(clock.getUTCNow())
                                                  .setEffectiveDate(clock.getUTCNow())
                                                  .setPaymentNumber("12345")
                                                  .setReferenceId("12345")
                                                  .setType("Electronic")
                                                  .build();
-            payments.put(payment.getPaymentId(), payment);
+            payments.put(payment.getId(), payment);
             return Either.right(payment);
         }
     }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestHelper.java b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
index c38e887..33dc142 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -16,12 +16,10 @@
 
 package com.ning.billing.payment;
 
-import java.math.BigDecimal;
 import java.util.UUID;
 
 import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 
 import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
@@ -31,8 +29,8 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
+import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
-import com.ning.billing.mock.MockAccountBuilder;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.Bus.EventBusException;
 import com.ning.billing.util.callcontext.CallContext;
@@ -57,32 +55,14 @@ public class TestHelper {
 
     // These helper methods can be overridden in a plugin implementation
     public Account createTestCreditCardAccount() throws EntityPersistenceException {
-        final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
-        final String externalKey = RandomStringUtils.randomAlphanumeric(10);
-        final Account account = new MockAccountBuilder(UUID.randomUUID()).name(name)
-                                                                     .firstNameLength(name.length())
-                                                                     .externalKey(externalKey)
-                                                                     .phone("123-456-7890")
-                                                                     .email("ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com")
-                                                                     .currency(Currency.USD)
-                                                                     .billingCycleDay(1)
-                                                                     .build();
+        final Account account = createTestAccount("ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com");
         ((ZombieControl)accountUserApi).addResult("getAccountById", account);
         ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
         return account;
     }
 
     public Account createTestPayPalAccount() throws EntityPersistenceException {
-        final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
-        final String externalKey = RandomStringUtils.randomAlphanumeric(10);
-        final Account account = new MockAccountBuilder(UUID.randomUUID()).name(name)
-                                                                     .firstNameLength(name.length())
-                                                                     .externalKey(externalKey)
-                                                                     .phone("123-456-7890")
-                                                                     .email("ppuser@example.com")
-                                                                     .currency(Currency.USD)
-                                                                     .billingCycleDay(1)
-                                                                     .build();
+        final Account account = createTestAccount("ppuser@example.com");
         ((ZombieControl)accountUserApi).addResult("getAccountById", account);
         ((ZombieControl)accountUserApi).addResult("getAccountByKey", account);
         return account;
@@ -122,16 +102,22 @@ public class TestHelper {
         return invoice;
     }
 
-    public Invoice createTestInvoice(Account account) throws EventBusException {
-        final DateTime now = new DateTime(DateTimeZone.UTC);
-        final UUID subscriptionId = UUID.randomUUID();
-        final UUID bundleId = UUID.randomUUID();
-        final BigDecimal amount = new BigDecimal("10.00");
-        
-        final InvoiceItem item = new MockRecurringInvoiceItem(null, account.getId(), bundleId, subscriptionId, "test plan", "test phase", now, now.plusMonths(1),
-                amount, new BigDecimal("1.0"), Currency.USD);
+    public Account createTestAccount(String email) {
+        final String name = "First" + RandomStringUtils.randomAlphanumeric(5) + " " + "Last" + RandomStringUtils.randomAlphanumeric(5);
+        final String externalKey = RandomStringUtils.randomAlphanumeric(10);
 
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ZombieControl zombie = (ZombieControl) account;
+        zombie.addResult("getId", UUID.randomUUID());
+        zombie.addResult("getExternalKey", externalKey);
+        zombie.addResult("getName", name);
+        zombie.addResult("getFirstNameLength", 10);
+        zombie.addResult("getPhone", "123-456-7890");
+        zombie.addResult("getEmail", email);
+        zombie.addResult("getCurrency", Currency.USD);
+        zombie.addResult("getBillCycleDay", 1);
+        zombie.addResult("getPaymentProviderName", "");
 
-        return createTestInvoice(account, now, Currency.USD, item);
+        return account;
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
index 9a49780..2c519d0 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestRetryService.java
@@ -25,6 +25,11 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.payment.api.DefaultPaymentAttempt;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContext;
+import com.ning.billing.util.callcontext.UserType;
 import org.joda.time.DateTime;
 import org.joda.time.Days;
 import org.testng.annotations.AfterMethod;
@@ -42,11 +47,9 @@ import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.mock.BrainDeadProxyFactory;
 import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
 import com.ning.billing.mock.glue.MockJunctionModule;
-import com.ning.billing.payment.api.Either;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentApiException;
 import com.ning.billing.payment.api.PaymentAttempt;
-import com.ning.billing.payment.api.PaymentErrorEvent;
 import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.PaymentDao;
@@ -54,10 +57,6 @@ import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
 import com.ning.billing.util.bus.Bus;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.DefaultCallContext;
-import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.clock.MockClockModule;
@@ -156,7 +155,7 @@ public class TestRetryService {
         List<PaymentAttempt> paymentAttempts = paymentApi.getPaymentAttemptsForInvoiceId(invoice.getId().toString());
 
         assertNotNull(paymentAttempts);
-        assertEquals(notification.getNotificationKey(), paymentAttempts.get(0).getPaymentAttemptId().toString());
+        assertEquals(notification.getNotificationKey(), paymentAttempts.get(0).getId().toString());
 
         DateTime expectedRetryDate = paymentAttempts.get(0).getPaymentAttemptDate().plusDays(paymentConfig.getPaymentRetryDays().get(0));
 
@@ -186,7 +185,7 @@ public class TestRetryService {
 
         int numberOfDays = paymentConfig.getPaymentRetryDays().get(0);
         DateTime nextRetryDate = now.plusDays(numberOfDays);
-        PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice).cloner()
+        PaymentAttempt paymentAttempt = new DefaultPaymentAttempt(UUID.randomUUID(), invoice).cloner()
                                                                                       .setRetryCount(1)
                                                                                       .setPaymentAttemptDate(now)
                                                                                       .build();
@@ -199,14 +198,14 @@ public class TestRetryService {
         List<Notification> pendingNotifications = mockNotificationQueue.getPendingEvents();
         assertEquals(pendingNotifications.size(), 0);
 
-        List<PaymentInfoEvent> paymentInfoList = paymentApi.getPaymentInfo(Arrays.asList(invoice.getId().toString()));
+        List<PaymentInfoEvent> paymentInfoList = paymentApi.getPaymentInfoList(Arrays.asList(invoice.getId().toString()));
         assertEquals(paymentInfoList.size(), 1);
 
         PaymentInfoEvent paymentInfo = paymentInfoList.get(0);
         assertEquals(paymentInfo.getStatus(), PaymentStatus.Processed.toString());
 
         List<PaymentAttempt> updatedAttempts = paymentApi.getPaymentAttemptsForInvoiceId(invoice.getId().toString());
-        assertEquals(paymentInfo.getPaymentId(), updatedAttempts.get(0).getPaymentId());
+        assertEquals(paymentInfo.getId(), updatedAttempts.get(0).getPaymentId());
 
     }
 }
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
index 227e94a..1aaef9b 100644
--- a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -72,9 +72,11 @@ public class KillbillGuiceListener extends SetupServer
         killbillBusService = theInjector.getInstance(BusService.class);
         killbilleventHandler = theInjector.getInstance(KillbillEventHandler.class); 
         
+        /*
         ObjectMapper mapper = theInjector.getInstance(ObjectMapper.class);
         mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
-
+*/
+        
         //
         // Fire all Startup levels up to service start
         //
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index a5311c7..414f2a0 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -72,10 +72,10 @@ public class TestAccount extends TestJaxrsBase {
 		Assert.assertTrue(objFromJson.equals(input));
 		
 		// Update Account
-		AccountJson newInput = new AccountJson(objFromJson.getAcountId(),
+		AccountJson newInput = new AccountJson(objFromJson.getAccountId(),
 				"zozo", 4, objFromJson.getExternalKey(), "rr@google.com", 18, "EUR", "none", "UTC", "bl1", "bh2", "", "ca", "usa", "415-255-2991");
 		baseJson = mapper.writeValueAsString(newInput);
-		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + objFromJson.getAcountId();
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + objFromJson.getAccountId();
 		response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
 		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
 		baseJson = response.getResponseBody();
@@ -88,7 +88,7 @@ public class TestAccount extends TestJaxrsBase {
 	public void testUpdateNonExistentAccount() throws Exception {
 		AccountJson input = getAccountJson("xoxo", "shghaahwe", "xoxo@yahoo.com");
 		String baseJson = mapper.writeValueAsString(input);
-		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + input.getAcountId();
+		final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + input.getAccountId();
 		Response response = doPut(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
 		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
 		String body = response.getResponseBody();
@@ -119,7 +119,7 @@ public class TestAccount extends TestJaxrsBase {
 	    AccountJson accountJson = createAccount("poney", "shdddqgfhwe", "poney@yahoo.com");
 	    assertNotNull(accountJson);
 	    
-	    BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAcountId(), "996599");
+	    BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAccountId(), "996599");
 	    assertNotNull(bundleJson);
 	    
         SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
@@ -131,7 +131,7 @@ public class TestAccount extends TestJaxrsBase {
         crappyWaitForLackOfProperSynchonization();
         
         
-        final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAcountId() + "/" + BaseJaxrsResource.TIMELINE;
+        final String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + BaseJaxrsResource.TIMELINE;
         
         Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
@@ -160,7 +160,7 @@ public class TestAccount extends TestJaxrsBase {
 	        
 	    Map<String, String> queryParams = new HashMap<String, String>();
         queryParams.put(BaseJaxrsResource.QUERY_TAGS, input.getName());
-        String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.TAGS + "/" + accountJson.getAcountId() ;
+        String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.TAGS + "/" + accountJson.getAccountId() ;
 	    response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
         
@@ -190,7 +190,7 @@ public class TestAccount extends TestJaxrsBase {
         customFields.add(new CustomFieldJson("3", "value3"));  
         String baseJson = mapper.writeValueAsString(customFields);
 
-        String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.CUSTOM_FIELDS + "/" + accountJson.getAcountId() ;
+        String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + BaseJaxrsResource.CUSTOM_FIELDS + "/" + accountJson.getAccountId() ;
         Response response = doPost(uri,baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
         String location = response.getHeader("Location");
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
index f0182bd..7795d0c 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestBundle.java
@@ -44,7 +44,7 @@ public class TestBundle extends TestJaxrsBase {
 	public void testBundleOk() throws Exception {
 
 		AccountJson accountJson = createAccount("xlxl", "shdgfhkkl", "xlxl@yahoo.com");
-		BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAcountId(), "12345");
+		BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAccountId(), "12345");
 		
 		// Retrieves by external key
 		Map<String, String> queryParams = new HashMap<String, String>();
@@ -61,10 +61,10 @@ public class TestBundle extends TestJaxrsBase {
 	public void testBundleFromAccount() throws Exception {
 
 		AccountJson accountJson = createAccount("xaxa", "saagfhkkl", "xaxa@yahoo.com");
-		BundleJsonNoSubsciptions bundleJson1 = createBundle(accountJson.getAcountId(), "156567");
-		BundleJsonNoSubsciptions bundleJson2 = createBundle(accountJson.getAcountId(), "265658");
+		BundleJsonNoSubsciptions bundleJson1 = createBundle(accountJson.getAccountId(), "156567");
+		BundleJsonNoSubsciptions bundleJson2 = createBundle(accountJson.getAccountId(), "265658");
 
-		String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAcountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
+		String uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
 		Response response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
 		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
 		String baseJson = response.getResponseBody();
@@ -96,7 +96,7 @@ public class TestBundle extends TestJaxrsBase {
 		Assert.assertEquals(response.getStatusCode(), Status.NO_CONTENT.getStatusCode());
 		
 		
-		uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAcountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
+		uri = BaseJaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId().toString() + "/" + BaseJaxrsResource.BUNDLES;
 		response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
 		Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
 		String baseJson = response.getResponseBody();
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
index 9a039fd..aba67b8 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -38,7 +38,7 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.jaxrs.json.AccountJson;
 import com.ning.billing.jaxrs.json.BundleJsonNoSubsciptions;
-import com.ning.billing.jaxrs.json.InvoiceJson;
+import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
 import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
 import com.ning.billing.jaxrs.resources.BaseJaxrsResource;
 import com.ning.http.client.Response;
@@ -60,7 +60,7 @@ public class TestInvoice extends TestJaxrsBase  {
         AccountJson accountJson = createAccount("poupou", "qhddffrwe", "poupou@yahoo.com");
         assertNotNull(accountJson);
         
-        BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAcountId(), "9967599");
+        BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAccountId(), "9967599");
         assertNotNull(bundleJson);
         
         SubscriptionJsonNoEvents subscriptionJson = createSubscription(bundleJson.getBundleId(), "Shotgun", ProductCategory.BASE.toString(), BillingPeriod.MONTHLY.toString(), true);
@@ -74,12 +74,12 @@ public class TestInvoice extends TestJaxrsBase  {
         
         String uri = BaseJaxrsResource.INVOICES_PATH;
         Map<String, String> queryParams = new HashMap<String, String>();
-        queryParams.put(BaseJaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAcountId());
+        queryParams.put(BaseJaxrsResource.QUERY_ACCOUNT_ID, accountJson.getAccountId());
         
         Response response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
         String baseJson = response.getResponseBody();
-        List<InvoiceJson> objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJson>>() {});
+        List<InvoiceJsonSimple> objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJsonSimple>>() {});
         assertNotNull(objFromJson);
         log.info(baseJson);
         assertEquals(objFromJson.size(), 4);
@@ -89,7 +89,7 @@ public class TestInvoice extends TestJaxrsBase  {
         response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());        
         baseJson = response.getResponseBody();
-        InvoiceJson firstInvoiceJson = mapper.readValue(baseJson, InvoiceJson.class);
+        InvoiceJsonSimple firstInvoiceJson = mapper.readValue(baseJson, InvoiceJsonSimple.class);
         assertNotNull(objFromJson);    
         assertEquals(firstInvoiceJson, objFromJson.get(0));
         
@@ -101,7 +101,7 @@ public class TestInvoice extends TestJaxrsBase  {
         response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode()); 
         baseJson = response.getResponseBody();
-        InvoiceJson futureInvoice = mapper.readValue(baseJson, InvoiceJson.class);
+        InvoiceJsonSimple futureInvoice = mapper.readValue(baseJson, InvoiceJsonSimple.class);
         assertNotNull(futureInvoice);    
         log.info(baseJson);
         
@@ -118,7 +118,7 @@ public class TestInvoice extends TestJaxrsBase  {
         response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
         baseJson = response.getResponseBody();
-        objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJson>>() {});
+        objFromJson = mapper.readValue(baseJson, new TypeReference<List<InvoiceJsonSimple>>() {});
         assertNotNull(objFromJson);
         log.info(baseJson);
         assertEquals(objFromJson.size(), 5);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index a45ee00..0a0d619 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -91,7 +91,7 @@ public class TestJaxrsBase {
 
     private final static String PLUGIN_NAME = "noop";
 
-    protected static final int DEFAULT_HTTP_TIMEOUT_SEC = 5;
+    protected static final int DEFAULT_HTTP_TIMEOUT_SEC =  500000; // 5;
 
     protected static final Map<String, String> DEFAULT_EMPTY_QUERY = new HashMap<String, String>();
 
@@ -235,7 +235,7 @@ public class TestJaxrsBase {
         mapper.registerModule(new JodaModule());
         mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
 
-        mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());        
+        //mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());        
 
         busHandler = new TestApiListener(null);
         this.helper = listener.getMysqlTestingHelper();
@@ -491,7 +491,7 @@ public class TestJaxrsBase {
      * but until we have a strong need for it, this is in the TODO list...
      */
     protected void crappyWaitForLackOfProperSynchonization() throws Exception {
-        Thread.sleep(10000);
+        Thread.sleep(5000);
     }
 
 }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
index 4a74dfc..d43c858 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestSubscription.java
@@ -53,7 +53,7 @@ public class TestSubscription extends TestJaxrsBase {
         clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
         
         AccountJson accountJson = createAccount("xil", "shdxilhkkl", "xil@yahoo.com");
-        BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAcountId(), "99999");
+        BundleJsonNoSubsciptions bundleJson = createBundle(accountJson.getAccountId(), "99999");
 
         String productName = "Shotgun";
         BillingPeriod term = BillingPeriod.MONTHLY;
diff --git a/server/src/test/resources/killbill.properties b/server/src/test/resources/killbill.properties
index 3463266..9aa3e66 100644
--- a/server/src/test/resources/killbill.properties
+++ b/server/src/test/resources/killbill.properties
@@ -10,6 +10,11 @@ user.timezone=UTC
 
 com.ning.core.server.jetty.logPath=/var/tmp/.logs
 
+killbill.payment.engine.notifications.sleep=100
+killbill.invoice.engine.notifications.sleep=100
+killbill.entitlement.engine.notifications.sleep=100
+killbill.billing.util.persistent.bus.sleep=100
+killbill.billing.util.persistent.bus.nbThreads=1
 # Local DB 
 #com.ning.billing.dbi.test.useLocalDb=true
 
diff --git a/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java b/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
index b9c6faa..8e98211 100644
--- a/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
+++ b/util/src/main/java/com/ning/billing/util/bus/dao/BusEventEntry.java
@@ -17,19 +17,19 @@ package com.ning.billing.util.bus.dao;
 
 import org.joda.time.DateTime;
 
-import com.ning.billing.util.notificationq.NotificationLifecycle;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle;
 
-public class BusEventEntry implements NotificationLifecycle  {
+public class BusEventEntry implements PersistentQueueEntryLifecycle  {
     
     private final long id;
     private final String owner;
     private final String createdOwner;
     private final DateTime nextAvailable;
-    private final NotificationLifecycleState processingState;
+    private final PersistentQueueEntryLifecycleState processingState;
     private final String busEventClass;
     private final String busEventJson;
 
-    public BusEventEntry(final long id, final String createdOwner, final String owner, final DateTime nextAvailable, NotificationLifecycleState processingState, final String busEventClass, final String busEventJson) {
+    public BusEventEntry(final long id, final String createdOwner, final String owner, final DateTime nextAvailable, PersistentQueueEntryLifecycleState processingState, final String busEventClass, final String busEventJson) {
         this.id = id;
         this.createdOwner = createdOwner;
         this.owner = owner;
@@ -73,7 +73,7 @@ public class BusEventEntry implements NotificationLifecycle  {
     }
 
     @Override
-    public NotificationLifecycleState getProcessingState() {
+    public PersistentQueueEntryLifecycleState getProcessingState() {
         return processingState;
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java b/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
index f8007de..ca98098 100644
--- a/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/bus/dao/PersistentBusSqlDao.java
@@ -34,7 +34,7 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
 import com.ning.billing.util.dao.BinderBase;
 import com.ning.billing.util.dao.MapperBase;
-import com.ning.billing.util.notificationq.NotificationLifecycle.NotificationLifecycleState;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle.PersistentQueueEntryLifecycleState;
 
 @ExternalizedSqlViaStringTemplate3()
 public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>, CloseMe {
@@ -45,32 +45,34 @@ public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>,
     public BusEventEntry getNextBusEventEntry(@Bind("max") int max, @Bind("owner") String owner, @Bind("now") Date now);
     
     @SqlUpdate
-    public int claimBusEvent(@Bind("owner") String owner, @Bind("next_available") Date nextAvailable, @Bind("id") long id, @Bind("now") Date now);
+    public int claimBusEvent(@Bind("owner") String owner, @Bind("nextAvailable") Date nextAvailable,
+                             @Bind("recordId") Long id, @Bind("now") Date now);
 
     @SqlUpdate
-    public void clearBusEvent(@Bind("id") long id, @Bind("owner") String owner);
+    public void clearBusEvent(@Bind("recordId") Long id, @Bind("owner") String owner);
 
     @SqlUpdate
-    public void removeBusEventsById(@Bind("id") long id);
+    public void removeBusEventsById(@Bind("recordId") Long id);
     
     @SqlUpdate
     public void insertBusEvent(@Bind(binder = PersistentBusSqlBinder.class) BusEventEntry evt);
 
     @SqlUpdate
-    public void insertClaimedHistory(@Bind("owner_id") String owner, @Bind("claimed_dt") Date claimedDate, @Bind("bus_event_id") long id);
+    public void insertClaimedHistory(@Bind("ownerId") String owner, @Bind("claimedDate") Date claimedDate,
+                                     @Bind("busEventId") long id);
 
     
     public static class PersistentBusSqlBinder extends BinderBase implements Binder<Bind, BusEventEntry> {
 
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, BusEventEntry evt) {
-            stmt.bind("class_name", evt.getBusEventClass());
-            stmt.bind("event_json", evt.getBusEventJson()); 
-            stmt.bind("created_dt", getDate(new DateTime()));
-            stmt.bind("creating_owner", evt.getCreatedOwner());
-            stmt.bind("processing_available_dt", getDate(evt.getNextAvailableDate()));
-            stmt.bind("processing_owner", evt.getOwner());
-            stmt.bind("processing_state", NotificationLifecycleState.AVAILABLE.toString());
+            stmt.bind("className", evt.getBusEventClass());
+            stmt.bind("eventJson", evt.getBusEventJson());
+            stmt.bind("createdDate", getDate(new DateTime()));
+            stmt.bind("creatingOwner", evt.getCreatedOwner());
+            stmt.bind("processingAvailableDate", getDate(evt.getNextAvailableDate()));
+            stmt.bind("processingOwner", evt.getOwner());
+            stmt.bind("processingState", PersistentQueueEntryLifecycleState.AVAILABLE.toString());
         }
     }
     
@@ -80,15 +82,15 @@ public interface PersistentBusSqlDao extends Transactional<PersistentBusSqlDao>,
         public BusEventEntry map(int index, ResultSet r, StatementContext ctx)
                 throws SQLException {
 
-            final long id = r.getLong("id");
+            final Long recordId = r.getLong("record_id");
             final String className = r.getString("class_name"); 
             final String createdOwner = r.getString("creating_owner");
             final String eventJson = r.getString("event_json"); 
-            final DateTime nextAvailableDate = getDate(r, "processing_available_dt");
+            final DateTime nextAvailableDate = getDate(r, "processing_available_date");
             final String processingOwner = r.getString("processing_owner");
-            final NotificationLifecycleState processingState = NotificationLifecycleState.valueOf(r.getString("processing_state"));
+            final PersistentQueueEntryLifecycleState processingState = PersistentQueueEntryLifecycleState.valueOf(r.getString("processing_state"));
             
-            return new BusEventEntry(id, createdOwner, processingOwner, nextAvailableDate, processingState, className, eventJson);
+            return new BusEventEntry(recordId, createdOwner, processingOwner, nextAvailableDate, processingState, className, eventJson);
         }
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
index bfce245..92b35d7 100644
--- a/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
+++ b/util/src/main/java/com/ning/billing/util/bus/PersistentBus.java
@@ -33,19 +33,19 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.EventBus;
 import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.ning.billing.config.PersistentQueueConfig;
 import com.ning.billing.util.Hostname;
 import com.ning.billing.util.bus.dao.BusEventEntry;
 import com.ning.billing.util.bus.dao.PersistentBusSqlDao;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.queue.PersistentQueueBase;
 
 
 public class PersistentBus extends PersistentQueueBase implements Bus {
 
-    private final static int NB_BUS_THREADS = 1;
-    private final static long TIMEOUT_MSEC = 15L * 1000L; // 15 sec
     private final static long DELTA_IN_PROCESSING_TIME_MS = 1000L * 60L * 5L; // 5 minutes
-    private final static long SLEEP_TIME_MS = 1000; // 1 sec
     private final static int MAX_BUS_EVENTS = 1;
     
     private static final Logger log = LoggerFactory.getLogger(PersistentBus.class);
@@ -80,15 +80,16 @@ public class PersistentBus extends PersistentQueueBase implements Bus {
     }
     
     @Inject
-    public PersistentBus(final IDBI dbi, final Clock clock) {
-        super("Bus", Executors.newFixedThreadPool(NB_BUS_THREADS, new ThreadFactory() {
+    public PersistentBus(final IDBI dbi, final Clock clock, final PersistentBusConfig config) {
+        
+        super("Bus", Executors.newFixedThreadPool(config.getNbThreads(), new ThreadFactory() {
             @Override
             public Thread newThread(Runnable r) {
                 return new Thread(new ThreadGroup(DefaultBusService.EVENT_BUS_GROUP_NAME),
                         r,
                         DefaultBusService.EVENT_BUS_TH_NAME);
             }
-        }), NB_BUS_THREADS, TIMEOUT_MSEC, SLEEP_TIME_MS);
+        }), config.getNbThreads(), config);
         this.dao = dbi.onDemand(PersistentBusSqlDao.class);
         this.clock = clock;
         this.objectMapper = new ObjectMapper();
diff --git a/util/src/main/java/com/ning/billing/util/bus/PersistentBusConfig.java b/util/src/main/java/com/ning/billing/util/bus/PersistentBusConfig.java
new file mode 100644
index 0000000..a2e9879
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/bus/PersistentBusConfig.java
@@ -0,0 +1,33 @@
+/* 
+ * Copyright 2010-2011 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.bus;
+
+import org.skife.config.Config;
+import org.skife.config.Default;
+
+import com.ning.billing.config.PersistentQueueConfig;
+
+public interface PersistentBusConfig extends PersistentQueueConfig {
+
+    @Override
+    @Config("killbill.billing.util.persistent.bus.sleep")
+    @Default("500")
+    public long getSleepTimeMs();
+    
+    @Config("killbill.billing.util.persistent.bus.nbThreads")
+    @Default("3")
+    public int getNbThreads();
+}
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
index e319117..b918fac 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/AuditedCustomFieldDao.java
@@ -16,66 +16,90 @@
 
 package com.ning.billing.util.customfield.dao;
 
-import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.callcontext.CallContext;
+import com.google.inject.Inject;
 import com.ning.billing.util.customfield.CustomField;
-import com.ning.billing.util.customfield.CustomFieldHistory;
+import com.ning.billing.util.dao.AuditedCollectionDaoBase;
+import com.ning.billing.util.dao.TableName;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
+import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.UUID;
+public class AuditedCustomFieldDao extends AuditedCollectionDaoBase<CustomField> implements CustomFieldDao {
+    private final CustomFieldSqlDao dao;
 
-public class AuditedCustomFieldDao implements CustomFieldDao {
-    @Override
-    public void saveFields(Transmogrifier dao, UUID objectId, String objectType, List<CustomField> fields, CallContext context) {
-        CustomFieldSqlDao customFieldSqlDao = dao.become(CustomFieldSqlDao.class);
-
-        // get list of existing fields
-        List<CustomField> existingFields = customFieldSqlDao.load(objectId.toString(), objectType);
-        List<CustomField> fieldsToUpdate = new ArrayList<CustomField>();
-
-        // sort into fields to update (fieldsToUpdate), fields to add (fields), and fields to delete (existingFields)
-        Iterator<CustomField> fieldIterator = fields.iterator();
-        while (fieldIterator.hasNext()) {
-            CustomField field = fieldIterator.next();
-
-            Iterator<CustomField> existingFieldIterator = existingFields.iterator();
-            while (existingFieldIterator.hasNext()) {
-                CustomField existingField = existingFieldIterator.next();
-                if (field.getName().equals(existingField.getName())) {
-                    // if the tagStore match, remove from both lists
-                    fieldsToUpdate.add(field);
-                    fieldIterator.remove();
-                    existingFieldIterator.remove();
-                }
-            }
-        }
-
-        customFieldSqlDao.batchInsertFromTransaction(objectId.toString(), objectType, fields, context);
-        customFieldSqlDao.batchUpdateFromTransaction(objectId.toString(), objectType, fieldsToUpdate, context);
-        customFieldSqlDao.batchDeleteFromTransaction(objectId.toString(), objectType, existingFields, context);
-
-        List<CustomFieldHistory> fieldHistories = new ArrayList<CustomFieldHistory>();
-        fieldHistories.addAll(convertToHistoryEntry(fields, ChangeType.INSERT));
-        fieldHistories.addAll(convertToHistoryEntry(fieldsToUpdate, ChangeType.UPDATE));
-        fieldHistories.addAll(convertToHistoryEntry(existingFields, ChangeType.DELETE));
-
-        CustomFieldHistorySqlDao historyDao = dao.become(CustomFieldHistorySqlDao.class);
-        historyDao.batchAddHistoryFromTransaction(objectId.toString(), objectType, fieldHistories, context);
-
-        CustomFieldAuditSqlDao auditDao = dao.become(CustomFieldAuditSqlDao.class);
-        auditDao.batchInsertAuditLogFromTransaction(objectId.toString(), objectType, fieldHistories, context);
+    @Inject
+    public AuditedCustomFieldDao(final IDBI dbi) {
+        dao = dbi.onDemand(CustomFieldSqlDao.class);
     }
 
-    private List<CustomFieldHistory> convertToHistoryEntry(List<CustomField> fields, ChangeType changeType) {
-        List<CustomFieldHistory> result = new ArrayList<CustomFieldHistory>();
+    @Override
+    protected TableName getTableName() {
+        return TableName.CUSTOM_FIELD_HISTORY;
+    }
 
-        for (CustomField field : fields) {
-            result.add(new CustomFieldHistory(field, changeType));
-        }
+    @Override
+    protected UpdatableEntityCollectionSqlDao<CustomField> transmogrifyDao(Transmogrifier transactionalDao) {
+        return transactionalDao.become(CustomFieldSqlDao.class);
+    }
 
-        return result;
+    @Override
+    protected UpdatableEntityCollectionSqlDao<CustomField> getSqlDao() {
+        return dao;
     }
+
+//    @Override
+//    public void saveEntitiesFromTransaction(Transmogrifier dao, UUID objectId, ObjectType objectType, List<CustomField> fields, CallContext context) {
+//        CustomFieldSqlDao customFieldSqlDao = dao.become(CustomFieldSqlDao.class);
+//
+//        // get list of existing fields
+//        List<CustomField> existingFields = customFieldSqlDao.load(objectId.toString(), objectType);
+//        List<CustomField> fieldsToUpdate = new ArrayList<CustomField>();
+//
+//        // sort into fields to update (fieldsToUpdate), fields to add (fields), and fields to delete (existingFields)
+//        Iterator<CustomField> fieldIterator = fields.iterator();
+//        while (fieldIterator.hasNext()) {
+//            CustomField field = fieldIterator.next();
+//
+//            Iterator<CustomField> existingFieldIterator = existingFields.iterator();
+//            while (existingFieldIterator.hasNext()) {
+//                CustomField existingField = existingFieldIterator.next();
+//                if (field.getName().equals(existingField.getName())) {
+//                    // if the tagStore match, remove from both lists
+//                    fieldsToUpdate.add(field);
+//                    fieldIterator.remove();
+//                    existingFieldIterator.remove();
+//                }
+//            }
+//        }
+//
+//        customFieldSqlDao.batchInsertFromTransaction(objectId.toString(), objectType, fields, context);
+//        customFieldSqlDao.batchUpdateFromTransaction(objectId.toString(), objectType, fieldsToUpdate, context);
+//
+//        // get all custom fields (including those that are about to be deleted) from the database in order to get the record ids
+//        List<Mapper> recordIds = customFieldSqlDao.getRecordIds(objectId.toString(), objectType);
+//        Map<UUID, Long> recordIdMap = new HashMap<UUID, Long>();
+//        for (Mapper recordId : recordIds) {
+//            recordIdMap.put(recordId.getId(), recordId.getRecordId());
+//        }
+//
+//        customFieldSqlDao.batchDeleteFromTransaction(objectId.toString(), objectType, existingFields, context);
+//
+//        List<MappedEntity<CustomField>> fieldHistories = new ArrayList<MappedEntity<CustomField>>();
+//        fieldHistories.addAll(convertToHistory(fields, recordIdMap, ChangeType.INSERT));
+//        fieldHistories.addAll(convertToHistory(fieldsToUpdate, recordIdMap, ChangeType.UPDATE));
+//        fieldHistories.addAll(convertToHistory(existingFields, recordIdMap, ChangeType.DELETE));
+//
+//        customFieldSqlDao.batchAddHistoryFromTransaction(objectId.toString(), objectType, fieldHistories, context);
+//        customFieldSqlDao.batchInsertAuditLogFromTransaction(TableName.CUSTOM_FIELD_HISTORY, objectId.toString(), objectType, fieldHistories, context);
+//    }
+//
+//    private List<MappedEntity<CustomField>> convertToHistory(List<CustomField> fields, Map<UUID, Long> recordIds, ChangeType changeType) {
+//        List<MappedEntity<CustomField>> result = new ArrayList<MappedEntity<CustomField>>();
+//
+//        for (CustomField field : fields) {
+//            result.add(new MappedEntity<CustomField>(recordIds.get(field.getId()), field, changeType));
+//        }
+//
+//        return result;
+//    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
index a987c4d..66cd734 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldDao.java
@@ -16,13 +16,8 @@
 
 package com.ning.billing.util.customfield.dao;
 
-import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
-import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+import com.ning.billing.util.dao.AuditedCollectionDao;
 
-import java.util.List;
-import java.util.UUID;
-
-public interface CustomFieldDao {
-    void saveFields(Transmogrifier dao, UUID objectId, String objectType, List<CustomField> fields, CallContext context);
+public interface CustomFieldDao extends AuditedCollectionDao<CustomField> {
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.java
index 733bfeb..e73dbf4 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.java
@@ -20,9 +20,10 @@ import java.util.List;
 
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.customfield.CustomFieldBinder;
-import com.ning.billing.util.customfield.CustomFieldMapper;
-import com.ning.billing.util.entity.UpdatableEntityCollectionDao;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.ObjectTypeBinder;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
@@ -33,25 +34,33 @@ import com.ning.billing.util.customfield.CustomField;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(CustomFieldMapper.class)
-public interface CustomFieldSqlDao extends UpdatableEntityCollectionDao<CustomField>, Transactional<CustomFieldSqlDao>, Transmogrifier {
+public interface CustomFieldSqlDao extends UpdatableEntityCollectionSqlDao<CustomField>,
+                                           Transactional<CustomFieldSqlDao>, Transmogrifier {
     @Override
     @SqlBatch(transactional=false)
-    public void batchInsertFromTransaction(@Bind("objectId") final String objectId,
-                                           @Bind("objectType") final String objectType,
-                                           @CustomFieldBinder final List<CustomField> entities,
-                                           @CallContextBinder final CallContext context);
+    public void insertFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @CustomFieldBinder final List<CustomField> entities,
+                                      @CallContextBinder final CallContext context);
 
     @Override
     @SqlBatch(transactional=false)
-    public void batchUpdateFromTransaction(@Bind("objectId") final String objectId,
-                                           @Bind("objectType") final String objectType,
-                                           @CustomFieldBinder final List<CustomField> entities,
-                                           @CallContextBinder final CallContext context);
+    public void updateFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @CustomFieldBinder final List<CustomField> entities,
+                                      @CallContextBinder final CallContext context);
 
     @Override
     @SqlBatch(transactional=false)
-    public void batchDeleteFromTransaction(@Bind("objectId") final String objectId,
-                                           @Bind("objectType") final String objectType,
-                                           @CustomFieldBinder final List<CustomField> entities,
-                                           @CallContextBinder final CallContext context);
+    public void deleteFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @CustomFieldBinder final List<CustomField> entities,
+                                      @CallContextBinder final CallContext context);
+
+    @Override
+    @SqlBatch(transactional=false)
+    public void addHistoryFromTransaction(@Bind("objectId") final String objectId,
+                                               @ObjectTypeBinder final ObjectType objectType,
+                                               @CustomFieldHistoryBinder final List<EntityHistory<CustomField>> entities,
+                                               @CallContextBinder final CallContext context);
 }
diff --git a/util/src/main/java/com/ning/billing/util/customfield/DefaultFieldStore.java b/util/src/main/java/com/ning/billing/util/customfield/DefaultFieldStore.java
index 4a31dd4..8698787 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/DefaultFieldStore.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/DefaultFieldStore.java
@@ -17,14 +17,16 @@
 package com.ning.billing.util.customfield;
 
 import java.util.UUID;
-import com.ning.billing.util.entity.EntityCollectionBase;
+
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.entity.collection.EntityCollectionBase;
 
 public class DefaultFieldStore extends EntityCollectionBase<CustomField> implements FieldStore {
-    public DefaultFieldStore(UUID objectId, String objectType) {
+    public DefaultFieldStore(UUID objectId, ObjectType objectType) {
         super(objectId, objectType);
     }
 
-    public static DefaultFieldStore create(UUID objectId, String objectType) {
+    public static DefaultFieldStore create(UUID objectId, ObjectType objectType) {
         return new DefaultFieldStore(objectId, objectType);
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/customfield/StringCustomField.java b/util/src/main/java/com/ning/billing/util/customfield/StringCustomField.java
index f60093c..074f322 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/StringCustomField.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/StringCustomField.java
@@ -18,7 +18,6 @@ package com.ning.billing.util.customfield;
 
 import java.util.UUID;
 import com.ning.billing.util.entity.UpdatableEntityBase;
-import org.joda.time.DateTime;
 
 public class StringCustomField extends UpdatableEntityBase implements CustomField {
     private String name;
@@ -30,9 +29,8 @@ public class StringCustomField extends UpdatableEntityBase implements CustomFiel
         this.value = value;
     }
 
-    public StringCustomField(UUID id, String createdBy, DateTime createdDate,
-                             String updatedBy, DateTime updatedDate, String name, String value) {
-        super(id, createdBy, createdDate, updatedBy, updatedDate);
+    public StringCustomField(UUID id, String name, String value) {
+        super(id);
         this.name = name;
         this.value = value;
     }
@@ -51,4 +49,24 @@ public class StringCustomField extends UpdatableEntityBase implements CustomFiel
     public void setValue(String value) {
         this.value = value;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        StringCustomField that = (StringCustomField) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+        //if (value != null ? !value.equals(that.value) : that.value != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (value != null ? value.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java b/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java
new file mode 100644
index 0000000..a518578
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditBinder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010-2011 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 org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(AuditBinder.AuditBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface AuditBinder {
+    public static class AuditBinderFactory implements BinderFactory {
+        @Override
+        public Binder build(Annotation annotation) {
+            return new Binder<AuditBinder, EntityAudit>() {
+                @Override
+                public void bind(SQLStatement q, AuditBinder bind, EntityAudit audit) {
+                    q.bind("tableName", audit.getTableName().toString());
+                    q.bind("recordId", audit.getRecordId());
+                    q.bind("changeType", audit.getChangeType().toString());
+                }
+            };
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDao.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDao.java
new file mode 100644
index 0000000..d757f70
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDao.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.entity.Entity;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface AuditedCollectionDao<T extends Entity> {
+    void saveEntitiesFromTransaction(Transmogrifier transactionalDao, UUID objectId, ObjectType objectType,
+                                     List<T> entities, CallContext context);
+
+    List<T> loadEntities(UUID objectId, ObjectType objectType);
+
+    List<T> loadEntitiesFromTransaction(Transmogrifier dao, UUID objectId, ObjectType objectType);
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
new file mode 100644
index 0000000..da6df68
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/AuditedCollectionDaoBase.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.util.ChangeType;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.entity.Entity;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
+import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public abstract class AuditedCollectionDaoBase<T extends Entity> implements AuditedCollectionDao<T> {
+    @Override
+    public void saveEntitiesFromTransaction(Transmogrifier transactionalDao, UUID objectId, ObjectType objectType, List<T> entities, CallContext context) {
+        UpdatableEntityCollectionSqlDao<T> dao = transmogrifyDao(transactionalDao);
+
+        // get list of existing entities
+        List<T> existingEntities = dao.load(objectId.toString(), objectType);
+        List<T> entitiesToUpdate = new ArrayList<T>();
+
+        // sort into entities to update (entitiesToUpdate), entities to add (entities), and entities to delete (existingEntities)
+        Iterator<T> entityIterator = entities.iterator();
+        while (entityIterator.hasNext()) {
+            T entity = entityIterator.next();
+
+            Iterator<T> existingEntityIterator = existingEntities.iterator();
+            while (existingEntityIterator.hasNext()) {
+                T existingEntity = existingEntityIterator.next();
+                if (entity.equals(existingEntity)) {
+                    // if the entities match, remove from both lists
+                    entitiesToUpdate.add(entity);
+                    entityIterator.remove();
+                    existingEntityIterator.remove();
+                }
+            }
+        }
+
+        dao.insertFromTransaction(objectId.toString(), objectType, entities, context);
+        dao.updateFromTransaction(objectId.toString(), objectType, entitiesToUpdate, context);
+
+        // get all custom entities (including those that are about to be deleted) from the database in order to get the record ids
+        List<Mapper<UUID, Long>> recordIds = dao.getRecordIds(objectId.toString(), objectType);
+        Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+
+        dao.deleteFromTransaction(objectId.toString(), objectType, existingEntities, context);
+
+        List<EntityHistory<T>> entityHistories = new ArrayList<EntityHistory<T>>();
+        entityHistories.addAll(convertToHistory(entities, recordIdMap, ChangeType.INSERT));
+        entityHistories.addAll(convertToHistory(entitiesToUpdate, recordIdMap, ChangeType.UPDATE));
+        entityHistories.addAll(convertToHistory(existingEntities, recordIdMap, ChangeType.DELETE));
+
+        Long maxHistoryRecordId = dao.getMaxHistoryRecordId();
+        dao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
+
+        // have to fetch history record ids to update audit log
+        List<Mapper<Long, Long>> historyRecordIds = dao.getHistoryRecordIds(maxHistoryRecordId);
+        Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
+        List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
+
+        dao.insertAuditFromTransaction(entityAudits, context);
+    }
+
+    @Override
+    public List<T> loadEntities(final UUID objectId, final ObjectType objectType) {
+        UpdatableEntityCollectionSqlDao thisDao = getSqlDao();
+        return thisDao.load(objectId.toString(), objectType);
+    }
+
+    @Override
+    public List<T> loadEntitiesFromTransaction(final Transmogrifier dao, final UUID objectId, final ObjectType objectType) {
+        UpdatableEntityCollectionSqlDao<T> thisDao = transmogrifyDao(dao);
+        return thisDao.load(objectId.toString(), objectType);
+    }
+
+    protected List<EntityHistory<T>> convertToHistory(List<T> entities, Map<UUID, Long> recordIds, ChangeType changeType) {
+        List<EntityHistory<T>> histories = new ArrayList<EntityHistory<T>>();
+
+        for (T entity : entities) {
+            UUID id = entity.getId();
+            histories.add(new EntityHistory<T>(id, recordIds.get(id), entity, changeType));
+        }
+
+        return histories;
+    }
+
+    protected List<EntityAudit> convertToAudits(List<EntityHistory<T>> histories, Map<Long, Long> historyRecordIds) {
+        List<EntityAudit> audits = new ArrayList<EntityAudit>();
+
+        for (EntityHistory<T> history : histories) {
+            Long recordId = history.getValue();
+            Long historyRecordId = historyRecordIds.get(recordId);
+            audits.add(new EntityAudit(getTableName(), historyRecordId, history.getChangeType()));
+        }
+
+        return audits;
+    }
+
+    protected Map<UUID, Long> convertToHistoryMap(List<Mapper<UUID, Long>> recordIds) {
+        Map<UUID, Long> recordIdMap = new HashMap<UUID, Long>();
+        for (Mapper<UUID, Long> recordId : recordIds) {
+            recordIdMap.put(recordId.getKey(), recordId.getValue());
+        }
+        return recordIdMap;
+    }
+
+    protected Map<Long, Long> convertToAuditMap(List<Mapper<Long, Long>> historyRecordIds) {
+        Map<Long, Long> historyRecordIdMap = new HashMap<Long, Long>();
+        for (Mapper<Long, Long> historyRecordId : historyRecordIds) {
+            historyRecordIdMap.put(historyRecordId.getKey(), historyRecordId.getValue());
+        }
+        return historyRecordIdMap;
+    }
+
+    protected abstract TableName getTableName();
+    protected abstract UpdatableEntityCollectionSqlDao<T> transmogrifyDao(Transmogrifier transactionalDao);
+    protected abstract UpdatableEntityCollectionSqlDao<T> getSqlDao();
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/CollectionHistorySqlDao.java b/util/src/main/java/com/ning/billing/util/dao/CollectionHistorySqlDao.java
new file mode 100644
index 0000000..d3a01d5
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/CollectionHistorySqlDao.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.entity.Entity;
+import org.skife.jdbi.v2.sqlobject.SqlBatch;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface CollectionHistorySqlDao<T extends Entity> {
+    @SqlBatch(transactional = false)
+    public void addHistoryFromTransaction(String objectId, ObjectType objectType,
+                                           List<EntityHistory<T>> histories,
+                                           CallContext context);
+
+    @SqlUpdate
+    public void addHistoryFromTransaction(String objectId, ObjectType objectType,
+                                          EntityHistory<T> history,
+                                          CallContext context);
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java b/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java
new file mode 100644
index 0000000..15280fa
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/EntityAudit.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 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 com.ning.billing.util.ChangeType;
+
+public class EntityAudit {
+    private final TableName tableName;
+    private final Long recordId;
+    private final ChangeType changeType;
+
+    public EntityAudit(TableName tableName, Long recordId, ChangeType changeType) {
+        this.tableName = tableName;
+        this.recordId = recordId;
+        this.changeType = changeType;
+    }
+
+    public TableName getTableName() {
+        return tableName;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public ChangeType getChangeType() {
+        return changeType;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/HistoryRecordIdMapper.java b/util/src/main/java/com/ning/billing/util/dao/HistoryRecordIdMapper.java
new file mode 100644
index 0000000..3d6e3f5
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/HistoryRecordIdMapper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 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 org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class HistoryRecordIdMapper extends MapperBase implements ResultSetMapper<Mapper> {
+    @Override
+    public Mapper<Long, Long> map(int index, ResultSet resultSet, StatementContext ctx) throws SQLException {
+        Long recordId = resultSet.getLong("record_id");
+        Long historyRecordId = resultSet.getLong("history_record_id");
+
+        return new Mapper<Long, Long>(recordId, historyRecordId);
+    }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/dao/Mapper.java b/util/src/main/java/com/ning/billing/util/dao/Mapper.java
new file mode 100644
index 0000000..e4e178c
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/Mapper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 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;
+
+public class Mapper<K, V> {
+    private final K key;
+    private final V value;
+
+    public Mapper(K key, V value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    public K getKey() {
+        return key;
+    }
+
+    public V getValue() {
+        return value;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/MapperBase.java b/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
index d10e2a0..119b727 100644
--- a/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
+++ b/util/src/main/java/com/ning/billing/util/dao/MapperBase.java
@@ -22,11 +22,16 @@ import org.joda.time.DateTimeZone;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Timestamp;
-import java.util.Date;
+import java.util.UUID;
 
 public abstract class MapperBase {
     protected DateTime getDate(ResultSet rs, String fieldName) throws SQLException {
         final Timestamp resultStamp = rs.getTimestamp(fieldName);
         return rs.wasNull() ? null : new DateTime(resultStamp).toDateTime(DateTimeZone.UTC);
     }
+
+    protected UUID getUUID(ResultSet resultSet, String fieldName) throws SQLException {
+        String result = resultSet.getString(fieldName);
+        return result == null ? null : UUID.fromString(result);
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/ObjectTypeBinder.java b/util/src/main/java/com/ning/billing/util/dao/ObjectTypeBinder.java
new file mode 100644
index 0000000..18f0efc
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/ObjectTypeBinder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 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 org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(ObjectTypeBinder.ObjectTypeBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface ObjectTypeBinder {
+    public static class ObjectTypeBinderFactory implements BinderFactory {
+        public Binder build(Annotation annotation) {
+            return new Binder<ObjectTypeBinder, ObjectType>() {
+                public void bind(SQLStatement q, ObjectTypeBinder bind, ObjectType objectType) {
+                    q.bind("objectType", objectType.getObjectName());
+                }
+            };
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/RecordIdMapper.java b/util/src/main/java/com/ning/billing/util/dao/RecordIdMapper.java
new file mode 100644
index 0000000..35cdaf3
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/RecordIdMapper.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2011 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 org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.UUID;
+
+public class RecordIdMapper extends MapperBase implements ResultSetMapper<Mapper> {
+    @Override
+    public Mapper<UUID, Long> map(int index, ResultSet resultSet, StatementContext ctx) throws SQLException {
+        UUID id = getUUID(resultSet, "id");
+        Long recordId = resultSet.getLong("record_id");
+
+        return new Mapper<UUID, Long>(id, recordId);
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableName.java b/util/src/main/java/com/ning/billing/util/dao/TableName.java
new file mode 100644
index 0000000..28a070a
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/TableName.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010-2011 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;
+
+public enum TableName {
+    ACCOUNT("accounts"),
+    ACCOUNT_HISTORY("account_history"),
+    ACCOUNT_EMAIL_HISTORY("account_email_history"),
+    BUNDLES("bundles"),
+    CUSTOM_FIELD_HISTORY("custom_field_history"),
+    ENTITLEMENT_EVENTS("entitlement_events"),
+    FIXED_INVOICE_ITEMS("fixed_invoice_items"),
+    INVOICE_PAYMENTS("invoice_payments"),
+    INVOICES("invoices"),
+    PAYMENT_ATTEMPTS("payment_attempts"),
+    PAYMENT_HISTORY("payment_history"),
+    PAYMENTS("payments"),
+    RECURRING_INVOICE_ITEMS("recurring_invoice_items"),
+    SUBSCRIPTIONS("subscriptions"),
+    TAG_HISTORY("tag_history");
+    
+    private final String tableName;
+    
+    TableName(String tableName) {
+        this.tableName = tableName;
+    }
+    
+    public String getTableName() {
+        return tableName;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java b/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java
new file mode 100644
index 0000000..a93d915
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/dao/TableNameBinder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010-2011 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 org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(TableNameBinder.TableNameBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface TableNameBinder {
+    public static class TableNameBinderFactory implements BinderFactory {
+        public Binder build(Annotation annotation) {
+            return new Binder<TableNameBinder, TableName>() {
+                public void bind(SQLStatement q, TableNameBinder bind, TableName tableName) {
+                    q.bind("tableName", tableName.getTableName());
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java b/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java
new file mode 100644
index 0000000..59bc69e
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/entity/dao/UpdatableEntitySqlDao.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2011 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.entity.dao;
+
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.AuditSqlDao;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.entity.Entity;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+
+// this interface needs to be extended by an interface that provides (externalized) sql and object binders and mappers
+public interface UpdatableEntitySqlDao<T extends Entity> extends EntitySqlDao<T>, AuditSqlDao {
+    @SqlUpdate
+    public void update(final T entity, final CallContext context);
+
+    @SqlUpdate
+    public void insertHistoryFromTransaction(final EntityHistory<T> account,
+                                            final CallContext context);
+}
diff --git a/util/src/main/java/com/ning/billing/util/entity/EntityBase.java b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
index 4de0312..6a03828 100644
--- a/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
@@ -22,35 +22,19 @@ import java.util.UUID;
 
 public abstract class EntityBase implements Entity {
     protected final UUID id;
-    protected final String createdBy;
-    protected final DateTime createdDate;
 
     // used to hydrate objects
-    public EntityBase(UUID id, String createdBy, DateTime createdDate) {
+    public EntityBase(UUID id) {
         this.id = id;
-        this.createdBy = createdBy;
-        this.createdDate = createdDate;
     }
 
     // used to create new objects
     public EntityBase() {
         this.id = UUID.randomUUID();
-        this.createdBy = null;
-        this.createdDate = null;
     }
 
     @Override
     public UUID getId() {
         return id;
     }
-
-    @Override
-    public String getCreatedBy() {
-        return createdBy;
-    }
-
-    @Override
-    public DateTime getCreatedDate() {
-        return createdDate;
-    }
 }
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/entity/ExtendedEntityBase.java b/util/src/main/java/com/ning/billing/util/entity/ExtendedEntityBase.java
index a52e276..c598893 100644
--- a/util/src/main/java/com/ning/billing/util/entity/ExtendedEntityBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/ExtendedEntityBase.java
@@ -21,6 +21,7 @@ import com.ning.billing.util.customfield.CustomField;
 import com.ning.billing.util.customfield.Customizable;
 import com.ning.billing.util.customfield.DefaultFieldStore;
 import com.ning.billing.util.customfield.FieldStore;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.DefaultControlTag;
 import com.ning.billing.util.tag.DefaultTagStore;
@@ -29,9 +30,7 @@ import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
 import com.ning.billing.util.tag.TagStore;
 import com.ning.billing.util.tag.Taggable;
-import org.joda.time.DateTime;
 
-import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
@@ -42,14 +41,14 @@ public abstract class ExtendedEntityBase extends EntityBase implements Customiza
 
     public ExtendedEntityBase() {
         super();
-        this.fields = DefaultFieldStore.create(getId(), getObjectName());
-        this.tagStore = new DefaultTagStore(id, getObjectName());
+        this.fields = DefaultFieldStore.create(getId(), getObjectType());
+        this.tagStore = new DefaultTagStore(id, getObjectType());
     }
 
-    public ExtendedEntityBase(final UUID id, @Nullable final String createdBy, @Nullable final DateTime createdDate) {
-        super(id, createdBy, createdDate);
-        this.fields = DefaultFieldStore.create(getId(), getObjectName());
-        this.tagStore = new DefaultTagStore(id, getObjectName());
+    public ExtendedEntityBase(final UUID id) {
+        super(id);
+        this.fields = DefaultFieldStore.create(getId(), getObjectType());
+        this.tagStore = new DefaultTagStore(id, getObjectType());
     }
 
     @Override
@@ -145,7 +144,7 @@ public abstract class ExtendedEntityBase extends EntityBase implements Customiza
 	}
 
     @Override
-    public abstract String getObjectName();
+    public abstract ObjectType getObjectType();
 
     @Override
     public abstract void saveFieldValue(String fieldName, String fieldValue, CallContext context);
diff --git a/util/src/main/java/com/ning/billing/util/entity/UpdatableEntityBase.java b/util/src/main/java/com/ning/billing/util/entity/UpdatableEntityBase.java
index 3aaffbc..625aaec 100644
--- a/util/src/main/java/com/ning/billing/util/entity/UpdatableEntityBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/UpdatableEntityBase.java
@@ -16,33 +16,14 @@
 
 package com.ning.billing.util.entity;
 
-import org.joda.time.DateTime;
-
 import java.util.UUID;
 
 public abstract class UpdatableEntityBase extends EntityBase implements UpdatableEntity {
-    private final String updatedBy;
-    private final DateTime updatedDate;
-
     public UpdatableEntityBase() {
         super();
-        this.updatedBy = null;
-        this.updatedDate = null;
-    }
-
-    public UpdatableEntityBase(UUID id, String createdBy, DateTime createdDate, String updatedBy, DateTime updatedDate) {
-        super(id, createdBy, createdDate);
-        this.updatedBy = updatedBy;
-        this.updatedDate = updatedDate;
-    }
-
-    @Override
-    public String getUpdatedBy() {
-        return updatedBy;
     }
 
-    @Override
-    public DateTime getUpdatedDate() {
-        return updatedDate;
+    public UpdatableEntityBase(UUID id) {
+        super(id);
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/glue/BusModule.java b/util/src/main/java/com/ning/billing/util/glue/BusModule.java
index 656253d..2793208 100644
--- a/util/src/main/java/com/ning/billing/util/glue/BusModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/BusModule.java
@@ -16,10 +16,16 @@
 
 package com.ning.billing.util.glue;
 
+import org.skife.config.ConfigurationObjectFactory;
+
 import com.google.inject.AbstractModule;
+import com.google.inject.name.Names;
+import com.ning.billing.config.EntitlementConfig;
+import com.ning.billing.config.PersistentQueueConfig;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.Bus;
 import com.ning.billing.util.bus.BusService;
+import com.ning.billing.util.bus.PersistentBusConfig;
 import com.ning.billing.util.bus.InMemoryBus;
 import com.ning.billing.util.bus.PersistentBus;
 
@@ -58,9 +64,14 @@ public class BusModule extends AbstractModule {
         
     }
 
+    protected void configurePersistentBusConfig() {
+        final PersistentBusConfig config = new ConfigurationObjectFactory(System.getProperties()).build(PersistentBusConfig.class);
+        bind(PersistentBusConfig.class).toInstance(config);
+    }
+    
     private void configurePersistentEventBus() {
+        configurePersistentBusConfig();        
         bind(Bus.class).to(PersistentBus.class).asEagerSingleton();
-        
     }
     
     private void configureInMemoryEventBus() {
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
index f943d0b..cbfc564 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/dao/NotificationSqlDao.java
@@ -39,7 +39,7 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
 import com.ning.billing.util.notificationq.DefaultNotification;
 import com.ning.billing.util.notificationq.Notification;
-import com.ning.billing.util.notificationq.NotificationLifecycle.NotificationLifecycleState;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle.PersistentQueueEntryLifecycleState;
 
 @ExternalizedSqlViaStringTemplate3()
 public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, CloseMe {
@@ -49,35 +49,36 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
     //
     @SqlQuery
     @Mapper(NotificationSqlMapper.class)
-    public List<Notification> getReadyNotifications(@Bind("now") Date now, @Bind("owner") String owner, @Bind("max") int max, @Bind("queue_name") String queueName);
+    public List<Notification> getReadyNotifications(@Bind("now") Date now, @Bind("owner") String owner, @Bind("max") int max, @Bind("queueName") String queueName);
 
     @SqlUpdate
-    public int claimNotification(@Bind("owner") String owner, @Bind("next_available") Date nextAvailable, @Bind("id") long id, @Bind("now") Date now);
+    public int claimNotification(@Bind("owner") String owner, @Bind("nextAvailable") Date nextAvailable,
+                                 @Bind("id") String id, @Bind("now") Date now);
 
     @SqlUpdate
-    public void clearNotification(@Bind("id") long id, @Bind("owner") String owner);
+    public void clearNotification(@Bind("id") String id, @Bind("owner") String owner);
 
     @SqlUpdate
-    public void removeNotificationsByKey(@Bind("notification_key") String key);
+    public void removeNotificationsByKey(@Bind("notificationKey") String key);
     
     @SqlUpdate
     public void insertNotification(@Bind(binder = NotificationSqlDaoBinder.class) Notification evt);
 
     @SqlUpdate
-    public void insertClaimedHistory(@Bind("owner") String owner, @Bind("claimed_dt") Date clainedDate, @Bind("notification_id") String notificationId);
+    public void insertClaimedHistory(@Bind("ownerId") String ownerId, @Bind("claimedDate") Date claimedDate, @Bind("notificationId") String notificationId);
 
     public static class NotificationSqlDaoBinder extends BinderBase implements Binder<Bind, Notification> {
         @Override
         public void bind(@SuppressWarnings("rawtypes") SQLStatement stmt, Bind bind, Notification evt) {
-            stmt.bind("notification_id", evt.getUUID().toString());
-            stmt.bind("created_dt", getDate(new DateTime()));
-            stmt.bind("creating_owner", evt.getCreatedOwner());            
-            stmt.bind("notification_key", evt.getNotificationKey());
-            stmt.bind("effective_dt", getDate(evt.getEffectiveDate()));
-            stmt.bind("queue_name", evt.getQueueName());
-            stmt.bind("processing_available_dt", getDate(evt.getNextAvailableDate()));
-            stmt.bind("processing_owner", evt.getOwner());
-            stmt.bind("processing_state", NotificationLifecycleState.AVAILABLE.toString());
+            stmt.bind("id", evt.getId().toString());
+            stmt.bind("createdDate", getDate(new DateTime()));
+            stmt.bind("creatingOwner", evt.getCreatedOwner());            
+            stmt.bind("notificationKey", evt.getNotificationKey());
+            stmt.bind("effectiveDate", getDate(evt.getEffectiveDate()));
+            stmt.bind("queueName", evt.getQueueName());
+            stmt.bind("processingAvailableDate", getDate(evt.getNextAvailableDate()));
+            stmt.bind("processingOwner", evt.getOwner());
+            stmt.bind("processingState", PersistentQueueEntryLifecycleState.AVAILABLE.toString());
         }
     }
 
@@ -87,17 +88,17 @@ public interface NotificationSqlDao extends Transactional<NotificationSqlDao>, C
         public Notification map(int index, ResultSet r, StatementContext ctx)
         throws SQLException {
 
-            final long id = r.getLong("id");
-            final UUID uuid = UUID.fromString(r.getString("notification_id"));
+            final Long ordering = r.getLong("record_id");
+            final UUID id = getUUID(r, "id");
             final String createdOwner = r.getString("creating_owner");            
             final String notificationKey = r.getString("notification_key");
             final String queueName = r.getString("queue_name");
-            final DateTime effectiveDate = getDate(r, "effective_dt");
-            final DateTime nextAvailableDate = getDate(r, "processing_available_dt");
+            final DateTime effectiveDate = getDate(r, "effective_date");
+            final DateTime nextAvailableDate = getDate(r, "processing_available_date");
             final String processingOwner = r.getString("processing_owner");
-            final NotificationLifecycleState processingState = NotificationLifecycleState.valueOf(r.getString("processing_state"));
+            final PersistentQueueEntryLifecycleState processingState = PersistentQueueEntryLifecycleState.valueOf(r.getString("processing_state"));
 
-            return new DefaultNotification(id, uuid, createdOwner, processingOwner, queueName, nextAvailableDate,
+            return new DefaultNotification(ordering, id, createdOwner, processingOwner, queueName, nextAvailableDate,
                     processingState, notificationKey, effectiveDate);
 
         }
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
index 9d2c601..c71343d 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotification.java
@@ -18,27 +18,25 @@ package com.ning.billing.util.notificationq;
 
 import java.util.UUID;
 
+import com.ning.billing.util.entity.EntityBase;
 import org.joda.time.DateTime;
 
-public class DefaultNotification implements Notification {
-
-    private final long id;
-    private final UUID uuid;
+public class DefaultNotification extends EntityBase implements Notification {
+    private final long ordering;
     private final String owner;
     private final String createdOwner;
     private final String queueName;
     private final DateTime nextAvailableDate;
-    private final NotificationLifecycleState lifecycleState;
+    private final PersistentQueueEntryLifecycleState lifecycleState;
     private final String notificationKey;
     private final DateTime effectiveDate;
 
 
-    public DefaultNotification(long id, UUID uuid, String createdOwner, String owner, String queueName, DateTime nextAvailableDate,
-            NotificationLifecycleState lifecycleState,
+    public DefaultNotification(long ordering, UUID id, String createdOwner, String owner, String queueName, DateTime nextAvailableDate,
+            PersistentQueueEntryLifecycleState lifecycleState,
             String notificationKey, DateTime effectiveDate) {
-        super();
-        this.id = id;
-        this.uuid = uuid;
+        super(id);
+        this.ordering = ordering;
         this.owner = owner;
         this.createdOwner = createdOwner;
         this.queueName = queueName;
@@ -48,17 +46,12 @@ public class DefaultNotification implements Notification {
         this.effectiveDate = effectiveDate;
     }
 
-    @Override
-    public long getId() {
-        return id;
-    }
-
     public DefaultNotification(String queueName, String createdOwner, String notificationKey, DateTime effectiveDate) {
-        this(-1L, UUID.randomUUID(), createdOwner, null, queueName, null, NotificationLifecycleState.AVAILABLE, notificationKey, effectiveDate);
+        this(-1L, UUID.randomUUID(), createdOwner, null, queueName, null, PersistentQueueEntryLifecycleState.AVAILABLE, notificationKey, effectiveDate);
     }
     @Override
-    public UUID getUUID() {
-        return uuid;
+    public Long getOrdering() {
+        return ordering;
     }
 
     @Override
@@ -72,7 +65,7 @@ public class DefaultNotification implements Notification {
     }
 
     @Override
-    public NotificationLifecycleState getProcessingState() {
+    public PersistentQueueEntryLifecycleState getProcessingState() {
         return lifecycleState;
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
index 3db7ce1..6b50914 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/DefaultNotificationQueue.java
@@ -56,12 +56,12 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
         for (final Notification cur : notifications) {
             nbProcessedEvents.incrementAndGet();
             logDebug("handling notification %s, key = %s for time %s",
-                    cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
+                    cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
             handler.handleReadyNotification(cur.getNotificationKey(), cur.getEffectiveDate());
             result++;
             clearNotification(cur);
             logDebug("done handling notification %s, key = %s for time %s",
-                    cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
+                    cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
         }
         return result;
     }
@@ -82,26 +82,26 @@ public class DefaultNotificationQueue extends NotificationQueueBase {
 
 
     private void clearNotification(final Notification cleared) {
-        dao.clearNotification(cleared.getId(), hostname);
+        dao.clearNotification(cleared.getId().toString(), hostname);
     }
 
     private List<Notification> getReadyNotifications() {
 
         final Date now = clock.getUTCNow().toDate();
-        final Date nextAvailable = clock.getUTCNow().plus(config.getDaoClaimTimeMs()).toDate();
+        final Date nextAvailable = clock.getUTCNow().plus(CLAIM_TIME_MS).toDate();
 
-        List<Notification> input = dao.getReadyNotifications(now, hostname, config.getDaoMaxReadyEvents(), getFullQName());
+        List<Notification> input = dao.getReadyNotifications(now, hostname, CLAIM_TIME_MS, getFullQName());
 
         List<Notification> claimedNotifications = new ArrayList<Notification>();
         for (Notification cur : input) {
             logDebug("about to claim notification %s,  key = %s for time %s",
-                    cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate());
-            final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId(), now) == 1);
+                    cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate());
+            final boolean claimed = (dao.claimNotification(hostname, nextAvailable, cur.getId().toString(), now) == 1);
             logDebug("claimed notification %s, key = %s for time %s result = %s",
-                    cur.getUUID(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
+                    cur.getId(), cur.getNotificationKey(), cur.getEffectiveDate(), Boolean.valueOf(claimed));
             if (claimed) {
                 claimedNotifications.add(cur);
-                dao.insertClaimedHistory(hostname, now, cur.getUUID().toString());
+                dao.insertClaimedHistory(hostname, now, cur.getId().toString());
             }
         }
 
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
index 0b60c2d..37caa4e 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/Notification.java
@@ -16,22 +16,17 @@
 
 package com.ning.billing.util.notificationq;
 
-import java.util.UUID;
+import com.ning.billing.util.entity.Entity;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle;
 
 import org.joda.time.DateTime;
 
+public interface Notification extends PersistentQueueEntryLifecycle, Entity {
+    public Long getOrdering();
 
-public interface Notification extends NotificationLifecycle {
-
-    public long getId();
-
-    public UUID getUUID();
-    
     public String getNotificationKey();
 
     public DateTime getEffectiveDate();
 
     public String getQueueName();
-
-
 }
diff --git a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
index 7c82db6..cd3c0c2 100644
--- a/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
+++ b/util/src/main/java/com/ning/billing/util/notificationq/NotificationQueueBase.java
@@ -35,11 +35,15 @@ public abstract class NotificationQueueBase extends PersistentQueueBase implemen
 
     protected final static Logger log = LoggerFactory.getLogger(NotificationQueueBase.class);
 
-    protected static final String NOTIFICATION_THREAD_PREFIX = "Notification-";
-    protected static final long STOP_WAIT_TIMEOUT_MS = 60000;
-
-    protected final String svcName;
-    protected final String queueName;
+    public final static int CLAIM_TIME_MS = (5 * 60 * 1000); // 5 minutes
+    
+    private final static String NOTIFICATION_THREAD_PREFIX = "Notification-";
+    private final static int NB_THREADS = 1;
+
+    
+    private final String svcName;
+    private final String queueName;
+    
     protected final NotificationQueueHandler handler;
     protected final NotificationConfig config;
 
@@ -64,7 +68,7 @@ public abstract class NotificationQueueBase extends PersistentQueueBase implemen
                 });
                 return th;
             }
-        }), 1, STOP_WAIT_TIMEOUT_MS, config.getNotificationSleepTimeMs());
+        }), NB_THREADS, config);
 
         this.clock = clock;
         this.svcName = svcName;
@@ -75,6 +79,21 @@ public abstract class NotificationQueueBase extends PersistentQueueBase implemen
         this.nbProcessedEvents = new AtomicLong();
     }
 
+    @Override
+    public void startQueue() {
+        if (config.isNotificationProcessingOff()) {
+            return;
+        }
+        super.startQueue();
+    }
+    
+    @Override
+    public void stopQueue() {
+        if (config.isNotificationProcessingOff()) {
+            return;
+        }
+        super.stopQueue();
+    }
 
     @Override
     public int processReadyNotification() {
diff --git a/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java b/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java
index a6844ad..0ffe882 100644
--- a/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java
+++ b/util/src/main/java/com/ning/billing/util/queue/PersistentQueueBase.java
@@ -22,26 +22,28 @@ import java.util.concurrent.TimeUnit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.config.PersistentQueueConfig;
+
 
 public abstract class PersistentQueueBase implements QueueLifecycle {
 
     private static final Logger log = LoggerFactory.getLogger(PersistentQueueBase.class);
-
+    
+    private static final long waitTimeoutMs = 15L * 1000L; // 15 seconds
+    
     private final int nbThreads;
     private final Executor executor;
     private final String svcName;
     private final long sleepTimeMs;
-    private final long waitTimeoutMs;
 
     private boolean isProcessingEvents;
     private int curActiveThreads;
     
-    public PersistentQueueBase(final String svcName, final Executor executor, final int nbThreads, final long waitTimeoutMs, final long sleepTimeMs) {
+    public PersistentQueueBase(final String svcName, final Executor executor, final int nbThreads, final PersistentQueueConfig config) {
         this.executor = executor;
         this.nbThreads = nbThreads;
         this.svcName = svcName;
-        this.waitTimeoutMs = waitTimeoutMs;
-        this.sleepTimeMs = sleepTimeMs;
+        this.sleepTimeMs = config.getSleepTimeMs();
         this.isProcessingEvents = false;
         this.curActiveThreads = 0;
     }
diff --git a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagDefinitionUserApi.java b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagDefinitionUserApi.java
index 53d8841..680fb96 100644
--- a/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagDefinitionUserApi.java
+++ b/util/src/main/java/com/ning/billing/util/tag/api/DefaultTagDefinitionUserApi.java
@@ -17,7 +17,9 @@
 package com.ning.billing.util.tag.api;
 
 import java.util.List;
+import java.util.UUID;
 
+import com.ning.billing.util.dao.ObjectType;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
@@ -46,8 +48,8 @@ public class DefaultTagDefinitionUserApi implements TagUserApi {
     }
 
     @Override
-    public TagDefinition create(final String name, final String description, final CallContext context) throws TagDefinitionApiException {
-        return dao.create(name, description, context);
+    public TagDefinition create(final String definitionName, final String description, final CallContext context) throws TagDefinitionApiException {
+        return dao.create(definitionName, description, context);
     }
 
     @Override
@@ -68,24 +70,44 @@ public class DefaultTagDefinitionUserApi implements TagUserApi {
 	}
 
     @Override
-    public Tag createControlTag(String controlTagName) throws TagDefinitionApiException {
-        ControlTagType type = null;
-        for(ControlTagType t : ControlTagType.values()) {
-            if(t.toString().equals(controlTagName)) {
-                type = t;
-            }
-        }
-        
-        if(type == null) {
-            throw new TagDefinitionApiException(ErrorCode.CONTROL_TAG_DOES_NOT_EXIST, controlTagName);
-        }
-        return new DefaultControlTag(type);
+    public List<Tag> createControlTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions) throws TagDefinitionApiException {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
 
     @Override
-    public Tag createDescriptiveTag(String tagDefinitionName) throws TagDefinitionApiException {
-        TagDefinition tagDefinition = getTagDefinition(tagDefinitionName);
-        
-        return new DescriptiveTag(tagDefinition);
+    public Tag createControlTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition) throws TagDefinitionApiException {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
+
+    @Override
+    public List<Tag> createDescriptiveTags(UUID objectId, ObjectType objectType, List<TagDefinition> tagDefinitions) throws TagDefinitionApiException {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public Tag createDescriptiveTag(UUID objectId, ObjectType objectType, TagDefinition tagDefinition) throws TagDefinitionApiException {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+//    @Override
+//    public Tag createControlTags(String controlTagName) throws TagDefinitionApiException {
+//        ControlTagType type = null;
+//        for(ControlTagType t : ControlTagType.values()) {
+//            if(t.toString().equals(controlTagName)) {
+//                type = t;
+//            }
+//        }
+//
+//        if(type == null) {
+//            throw new TagDefinitionApiException(ErrorCode.CONTROL_TAG_DOES_NOT_EXIST, controlTagName);
+//        }
+//        return new DefaultControlTag(type);
+//    }
+//
+//    @Override
+//    public Tag createDescriptiveTags(List) throws TagDefinitionApiException {
+//        TagDefinition tagDefinition = getTagDefinition(tagDefinitionName);
+//
+//        return new DescriptiveTag(tagDefinition);
+//    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
index 3b238c0..a9a2373 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/AuditedTagDao.java
@@ -20,20 +20,26 @@ import com.google.inject.Inject;
 import com.ning.billing.ErrorCode;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.util.ChangeType;
-import com.ning.billing.util.audit.dao.AuditSqlDao;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.dao.AuditedDaoBase;
+import com.ning.billing.util.dao.AuditedCollectionDaoBase;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.Mapper;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.TableName;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
 import com.ning.billing.util.tag.Tag;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
 import org.skife.jdbi.v2.TransactionStatus;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
-import java.util.Iterator;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
-public class AuditedTagDao extends AuditedDaoBase implements TagDao {
+public class AuditedTagDao extends AuditedCollectionDaoBase<Tag> implements TagDao {
     private final TagSqlDao tagSqlDao;
 
     @Inject
@@ -42,70 +48,31 @@ public class AuditedTagDao extends AuditedDaoBase implements TagDao {
     }
 
     @Override
-    public void saveTags(final UUID objectId, final String objectType,
-                         final List<Tag> tags, final CallContext context) {
-        saveTagsFromTransaction(tagSqlDao, objectId, objectType, tags, context);
-    }
-
-    @Override
-    public void saveTagsFromTransaction(final Transmogrifier dao, final UUID objectId, final String objectType,
-                                        final List<Tag> tags, final CallContext context) {
-        TagSqlDao tagSqlDao = dao.become(TagSqlDao.class);
-
-        // get list of existing tagStore
-        List<Tag> existingTags = tagSqlDao.load(objectId.toString(), objectType);
-
-        // sort into tagStore to update (tagsToUpdate), tagStore to add (tagStore), and tagStore to delete (existingTags)
-        Iterator<Tag> tagIterator = tags.iterator();
-        while (tagIterator.hasNext()) {
-            Tag tag = tagIterator.next();
-
-            Iterator<Tag> existingTagIterator = existingTags.iterator();
-            while (existingTagIterator.hasNext()) {
-                Tag existingTag = existingTagIterator.next();
-                if (tag.getTagDefinitionName().equals(existingTag.getTagDefinitionName())) {
-                    // if the tagStore match, remove from both lists
-                    // in the case of tag, this just means the tag remains associated
-                    tagIterator.remove();
-                    existingTagIterator.remove();
-                }
-            }
-        }
-
-        tagSqlDao.batchInsertFromTransaction(objectId.toString(), objectType, tags, context);
-        tagSqlDao.batchDeleteFromTransaction(objectId.toString(), objectType, existingTags, context);
-
-        List<String> historyIdsForInsert = getIdList(tags.size());
-        tagSqlDao.batchInsertHistoryFromTransaction(objectId.toString(), objectType, historyIdsForInsert, tags, ChangeType.INSERT, context);
-        List<String> historyIdsForDelete = getIdList(existingTags.size());
-        tagSqlDao.batchInsertHistoryFromTransaction(objectId.toString(), objectType, historyIdsForDelete, existingTags, ChangeType.DELETE, context);
-
-        AuditSqlDao auditSqlDao = tagSqlDao.become(AuditSqlDao.class);
-        auditSqlDao.insertAuditFromTransaction("tag_history", historyIdsForInsert, ChangeType.INSERT, context);
-        auditSqlDao.insertAuditFromTransaction("tag_history", historyIdsForDelete, ChangeType.DELETE, context);
-    }
-
-    @Override
-    public List<Tag> loadTags(final UUID objectId, final String objectType) {
-        return tagSqlDao.load(objectId.toString(), objectType);
-    }
-
-    @Override
-    public List<Tag> loadTagsFromTransaction(final Transmogrifier dao, final UUID objectId, final String objectType) {
-        TagSqlDao tagSqlDao = dao.become(TagSqlDao.class);
-        return tagSqlDao.load(objectId.toString(), objectType);
-    }
-
-    @Override
-    public void addTag(final String tagName, final UUID objectId, final String objectType, final CallContext context) {
+    public void addTag(final String tagName, final UUID objectId, final ObjectType objectType, final CallContext context) {
         tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
             @Override
             public Void inTransaction(final TagSqlDao tagSqlDao, final TransactionStatus status) throws Exception {
                 String tagId = UUID.randomUUID().toString();
                 tagSqlDao.addTagFromTransaction(tagId, tagName, objectId.toString(), objectType, context);
 
-                TagAuditSqlDao auditDao = tagSqlDao.become(TagAuditSqlDao.class);
-                auditDao.addTagFromTransaction(tagId, context);
+                Tag tag = tagSqlDao.findTag(tagName, objectId.toString(), objectType);
+                List<Tag> tagList = new ArrayList<Tag>();
+                tagList.add(tag);
+
+                List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
+                Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
+
+                List<EntityHistory<Tag>> entityHistories = new ArrayList<EntityHistory<Tag>>();
+                entityHistories.addAll(convertToHistory(tagList, recordIdMap, ChangeType.INSERT));
+
+                Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId();
+                tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
+
+                // have to fetch history record ids to update audit log
+                List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
+                Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
+                List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
+                tagSqlDao.insertAuditFromTransaction(entityAudits, context);
 
                 return null;
             }
@@ -113,7 +80,7 @@ public class AuditedTagDao extends AuditedDaoBase implements TagDao {
     }
 
     @Override
-    public void removeTag(final String tagName, final UUID objectId, final String objectType, final CallContext context) {
+    public void removeTag(final String tagName, final UUID objectId, final ObjectType objectType, final CallContext context) {
         tagSqlDao.inTransaction(new Transaction<Void, TagSqlDao>() {
             @Override
             public Void inTransaction(final TagSqlDao tagSqlDao, final TransactionStatus status) throws Exception {
@@ -123,13 +90,43 @@ public class AuditedTagDao extends AuditedDaoBase implements TagDao {
                     throw new InvoiceApiException(ErrorCode.TAG_DOES_NOT_EXIST, tagName);
                 }
 
-                tagSqlDao.removeTagFromTransaction(tagName, objectId.toString(), objectType, context);
+                List<Tag> tagList = new ArrayList<Tag>();
+                tagList.add(tag);
+
+                List<Mapper<UUID, Long>> recordIds = tagSqlDao.getRecordIds(objectId.toString(), objectType);
+                Map<UUID, Long> recordIdMap = convertToHistoryMap(recordIds);
 
-                TagAuditSqlDao auditDao = tagSqlDao.become(TagAuditSqlDao.class);
-                auditDao.removeTagFromTransaction(tag.getId().toString(), context);
+                tagSqlDao.deleteFromTransaction(objectId.toString(), objectType, tagList, context);
+
+                List<EntityHistory<Tag>> entityHistories = new ArrayList<EntityHistory<Tag>>();
+                entityHistories.addAll(convertToHistory(tagList, recordIdMap, ChangeType.DELETE));
+
+                Long maxHistoryRecordId = tagSqlDao.getMaxHistoryRecordId();
+                tagSqlDao.addHistoryFromTransaction(objectId.toString(), objectType, entityHistories, context);
+
+                // have to fetch history record ids to update audit log
+                List<Mapper<Long, Long>> historyRecordIds = tagSqlDao.getHistoryRecordIds(maxHistoryRecordId);
+                Map<Long, Long> historyRecordIdMap = convertToAuditMap(historyRecordIds);
+                List<EntityAudit> entityAudits = convertToAudits(entityHistories, historyRecordIdMap);
+                tagSqlDao.insertAuditFromTransaction(entityAudits, context);
 
                 return null;
             }
         });
     }
+
+    @Override
+    protected TableName getTableName() {
+        return TableName.TAG_HISTORY;
+    }
+
+    @Override
+    protected UpdatableEntityCollectionSqlDao<Tag> transmogrifyDao(Transmogrifier transactionalDao) {
+        return transactionalDao.become(TagSqlDao.class);
+    }
+
+    @Override
+    protected UpdatableEntityCollectionSqlDao<Tag> getSqlDao() {
+        return tagSqlDao;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 884dacd..1b6ce2a 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -44,7 +44,7 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
 
         // add control tag definitions
         for (ControlTagType controlTag : ControlTagType.values()) {
-            definitionList.add(new DefaultTagDefinition(controlTag.toString(), controlTag.getDescription()));
+            definitionList.add(new DefaultTagDefinition(controlTag.toString(), controlTag.getDescription(), true));
         }
 
         return definitionList;
@@ -68,7 +68,7 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
             throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_ALREADY_EXISTS, definitionName);
         }
 
-        TagDefinition definition = new DefaultTagDefinition(definitionName, description);
+        TagDefinition definition = new DefaultTagDefinition(definitionName, description, false);
         dao.create(definition, context);
         return definition;
     }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
index 2416b21..d2d4a6f 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagBinder.java
@@ -22,8 +22,6 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import com.google.inject.Inject;
-import com.ning.billing.util.clock.Clock;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.sqlobject.Binder;
 import org.skife.jdbi.v2.sqlobject.BinderFactory;
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
index 11594ac..a680862 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDao.java
@@ -17,6 +17,8 @@
 package com.ning.billing.util.tag.dao;
 
 import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.dao.AuditedCollectionDao;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
@@ -24,16 +26,8 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import java.util.List;
 import java.util.UUID;
 
-public interface TagDao {
-    void saveTagsFromTransaction(Transmogrifier dao, UUID objectId, String objectType, List<Tag> tags, CallContext context);
+public interface TagDao extends AuditedCollectionDao<Tag> {
+    void addTag(String tagName, UUID objectId, ObjectType objectType, CallContext context);
 
-    void saveTags(UUID objectId, String objectType, List<Tag> tags, CallContext context);
-
-    List<Tag> loadTags(UUID objectId, String objectType);
-
-    List<Tag> loadTagsFromTransaction(Transmogrifier dao, UUID objectId, String objectType);
-
-    void addTag(String tagName, UUID objectId, String objectType, CallContext context);
-
-    void removeTag(String tagName, UUID objectId, String objectType, CallContext context);
+    void removeTag(String tagName, UUID objectId, ObjectType objectType, CallContext context);
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
index 1308ae1..efe7587 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
@@ -27,10 +27,9 @@ import java.util.UUID;
 
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.entity.EntityDao;
+import com.ning.billing.util.entity.dao.EntitySqlDao;
 import com.ning.billing.util.tag.DefaultTagDefinition;
 import com.ning.billing.util.tag.TagDefinition;
-import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
 import org.skife.jdbi.v2.sqlobject.Bind;
@@ -45,7 +44,7 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(TagDefinitionSqlDao.TagDefinitionMapper.class)
-public interface TagDefinitionSqlDao extends EntityDao<TagDefinition> {
+public interface TagDefinitionSqlDao extends EntitySqlDao<TagDefinition> {
     @Override
     @SqlUpdate
     public void create(@TagDefinitionBinder final TagDefinition entity, @CallContextBinder final CallContext context);
@@ -68,9 +67,7 @@ public interface TagDefinitionSqlDao extends EntityDao<TagDefinition> {
             UUID id = UUID.fromString(result.getString("id"));
             String name = result.getString("name");
             String description = result.getString("description");
-            String createdBy = result.getString("created_by");
-            DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
-            return new DefaultTagDefinition(id, createdBy, createdDate, name, description);
+            return new DefaultTagDefinition(id, name, description);
         }
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java
new file mode 100644
index 0000000..67bb3ca
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagHistoryBinder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2011 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.tag.dao;
+
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.MappedEntity;
+import com.ning.billing.util.tag.Tag;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@BindingAnnotation(TagHistoryBinder.TagHistoryBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface TagHistoryBinder {
+    public static class TagHistoryBinderFactory implements BinderFactory {
+        @Override
+        public Binder build(Annotation annotation) {
+            return new Binder<TagHistoryBinder, EntityHistory<Tag>>() {
+                @Override
+                public void bind(SQLStatement q, TagHistoryBinder bind, EntityHistory<Tag> tagHistory) {
+                    q.bind("recordId", tagHistory.getValue());
+                    q.bind("changeType", tagHistory.getChangeType().toString());
+                    q.bind("id", tagHistory.getId().toString());
+                    q.bind("tagDefinitionName", tagHistory.getEntity().getTagDefinitionName());
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
index 211ae5a..986e49d 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
@@ -44,10 +44,8 @@ public class TagMapper extends MapperBase implements ResultSetMapper<Tag> {
 
         if (thisTagType == null) {
             UUID id = UUID.fromString(result.getString("id"));
-            String createdBy = result.getString("created_by");
-            DateTime createdDate = new DateTime(result.getTimestamp("created_date"));
 
-            return new DescriptiveTag(id, createdBy, createdDate, name);
+            return new DescriptiveTag(id, name);
         } else {
             return new DefaultControlTag(thisTagType);
         }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
index a20e757..ee62b60 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagSqlDao.java
@@ -18,10 +18,16 @@ package com.ning.billing.util.tag.dao;
 
 import java.util.List;
 
-import com.ning.billing.util.ChangeType;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
-import com.ning.billing.util.dao.ChangeTypeBinder;
+import com.ning.billing.util.dao.AuditBinder;
+import com.ning.billing.util.dao.EntityAudit;
+import com.ning.billing.util.dao.EntityHistory;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.dao.ObjectTypeBinder;
+import com.ning.billing.util.dao.TableName;
+import com.ning.billing.util.dao.TableNameBinder;
+import com.ning.billing.util.entity.collection.dao.UpdatableEntityCollectionSqlDao;
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
@@ -30,49 +36,54 @@ import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
-import com.ning.billing.util.entity.EntityCollectionDao;
 import com.ning.billing.util.tag.Tag;
 
 @ExternalizedSqlViaStringTemplate3
 @RegisterMapper(TagMapper.class)
-public interface TagSqlDao extends EntityCollectionDao<Tag>, Transactional<TagSqlDao>, Transmogrifier {
+public interface TagSqlDao extends UpdatableEntityCollectionSqlDao<Tag>, Transactional<TagSqlDao>, Transmogrifier {
     @Override
     @SqlBatch(transactional=false)
-    public void batchInsertFromTransaction(@Bind("objectId") final String objectId,
-                                           @Bind("objectType") final String objectType,
-                                           @TagBinder final List<Tag> entities,
-                                           @CallContextBinder final CallContext context);
+    public void insertFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @TagBinder final List<Tag> tags,
+                                      @CallContextBinder final CallContext context);
+
+    @Override
+    @SqlBatch(transactional=false)
+    public void updateFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @TagBinder final List<Tag> tags,
+                                      @CallContextBinder final CallContext context);
 
     @Override
     @SqlBatch(transactional=false)
-    public void batchDeleteFromTransaction(@Bind("objectId") final String objectId,
-                                           @Bind("objectType") final String objectType,
-                                           @TagBinder final List<Tag> entities,
-                                           @CallContextBinder final CallContext context);
+    public void deleteFromTransaction(@Bind("objectId") final String objectId,
+                                      @ObjectTypeBinder final ObjectType objectType,
+                                      @TagBinder final List<Tag> tags,
+                                      @CallContextBinder final CallContext context);
 
-    @SqlBatch(transactional = false)
-    public void batchInsertHistoryFromTransaction(@Bind("objectId") final String objectId,
-                                                  @Bind("objectType") final String objectType,
-                                                  @Bind("historyRecordId") final List<String> historyRecordIdList,
-                                                  @TagBinder final List<Tag> tags,
-                                                  @ChangeTypeBinder final ChangeType changeType,
-                                                  @CallContextBinder final CallContext context);
+    @Override
+    @SqlBatch(transactional=false)
+    public void addHistoryFromTransaction(@Bind("objectId") final String objectId,
+                                               @ObjectTypeBinder final ObjectType objectType,
+                                               @TagHistoryBinder final List<EntityHistory<Tag>> histories,
+                                               @CallContextBinder final CallContext context);
 
     @SqlUpdate
     public void addTagFromTransaction(@Bind("id") final String tagId,
                                       @Bind("tagDefinitionName") final String tagName,
                                       @Bind("objectId") final String objectId,
-                                      @Bind("objectType") final String objectType,
+                                      @ObjectTypeBinder final ObjectType objectType,
                                       @CallContextBinder final CallContext context);
 
     @SqlUpdate
     public void removeTagFromTransaction(@Bind("tagDefinitionName") final String tagName,
                                          @Bind("objectId") final String objectId,
-                                         @Bind("objectType") final String objectType,
+                                         @ObjectTypeBinder final ObjectType objectType,
                                          @CallContextBinder final CallContext context);
 
     @SqlQuery
     public Tag findTag(@Bind("tagDefinitionName") final String tagName,
                        @Bind("objectId") final String objectId,
-                       @Bind("objectType") final String objectType);
+                       @ObjectTypeBinder final ObjectType objectType);
 }
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java b/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
index 662de60..f41fe12 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultControlTag.java
@@ -17,7 +17,6 @@
 package com.ning.billing.util.tag;
 
 import java.util.UUID;
-import org.joda.time.DateTime;
 
 public class DefaultControlTag extends DescriptiveTag implements ControlTag {
     private final ControlTagType controlTagType;
@@ -29,9 +28,8 @@ public class DefaultControlTag extends DescriptiveTag implements ControlTag {
     }
 
     // use to hydrate objects when loaded from the persistence layer
-    public DefaultControlTag(final UUID id, final String createdBy,
-                             final DateTime createdDate, final ControlTagType controlTagType) {
-        super(id, createdBy, createdDate, controlTagType.toString());
+    public DefaultControlTag(final UUID id, final ControlTagType controlTagType) {
+        super(id, controlTagType.toString());
         this.controlTagType = controlTagType;
     }
 
@@ -39,4 +37,21 @@ public class DefaultControlTag extends DescriptiveTag implements ControlTag {
     public ControlTagType getControlTagType() {
         return controlTagType;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DefaultControlTag that = (DefaultControlTag) o;
+
+        if (controlTagType != that.controlTagType) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return controlTagType != null ? controlTagType.hashCode() : 0;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
index 0eb0ac9..c16a621 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
@@ -18,20 +18,21 @@ package com.ning.billing.util.tag;
 
 import java.util.UUID;
 import com.ning.billing.util.entity.EntityBase;
-import org.joda.time.DateTime;
 
 public class DefaultTagDefinition extends EntityBase implements TagDefinition {
     private String name;
     private String description;
+    private Boolean isControlTag;
 
-    public DefaultTagDefinition(String name, String description) {
+    public DefaultTagDefinition(String name, String description, Boolean isControlTag) {
         super();
         this.name = name;
         this.description = description;
+        this.isControlTag = isControlTag;
     }
 
-    public DefaultTagDefinition(UUID id, String createdBy, DateTime createdDate, String name, String description) {
-        super(id, createdBy, createdDate);
+    public DefaultTagDefinition(UUID id, String name, String description) {
+        super(id);
         this.name = name;
         this.description = description;
     }
@@ -45,4 +46,9 @@ public class DefaultTagDefinition extends EntityBase implements TagDefinition {
     public String getDescription() {
         return description;
     }
+
+    @Override
+    public Boolean isControlTag() {
+        return isControlTag;
+    }
 }
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultTagStore.java b/util/src/main/java/com/ning/billing/util/tag/DefaultTagStore.java
index aa9c3af..a35b424 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultTagStore.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultTagStore.java
@@ -17,10 +17,12 @@
 package com.ning.billing.util.tag;
 
 import java.util.UUID;
-import com.ning.billing.util.entity.EntityCollectionBase;
+
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.entity.collection.EntityCollectionBase;
 
 public class DefaultTagStore extends EntityCollectionBase<Tag> implements TagStore {
-    public DefaultTagStore(final UUID objectId, final String objectType) {
+    public DefaultTagStore(final UUID objectId, final ObjectType objectType) {
         super(objectId, objectType);
     }
 
diff --git a/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java b/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
index 1ad70fe..2633643 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DescriptiveTag.java
@@ -18,21 +18,14 @@ package com.ning.billing.util.tag;
 
 import java.util.UUID;
 
-import com.google.inject.Inject;
-import com.ning.billing.util.clock.Clock;
 import com.ning.billing.util.entity.EntityBase;
-import com.ning.billing.util.entity.UpdatableEntityBase;
-import org.joda.time.DateTime;
 
 public class DescriptiveTag extends EntityBase implements Tag {
     private final String tagDefinitionName;
 
-    @Inject
-    private Clock clock;
-
     // use to hydrate objects from the persistence layer
-    public DescriptiveTag(UUID id, String createdBy, DateTime createdDate, String tagDefinitionName) {
-        super(id, createdBy, createdDate);
+    public DescriptiveTag(UUID id, String tagDefinitionName) {
+        super(id);
         this.tagDefinitionName = tagDefinitionName;
     }
 
@@ -52,4 +45,22 @@ public class DescriptiveTag extends EntityBase implements Tag {
     public String getTagDefinitionName() {
         return tagDefinitionName;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DescriptiveTag that = (DescriptiveTag) o;
+
+        if (tagDefinitionName != null ? !tagDefinitionName.equals(that.tagDefinitionName) : that.tagDefinitionName != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return tagDefinitionName != null ? tagDefinitionName.hashCode() : 0;
+    }
 }
diff --git a/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
index 2ac1869..0cbd4ec 100644
--- a/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/bus/dao/PersistentBusSqlDao.sql.stg
@@ -1,56 +1,56 @@
 group PersistentBusSqlDao;
           
-getNextBusEventEntry(max, now) ::= <<
+getNextBusEventEntry() ::= <<
     select
-      id
+      record_id
       , class_name
       , event_json
-      , created_dt
+      , created_date
       , creating_owner
       , processing_owner
-      , processing_available_dt
+      , processing_available_date
       , processing_state
     from bus_events
     where
       processing_state != 'PROCESSED'
       and processing_state != 'REMOVED'
-      and (processing_owner IS NULL OR processing_available_dt \<= :now)
+      and (processing_owner IS NULL OR processing_available_date \<= :now)
     order by
-      id asc
+      record_id asc
     limit :max
     ;
 >>
 
 
-claimBusEvent(owner, next_available, id, now) ::= <<
+claimBusEvent() ::= <<
     update bus_events
     set
       processing_owner = :owner
-      , processing_available_dt = :next_available
+      , processing_available_date = :nextAvailable
       , processing_state = 'IN_PROCESSING'
     where
-      id = :id
+      record_id = :recordId
       and processing_state != 'PROCESSED'
       and processing_state != 'REMOVED'
-      and (processing_owner IS NULL OR processing_available_dt \<= :now)
+      and (processing_owner IS NULL OR processing_available_date \<= :now)
     ;
 >>
 
-clearBusEvent(id, owner) ::= <<
+clearBusEvent() ::= <<
     update bus_events
     set
       processing_state = 'PROCESSED'
     where
-      id = :id
+      record_id = :recordId
     ;
 >>
 
-removeBusEventsById(id) ::= <<
+removeBusEventsById() ::= <<
     update bus_events
     set
       processing_state = 'REMOVED'
     where
-      id = :id
+      record_id = :recordId
     ;
 >>
 
@@ -59,31 +59,30 @@ insertBusEvent() ::= <<
     insert into bus_events (
       class_name
     , event_json
-    , created_dt
+    , created_date
     , creating_owner
     , processing_owner
-    , processing_available_dt
+    , processing_available_date
     , processing_state
     ) values (
-      :class_name
-    , :event_json
-    , :created_dt
-    , :creating_owner
-    , :processing_owner
-    , :processing_available_dt
-    , :processing_state
+      :className
+    , :eventJson
+    , :createdDate
+    , :creatingOwner
+    , :processingOwner
+    , :processingAvailableDate
+    , :processingState
     );   
 >>
 
-
-insertClaimedHistory(owner_id, claimed_dt, bus_event_id) ::= <<
+insertClaimedHistory() ::= <<
     insert into claimed_bus_events (
           owner_id
-        , claimed_dt
+        , claimed_date
         , bus_event_id
       ) values (
-          :owner_id
-        , :claimed_dt
-        , :bus_event_id
+          :ownerId
+        , :claimedDate
+        , :busEventId
       );
 >>
diff --git a/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
index 1fbf994..018e1ec 100644
--- a/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/customfield/dao/CustomFieldSqlDao.sql.stg
@@ -1,17 +1,17 @@
 group CustomFieldSqlDao;
 
-batchInsertFromTransaction() ::= <<
+insertFromTransaction() ::= <<
     INSERT INTO custom_fields(id, object_id, object_type, field_name, field_value, created_by, created_date, updated_by, updated_date)
     VALUES (:id, :objectId, :objectType, :fieldName, :fieldValue, :userName, :createdDate, :userName, :updatedDate);
 >>
 
-batchUpdateFromTransaction() ::= <<
+updateFromTransaction() ::= <<
     UPDATE custom_fields
     SET field_value = :fieldValue, updated_by = :userName, updated_date = :updatedDate
     WHERE object_id = :objectId AND object_type = :objectType AND field_name = :fieldName;
 >>
 
-batchDeleteFromTransaction() ::= <<
+deleteFromTransaction() ::= <<
     DELETE FROM custom_fields
     WHERE object_id = :objectId AND object_type = :objectType AND field_name = :fieldName;
 >>
@@ -22,6 +22,56 @@ load() ::= <<
     WHERE object_id = :objectId AND object_type = :objectType;
 >>
 
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM custom_fields
+    WHERE object_id = :objectId AND object_type = :objectType;
+>>
+
+historyFields(prefix) ::= <<
+  <prefix>record_id,
+  <prefix>id,
+  <prefix>object_id,
+  <prefix>object_type,
+  <prefix>field_name,
+  <prefix>field_value,
+  <prefix>updated_by,
+  <prefix>date,
+  <prefix>change_type
+>>
+
+addHistoryFromTransaction() ::= <<
+    INSERT INTO custom_field_history(<historyFields()>)
+    VALUES(:recordId, :id, :objectId, :objectType, :fieldName, :fieldValue, :userName, :updatedDate, :changeType);
+>>
+
+getMaxHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM custom_field_history;
+>>
+
+getHistoryRecordIds() ::= <<
+    SELECT history_record_id, record_id
+    FROM custom_field_history
+    WHERE history_record_id > :maxHistoryRecordId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
     SELECT 1 FROM custom_fields;
 >>
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index e32e27b..9ea7c1a 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -1,116 +1,135 @@
 DROP TABLE IF EXISTS custom_fields;
 CREATE TABLE custom_fields (
-  id char(36) NOT NULL,
-  object_id char(36) NOT NULL,
-  object_type varchar(30) NOT NULL,
-  field_name varchar(30) NOT NULL,
-  field_value varchar(255),
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  updated_by varchar(50) DEFAULT NULL,
-  updated_date datetime DEFAULT NULL,
-  PRIMARY KEY(id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    object_id char(36) NOT NULL,
+    object_type varchar(30) NOT NULL,
+    field_name varchar(30) NOT NULL,
+    field_value varchar(255),
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) DEFAULT NULL,
+    updated_date datetime DEFAULT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX custom_fields_id ON custom_fields(id);
 CREATE INDEX custom_fields_object_id_object_type ON custom_fields(object_id, object_type);
 CREATE UNIQUE INDEX custom_fields_unique ON custom_fields(object_id, object_type, field_name);
 
 DROP TABLE IF EXISTS custom_field_history;
 CREATE TABLE custom_field_history (
-  history_record_id char(36) NOT NULL,
-  id char(36) NOT NULL,
-  object_id char(36) NOT NULL,
-  object_type varchar(30) NOT NULL,
-  field_name varchar(30),
-  field_value varchar(255),
-  updated_by varchar(50) NOT NULL,
-  date datetime NOT NULL,
-  change_type char(6) NOT NULL
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
+    id char(36) NOT NULL,
+    object_id char(36) NOT NULL,
+    object_type varchar(30) NOT NULL,
+    field_name varchar(30),
+    field_value varchar(255),
+    updated_by varchar(50) NOT NULL,
+    date datetime NOT NULL,
+    change_type char(6) NOT NULL,
+    PRIMARY KEY(history_record_id)
 ) ENGINE=innodb;
+CREATE INDEX custom_field_history_record_id ON custom_field_history(record_id);
 CREATE INDEX custom_field_history_object_id_object_type ON custom_fields(object_id, object_type);
 
 DROP TABLE IF EXISTS tag_descriptions;
 DROP TABLE IF EXISTS tag_definitions;
 CREATE TABLE tag_definitions (
-  id char(36) NOT NULL,
-  name varchar(20) NOT NULL,
-  description varchar(200) NOT NULL,
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    name varchar(20) NOT NULL,
+    description varchar(200) NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    updated_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
+CREATE UNIQUE INDEX tag_definitions_id ON tag_definitions(id);
 CREATE UNIQUE INDEX tag_definitions_name ON tag_definitions(name);
 
 DROP TABLE IF EXISTS tag_definition_history;
 CREATE TABLE tag_definition_history (
-  id char(36) NOT NULL,
-  name varchar(30) NOT NULL,
-  created_by varchar(50),
-  description varchar(200),
-  change_type char(6) NOT NULL,
-  updated_by varchar(50) NOT NULL,
-  date datetime NOT NULL
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
+    id char(36) NOT NULL,
+    name varchar(30) NOT NULL,
+    created_by varchar(50),
+    description varchar(200),
+    change_type char(6) NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    date datetime NOT NULL,
+    PRIMARY KEY(history_record_id)
 ) ENGINE=innodb;
 CREATE INDEX tag_definition_history_id ON tag_definition_history(id);
+CREATE INDEX tag_definition_history_record_id ON tag_definition_history(record_id);
 CREATE INDEX tag_definition_history_name ON tag_definition_history(name);
 
 DROP TABLE IF EXISTS tags;
 CREATE TABLE tags (
-  id char(36) NOT NULL,
-  tag_definition_name varchar(20) NOT NULL,
-  object_id char(36) NOT NULL,
-  object_type varchar(30) NOT NULL,
-  created_by varchar(50) NOT NULL,
-  created_date datetime NOT NULL,
-  PRIMARY KEY(id)
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    tag_definition_name varchar(20) NOT NULL,
+    object_id char(36) NOT NULL,
+    object_type varchar(30) NOT NULL,
+    created_by varchar(50) NOT NULL,
+    created_date datetime NOT NULL,
+    PRIMARY KEY(record_id)
 ) ENGINE = innodb;
+CREATE UNIQUE INDEX tags_id ON tags(id);
 CREATE INDEX tags_by_object ON tags(object_id);
 CREATE UNIQUE INDEX tags_unique ON tags(tag_definition_name, object_id);
 
 DROP TABLE IF EXISTS tag_history;
 CREATE TABLE tag_history (
-  history_record_id char(36) NOT NULL,
-  id char(36) NOT NULL,
-  tag_definition_name varchar(20) NOT NULL,
-  object_id char(36) NOT NULL,
-  object_type varchar(30) NOT NULL,
-  change_type char(6) NOT NULL,
-  updated_by varchar(50) NOT NULL,
-  date datetime NOT NULL
+    history_record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL,
+    id char(36) NOT NULL,
+    object_id char(36) NOT NULL,
+    object_type varchar(30) NOT NULL,
+    tag_definition_name varchar(20) NOT NULL,
+    updated_by varchar(50) NOT NULL,
+    date datetime NOT NULL,
+    change_type char(6) NOT NULL,
+    PRIMARY KEY(history_record_id)
 ) ENGINE = innodb;
+CREATE INDEX tag_history_record_id ON tag_history(record_id);
 CREATE INDEX tag_history_by_object ON tags(object_id);
 
 DROP TABLE IF EXISTS notifications;
 CREATE TABLE notifications (
-    id int(11) unsigned NOT NULL AUTO_INCREMENT,
-    notification_id char(36) NOT NULL,
-    created_dt datetime NOT NULL,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    id char(36) NOT NULL,
+    created_date datetime NOT NULL,
 	notification_key varchar(256) NOT NULL,
 	creating_owner char(50) NOT NULL,
-    effective_dt datetime NOT NULL,
+    effective_date datetime NOT NULL,
     queue_name char(64) NOT NULL,
     processing_owner char(50) DEFAULT NULL,
-    processing_available_dt datetime DEFAULT NULL,
+    processing_available_date datetime DEFAULT NULL,
     processing_state varchar(14) DEFAULT 'AVAILABLE',
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
-CREATE INDEX  `idx_comp_where` ON notifications (`effective_dt`, `queue_name`, `processing_state`,`processing_owner`,`processing_available_dt`);
-CREATE INDEX  `idx_update` ON notifications (`processing_state`,`processing_owner`,`processing_available_dt`);
-CREATE INDEX  `idx_get_ready` ON notifications (`effective_dt`,`created_dt`,`id`);
+CREATE UNIQUE INDEX notifications_id ON notifications(id);
+CREATE INDEX  `idx_comp_where` ON notifications (`effective_date`, `queue_name`, `processing_state`,`processing_owner`,`processing_available_date`);
+CREATE INDEX  `idx_update` ON notifications (`processing_state`,`processing_owner`,`processing_available_date`);
+CREATE INDEX  `idx_get_ready` ON notifications (`effective_date`,`created_date`,`id`);
 
 DROP TABLE IF EXISTS claimed_notifications;
 CREATE TABLE claimed_notifications (
-    id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     owner_id varchar(64) NOT NULL,
-    claimed_dt datetime NOT NULL,
+    claimed_date datetime NOT NULL,
     notification_id char(36) NOT NULL,
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
 
 DROP TABLE IF EXISTS audit_log;
 CREATE TABLE audit_log (
     id int(11) unsigned NOT NULL AUTO_INCREMENT,
     table_name varchar(50) NOT NULL,
-    record_id char(36) NOT NULL,
+    record_id int(11) NOT NULL,
     change_type char(6) NOT NULL,
     change_date datetime NOT NULL,
     changed_by varchar(50) NOT NULL,
@@ -124,26 +143,23 @@ CREATE INDEX audit_log_user_name ON audit_log(changed_by);
 
 DROP TABLE IF EXISTS bus_events;
 CREATE TABLE bus_events (
-    id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     class_name varchar(128) NOT NULL, 
     event_json varchar(2048) NOT NULL,     
-    created_dt datetime NOT NULL,
+    created_date datetime NOT NULL,
     creating_owner char(50) NOT NULL,
     processing_owner char(50) DEFAULT NULL,
-    processing_available_dt datetime DEFAULT NULL,
+    processing_available_date datetime DEFAULT NULL,
     processing_state varchar(14) DEFAULT 'AVAILABLE',
-    PRIMARY KEY(id)
+    PRIMARY KEY(record_id)
 ) ENGINE=innodb;
-CREATE INDEX  `idx_bus_where` ON bus_events (`processing_state`,`processing_owner`,`processing_available_dt`);
-
+CREATE INDEX  `idx_bus_where` ON bus_events (`processing_state`,`processing_owner`,`processing_available_date`);
 
 DROP TABLE IF EXISTS claimed_bus_events;
 CREATE TABLE claimed_bus_events (
-    id int(11) unsigned NOT NULL AUTO_INCREMENT,
+    record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     owner_id varchar(64) NOT NULL,
-    claimed_dt datetime NOT NULL,
+    claimed_date datetime NOT NULL,
     bus_event_id char(36) NOT NULL,
-    PRIMARY KEY(id)
-) ENGINE=innodb;
-
-
+    PRIMARY KEY(record_id)
+) ENGINE=innodb;
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
index 5797d5a..0731adc 100644
--- a/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/notificationq/dao/NotificationSqlDao.sql.stg
@@ -1,48 +1,47 @@
 group NotificationSqlDao;
 
-getReadyNotifications(now, max) ::= <<
+getReadyNotifications() ::= <<
     select
-      id
-      ,  notification_id
+      record_id
+      , id
       , notification_key
-      , created_dt
+      , created_date
       , creating_owner
-      , effective_dt
+      , effective_date
       , queue_name
       , processing_owner
-      , processing_available_dt
+      , processing_available_date
       , processing_state
     from notifications
     where
-      effective_dt \<= :now
-      and queue_name = :queue_name
+      effective_date \<= :now
+      and queue_name = :queueName
       and processing_state != 'PROCESSED'
       and processing_state != 'REMOVED'
-      and (processing_owner IS NULL OR processing_available_dt \<= :now)
+      and (processing_owner IS NULL OR processing_available_date \<= :now)
     order by
-      effective_dt asc
-      , created_dt asc
-      , id
+      effective_date asc
+      , created_date asc
+      , record_id
     limit :max
     ;
 >>
 
-
-claimNotification(owner, next_available, id, now) ::= <<
+claimNotification() ::= <<
     update notifications
     set
       processing_owner = :owner
-      , processing_available_dt = :next_available
+      , processing_available_date = :nextAvailable
       , processing_state = 'IN_PROCESSING'
     where
       id = :id
       and processing_state != 'PROCESSED'
       and processing_state != 'REMOVED'
-      and (processing_owner IS NULL OR processing_available_dt \<= :now)
+      and (processing_owner IS NULL OR processing_available_date \<= :now)
     ;
 >>
 
-clearNotification(id, owner) ::= <<
+clearNotification() ::= <<
     update notifications
     set
       processing_state = 'PROCESSED'
@@ -51,49 +50,47 @@ clearNotification(id, owner) ::= <<
     ;
 >>
 
-removeNotificationsByKey(notification_key) ::= <<
+removeNotificationsByKey() ::= <<
     update notifications
     set
       processing_state = 'REMOVED'
     where
-      notification_key = :notification_key
+      notification_key = :notificationKey
     ;
 >>
 
-
 insertNotification() ::= <<
     insert into notifications (
-      notification_id
-    , notification_key
-      , created_dt
+      id
+      , notification_key
+      , created_date
       , creating_owner
-      , effective_dt
+      , effective_date
       , queue_name
       , processing_owner
-      , processing_available_dt
+      , processing_available_date
       , processing_state
     ) values (
-      :notification_id
-      , :notification_key
-      , :created_dt
-      , :creating_owner
-      , :effective_dt
-      , :queue_name
-      , :processing_owner
-      , :processing_available_dt
-      , :processing_state
+      :id
+      , :notificationKey
+      , :createdDate
+      , :creatingOwner
+      , :effectiveDate
+      , :queueName
+      , :processingOwner
+      , :processingAvailableDate
+      , :processingState
     );   
 >>
 
-
-insertClaimedHistory(sequence_id, owner, hostname, claimed_dt, notification_id) ::= <<
+insertClaimedHistory() ::= <<
     insert into claimed_notifications (
           owner_id
-        , claimed_dt
+        , claimed_date
         , notification_id
       ) values (
-          :owner
-        , :claimed_dt
-        , :notification_id
+          :ownerId
+        , :claimedDate
+        , :notificationId
       );
 >>
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
index 54bdfa9..2a03325 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
@@ -5,7 +5,9 @@ fields(prefix) ::= <<
     <prefix>name,
     <prefix>description,
     <prefix>created_by,
-    <prefix>created_date
+    <prefix>created_date ,
+    <prefix>updated_by,
+    <prefix>updated_date
 >>
 
 get() ::= <<
@@ -15,7 +17,7 @@ get() ::= <<
 
 create() ::= <<
   INSERT INTO tag_definitions(<fields()>)
-  VALUES(:id, :name, :description, :userName, :createdDate);
+  VALUES(:id, :name, :description, :userName, :createdDate, :userName, :updatedDate);
 >>
 
 load() ::= <<
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
index 8f98452..f0a5805 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagSqlDao.sql.stg
@@ -9,17 +9,12 @@ fields(prefix) ::= <<
     <prefix>created_date
 >>
 
-batchInsertFromTransaction() ::= <<
+insertFromTransaction() ::= <<
   INSERT INTO tags(<fields()>)
   VALUES (:id, :tagDefinitionName, :objectId, :objectType, :userName, :createdDate);
 >>
 
-batchInsertHistoryFromTransaction() ::= <<
-    INSERT INTO tag_history (history_record_id, id, tag_definition_name, object_id, object_type, change_type, updated_by, date)
-    VALUES (:historyRecordId, :id, :tagDefinitionName, :objectId, :objectType, :changeType, :userName, :updatedDate);
->>
-
-batchDeleteFromTransaction() ::= <<
+deleteFromTransaction() ::= <<
     DELETE FROM tags
     WHERE tag_definition_name = :tagDefinitionName
         AND object_id = :objectId AND object_type = :objectType;
@@ -53,6 +48,55 @@ load() ::= <<
     WHERE t.object_id = :objectId AND t.object_type = :objectType;
 >>
 
+getRecordIds() ::= <<
+    SELECT record_id, id
+    FROM tags
+    WHERE object_id = :objectId AND object_type = :objectType;
+>>
+
+historyFields(prefix) ::= <<
+  <prefix>record_id,
+  <prefix>id,
+  <prefix>object_id,
+  <prefix>object_type,
+  <prefix>tag_definition_name,
+  <prefix>updated_by,
+  <prefix>date,
+  <prefix>change_type
+>>
+
+addHistoryFromTransaction() ::= <<
+    INSERT INTO tag_history(<historyFields()>)
+    VALUES(:recordId, :id, :objectId, :objectType, :tagDefinitionName, :userName, :updatedDate, :changeType);
+>>
+
+getMaxHistoryRecordId() ::= <<
+    SELECT MAX(history_record_id)
+    FROM tag_history;
+>>
+
+getHistoryRecordIds() ::= <<
+    SELECT history_record_id, record_id
+    FROM tag_history
+    WHERE history_record_id > :maxHistoryRecordId;
+>>
+
+auditFields(prefix) ::= <<
+    <prefix>table_name,
+    <prefix>record_id,
+    <prefix>change_type,
+    <prefix>change_date,
+    <prefix>changed_by,
+    <prefix>reason_code,
+    <prefix>comments,
+    <prefix>user_token
+>>
+
+insertAuditFromTransaction() ::= <<
+    INSERT INTO audit_log(<auditFields()>)
+    VALUES(:tableName, :recordId, :changeType, :createdDate, :userName, NULL, NULL, NULL);
+>>
+
 test() ::= <<
   SELECT 1 FROM tags;
 >>
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 1b0d9f6..c68c759 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -158,10 +158,14 @@ public class MysqlTestingHelper
     
     public void stopMysql()
     {
-        if (mysqldResource != null) {
-            mysqldResource.shutdown();
-            FileUtils.deleteQuietly(dbDir);
-            log.info("MySQLd stopped");
+        try {
+            if (mysqldResource != null) {
+                mysqldResource.shutdown();
+                FileUtils.deleteQuietly(dbDir);
+                log.info("MySQLd stopped");
+            }
+        } catch (Exception ex) {
+            //fail silently
         }
     }
 
diff --git a/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java b/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java
index ec2b431..8b9c2ee 100644
--- a/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java
+++ b/util/src/test/java/com/ning/billing/mock/MockAccountBuilder.java
@@ -29,6 +29,7 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.junction.api.BlockingState;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.customfield.CustomField;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.ControlTagType;
 import com.ning.billing.util.tag.Tag;
 import com.ning.billing.util.tag.TagDefinition;
@@ -54,10 +55,6 @@ public class MockAccountBuilder {
     private String phone;
     private boolean migrated;
     private boolean isNotifiedForInvoices;
-    private String createdBy;
-    private DateTime createdDate;
-    private String updatedBy;
-    private DateTime updatedDate;
 
     public MockAccountBuilder() {
         this(UUID.randomUUID());
@@ -162,26 +159,6 @@ public class MockAccountBuilder {
         return this;
     }
 
-    public MockAccountBuilder createdBy(final String createdBy) {
-        this.createdBy = createdBy;
-        return this;
-    }
-
-    public MockAccountBuilder createdDate(final DateTime createdDate) {
-        this.createdDate = createdDate;
-        return this;
-    }
-
-    public MockAccountBuilder updatedBy(final String updatedBy) {
-        this.updatedBy = updatedBy;
-        return this;
-    }
-
-    public MockAccountBuilder updatedDate(final DateTime updatedDate) {
-        this.updatedDate = updatedDate;
-        return this;
-    }
-
     public Account build() {
         return new Account(){
             
@@ -318,145 +295,89 @@ public class MockAccountBuilder {
 
             @Override
             public List<CustomField> getFieldList() {
-               
                 return null;
             }
 
             @Override
             public void setFields(List<CustomField> fields) {
-               
-                
             }
 
             @Override
             public void saveFields(List<CustomField> fields, CallContext context) {
-               
-                
             }
 
             @Override
             public void clearFields() {
-               
-                
             }
 
             @Override
             public void clearPersistedFields(CallContext context) {
-               
-                
             }
 
             @Override
-            public String getObjectName() {
-               
-                return null;
-            }
-
-            @Override
-            public String getUpdatedBy() {
-               
-                return updatedBy;
-            }
-
-            @Override
-            public DateTime getUpdatedDate() {
-               
-                return updatedDate;
+            public ObjectType getObjectType() {
+                throw new UnsupportedOperationException();
             }
 
             @Override
             public UUID getId() {
-               
                 return id;
             }
 
             @Override
-            public String getCreatedBy() {
-               
-                return createdBy;
-            }
-
-            @Override
-            public DateTime getCreatedDate() {
-               
-                return createdDate;
-            }
-
-            @Override
             public List<Tag> getTagList() {
-               
                 return null;
             }
 
             @Override
             public boolean hasTag(TagDefinition tagDefinition) {
-               
                 return false;
             }
 
             @Override
             public boolean hasTag(ControlTagType controlTagType) {
-               
                 return false;
             }
 
             @Override
             public void addTag(TagDefinition definition) {
-               
-                
             }
 
             @Override
             public void addTags(List<Tag> tags) {
-               
-                
             }
 
             @Override
             public void addTagsFromDefinitions(List<TagDefinition> tagDefinitions) {
-               
-                
             }
 
             @Override
             public void clearTags() {
-               
-                
             }
 
             @Override
             public void removeTag(TagDefinition definition) {
-               
-                
             }
 
             @Override
             public boolean generateInvoice() {
-               
                 return true;
             }
 
             @Override
             public boolean processPayment() {
-               
                 return true;
             }
 
             @Override
             public BlockingState getBlockingState() {
-               
                 return null;
             }
 
             @Override
             public MutableAccountData toMutableAccountData() {
-               
                 throw new NotImplementedException();
             }
-            
-            
         };
-        
-       
     }
 }
diff --git a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
index fbd2be3..7a31ab8 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
@@ -19,18 +19,14 @@ package com.ning.billing.util.customfield;
 import java.io.IOException;
 import java.util.UUID;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Stage;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.MockClockModule;
+import com.ning.billing.util.clock.ClockMock;
 import com.ning.billing.util.customfield.dao.AuditedCustomFieldDao;
 import com.ning.billing.util.customfield.dao.CustomFieldDao;
-import com.ning.billing.util.glue.FieldStoreModule;
+import com.ning.billing.util.dao.ObjectType;
 import org.apache.commons.io.IOUtils;
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
@@ -62,13 +58,8 @@ public class TestFieldStore {
             helper.initDb(utilDdl);
 
             dbi = helper.getDBI();
-            customFieldDao = new AuditedCustomFieldDao();
-
-            FieldStoreModule module = new FieldStoreModule();
-            final Injector injector = Guice.createInjector(Stage.DEVELOPMENT, module, new MockClockModule());
-            Clock clock = injector.getInstance(Clock.class);
-            context = new DefaultCallContextFactory(clock).createCallContext("Fezzik", CallOrigin.TEST, UserType.TEST);
-
+            customFieldDao = new AuditedCustomFieldDao(dbi);
+            context = new DefaultCallContextFactory(new ClockMock()).createCallContext("Fezzik", CallOrigin.TEST, UserType.TEST);
         }
         catch (Throwable t) {
             log.error("Setup failed", t);
@@ -87,7 +78,7 @@ public class TestFieldStore {
     @Test
     public void testFieldStore() {
         final UUID id = UUID.randomUUID();
-        final String objectType = "Test widget";
+        final ObjectType objectType = ObjectType.ACCOUNT;
 
         final FieldStore fieldStore1 = new DefaultFieldStore(id, objectType);
 
@@ -96,7 +87,7 @@ public class TestFieldStore {
         fieldStore1.setValue(fieldName, fieldValue);
 
         CustomFieldSqlDao customFieldSqlDao = dbi.onDemand(CustomFieldSqlDao.class);
-        customFieldDao.saveFields(customFieldSqlDao, id, objectType, fieldStore1.getEntityList(), context);
+        customFieldDao.saveEntitiesFromTransaction(customFieldSqlDao, id, objectType, fieldStore1.getEntityList(), context);
 
         final FieldStore fieldStore2 = DefaultFieldStore.create(id, objectType);
         fieldStore2.add(customFieldSqlDao.load(id.toString(), objectType));
@@ -106,7 +97,7 @@ public class TestFieldStore {
         fieldValue = "Cape Canaveral";
         fieldStore2.setValue(fieldName, fieldValue);
         assertEquals(fieldStore2.getValue(fieldName), fieldValue);
-        customFieldDao.saveFields(customFieldSqlDao, id, objectType, fieldStore2.getEntityList(), context);
+        customFieldDao.saveEntitiesFromTransaction(customFieldSqlDao, id, objectType, fieldStore2.getEntityList(), context);
 
         final FieldStore fieldStore3 = DefaultFieldStore.create(id, objectType);
         assertEquals(fieldStore3.getValue(fieldName), null);
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
index 4702409..7c61363 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/dao/TestNotificationSqlDao.java
@@ -20,11 +20,10 @@ import java.io.IOException;
 import java.sql.SQLException;
 import java.util.List;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
+
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.skife.jdbi.v2.DBI;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.tweak.HandleCallback;
@@ -39,8 +38,8 @@ import com.google.inject.Inject;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.util.notificationq.DefaultNotification;
 import com.ning.billing.util.notificationq.Notification;
-import com.ning.billing.util.notificationq.NotificationLifecycle.NotificationLifecycleState;
 import com.ning.billing.util.notificationq.dao.NotificationSqlDao.NotificationSqlMapper;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle.PersistentQueueEntryLifecycleState;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -117,28 +116,28 @@ public class TestNotificationSqlDao {
         assertEquals(notification.getNotificationKey(), notificationKey);
         validateDate(notification.getEffectiveDate(), effDt);
         assertEquals(notification.getOwner(), null);
-        assertEquals(notification.getProcessingState(), NotificationLifecycleState.AVAILABLE);
+        assertEquals(notification.getProcessingState(), PersistentQueueEntryLifecycleState.AVAILABLE);
         assertEquals(notification.getNextAvailableDate(), null);
 
         DateTime nextAvailable = now.plusMinutes(5);
-        int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId(), now.toDate());
+        int res = dao.claimNotification(ownerId, nextAvailable.toDate(), notification.getId().toString(), now.toDate());
         assertEquals(res, 1);
-        dao.insertClaimedHistory(ownerId, now.toDate(), notification.getUUID().toString());
+        dao.insertClaimedHistory(ownerId, now.toDate(), notification.getId().toString());
 
-        notification = fetchNotification(notification.getUUID().toString());
+        notification = fetchNotification(notification.getId().toString());
         assertEquals(notification.getNotificationKey(), notificationKey);
         validateDate(notification.getEffectiveDate(), effDt);
         assertEquals(notification.getOwner().toString(), ownerId);
-        assertEquals(notification.getProcessingState(), NotificationLifecycleState.IN_PROCESSING);
+        assertEquals(notification.getProcessingState(), PersistentQueueEntryLifecycleState.IN_PROCESSING);
         validateDate(notification.getNextAvailableDate(), nextAvailable);
 
-        dao.clearNotification(notification.getId(), ownerId);
+        dao.clearNotification(notification.getId().toString(), ownerId);
 
-        notification = fetchNotification(notification.getUUID().toString());
+        notification = fetchNotification(notification.getId().toString());
         assertEquals(notification.getNotificationKey(), notificationKey);
         validateDate(notification.getEffectiveDate(), effDt);
         //assertEquals(notification.getOwner(), null);
-        assertEquals(notification.getProcessingState(), NotificationLifecycleState.PROCESSED);
+        assertEquals(notification.getProcessingState(), PersistentQueueEntryLifecycleState.PROCESSED);
         validateDate(notification.getNextAvailableDate(), nextAvailable);
 
     }
@@ -149,19 +148,19 @@ public class TestNotificationSqlDao {
             @Override
             public Notification withHandle(Handle handle) throws Exception {
                 Notification res = handle.createQuery("   select" +
-                        " id " +
-                		", notification_id" +
+                        " record_id " +
+                		", id" +
                 		", notification_key" +
-                		", created_dt" +
+                		", created_date" +
                 		", creating_owner" +
-                		", effective_dt" +
+                		", effective_date" +
                 		", queue_name" +
                 		", processing_owner" +
-                		", processing_available_dt" +
+                		", processing_available_date" +
                 		", processing_state" +
                 		"    from notifications " +
                 		" where " +
-                		" notification_id = '" + notificationId + "';")
+                		" id = '" + notificationId + "';")
                 		.map(new NotificationSqlMapper())
                 		.first();
                 return res;
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
index 86ec0ea..8e9cce4 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/MockNotificationQueue.java
@@ -28,8 +28,8 @@ import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
 import com.ning.billing.config.NotificationConfig;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.notificationq.NotificationLifecycle.NotificationLifecycleState;
 import com.ning.billing.util.notificationq.NotificationQueueService.NotificationQueueHandler;
+import com.ning.billing.util.queue.PersistentQueueEntryLifecycle.PersistentQueueEntryLifecycleState;
 
 public class MockNotificationQueue extends NotificationQueueBase implements NotificationQueue {
     private final TreeSet<Notification> notifications;
@@ -67,7 +67,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
         List<Notification> result = new ArrayList<Notification>();
 
         for (Notification notification : notifications) {
-            if (notification.getProcessingState() == NotificationLifecycleState.AVAILABLE) {
+            if (notification.getProcessingState() == PersistentQueueEntryLifecycleState.AVAILABLE) {
                 result.add(notification);
             }
         }
@@ -96,7 +96,7 @@ public class MockNotificationQueue extends NotificationQueueBase implements Noti
         result = readyNotifications.size();
         for (Notification cur : readyNotifications) {
             handler.handleReadyNotification(cur.getNotificationKey(), cur.getEffectiveDate());
-            DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getUUID(), hostname, hostname, "MockQueue", clock.getUTCNow().plus(config.getDaoClaimTimeMs()), NotificationLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
+            DefaultNotification processedNotification = new DefaultNotification(-1L, cur.getId(), hostname, hostname, "MockQueue", clock.getUTCNow().plus(CLAIM_TIME_MS), PersistentQueueEntryLifecycleState.PROCESSED, cur.getNotificationKey(), cur.getEffectiveDate());
             oldNotifications.add(cur);
             processedNotifications.add(processedNotification);
         }
diff --git a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
index 80f4a5c..50f0a68 100644
--- a/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
+++ b/util/src/test/java/com/ning/billing/util/notificationq/TestNotificationQueue.java
@@ -288,17 +288,9 @@ public class TestNotificationQueue {
                 return false;
             }
             @Override
-            public long getNotificationSleepTimeMs() {
+            public long getSleepTimeMs() {
                 return 10;
             }
-            @Override
-            public int getDaoMaxReadyEvents() {
-                return 1;
-            }
-            @Override
-            public long getDaoClaimTimeMs() {
-                return 60000;
-            }
         };
 
 
@@ -397,17 +389,9 @@ public class TestNotificationQueue {
                 return off;
             }
             @Override
-            public long getNotificationSleepTimeMs() {
+            public long getSleepTimeMs() {
                 return sleepTime;
             }
-            @Override
-            public int getDaoMaxReadyEvents() {
-                return maxReadyEvents;
-            }
-            @Override
-            public long getDaoClaimTimeMs() {
-                return claimTimeMs;
-            }
         };
     }
     
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
index 553bc3c..b64d7ff 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDao.java
@@ -16,11 +16,9 @@
 
 package com.ning.billing.util.tag.dao;
 
-import com.google.inject.Inject;
 import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.Tag;
-import org.joda.time.DateTime;
 import org.skife.jdbi.v2.sqlobject.mixins.Transmogrifier;
 
 import java.util.HashMap;
@@ -31,39 +29,27 @@ import java.util.UUID;
 
 public class MockTagDao implements TagDao {
     private Map<UUID, List<Tag>> tagStore = new HashMap<UUID, List<Tag>>();
-    private final Clock clock;
-
-    @Inject
-    public MockTagDao(Clock clock) {
-        this.clock = clock;
-    }
 
     @Override
-    public void saveTagsFromTransaction(final Transmogrifier dao, final UUID objectId, final String objectType,
+    public void saveEntitiesFromTransaction(final Transmogrifier dao, final UUID objectId, final ObjectType objectType,
                                         final List<Tag> tags, final CallContext context) {
         tagStore.put(objectId, tags);
     }
 
     @Override
-    public void saveTags(UUID objectId, String objectType, List<Tag> tags, CallContext context) {
-        tagStore.put(objectId, tags);
-    }
-
-    @Override
-    public List<Tag> loadTags(UUID objectId, String objectType) {
+    public List<Tag> loadEntities(UUID objectId, ObjectType objectType) {
         return tagStore.get(objectId);
     }
 
     @Override
-    public List<Tag> loadTagsFromTransaction(Transmogrifier dao, UUID objectId, String objectType) {
+    public List<Tag> loadEntitiesFromTransaction(Transmogrifier dao, UUID objectId, ObjectType objectType) {
         return tagStore.get(objectId);
     }
 
     @Override
-    public void addTag(final String tagName, final UUID objectId, final String objectType, final CallContext context) {
+    public void addTag(final String tagName, final UUID objectId, final ObjectType objectType, final CallContext context) {
         Tag tag = new Tag() {
             private UUID id = UUID.randomUUID();
-            private DateTime createdDate = clock.getUTCNow();
 
             @Override
             public String getTagDefinitionName() {
@@ -74,24 +60,13 @@ public class MockTagDao implements TagDao {
             public UUID getId() {
                 return id;
             }
-
-            @Override
-            public String getCreatedBy() {
-                return context.getUserName();
-            }
-
-            @Override
-            public DateTime getCreatedDate() {
-                return createdDate;
-            }
         };
 
-
         tagStore.get(objectId).add(tag);
     }
 
     @Override
-    public void removeTag(String tagName, UUID objectId, String objectType, CallContext context) {
+    public void removeTag(String tagName, UUID objectId, ObjectType objectType, CallContext context) {
         List<Tag> tags = tagStore.get(objectId);
         if (tags != null) {
             Iterator<Tag> tagIterator = tags.iterator();
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java
index adcb848..5b5956b 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/MockTagDefinitionDao.java
@@ -42,7 +42,7 @@ public class MockTagDefinitionDao implements TagDefinitionDao {
     @Override
     public TagDefinition create(final String definitionName, final String description,
                                 final CallContext context) throws TagDefinitionApiException {
-        TagDefinition tag = new DefaultTagDefinition(definitionName, description);
+        TagDefinition tag = new DefaultTagDefinition(definitionName, description, false);
 
         tags.put(definitionName, tag);
         return tag;
diff --git a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
index 0e5041a..c9b40d1 100644
--- a/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
+++ b/util/src/test/java/com/ning/billing/util/tag/TestTagStore.java
@@ -21,12 +21,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import com.ning.billing.account.api.Account;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.callcontext.DefaultCallContextFactory;
 import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.dao.ObjectType;
 import com.ning.billing.util.tag.dao.TagDao;
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
@@ -127,13 +127,13 @@ public class TestTagStore {
     public void testTagCreationAndRetrieval() {
         UUID accountId = UUID.randomUUID();
 
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
         Tag tag = new DescriptiveTag(testTag);
         tagStore.add(tag);
 
-        tagDao.saveTagsFromTransaction(dao, accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
-        List<Tag> savedTags = tagDao.loadTags(accountId, Account.ObjectType);
+        List<Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         assertEquals(savedTags.size(), 1);
 
         Tag savedTag = savedTags.get(0);
@@ -145,19 +145,19 @@ public class TestTagStore {
     @Test(groups="slow")
     public void testControlTagCreation() {
         UUID accountId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
 
         ControlTag tag = new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF);
         tagStore.add(tag);
         assertEquals(tagStore.generateInvoice(), false);
 
         List<Tag> tagList = tagStore.getEntityList();
-        tagDao.saveTagsFromTransaction(dao, accountId, Account.ObjectType, tagList, context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagList, context);
 
         tagStore.clear();
         assertEquals(tagStore.getEntityList().size(), 0);
 
-        tagList = tagDao.loadTags(accountId, Account.ObjectType);
+        tagList = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         tagStore.add(tagList);
         assertEquals(tagList.size(), 1);
 
@@ -167,7 +167,7 @@ public class TestTagStore {
     @Test(groups="slow")
     public void testDescriptiveTagCreation() {
         UUID accountId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
 
         String definitionName = "SomeTestTag";
         TagDefinition tagDefinition = null;
@@ -181,12 +181,12 @@ public class TestTagStore {
         tagStore.add(tag);
         assertEquals(tagStore.generateInvoice(), true);
 
-        tagDao.saveTagsFromTransaction(dao, accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
         tagStore.clear();
         assertEquals(tagStore.getEntityList().size(), 0);
 
-        List<Tag> tagList = tagDao.loadTags(accountId, Account.ObjectType);
+        List<Tag> tagList = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         tagStore.add(tagList);
         assertEquals(tagList.size(), 1);
 
@@ -196,7 +196,7 @@ public class TestTagStore {
     @Test(groups="slow")
     public void testMixedTagCreation() {
         UUID accountId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
 
         String definitionName = "MixedTagTest";
         TagDefinition tagDefinition = null;
@@ -214,12 +214,12 @@ public class TestTagStore {
         tagStore.add(controlTag);
         assertEquals(tagStore.generateInvoice(), false);
 
-        tagDao.saveTagsFromTransaction(dao, accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
         tagStore.clear();
         assertEquals(tagStore.getEntityList().size(), 0);
 
-        List<Tag> tagList = tagDao.loadTags(accountId, Account.ObjectType);
+        List<Tag> tagList = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         tagStore.add(tagList);
         assertEquals(tagList.size(), 2);
 
@@ -229,7 +229,7 @@ public class TestTagStore {
     @Test(groups="slow")
     public void testControlTags() {
         UUID accountId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
         assertEquals(tagStore.generateInvoice(), true);
         assertEquals(tagStore.processPayment(), true);
 
@@ -272,13 +272,13 @@ public class TestTagStore {
         assertNotNull(tagDefinition);
 
         UUID objectId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(objectId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(objectId, ObjectType.ACCOUNT);
         Tag tag = new DescriptiveTag(tagDefinition);
         tagStore.add(tag);
 
-        tagDao.saveTags(objectId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, objectId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
-        List<Tag> tags = tagDao.loadTags(objectId, Account.ObjectType);
+        List<Tag> tags = tagDao.loadEntities(objectId, ObjectType.ACCOUNT);
         assertEquals(tags.size(), 1);
 
         tagDefinitionDao.deleteTagDefinition(definitionName, context);
@@ -297,13 +297,13 @@ public class TestTagStore {
         assertNotNull(tagDefinition);
 
         UUID objectId = UUID.randomUUID();
-        TagStore tagStore = new DefaultTagStore(objectId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(objectId, ObjectType.ACCOUNT);
         Tag tag = new DescriptiveTag(tagDefinition);
         tagStore.add(tag);
 
-        tagDao.saveTags(objectId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, objectId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
-        List<Tag> tags = tagDao.loadTags(objectId, Account.ObjectType);
+        List<Tag> tags = tagDao.loadEntities(objectId, ObjectType.ACCOUNT);
         assertEquals(tags.size(), 1);
 
         try {
@@ -376,13 +376,13 @@ public class TestTagStore {
     public void testTagInsertAudit() {
         UUID accountId = UUID.randomUUID();
 
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
         Tag tag = new DescriptiveTag(testTag);
         tagStore.add(tag);
 
-        tagDao.saveTagsFromTransaction(dao, accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
-        List<Tag> savedTags = tagDao.loadTags(accountId, Account.ObjectType);
+        List<Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         assertEquals(savedTags.size(), 1);
 
         Tag savedTag = savedTags.get(0);
@@ -408,16 +408,16 @@ public class TestTagStore {
     public void testTagDeleteAudit() {
         UUID accountId = UUID.randomUUID();
 
-        TagStore tagStore = new DefaultTagStore(accountId, Account.ObjectType);
+        TagStore tagStore = new DefaultTagStore(accountId, ObjectType.ACCOUNT);
         Tag tag = new DescriptiveTag(testTag);
         tagStore.add(tag);
 
-        tagDao.saveTags(accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
         tagStore.remove(tag);
-        tagDao.saveTags(accountId, Account.ObjectType, tagStore.getEntityList(), context);
+        tagDao.saveEntitiesFromTransaction(dao, accountId, ObjectType.ACCOUNT, tagStore.getEntityList(), context);
 
-        List<Tag> savedTags = tagDao.loadTags(accountId, Account.ObjectType);
+        List<Tag> savedTags = tagDao.loadEntities(accountId, ObjectType.ACCOUNT);
         assertEquals(savedTags.size(), 0);
 
         Handle handle = dbi.open();