killbill-memoizeit

invoice audit

3/31/2012 4:19:59 PM

Changes

Details

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 f5e597c..ff9a41c 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -20,9 +20,9 @@ CREATE TABLE accounts (
     phone varchar(25) DEFAULT NULL,
     migrated bool DEFAULT false,
     created_date datetime NOT NULL,
-    created_by varchar(30) NOT NULL,
+    created_by varchar(50) NOT NULL,
     updated_date datetime DEFAULT NULL,
-    updated_by varchar(30) DEFAULT NULL,
+    updated_by varchar(50) DEFAULT NULL,
     PRIMARY KEY(id)
 ) ENGINE=innodb;
 CREATE UNIQUE INDEX accounts_external_key ON accounts(external_key);
@@ -50,7 +50,7 @@ CREATE TABLE account_history (
     postal_code varchar(11) DEFAULT NULL,
     phone varchar(25) DEFAULT NULL,
     change_type char(6) NOT NULL,
-    updated_by varchar(30) NOT NULL,
+    updated_by varchar(50) NOT NULL,
     date datetime
 ) ENGINE=innodb;
 CREATE INDEX account_id ON account_history(id);
\ No newline at end of file
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 fde6a1a..84cc7eb 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
@@ -264,8 +264,8 @@ public class TestAnalyticsService {
         paymentInfoNotification = new PaymentInfo.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);
-        paymentDao.createPaymentAttempt(paymentAttempt);
-        paymentDao.savePaymentInfo(paymentInfoNotification);
+        paymentDao.createPaymentAttempt(paymentAttempt, context);
+        paymentDao.savePaymentInfo(paymentInfoNotification, context);
         Assert.assertEquals(paymentDao.getPaymentInfo(Arrays.asList(invoice.getId().toString())).size(), 1);
     }
 
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
index 5cdf0de..29f175b 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
@@ -22,7 +22,7 @@ import org.joda.time.DateTime;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.entity.Entity;
 
-public interface InvoicePayment {
+public interface InvoicePayment extends Entity {
     UUID getPaymentAttemptId();
 
     UUID getInvoiceId();
@@ -32,6 +32,4 @@ public interface InvoicePayment {
     BigDecimal getAmount();
 
     Currency getCurrency();
-
-    DateTime getCreatedDate();
 }
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
index 84292c4..9fb0bb3 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePaymentApi.java
@@ -20,6 +20,7 @@ import java.math.BigDecimal;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
@@ -38,10 +39,10 @@ public interface InvoicePaymentApi {
 
     public InvoicePayment getInvoicePayment(UUID paymentAttemptId);
 
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment);
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context);
 
-    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate);
+    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
 
-    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate);
+    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context);
 
 }
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
index 909f3c0..66016df 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceUserApi.java
@@ -33,7 +33,7 @@ public interface InvoiceUserApi {
 
     public Invoice getInvoice(UUID invoiceId);
 
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment);
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context);
 
     public Collection<Invoice> getUnpaidInvoicesByAccountId(UUID accountId, DateTime upToDate);
     
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 3b593fd..9076256 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
@@ -22,32 +22,33 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import com.ning.billing.account.api.Account;
+import com.ning.billing.util.callcontext.CallContext;
 
 public interface PaymentApi {
 
-    Either<PaymentError, Void> updatePaymentGateway(String accountKey);
+    Either<PaymentError, Void> updatePaymentGateway(String accountKey, CallContext context);
 
     Either<PaymentError, PaymentMethodInfo> getPaymentMethod(@Nullable String accountKey, String paymentMethodId);
 
     Either<PaymentError, List<PaymentMethodInfo>> getPaymentMethods(String accountKey);
 
-    Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod);
+    Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context);
 
-    Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo);
+    Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context);
 
-    Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId);
+    Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context);
 
-    List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds);
-    List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds);
-    Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId);
+    List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds, CallContext context);
+    List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds, CallContext context);
+    Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context);
 
-    List<Either<PaymentError, PaymentInfo>> createRefund(Account account, List<String> invoiceIds); //TODO
+    List<Either<PaymentError, PaymentInfo>> createRefund(Account account, List<String> invoiceIds, CallContext context); //TODO
 
     Either<PaymentError, PaymentProviderAccount> getPaymentProviderAccount(String accountKey);
 
-    Either<PaymentError, String> createPaymentProviderAccount(Account account);
+    Either<PaymentError, String> createPaymentProviderAccount(Account account, CallContext context);
 
-    Either<PaymentError, Void> updatePaymentProviderAccountContact(String accountKey);
+    Either<PaymentError, Void> updatePaymentProviderAccountContact(String accountKey, CallContext context);
 
     PaymentAttempt getPaymentAttemptForPaymentId(String id);
 
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 8085310..15ac4ee 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
@@ -59,8 +59,8 @@ public class PaymentAttempt {
         this.paymentAttemptDate = paymentAttemptDate == null ? new DateTime(DateTimeZone.UTC) : paymentAttemptDate;
         this.paymentId = paymentId;
         this.retryCount = retryCount == null ? 0 : retryCount;
-        this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
-        this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
+        this.createdDate = createdDate;
+        this.updatedDate = updatedDate;
     }
 
     public PaymentAttempt(UUID paymentAttemptId,
diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java b/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
index b0fbca6..e325d9a 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentInfo.java
@@ -38,7 +38,7 @@ public class PaymentInfo implements BusEvent {
     private final String paymentMethodId;
     private final String paymentMethod;
     private final String cardType;
-    private final String cardCoutry;
+    private final String cardCountry;
     private final DateTime effectiveDate;
     private final DateTime createdDate;
     private final DateTime updatedDate;
@@ -70,7 +70,7 @@ public class PaymentInfo implements BusEvent {
         this.paymentMethodId = paymentMethodId;
         this.paymentMethod = paymentMethod;
         this.cardType = cardType;
-        this.cardCoutry = cardCountry;
+        this.cardCountry = cardCountry;
         this.effectiveDate = effectiveDate;
         this.createdDate = createdDate == null ? new DateTime(DateTimeZone.UTC) : createdDate;
         this.updatedDate = updatedDate == null ? new DateTime(DateTimeZone.UTC) : updatedDate;
@@ -88,7 +88,7 @@ public class PaymentInfo implements BusEvent {
              src.paymentMethodId,
              src.paymentMethod,
              src.cardType,
-             src.cardCoutry,
+             src.cardCountry,
              src.effectiveDate,
              src.createdDate,
              src.updatedDate);
@@ -131,7 +131,7 @@ public class PaymentInfo implements BusEvent {
     }
 
     public String getCardCountry() {
-        return cardCoutry;
+        return cardCountry;
     }
 
     public String getReferenceId() {
@@ -191,7 +191,7 @@ public class PaymentInfo implements BusEvent {
             this.paymentMethodId = src.paymentMethodId;
             this.paymentMethod = src.paymentMethod;
             this.cardType = src.cardType;
-            this.cardCountry = src.cardCoutry;
+            this.cardCountry = src.cardCountry;
             this.createdDate = src.createdDate;
             this.updatedDate = src.updatedDate;
         }
@@ -303,7 +303,7 @@ public class PaymentInfo implements BusEvent {
                                 paymentMethodId,
                                 paymentMethod,
                                 cardType,
-                                cardCoutry,
+                cardCountry,
                                 effectiveDate,
                                 createdDate,
                                 updatedDate);
@@ -319,7 +319,7 @@ public class PaymentInfo implements BusEvent {
         if (amount != null ? !(amount.compareTo(that.amount) == 0) : that.amount != null) return false;
         if (bankIdentificationNumber != null ? !bankIdentificationNumber.equals(that.bankIdentificationNumber) : that.bankIdentificationNumber != null)
             return false;
-        if (cardCoutry != null ? !cardCoutry.equals(that.cardCoutry) : that.cardCoutry != null) 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)
@@ -342,7 +342,7 @@ public class PaymentInfo implements BusEvent {
 
     @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=" + cardCoutry + ", effectiveDate=" + effectiveDate + ", createdDate=" + createdDate + ", updatedDate=" + updatedDate + "]";
+        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) {
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
index 3a04c3f..11712d2 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
 import com.google.inject.Inject;
@@ -40,8 +41,8 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
      }
 
     @Override
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
-        dao.notifyOfPaymentAttempt(invoicePayment);
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context) {
+        dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
 	@Override
@@ -66,15 +67,15 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
     }
 
     @Override
-    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amount, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate) {
-        InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate, amount, currency, null);
-        dao.notifyOfPaymentAttempt(invoicePayment);
+    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amount, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context) {
+        InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate, amount, currency);
+        dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
-    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate) {
+    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context) {
         InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate);
-        dao.notifyOfPaymentAttempt(invoicePayment);
+        dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 6109ca2..f556778 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -53,8 +53,8 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
     }
 
     @Override
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
-        dao.notifyOfPaymentAttempt(invoicePayment);
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context) {
+        dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
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 c8ddda3..13272c4 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
@@ -17,12 +17,15 @@
 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 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.CustomField;
 import com.ning.billing.util.customfield.dao.CustomFieldSqlDao;
@@ -173,7 +176,14 @@ public class DefaultInvoiceDao implements InvoiceDao {
                     // STEPH Why do we need that? Are the payments not always null at this point?
                     List<InvoicePayment> invoicePayments = invoice.getPayments();
                     InvoicePaymentSqlDao invoicePaymentSqlDao = invoiceDao.become(InvoicePaymentSqlDao.class);
-                    invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments);
+                    invoicePaymentSqlDao.batchCreateFromTransaction(invoicePayments, context);
+
+                    AuditSqlDao auditSqlDao = invoiceDao.become(AuditSqlDao.class);
+                    auditSqlDao.insertAuditFromTransaction("invoices", invoice.getId().toString(), ChangeType.INSERT.toString(), context);
+                    auditSqlDao.insertAuditFromTransaction("recurring_invoice_items", getIdsFromInvoiceItems(recurringInvoiceItems), ChangeType.INSERT.toString(), context);
+                    auditSqlDao.insertAuditFromTransaction("fixed_invoice_items", getIdsFromInvoiceItems(fixedPriceInvoiceItems), ChangeType.INSERT.toString(), context);
+                    auditSqlDao.insertAuditFromTransaction("invoice_payments", getIdsFromInvoicePayments(invoicePayments), ChangeType.INSERT.toString(), context);
+
                 }
 
                 return null;
@@ -192,6 +202,26 @@ public class DefaultInvoiceDao implements InvoiceDao {
         }
     }
 
+    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());
+        }
+
+        return ids;
+    }
+
     @Override
     public List<Invoice> getInvoicesBySubscription(final UUID subscriptionId) {
         return invoiceSqlDao.inTransaction(new Transaction<List<Invoice>, InvoiceSqlDao>() {
@@ -212,8 +242,8 @@ public class DefaultInvoiceDao implements InvoiceDao {
     }
 
     @Override
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
-        invoicePaymentSqlDao.notifyOfPaymentAttempt(invoicePayment);
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context) {
+        invoicePaymentSqlDao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
index 6dc7d9e..2b22c90 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceDao.java
@@ -44,7 +44,7 @@ public interface InvoiceDao extends TaggableDao {
 
     InvoicePayment getInvoicePayment(final UUID paymentAttemptId);
 
-    void notifyOfPaymentAttempt(final InvoicePayment invoicePayment);
+    void notifyOfPaymentAttempt(final InvoicePayment invoicePayment, final CallContext context);
 
     BigDecimal getAccountBalance(final UUID accountId);
 
@@ -52,5 +52,5 @@ public interface InvoiceDao extends TaggableDao {
 
     void test();
 
-	List<Invoice> getAllInvoicesByAccount(UUID accountId);
+	List<Invoice> getAllInvoicesByAccount(final UUID accountId);
 }
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 9c2d10c..eed9680 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
@@ -24,14 +24,14 @@ import java.lang.annotation.Target;
 import java.math.BigDecimal;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Timestamp;
 import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.entity.MapperBase;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
 import org.skife.jdbi.v2.sqlobject.Bind;
@@ -57,33 +57,42 @@ public interface InvoicePaymentSqlDao {
     public List<InvoicePayment> get();
 
     @SqlUpdate
-    public void create(@InvoicePaymentBinder  InvoicePayment invoicePayment);
+    public void create(@InvoicePaymentBinder final InvoicePayment invoicePayment,
+                       @CallContextBinder final CallContext context);
 
     @SqlBatch(transactional=false)
-    void batchCreateFromTransaction(@InvoicePaymentBinder List<InvoicePayment> items);
+    void batchCreateFromTransaction(@InvoicePaymentBinder final List<InvoicePayment> items,
+                                    @CallContextBinder final CallContext context);
 
     @SqlQuery
-    public List<InvoicePayment> getPaymentsForInvoice(@Bind("invoiceId") String invoiceId);
+    public List<InvoicePayment> getPaymentsForInvoice(@Bind("invoiceId") final String invoiceId);
 
     @SqlQuery
-    InvoicePayment getInvoicePayment(@Bind("paymentAttemptId") UUID paymentAttemptId);
+    InvoicePayment getInvoicePayment(@Bind("paymentAttemptId") final UUID paymentAttemptId);
 
     @SqlUpdate
-    void notifyOfPaymentAttempt(@InvoicePaymentBinder InvoicePayment invoicePayment);
+    void notifyOfPaymentAttempt(@InvoicePaymentBinder final InvoicePayment invoicePayment,
+                                @CallContextBinder final CallContext context);
 
     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 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
+                public UUID getId() {
+                    return id;
+                }
+                @Override
                 public UUID getPaymentAttemptId() {
                     return paymentAttemptId;
                 }
@@ -104,6 +113,10 @@ public interface InvoicePaymentSqlDao {
                     return currency;
                 }
                 @Override
+                public String getCreatedBy() {
+                    return createdBy;
+                }
+                @Override
                 public DateTime getCreatedDate() {
                     return createdDate ;
                 }
@@ -121,14 +134,13 @@ public interface InvoicePaymentSqlDao {
                 return new Binder<InvoicePaymentBinder, InvoicePayment>() {
                     @Override
                     public void bind(SQLStatement q, InvoicePaymentBinder bind, InvoicePayment payment) {
+                        q.bind("id", payment.getId().toString());
                         q.bind("invoiceId", payment.getInvoiceId().toString());
                         q.bind("paymentAttemptId", payment.getPaymentAttemptId().toString());
                         q.bind("paymentAttemptDate", payment.getPaymentAttemptDate().toDate());
                         q.bind("amount", payment.getAmount());
                         Currency currency = payment.getCurrency();
                         q.bind("currency", (currency == null) ? null : currency.toString());
-                        DateTime createdDate = payment.getCreatedDate();
-                        q.bind("createdDate", (createdDate == null) ? new DateTime().toDate() : createdDate.toDate());
                     }
                 };
             }
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 a0f518a..22eb5e6 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
@@ -18,47 +18,38 @@ package com.ning.billing.invoice.model;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.util.entity.EntityBase;
 import org.joda.time.DateTime;
 
 import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.util.UUID;
 
-public class DefaultInvoicePayment implements InvoicePayment {
+public class DefaultInvoicePayment extends EntityBase implements InvoicePayment {
     private final UUID paymentAttemptId;
     private final UUID invoiceId;
     private final DateTime paymentDate;
     private final BigDecimal amount;
     private final Currency currency;
-    private final DateTime createdDate;
-
-    public DefaultInvoicePayment(final UUID invoiceId, final DateTime paymentDate) {
-        this(UUID.randomUUID(), invoiceId, paymentDate, null, null, null);
-    }
 
     public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate) {
-        this(paymentAttemptId, invoiceId, paymentDate, null, null, null);
-    }
-
-    public DefaultInvoicePayment(final UUID invoiceId, final DateTime paymentDate,
-                                 final BigDecimal amount, final Currency currency) {
-        this(UUID.randomUUID(), invoiceId, paymentDate, amount, currency, null);
+        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null, null, null);
     }
 
     public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
                                  final BigDecimal amount, final Currency currency) {
-        this(paymentAttemptId, invoiceId, paymentDate, amount, currency, null);
+        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency, null, null);
     }
 
-    public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
+    public DefaultInvoicePayment(final UUID id, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
                                  @Nullable final BigDecimal amount, @Nullable final Currency currency,
-                                 @Nullable final DateTime createdDate) {
+                                 @Nullable final String createdBy, @Nullable final DateTime createdDate) {
+        super(id, createdBy, createdDate);
         this.paymentAttemptId = paymentAttemptId;
         this.amount = amount;
         this.invoiceId = invoiceId;
         this.paymentDate = paymentDate;
         this.currency = currency;
-        this.createdDate = (createdDate == null) ? new DateTime() : createdDate;
     }
 
     @Override
@@ -85,9 +76,4 @@ public class DefaultInvoicePayment implements InvoicePayment {
     public Currency getCurrency() {
         return currency;
     }
-
-    @Override
-    public DateTime getCreatedDate() {
-        return createdDate;
-    }
 }
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 5e1586e..a673b81 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
@@ -1,22 +1,24 @@
 group InvoicePayment;
 
 invoicePaymentFields(prefix) ::= <<
+  <prefix>id,
   <prefix>invoice_id,
   <prefix>payment_attempt_id,
   <prefix>payment_attempt_date,
   <prefix>amount,
   <prefix>currency,
+  <prefix>created_by,
   <prefix>created_date
 >>
 
 create() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :createdDate);
+  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :createdDate);
+  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
 >>
 
 getByPaymentAttemptId() ::= <<
@@ -38,7 +40,7 @@ getPaymentsForInvoice() ::= <<
 
 notifyOfPaymentAttempt() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, NOW());
+  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency, :userName, :createdDate);
 >>
 
 getInvoicePayment() ::= <<
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 28e0c1f..3adb40e 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -13,7 +13,7 @@ CREATE TABLE recurring_invoice_items (
   rate numeric(10,4) NULL,
   currency char(3) NOT NULL,
   reversed_item_id char(36),
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
@@ -32,7 +32,7 @@ CREATE TABLE fixed_invoice_items (
   end_date datetime NOT NULL,
   amount numeric(10,4) NULL,
   currency char(3) NOT NULL,
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
@@ -50,7 +50,7 @@ CREATE TABLE invoices (
   target_date datetime NOT NULL,
   currency char(3) NOT NULL,
   migrated bool NOT NULL,
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
   PRIMARY KEY(invoice_number)
 ) ENGINE=innodb;
@@ -60,11 +60,13 @@ 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)
 ) ENGINE=innodb;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
index 3384274..3a00c1b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import com.ning.billing.util.callcontext.CallContext;
 import org.joda.time.DateTime;
 
 import com.ning.billing.catalog.api.Currency;
@@ -37,7 +38,7 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi
     }
 
     @Override
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context) {
         for (InvoicePayment existingInvoicePayment : invoicePayments) {
             if (existingInvoicePayment.getInvoiceId().equals(invoicePayment.getInvoiceId()) && existingInvoicePayment.getPaymentAttemptId().equals(invoicePayment.getPaymentAttemptId())) {
                 invoicePayments.remove(existingInvoicePayment);
@@ -89,15 +90,15 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi
     }
 
     @Override
-    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate) {
+    public void notifyOfPaymentAttempt(UUID invoiceId, BigDecimal amountOutstanding, Currency currency, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context) {
         InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate, amountOutstanding, currency);
-        notifyOfPaymentAttempt(invoicePayment);
+        notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
-    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate) {
+    public void notifyOfPaymentAttempt(UUID invoiceId, UUID paymentAttemptId, DateTime paymentAttemptDate, CallContext context) {
         InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate);
-        notifyOfPaymentAttempt(invoicePayment);
+        notifyOfPaymentAttempt(invoicePayment, context);
     }
 
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index ff35bcd..ad329bc 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -102,7 +102,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal paymentAmount = new BigDecimal("11.00");
         UUID paymentAttemptId = UUID.randomUUID();
 
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoiceId, clock.getUTCNow().plusDays(12), paymentAmount, Currency.USD));
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoiceId, clock.getUTCNow().plusDays(12), paymentAmount, Currency.USD), context);
 
         Invoice retrievedInvoice = invoiceDao.getById(invoiceId);
         assertNotNull(retrievedInvoice);
@@ -129,7 +129,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal paymentAmount = new BigDecimal("14.0");
 
         invoiceDao.create(invoice, context);
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoice.getId(), paymentAttemptDate, paymentAmount, Currency.USD));
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoice.getId(), paymentAttemptDate, paymentAmount, Currency.USD), context);
 
         invoice = invoiceDao.getById(invoice.getId());
         assertEquals(invoice.getAmountPaid().compareTo(paymentAmount), 0);
@@ -146,7 +146,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime paymentAttemptDate = new DateTime(2011, 6, 24, 12, 14, 36, 0);
 
         invoiceDao.create(invoice, context);
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(invoice.getId(), paymentAttemptDate));
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(UUID.randomUUID(), invoice.getId(), paymentAttemptDate), context);
 
         invoice = invoiceDao.getById(invoice.getId());
         assertEquals(invoice.getLastPaymentAttempt().compareTo(paymentAttemptDate), 0);
@@ -279,8 +279,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         recurringInvoiceItemDao.create(item2, context);
 
         BigDecimal payment1 = new BigDecimal("48.0");
-        InvoicePayment payment = new DefaultInvoicePayment(invoice1.getId(), new DateTime(), payment1, Currency.USD);
-        invoicePaymentDao.create(payment);
+        InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        invoicePaymentDao.create(payment, context);
 
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(rate1.add(rate2).subtract(payment1)), 0);
@@ -319,8 +319,8 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         invoiceDao.create(invoice1, context);
 
         BigDecimal payment1 = new BigDecimal("48.0");
-        InvoicePayment payment = new DefaultInvoicePayment(invoice1.getId(), new DateTime(), payment1, Currency.USD);
-        invoicePaymentDao.create(payment);
+        InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        invoicePaymentDao.create(payment, context);
 
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(BigDecimal.ZERO.subtract(payment1)), 0);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
index 67a4833..dec7697 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockInvoiceDao.java
@@ -153,7 +153,7 @@ public class MockInvoiceDao implements InvoiceDao {
     }
 
     @Override
-    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment) {
+    public void notifyOfPaymentAttempt(InvoicePayment invoicePayment, CallContext context) {
         synchronized (monitor) {
             Invoice invoice = invoices.get(invoicePayment.getInvoiceId());
             if (invoice != null) {
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 e12d963..c014b45 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
@@ -23,6 +23,7 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
+import com.ning.billing.util.callcontext.CallContext;
 import org.apache.commons.lang.StringUtils;
 import org.joda.time.DateTime;
 import org.slf4j.Logger;
@@ -48,6 +49,7 @@ public class DefaultPaymentApi implements PaymentApi {
     private final PaymentDao paymentDao;
     private final PaymentConfig config;
 
+
     private static final Logger log = LoggerFactory.getLogger(DefaultPaymentApi.class);
 
     @Inject
@@ -101,7 +103,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentGateway(String accountKey) {
+    public Either<PaymentError, Void> updatePaymentGateway(String accountKey, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.updatePaymentGateway(accountKey);
     }
@@ -113,31 +115,31 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod) {
+    public Either<PaymentError, String> addPaymentMethod(@Nullable String accountKey, PaymentMethodInfo paymentMethod, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.addPaymentMethod(accountKey, paymentMethod);
     }
 
     @Override
-    public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId) {
+    public Either<PaymentError, Void> deletePaymentMethod(String accountKey, String paymentMethodId, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.deletePaymentMethod(accountKey, paymentMethodId);
     }
 
     @Override
-    public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo) {
+    public Either<PaymentError, PaymentMethodInfo> updatePaymentMethod(String accountKey, PaymentMethodInfo paymentMethodInfo, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(accountKey);
         return plugin.updatePaymentMethod(accountKey, paymentMethodInfo);
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds) {
+    public List<Either<PaymentError, PaymentInfo>> createPayment(String accountKey, List<String> invoiceIds, CallContext context) {
         final Account account = accountUserApi.getAccountByKey(accountKey);
-        return createPayment(account, invoiceIds);
+        return createPayment(account, invoiceIds, context);
     }
 
     @Override
-    public Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId) {
+    public Either<PaymentError, PaymentInfo> createPaymentForPaymentAttempt(UUID paymentAttemptId, CallContext context) {
         PaymentAttempt paymentAttempt = paymentDao.getPaymentAttemptById(paymentAttemptId);
 
         if (paymentAttempt != null) {
@@ -159,8 +161,8 @@ public class DefaultPaymentApi implements PaymentApi {
                                                                          .setPaymentAttemptId(UUID.randomUUID())
                                                                          .build();
 
-                    paymentDao.createPaymentAttempt(newPaymentAttempt);
-                    return processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt);
+                    paymentDao.createPaymentAttempt(newPaymentAttempt, context);
+                    return processPayment(getPaymentProviderPlugin(account), account, invoice, newPaymentAttempt, context);
                 }
             }
         }
@@ -171,7 +173,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds) {
+    public List<Either<PaymentError, PaymentInfo>> createPayment(Account account, List<String> invoiceIds, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
 
         List<Either<PaymentError, PaymentInfo>> processedPaymentsOrErrors = new ArrayList<Either<PaymentError, PaymentInfo>>(invoiceIds.size());
@@ -197,16 +199,17 @@ public class DefaultPaymentApi implements PaymentApi {
             			processedPaymentsOrErrors.add(result);
             }
             else {
-                PaymentAttempt paymentAttempt = paymentDao.createPaymentAttempt(invoice);
+                PaymentAttempt paymentAttempt = paymentDao.createPaymentAttempt(invoice, context);
 
-                processedPaymentsOrErrors.add(processPayment(plugin, account, invoice, paymentAttempt));
+                processedPaymentsOrErrors.add(processPayment(plugin, account, invoice, paymentAttempt, context));
             }
         }
 
         return processedPaymentsOrErrors;
     }
 
-    private Either<PaymentError, PaymentInfo> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice, PaymentAttempt paymentAttempt) {
+    private Either<PaymentError, PaymentInfo> processPayment(PaymentProviderPlugin plugin, Account account, Invoice invoice,
+                                                             PaymentAttempt paymentAttempt, CallContext context) {
         Either<PaymentError, PaymentInfo> paymentOrError = plugin.processInvoice(account, invoice);
         PaymentInfo paymentInfo = null;
 
@@ -218,7 +221,7 @@ public class DefaultPaymentApi implements PaymentApi {
         }
         else {
             paymentInfo = paymentOrError.getRight();
-            paymentDao.savePaymentInfo(paymentInfo);
+            paymentDao.savePaymentInfo(paymentInfo, context);
 
             final String paymentMethodId = paymentInfo.getPaymentMethodId();
             log.debug("Fetching payment method info for payment method id " + ((paymentMethodId == null) ? "null" : paymentMethodId));
@@ -229,18 +232,18 @@ public class DefaultPaymentApi implements PaymentApi {
 
                 if (paymentMethodInfo instanceof CreditCardPaymentMethodInfo) {
                     CreditCardPaymentMethodInfo ccPaymentMethod = (CreditCardPaymentMethodInfo)paymentMethodInfo;
-                    paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getPaymentId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry());
+                    paymentDao.updatePaymentInfo(ccPaymentMethod.getType(), paymentInfo.getPaymentId(), ccPaymentMethod.getCardType(), ccPaymentMethod.getCardCountry(), context);
                 }
                 else if (paymentMethodInfo instanceof PaypalPaymentMethodInfo) {
                     PaypalPaymentMethodInfo paypalPaymentMethodInfo = (PaypalPaymentMethodInfo)paymentMethodInfo;
-                    paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getPaymentId(), null, null);
+                    paymentDao.updatePaymentInfo(paypalPaymentMethodInfo.getType(), paymentInfo.getPaymentId(), null, null, context);
                 }
             } else {
                 log.info(paymentMethodInfoOrError.getLeft().getMessage());
             }
 
             if (paymentInfo.getPaymentId() != null) {
-                paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getPaymentAttemptId(), paymentInfo.getPaymentId());
+                paymentDao.updatePaymentAttemptWithPaymentId(paymentAttempt.getPaymentAttemptId(), paymentInfo.getPaymentId(), context);
             }
         }
 
@@ -249,7 +252,8 @@ public class DefaultPaymentApi implements PaymentApi {
                                                                            paymentAttempt.getPaymentAttemptDate(),
                                                                            paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : paymentInfo.getAmount(),
 //                                                                         paymentInfo.getRefundAmount(), TODO
-                                                                           paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency()));
+                                                                           paymentInfo == null || paymentInfo.getStatus().equalsIgnoreCase("Error") ? null : invoice.getCurrency()),
+                                                                           context);
 
         return paymentOrError;
     }
@@ -286,13 +290,13 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public Either<PaymentError, String> createPaymentProviderAccount(Account account) {
+    public Either<PaymentError, String> createPaymentProviderAccount(Account account, CallContext context) {
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin((Account)null);
         return plugin.createPaymentProviderAccount(account);
     }
 
     @Override
-    public Either<PaymentError, Void> updatePaymentProviderAccountContact(String externalKey) {
+    public Either<PaymentError, Void> updatePaymentProviderAccountContact(String externalKey, CallContext context) {
     	Account account = accountUserApi.getAccountByKey(externalKey);
         final PaymentProviderPlugin plugin = getPaymentProviderPlugin(account);
         return plugin.updatePaymentProviderAccountExistingContact(account);
@@ -304,7 +308,7 @@ public class DefaultPaymentApi implements PaymentApi {
     }
 
     @Override
-    public List<Either<PaymentError, PaymentInfo>> createRefund(Account account, List<String> invoiceIds) {
+    public List<Either<PaymentError, PaymentInfo>> createRefund(Account account, List<String> invoiceIds, CallContext context) {
         //TODO
         throw new UnsupportedOperationException();
     }
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 2184841..ce6adf6 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
@@ -22,22 +22,23 @@ import java.util.UUID;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfo;
+import com.ning.billing.util.callcontext.CallContext;
 
 public interface PaymentDao {
 
-    PaymentAttempt createPaymentAttempt(Invoice invoice);
-    PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt);
+    PaymentAttempt createPaymentAttempt(Invoice invoice, CallContext context);
+    PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt, CallContext context);
 
-    void savePaymentInfo(PaymentInfo right);
+    void savePaymentInfo(PaymentInfo right, CallContext context);
 
     PaymentAttempt getPaymentAttemptForPaymentId(String paymentId);
     List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(List<String> invoiceIds);
 
-    void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId);
+    void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context);
 
     List<PaymentAttempt> getPaymentAttemptsForInvoiceId(String invoiceId);
 
-    void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry);
+    void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context);
 
     List<PaymentInfo> getPaymentInfo(List<String> invoiceIds);
 
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 8994109..245a971 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
@@ -24,6 +24,8 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallContextBinder;
 import com.ning.billing.util.entity.BinderBase;
 import com.ning.billing.util.entity.MapperBase;
 import org.joda.time.DateTime;
@@ -35,6 +37,7 @@ 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.Mapper;
+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;
@@ -47,53 +50,63 @@ import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfo;
 
 @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);
+    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
-    @Mapper(PaymentAttemptMapper.class)
     PaymentAttempt getPaymentAttemptForPaymentId(@Bind("payment_id") String paymentId);
 
     @SqlQuery
-    @Mapper(PaymentAttemptMapper.class)
     PaymentAttempt getPaymentAttemptById(@Bind("payment_attempt_id") String paymentAttemptId);
 
     @SqlQuery
-    @Mapper(PaymentAttemptMapper.class)
     List<PaymentAttempt> getPaymentAttemptsForInvoiceId(@Bind("invoice_id") String invoiceId);
 
     @SqlQuery
-    @Mapper(PaymentAttemptMapper.class)
     List<PaymentAttempt> getPaymentAttemptsForInvoiceIds(@BindIn("invoiceIds") List<String> invoiceIds);
 
     @SqlQuery
-    @Mapper(PaymentInfoMapper.class)
     PaymentInfo getPaymentInfoForPaymentAttemptId(@Bind("payment_attempt_id") String paymentAttemptId);
 
     @SqlUpdate
     void updatePaymentAttemptWithPaymentId(@Bind("payment_attempt_id") String paymentAttemptId,
                                            @Bind("payment_id") String paymentId,
-                                           @Bind("updated_dt") Date updatedDate);
+                                           @CallContextBinder CallContext context);
 
     @SqlUpdate
     void updatePaymentAttemptWithRetryInfo(@Bind("payment_attempt_id") String paymentAttemptId,
                                            @Bind("retry_count") int retryCount,
-                                           @Bind("updated_dt") Date updatedDate);
+                                           @CallContextBinder CallContext context);
 
     @SqlUpdate
     void updatePaymentInfo(@Bind("payment_method") String paymentMethod,
                            @Bind("payment_id") String paymentId,
                            @Bind("card_type") String cardType,
                            @Bind("card_country") String cardCountry,
-                           @Bind("updated_dt") Date updatedDate);
+                           @CallContextBinder CallContext context);
 
     @SqlQuery
-    @Mapper(PaymentInfoMapper.class)
-    List<PaymentInfo> getPaymentInfos(@BindIn("invoiceIds") List<String> invoiceIds);
+    List<PaymentInfo> getPaymentInfos(@BindIn("invoiceIds") final List<String> invoiceIds);
+
+    @SqlUpdate
+    void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) final PaymentInfo paymentInfo,
+                           @CallContextBinder final CallContext context);
 
     @SqlUpdate
-    void insertPaymentInfo(@Bind(binder = PaymentInfoBinder.class) PaymentInfo paymentInfo);
+    void insertPaymentInfoHistory(@Bind("historyRecordId") final String historyRecordId,
+                                  @Bind(binder = PaymentInfoBinder.class) final PaymentInfo paymentInfo,
+                                  @CallContextBinder final CallContext context);
+
+    @SqlQuery
+    PaymentInfo getPaymentInfo(@Bind("paymentId") final String paymentId);
 
     public static final class PaymentAttemptBinder extends BinderBase implements Binder<Bind, PaymentAttempt> {
         @Override
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 d53c236..e8034a1 100644
--- a/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/RequestProcessor.java
@@ -19,6 +19,11 @@ package com.ning.billing.payment;
 import java.util.Arrays;
 import java.util.List;
 
+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 org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,14 +45,17 @@ public class RequestProcessor {
     private final AccountUserApi accountUserApi;
     private final PaymentApi paymentApi;
     private final Bus eventBus;
+    private final Clock clock;
 
     private static final Logger log = LoggerFactory.getLogger(RequestProcessor.class);
 
     @Inject
-    public RequestProcessor(AccountUserApi accountUserApi,
+    public RequestProcessor(Clock clock,
+                            AccountUserApi accountUserApi,
                             PaymentApi paymentApi,
                             PaymentProviderPluginRegistry pluginRegistry,
                             Bus eventBus) {
+        this.clock = clock;
         this.accountUserApi = accountUserApi;
         this.paymentApi = paymentApi;
         this.eventBus = eventBus;
@@ -63,7 +71,8 @@ public class RequestProcessor {
                 log.info("could not process invoice payment: could not find a valid account for event {}", event);
             }
             else {
-                List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()));
+                CallContext context = new DefaultCallContext("PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
+                List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account, Arrays.asList(event.getInvoiceId().toString()), context);
                 if (!results.isEmpty()) {
                     Either<PaymentError, PaymentInfo> result = results.get(0);
                     eventBus.post(result.isLeft() ? result.getLeft() : result.getRight());
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 927df3f..d03b241 100644
--- a/payment/src/main/java/com/ning/billing/payment/RetryService.java
+++ b/payment/src/main/java/com/ning/billing/payment/RetryService.java
@@ -18,6 +18,11 @@ package com.ning.billing.payment;
 
 import java.util.UUID;
 
+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 org.joda.time.DateTime;
 
 import com.google.inject.Inject;
@@ -39,15 +44,18 @@ public class RetryService implements KillbillService {
     public static final String SERVICE_NAME = "retry-service";
     public static final String QUEUE_NAME = "retry-events";
 
+    private final Clock clock;
     private final NotificationQueueService notificationQueueService;
     private final PaymentConfig config;
     private final PaymentApi paymentApi;
     private NotificationQueue retryQueue;
 
     @Inject
-    public RetryService(NotificationQueueService notificationQueueService,
+    public RetryService(Clock clock,
+                        NotificationQueueService notificationQueueService,
                         PaymentConfig config,
                         PaymentApi paymentApi) {
+        this.clock = clock;
         this.notificationQueueService = notificationQueueService;
         this.paymentApi = paymentApi;
         this.config = config;
@@ -63,7 +71,8 @@ public class RetryService implements KillbillService {
         retryQueue = notificationQueueService.createNotificationQueue(SERVICE_NAME, QUEUE_NAME, new NotificationQueueHandler() {
             @Override
             public void handleReadyNotification(String notificationKey, DateTime eventDateTime) {
-                retry(notificationKey);
+                CallContext context = new DefaultCallContext("RetryService", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
+                retry(notificationKey, context);
             }
         },
         config);
@@ -93,7 +102,7 @@ public class RetryService implements KillbillService {
         retryQueue.recordFutureNotification(timeOfRetry, key);
     }
 
-    private void retry(String paymentAttemptId) {
+    private void retry(String paymentAttemptId, CallContext context) {
         PaymentInfo paymentInfo = paymentApi.getPaymentInfoForPaymentAttemptId(paymentAttemptId);
 
         if (paymentInfo != null && PaymentStatus.Processed.equals(PaymentStatus.valueOf(paymentInfo.getStatus()))) {
@@ -102,7 +111,7 @@ public class RetryService implements KillbillService {
         }
         else {
             System.out.println("Creating payment for payment attempt " + paymentAttemptId);
-            paymentApi.createPaymentForPaymentAttempt(UUID.fromString(paymentAttemptId));
+            paymentApi.createPaymentForPaymentAttempt(UUID.fromString(paymentAttemptId), context);
         }
     }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
index d3d9320..0c769fd 100644
--- a/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
+++ b/payment/src/main/java/com/ning/billing/payment/setup/PaymentModule.java
@@ -26,7 +26,7 @@ import com.ning.billing.payment.RetryService;
 import com.ning.billing.payment.api.DefaultPaymentApi;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentService;
-import com.ning.billing.payment.dao.DefaultPaymentDao;
+import com.ning.billing.payment.dao.AuditedPaymentDao;
 import com.ning.billing.payment.dao.PaymentDao;
 import com.ning.billing.payment.provider.PaymentProviderPluginRegistry;
 
@@ -42,7 +42,7 @@ public class PaymentModule extends AbstractModule {
     }
 
     protected void installPaymentDao() {
-        bind(PaymentDao.class).to(DefaultPaymentDao.class).asEagerSingleton();
+        bind(PaymentDao.class).to(AuditedPaymentDao.class).asEagerSingleton();
     }
 
     protected void installPaymentProviderPlugins(PaymentConfig config) {
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 55c3efa..87c8d8f 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
@@ -10,7 +10,9 @@ paymentAttemptFields(prefix) ::= <<
     <prefix>payment_attempt_dt,
     <prefix>invoice_dt,
     <prefix>retry_count,
+    <prefix>created_by,
     <prefix>created_dt,
+    <prefix>updated_by,
     <prefix>updated_dt
 >>
 
@@ -28,13 +30,22 @@ paymentInfoFields(prefix) ::= <<
     <prefix>card_type,
     <prefix>card_country,
     <prefix>effective_dt,
+    <prefix>created_by,
     <prefix>created_dt,
+    <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, :created_dt, :updated_dt);
+    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() ::= <<
@@ -64,13 +75,23 @@ getPaymentAttemptsForInvoiceId() ::= <<
 updatePaymentAttemptWithPaymentId() ::= <<
     UPDATE payment_attempts
        SET payment_id = :payment_id,
-           updated_dt = :updated_dt
+           updated_by = :userName,
+           updated_dt = :updatedDate
      WHERE payment_attempt_id = :payment_attempt_id
 >>
 
 insertPaymentInfo() ::= <<
     INSERT INTO payments (<paymentInfoFields()>)
-    VALUES (: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, :created_dt, :updated_dt);
+    VALUES (: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);
+>>
+
+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);
 >>
 
 updatePaymentInfo() ::= <<
@@ -78,7 +99,8 @@ updatePaymentInfo() ::= <<
        SET payment_method = :payment_method,
            card_type = :card_type,
            card_country = :card_country,
-           updated_dt = :updated_dt
+           updated_by = :userName,
+           updated_dt = :updatedDate
      WHERE payment_id = :payment_id
 >>
 
@@ -95,3 +117,9 @@ getPaymentInfoForPaymentAttemptId() ::= <<
      WHERE pa.payment_attempt_id = :payment_attempt_id
        AND pa.payment_id = p.payment_id
 >>
+
+getPaymentInfo() ::= <<
+    SELECT <paymentInfoFields()>
+    FROM payments
+    WHERE payment_id = :paymentId
+>>
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 3d0cc1a..3a344f9 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -9,11 +9,32 @@ CREATE TABLE payment_attempts (
       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)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
+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)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
 DROP TABLE IF EXISTS payments; 
 CREATE TABLE payments (
       payment_id varchar(36) COLLATE utf8_bin NOT NULL,
@@ -29,7 +50,32 @@ CREATE TABLE payments (
       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)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+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)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
index b9f761a..7c005ee 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestMockPaymentApi.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.payment.api;
 
+import com.google.inject.Inject;
+import com.ning.billing.util.clock.Clock;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -26,5 +28,8 @@ import com.ning.billing.payment.setup.PaymentTestModuleWithMocks;
 @Guice(modules = { PaymentTestModuleWithMocks.class, AccountModuleWithMocks.class, InvoiceModuleWithMocks.class })
 @Test(groups = "fast")
 public class TestMockPaymentApi extends TestPaymentApi {
-
+    @Inject
+    public TestMockPaymentApi(Clock clock) {
+        super(clock);
+    }
 }
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 9225a60..ad0bd03 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
@@ -26,6 +26,11 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+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 org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
@@ -53,6 +58,13 @@ public abstract class TestPaymentApi {
     @Inject
     protected TestHelper testHelper;
 
+    protected CallContext context;
+
+    @Inject
+    public TestPaymentApi(Clock clock) {
+        context = new DefaultCallContext("Payment Tests", CallOrigin.INTERNAL, UserType.SYSTEM, clock);
+    }
+
     @BeforeMethod(alwaysRun = true)
     public void setUp() throws EventBusException {
         eventBus.start();
@@ -80,7 +92,7 @@ public abstract class TestPaymentApi {
                                                        new BigDecimal("1.0"),
                                                        Currency.USD));
 
-        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()));
+        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
 
         assertEquals(results.size(), 1);
         assertTrue(results.get(0).isRight());
@@ -125,7 +137,7 @@ public abstract class TestPaymentApi {
 
     private PaymentProviderAccount setupAccountWithPaypalPaymentMethod() throws AccountApiException, EntityPersistenceException {
         final Account account = testHelper.createTestPayPalAccount();
-        paymentApi.createPaymentProviderAccount(account);
+        paymentApi.createPaymentProviderAccount(account, context);
 
         String accountKey = account.getExternalKey();
 
@@ -134,7 +146,7 @@ public abstract class TestPaymentApi {
                                                                            .setEmail(account.getEmail())
                                                                            .setDefaultMethod(true)
                                                                            .build();
-        Either<PaymentError, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod);
+        Either<PaymentError, String> paymentMethodIdOrError = paymentApi.addPaymentMethod(accountKey, paymentMethod, context);
 
         assertTrue(paymentMethodIdOrError.isRight());
         assertNotNull(paymentMethodIdOrError.getRight());
@@ -161,7 +173,7 @@ public abstract class TestPaymentApi {
     @Test(enabled=true)
     public void testUpdatePaymentProviderAccountContact() throws AccountApiException, EntityPersistenceException {
         final Account account = testHelper.createTestPayPalAccount();
-        paymentApi.createPaymentProviderAccount(account);
+        paymentApi.createPaymentProviderAccount(account, context);
 
         String newName = "Tester " + RandomStringUtils.randomAlphanumeric(10);
         String newNumber = "888-888-" + RandomStringUtils.randomNumeric(4);
@@ -176,7 +188,7 @@ public abstract class TestPaymentApi {
                                                                   .billingCycleDay(account.getBillCycleDay())
                                                                   .build();
 
-        Either<PaymentError, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey());
+        Either<PaymentError, Void> voidOrError = paymentApi.updatePaymentProviderAccountContact(accountToUpdate.getExternalKey(), context);
         assertTrue(voidOrError.isRight());
     }
 
@@ -184,7 +196,7 @@ public abstract class TestPaymentApi {
     public void testCannotDeleteDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
         PaymentProviderAccount account = setupAccountWithPaypalPaymentMethod();
 
-        Either<PaymentError, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId());
+        Either<PaymentError, Void> errorOrVoid = paymentApi.deletePaymentMethod(account.getAccountKey(), account.getDefaultPaymentMethodId(), context);
 
         assertTrue(errorOrVoid.isLeft());
     }
@@ -192,19 +204,19 @@ public abstract class TestPaymentApi {
     @Test(enabled=true)
     public void testDeleteNonDefaultPaymentMethod() throws AccountApiException, EntityPersistenceException {
         final Account account = testHelper.createTestPayPalAccount();
-        paymentApi.createPaymentProviderAccount(account);
+        paymentApi.createPaymentProviderAccount(account, context);
 
         String accountKey = account.getExternalKey();
 
         PaypalPaymentMethodInfo paymentMethod1 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(false).setBaid("12345").setEmail(account.getEmail()).build();
-        Either<PaymentError, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1);
+        Either<PaymentError, String> paymentMethodIdOrError1 = paymentApi.addPaymentMethod(accountKey, paymentMethod1, context);
 
         assertTrue(paymentMethodIdOrError1.isRight());
         assertNotNull(paymentMethodIdOrError1.getRight());
 
         PaypalPaymentMethodInfo paymentMethod2 = new PaypalPaymentMethodInfo.Builder().setDefaultMethod(true).setBaid("12345").setEmail(account.getEmail()).build();
 
-        Either<PaymentError, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2);
+        Either<PaymentError, String> paymentMethodIdOrError2 = paymentApi.addPaymentMethod(accountKey, paymentMethod2, context);
 
         assertTrue(paymentMethodIdOrError2.isRight());
         assertNotNull(paymentMethodIdOrError2.getRight());
@@ -213,8 +225,8 @@ public abstract class TestPaymentApi {
 
         assertTrue(paymentMethodsOrError.isRight());
 
-        Either<PaymentError, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight());
-        Either<PaymentError, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight());
+        Either<PaymentError, Void> errorOrVoid1 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError1.getRight(), context);
+        Either<PaymentError, Void> errorOrVoid2 = paymentApi.deletePaymentMethod(accountKey, paymentMethodIdOrError2.getRight(), context);
 
         assertTrue(errorOrVoid1.isRight());
         assertTrue(errorOrVoid2.isLeft());
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 c1ba1db..7c8239f 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,9 +23,8 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
+import com.ning.billing.util.callcontext.CallContext;
 import org.apache.commons.collections.CollectionUtils;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
@@ -48,25 +47,35 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public PaymentAttempt createPaymentAttempt(Invoice invoice) {
-        PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
-        paymentAttempts.put(paymentAttempt.getPaymentAttemptId(), paymentAttempt);
-        return paymentAttempt;
+    public PaymentAttempt createPaymentAttempt(Invoice invoice, CallContext context) {
+        PaymentAttempt updatedPaymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice.getId(), invoice.getAccountId(),
+                invoice.getBalance(), invoice.getCurrency(), invoice.getInvoiceDate(),
+                null, null, null, context.getCreatedDate(), context.getUpdatedDate());
+
+        paymentAttempts.put(updatedPaymentAttempt.getPaymentAttemptId(), updatedPaymentAttempt);
+        return updatedPaymentAttempt;
     }
 
     @Override
-    public PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt) {
-        paymentAttempts.put(paymentAttempt.getPaymentAttemptId(), paymentAttempt);
-        return paymentAttempt;
+    public PaymentAttempt createPaymentAttempt(PaymentAttempt paymentAttempt, CallContext context) {
+        PaymentAttempt updatedPaymentAttempt = new PaymentAttempt(paymentAttempt.getPaymentAttemptId(),
+                paymentAttempt.getInvoiceId(),
+                paymentAttempt.getAccountId(), paymentAttempt.getAmount(), paymentAttempt.getCurrency(),
+                paymentAttempt.getInvoiceDate(), paymentAttempt.getPaymentAttemptDate(),
+                paymentAttempt.getPaymentId(), paymentAttempt.getRetryCount(),
+                context.getCreatedDate(), context.getUpdatedDate());
+
+        paymentAttempts.put(updatedPaymentAttempt.getPaymentAttemptId(), updatedPaymentAttempt);
+        return updatedPaymentAttempt;
     }
 
     @Override
-    public void savePaymentInfo(PaymentInfo paymentInfo) {
+    public void savePaymentInfo(PaymentInfo paymentInfo, CallContext context) {
         payments.put(paymentInfo.getPaymentId(), paymentInfo);
     }
 
     @Override
-    public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId) {
+    public void updatePaymentAttemptWithPaymentId(UUID paymentAttemptId, String paymentId, CallContext context) {
         PaymentAttempt existingPaymentAttempt = paymentAttempts.get(paymentAttemptId);
 
         if (existingPaymentAttempt != null) {
@@ -87,15 +96,14 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry) {
+    public void updatePaymentInfo(String paymentMethodType, String paymentId, String cardType, String cardCountry, CallContext context) {
         PaymentInfo existingPayment = payments.get(paymentId);
         if (existingPayment != null) {
             PaymentInfo payment = existingPayment.cloner()
                     .setPaymentMethod(paymentMethodType)
                     .setCardType(cardType)
                     .setCardCountry(cardCountry)
-                    // TODO pass the clock?
-                    .setUpdatedDate(new DateTime(DateTimeZone.UTC))
+                    .setUpdatedDate(context.getUpdatedDate())
                     .build();
             payments.put(paymentId, payment);
         }
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 a97786d..472fc2f 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,8 +21,14 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+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;
 import org.testng.annotations.Test;
 
@@ -32,8 +38,8 @@ import com.ning.billing.payment.api.PaymentAttempt;
 import com.ning.billing.payment.api.PaymentInfo;
 
 public abstract class TestPaymentDao {
-
     protected PaymentDao paymentDao;
+    protected CallContext context = new TestCallContext("PaymentTests");
 
     @Test
     public void testCreatePayment() {
@@ -45,16 +51,14 @@ public abstract class TestPaymentDao {
                 .setPaymentMethodId("12345")
                 .setReferenceId("12345")
                 .setType("Electronic")
-                .setCreatedDate(new DateTime(DateTimeZone.UTC))
-                .setUpdatedDate(new DateTime(DateTimeZone.UTC))
-                .setEffectiveDate(new DateTime(DateTimeZone.UTC))
+                .setEffectiveDate(new DefaultClock().getUTCNow())
                 .build();
 
-        paymentDao.savePaymentInfo(paymentInfo);
+        paymentDao.savePaymentInfo(paymentInfo, context);
     }
 
     @Test
-    public void testUpdatePaymenInfo() {
+    public void testUpdatePaymentInfo() {
         PaymentInfo paymentInfo = new PaymentInfo.Builder().setPaymentId(UUID.randomUUID().toString())
                 .setAmount(BigDecimal.TEN)
                 .setStatus("Processed")
@@ -63,14 +67,14 @@ public abstract class TestPaymentDao {
                 .setPaymentMethodId("12345")
                 .setReferenceId("12345")
                 .setType("Electronic")
-                .setCreatedDate(new DateTime(DateTimeZone.UTC))
-                .setUpdatedDate(new DateTime(DateTimeZone.UTC))
-                .setEffectiveDate(new DateTime(DateTimeZone.UTC))
+                .setCreatedDate(new DefaultClock().getUTCNow())
+                .setUpdatedDate(new DefaultClock().getUTCNow())
+                .setEffectiveDate(new DefaultClock().getUTCNow())
                 .build();
 
-        paymentDao.savePaymentInfo(paymentInfo);
-
-        paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US");
+        CallContext context = new TestCallContext("PaymentTests");
+        paymentDao.savePaymentInfo(paymentInfo, context);
+        paymentDao.updatePaymentInfo("CreditCard", paymentInfo.getPaymentId(), "Visa", "US", context);
     }
 
     @Test
@@ -81,12 +85,10 @@ public abstract class TestPaymentDao {
                 .setAccountId(UUID.randomUUID())
                 .setAmount(BigDecimal.TEN)
                 .setCurrency(Currency.USD)
-                .setInvoiceDate(new DateTime(DateTimeZone.UTC))
-                .setCreatedDate(new DateTime(DateTimeZone.UTC))
-                .setUpdatedDate(new DateTime(DateTimeZone.UTC))
+                .setInvoiceDate(context.getCreatedDate())
                 .build();
 
-        paymentDao.createPaymentAttempt(paymentAttempt);
+        paymentDao.createPaymentAttempt(paymentAttempt, context);
     }
 
     @Test
@@ -98,11 +100,11 @@ public abstract class TestPaymentDao {
         final BigDecimal invoiceAmount = BigDecimal.TEN;
 
         // Move the clock backwards to test the updated_date field (see below)
-        final DateTime now = new DateTime(DateTimeZone.UTC).minusDays(1);
-
-        PaymentAttempt originalPaymenAttempt = new PaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, now, now, paymentId, 0);
+        ClockMock clock = new ClockMock();
+        CallContext thisContext = new DefaultCallContext("Payment Tests", CallOrigin.TEST, UserType.TEST, clock);
 
-        PaymentAttempt attempt = paymentDao.createPaymentAttempt(originalPaymenAttempt);
+        PaymentAttempt originalPaymentAttempt = new PaymentAttempt(paymentAttemptId, invoiceId, accountId, invoiceAmount, Currency.USD, clock.getUTCNow(), clock.getUTCNow(), paymentId, 0);
+        PaymentAttempt attempt = paymentDao.createPaymentAttempt(originalPaymentAttempt, thisContext);
 
         List<PaymentAttempt> attemptsFromGet = paymentDao.getPaymentAttemptsForInvoiceId(invoiceId.toString());
 
@@ -124,18 +126,19 @@ public abstract class TestPaymentDao {
                 .setPaymentMethodId("12345")
                 .setReferenceId("12345")
                 .setType("Electronic")
-                .setCreatedDate(now)
-                .setUpdatedDate(now)
-                .setEffectiveDate(now)
+                .setCreatedDate(clock.getUTCNow())
+                .setUpdatedDate(clock.getUTCNow())
+                .setEffectiveDate(clock.getUTCNow())
                 .build();
 
-        paymentDao.savePaymentInfo(originalPaymentInfo);
+        paymentDao.savePaymentInfo(originalPaymentInfo, thisContext);
         PaymentInfo paymentInfo = paymentDao.getPaymentInfo(Arrays.asList(invoiceId.toString())).get(0);
         Assert.assertEquals(paymentInfo, originalPaymentInfo);
 
-        paymentDao.updatePaymentInfo(originalPaymentInfo.getPaymentMethod(), originalPaymentInfo.getPaymentId(), originalPaymentInfo.getCardType(), originalPaymentInfo.getCardCountry());
+        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().getMillis() / 1000, originalPaymentInfo.getCreatedDate().getMillis() / 1000);
+        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/dao/TestPaymentDaoWithEmbeddedDb.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
index a5da11b..84e3e5a 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithEmbeddedDb.java
@@ -18,7 +18,6 @@ package com.ning.billing.payment.dao;
 
 import java.io.IOException;
 
-import com.ning.billing.util.clock.DefaultClock;
 import org.apache.commons.io.IOUtils;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -31,7 +30,7 @@ import com.ning.billing.dbi.MysqlTestingHelper;
 public class TestPaymentDaoWithEmbeddedDb extends TestPaymentDao {
     private final MysqlTestingHelper helper = new MysqlTestingHelper();
 
-    @BeforeClass(alwaysRun = true)
+    @BeforeClass(groups = { "slow", "database" })
     public void startMysql() throws IOException {
         final String paymentddl = IOUtils.toString(MysqlTestingHelper.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
 
@@ -39,13 +38,13 @@ public class TestPaymentDaoWithEmbeddedDb extends TestPaymentDao {
         helper.initDb(paymentddl);
     }
 
-    @AfterClass(alwaysRun = true)
+    @AfterClass(groups = { "slow", "database" })
     public void stopMysql() {
         helper.stopMysql();
     }
 
-    @BeforeMethod(alwaysRun = true)
+    @BeforeMethod(groups = { "slow", "database" })
     public void setUp() throws IOException {
-        paymentDao = new DefaultPaymentDao(helper.getDBI(), new DefaultClock());
+        paymentDao = new AuditedPaymentDao(helper.getDBI());
     }
 }
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
index 6e31f90..d540955 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDaoWithMock.java
@@ -23,7 +23,7 @@ import org.testng.annotations.Test;
 
 @Test(groups = { "fast" })
 public class TestPaymentDaoWithMock extends TestPaymentDao {
-    @BeforeMethod(alwaysRun = true)
+    @BeforeMethod(groups = { "fast" })
     public void setUp() throws IOException {
         paymentDao = new MockPaymentDao();
     }
diff --git a/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java b/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
index e38f14f..80bdd82 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestNotifyInvoicePaymentApi.java
@@ -20,6 +20,8 @@ import static org.testng.Assert.assertNotNull;
 
 import java.util.UUID;
 
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.TestCallContext;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -51,6 +53,8 @@ public class TestNotifyInvoicePaymentApi {
     @Inject
     private TestHelper testHelper;
 
+    private CallContext context = new TestCallContext("Payment Api Tests");
+
     @BeforeMethod(alwaysRun = true)
     public void setUp() throws EventBusException {
         eventBus.start();
@@ -74,7 +78,8 @@ public class TestNotifyInvoicePaymentApi {
                                      invoice.getBalance(),
                                      invoice.getCurrency(),
                                      paymentAttempt.getPaymentAttemptId(),
-                                     paymentAttempt.getPaymentAttemptDate());
+                                     paymentAttempt.getPaymentAttemptDate(),
+                                     context);
 
         InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getPaymentAttemptId());
 
@@ -89,7 +94,8 @@ public class TestNotifyInvoicePaymentApi {
         PaymentAttempt paymentAttempt = new PaymentAttempt(UUID.randomUUID(), invoice);
         invoicePaymentApi.notifyOfPaymentAttempt(invoice.getId(),
                                                  paymentAttempt.getPaymentAttemptId(),
-                                                 paymentAttempt.getPaymentAttemptDate());
+                                                 paymentAttempt.getPaymentAttemptDate(),
+                                                 context);
 
         InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(paymentAttempt.getPaymentAttemptId());
 
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 f8278f8..1379267 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,10 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+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;
@@ -83,6 +87,7 @@ public class TestRetryService {
 
     private MockPaymentProviderPlugin mockPaymentProviderPlugin;
     private MockNotificationQueue mockNotificationQueue;
+    private CallContext context;
 
     @BeforeClass(alwaysRun = true)
     public void initialize() throws Exception {
@@ -96,6 +101,7 @@ public class TestRetryService {
 
         mockPaymentProviderPlugin = (MockPaymentProviderPlugin)registry.getPlugin(null);
         mockNotificationQueue = (MockNotificationQueue)notificationQueueService.getNotificationQueue(RetryService.SERVICE_NAME, RetryService.QUEUE_NAME);
+        context = new DefaultCallContext("RetryServiceTests", CallOrigin.INTERNAL, UserType.TEST, clock);
     }
 
     @AfterMethod(alwaysRun = true)
@@ -125,7 +131,7 @@ public class TestRetryService {
 
         mockPaymentProviderPlugin.makeNextInvoiceFail();
 
-        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()));
+        List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()), context);
 
         assertEquals(results.size(), 1);
         assertTrue(results.get(0).isLeft());
@@ -171,7 +177,7 @@ public class TestRetryService {
                                                                                       .setPaymentAttemptDate(now)
                                                                                       .build();
 
-        paymentDao.createPaymentAttempt(paymentAttempt);
+        paymentDao.createPaymentAttempt(paymentAttempt, context);
         retryService.scheduleRetry(paymentAttempt, nextRetryDate);
         ((ClockMock)clock).setDeltaFromReality(Days.days(numberOfDays).toStandardSeconds().getSeconds() * 1000);
         Thread.sleep(2000);
diff --git a/util/src/main/java/com/ning/billing/util/audit/dao/AuditSqlDao.java b/util/src/main/java/com/ning/billing/util/audit/dao/AuditSqlDao.java
index 9a45533..f3f96f4 100644
--- a/util/src/main/java/com/ning/billing/util/audit/dao/AuditSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/audit/dao/AuditSqlDao.java
@@ -19,9 +19,12 @@ package com.ning.billing.util.audit.dao;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
 import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlBatch;
 import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 
+import java.util.List;
+
 @ExternalizedSqlViaStringTemplate3
 public interface AuditSqlDao {
     @SqlUpdate
@@ -29,4 +32,10 @@ public interface AuditSqlDao {
                                            @Bind("recordId") final String recordId,
                                            @Bind("changeType") String changeType,
                                            @CallContextBinder CallContext context);
+
+    @SqlBatch(transactional = false)
+    public void insertAuditFromTransaction(@Bind("tableName") final String tableName,
+                                           @Bind("recordId") final List<String> recordIds,
+                                           @Bind("changeType") String changeType,
+                                           @CallContextBinder CallContext context);
 }
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 7cf98f2..17442c1 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -5,9 +5,9 @@ CREATE TABLE custom_fields (
   object_type varchar(30) NOT NULL,
   field_name varchar(30) NOT NULL,
   field_value varchar(255),
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
-  updated_by varchar(30) DEFAULT NULL,
+  updated_by varchar(50) DEFAULT NULL,
   updated_date datetime DEFAULT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
@@ -22,7 +22,7 @@ CREATE TABLE custom_field_history (
   object_type varchar(30) NOT NULL,
   field_name varchar(30),
   field_value varchar(255),
-  updated_by varchar(30) NOT NULL,
+  updated_by varchar(50) NOT NULL,
   date datetime NOT NULL,
   change_type char(6) NOT NULL
 ) ENGINE=innodb;
@@ -34,7 +34,7 @@ CREATE TABLE tag_definitions (
   id char(36) NOT NULL,
   name varchar(20) NOT NULL,
   description varchar(200) NOT NULL,
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
@@ -47,7 +47,7 @@ CREATE TABLE tag_definition_history (
   created_by varchar(50),
   description varchar(200),
   change_type char(6) NOT NULL,
-  updated_by varchar(30) NOT NULL,
+  updated_by varchar(50) NOT NULL,
   date datetime NOT NULL
 ) ENGINE=innodb;
 CREATE INDEX tag_definition_history_id ON tag_definition_history(id);
@@ -59,7 +59,7 @@ CREATE TABLE tags (
   tag_definition_name varchar(20) NOT NULL,
   object_id char(36) NOT NULL,
   object_type varchar(30) NOT NULL,
-  created_by varchar(30) NOT NULL,
+  created_by varchar(50) NOT NULL,
   created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE = innodb;
@@ -73,7 +73,7 @@ CREATE TABLE tag_history (
   object_id char(36) NOT NULL,
   object_type varchar(30) NOT NULL,
   change_type char(6) NOT NULL,
-  updated_by varchar(30) NOT NULL,
+  updated_by varchar(50) NOT NULL,
   date datetime NOT NULL
 ) ENGINE = innodb;
 CREATE INDEX tag_history_by_object ON tags(object_id);
diff --git a/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java b/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.java
new file mode 100644
index 0000000..b632f2e
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/callcontext/TestCallContext.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.util.callcontext;
+
+import com.ning.billing.util.clock.DefaultClock;
+import org.joda.time.DateTime;
+
+public class TestCallContext implements CallContext {
+    private final String userName;
+    private final DateTime updatedDate;
+    private final DateTime createdDate;
+
+    public TestCallContext(String userName) {
+        this.userName = userName;
+        DateTime now = new DefaultClock().getUTCNow();
+        this.updatedDate = now;
+        this.createdDate = now;
+    }
+
+    public TestCallContext(String userName, DateTime createdDate, DateTime updatedDate) {
+        this.userName = userName;
+        this.createdDate = createdDate;
+        this.updatedDate = updatedDate;
+    }
+
+    @Override
+    public String getUserName() {
+        return userName;
+    }
+
+    @Override
+    public CallOrigin getCallOrigin() {
+        return CallOrigin.TEST;
+    }
+
+    @Override
+    public UserType getUserType() {
+        return UserType.TEST;
+    }
+
+    @Override
+    public DateTime getCreatedDate() {
+        return createdDate;
+    }
+
+    @Override
+    public DateTime getUpdatedDate() {
+        return updatedDate;
+    }
+}