killbill-memoizeit

Closes #4

9/25/2013 7:12:50 PM

Details

diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
index e4f6d82..b7d1296 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
@@ -432,18 +432,18 @@ public class PaymentProcessor extends ProcessorBase {
         final PaymentStatus paymentStatus = PaymentStatus.AUTO_PAY_OFF;
 
         final PaymentModelDao paymentInfo = new PaymentModelDao(account.getId(), invoice.getId(), paymentMethodId, requestedAmount, invoice.getCurrency(), clock.getUTCNow(), paymentStatus);
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), paymentStatus, clock.getUTCNow(), requestedAmount);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), paymentMethodId, paymentStatus, clock.getUTCNow(), requestedAmount);
 
-        paymentDao.insertPaymentWithAttempt(paymentInfo, attempt, context);
+        paymentDao.insertPaymentWithFirstAttempt(paymentInfo, attempt, context);
         return fromPaymentModelDao(paymentInfo, null, context);
     }
 
     private Payment processNewPaymentWithAccountLocked(final UUID paymentMethodId, final PaymentPluginApi plugin, final Account account, final Invoice invoice,
                                                        final BigDecimal requestedAmount, final boolean isInstantPayment, final InternalCallContext context) throws PaymentApiException {
         final PaymentModelDao payment = new PaymentModelDao(account.getId(), invoice.getId(), paymentMethodId, requestedAmount.setScale(2, RoundingMode.HALF_UP), invoice.getCurrency(), clock.getUTCNow());
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow(), requestedAmount);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), paymentMethodId, clock.getUTCNow(), requestedAmount);
 
-        final PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, context);
+        final PaymentModelDao savedPayment = paymentDao.insertPaymentWithFirstAttempt(payment, attempt, context);
         return processPaymentWithAccountLocked(plugin, account, invoice, savedPayment, attempt, isInstantPayment, context);
     }
 
@@ -464,9 +464,9 @@ public class PaymentProcessor extends ProcessorBase {
             default:
                 throw new IllegalStateException("Unexpected payment status for retry " + payment.getPaymentStatus());
         }
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow(), requestedAmount);
-        paymentDao.insertNewAttemptForPayment(payment.getId(), attempt, context);
-        paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(payment.getId(), paymentStatus, clock.getUTCNow(), attempt.getId(), null, terminalStateReason, context);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), account.getPaymentMethodId(), clock.getUTCNow(), requestedAmount);
+        paymentDao.updatePaymentWithNewAttempt(payment.getId(), attempt, context);
+        paymentDao.updatePaymentAndAttemptOnCompletion(payment.getId(), paymentStatus, attempt.getId(), null, terminalStateReason, context);
 
         final List<PaymentAttemptModelDao> allAttempts = paymentDao.getAttemptsForPayment(payment.getId(), context);
         return new DefaultPayment(payment, null, allAttempts, Collections.<RefundModelDao>emptyList());
@@ -475,8 +475,8 @@ public class PaymentProcessor extends ProcessorBase {
 
     private Payment processRetryPaymentWithAccountLocked(final PaymentPluginApi plugin, final Account account, final Invoice invoice, final PaymentModelDao payment,
                                                          final BigDecimal requestedAmount, final InternalCallContext context) throws PaymentApiException {
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), clock.getUTCNow(), requestedAmount);
-        paymentDao.insertNewAttemptForPayment(payment.getId(), attempt, context);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), payment.getId(), account.getPaymentMethodId(), clock.getUTCNow(), requestedAmount);
+        paymentDao.updatePaymentWithNewAttempt(payment.getId(), attempt, context);
         return processPaymentWithAccountLocked(plugin, account, invoice, payment, attempt, false, context);
     }
 
@@ -487,7 +487,7 @@ public class PaymentProcessor extends ProcessorBase {
 
         List<PaymentAttemptModelDao> allAttempts = null;
         if (paymentConfig.isPaymentOff()) {
-            paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), PaymentStatus.PAYMENT_SYSTEM_OFF, clock.getUTCNow(), attemptInput.getId(), null, null, context);
+            paymentDao.updatePaymentAndAttemptOnCompletion(paymentInput.getId(), PaymentStatus.PAYMENT_SYSTEM_OFF, attemptInput.getId(), null, null, context);
             allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
             return new DefaultPayment(paymentInput, null, allAttempts, Collections.<RefundModelDao>emptyList());
         }
@@ -498,7 +498,7 @@ public class PaymentProcessor extends ProcessorBase {
         final PaymentInfoPlugin paymentPluginInfo;
         try {
             try {
-                paymentPluginInfo = plugin.processPayment(account.getId(), paymentInput.getId(), paymentInput.getPaymentMethodId(), attemptInput.getRequestedAmount(), account.getCurrency(), context.toCallContext());
+                paymentPluginInfo = plugin.processPayment(account.getId(), paymentInput.getId(), attemptInput.getPaymentMethodId(), attemptInput.getRequestedAmount(), account.getCurrency(), context.toCallContext());
             } catch (RuntimeException e) {
                 // Handle case of plugin RuntimeException to be handled the same as a Plugin failure (PaymentPluginApiException)
                 final String formatError = String.format("Plugin threw RuntimeException for payment %s", paymentInput.getId());
@@ -509,12 +509,7 @@ public class PaymentProcessor extends ProcessorBase {
                     // Update Payment/PaymentAttempt status
                     paymentStatus = PaymentStatus.SUCCESS;
 
-                    /*
-                    UUID paymentId, PaymentStatus paymentStatus, DateTime newEffectiveDate,
-                                                                  String gatewayErrorMsg, UUID attemptId, InternalCallContext callcontext, String gatewayErrorCode
-                     */
-
-                    paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), null, context);
+                    paymentDao.updatePaymentAndAttemptOnCompletion(paymentInput.getId(), paymentStatus, attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), null, context);
 
                     // Fetch latest objects
                     allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
@@ -546,7 +541,7 @@ public class PaymentProcessor extends ProcessorBase {
                         paymentStatus = PaymentStatus.PAYMENT_FAILURE_ABORTED;
                     }
 
-                    paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(), context);
+                    paymentDao.updatePaymentAndAttemptOnCompletion(paymentInput.getId(), paymentStatus, attemptInput.getId(), paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(), context);
 
                     log.info(String.format("Could not process payment for account %s, invoice %s, error = %s",
                             account.getId(), invoice.getId(), paymentPluginInfo.getGatewayError()));
@@ -569,7 +564,7 @@ public class PaymentProcessor extends ProcessorBase {
             paymentStatus = isInstantPayment ? PaymentStatus.PAYMENT_FAILURE_ABORTED : scheduleRetryOnPluginFailure(paymentInput.getId(), context);
             // STEPH message might need truncation to fit??
 
-            paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(paymentInput.getId(), paymentStatus, clock.getUTCNow(), attemptInput.getId(), null, e.getMessage(), context);
+            paymentDao.updatePaymentAndAttemptOnCompletion(paymentInput.getId(), paymentStatus, attemptInput.getId(), null, e.getMessage(), context);
 
             event = new DefaultPaymentPluginErrorEvent(account.getId(), invoice.getId(), paymentInput.getId(), e.getMessage(),
                     context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
index a5fa055..0b50ee1 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/DefaultPaymentDao.java
@@ -22,7 +22,6 @@ import java.util.UUID;
 
 import javax.inject.Inject;
 
-import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 
 import com.ning.billing.payment.api.PaymentStatus;
@@ -50,24 +49,19 @@ public class DefaultPaymentDao implements PaymentDao {
         this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao);
     }
 
+
     @Override
-    public PaymentAttemptModelDao insertNewAttemptForPayment(final UUID paymentId, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
+    public PaymentAttemptModelDao getPaymentAttempt(final UUID attemptId, final InternalTenantContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
             @Override
             public PaymentAttemptModelDao inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                final PaymentAttemptSqlDao transactional = entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class);
-                transactional.create(attempt, context);
-                final PaymentAttemptModelDao savedAttempt = transactional.getById(attempt.getId().toString(), context);
-
-                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentAmount(paymentId.toString(), savedAttempt.getRequestedAmount(), context);
-
-                return savedAttempt;
+                return entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class).getById(attemptId.toString(), context);
             }
         });
     }
 
     @Override
-    public PaymentModelDao insertPaymentWithAttempt(final PaymentModelDao payment, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
+    public PaymentModelDao insertPaymentWithFirstAttempt(final PaymentModelDao payment, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentModelDao>() {
 
             @Override
@@ -84,28 +78,34 @@ public class DefaultPaymentDao implements PaymentDao {
     }
 
     @Override
-    public PaymentAttemptModelDao getPaymentAttempt(final UUID attemptId, final InternalTenantContext context) {
+    public PaymentAttemptModelDao updatePaymentWithNewAttempt(final UUID paymentId, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
         return transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<PaymentAttemptModelDao>() {
             @Override
             public PaymentAttemptModelDao inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                return entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class).getById(attemptId.toString(), context);
+                final PaymentAttemptSqlDao transactional = entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class);
+                transactional.create(attempt, context);
+                final PaymentAttemptModelDao savedAttempt = transactional.getById(attempt.getId().toString(), context);
+
+                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentForNewAttempt(paymentId.toString(), attempt.getPaymentMethodId().toString(),
+                                                                                                  savedAttempt.getRequestedAmount(), attempt.getEffectiveDate().toDate(), context);
+
+                return savedAttempt;
             }
         });
     }
 
     @Override
-    public void updateStatusAndEffectiveDateForPaymentWithAttempt(final UUID paymentId,
-                                                                  final PaymentStatus paymentStatus,
-                                                                  final DateTime newEffectiveDate,
-                                                                  final UUID attemptId,
-                                                                  final String gatewayErrorCode,
-                                                                  final String gatewayErrorMsg,
-                                                                  final InternalCallContext context) {
+    public void updatePaymentAndAttemptOnCompletion(final UUID paymentId,
+                                                    final PaymentStatus paymentStatus,
+                                                    final UUID attemptId,
+                                                    final String gatewayErrorCode,
+                                                    final String gatewayErrorMsg,
+                                                    final InternalCallContext context) {
         transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<Void>() {
 
             @Override
             public Void inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception {
-                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentStatus(paymentId.toString(), paymentStatus.toString(), newEffectiveDate.toDate(), context);
+                entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updatePaymentStatus(paymentId.toString(), paymentStatus.toString(), context);
                 entitySqlDaoWrapperFactory.become(PaymentAttemptSqlDao.class).updatePaymentAttemptStatus(attemptId.toString(), paymentStatus.toString(), gatewayErrorCode, gatewayErrorMsg, context);
                 return null;
             }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
index b321484..cbed1f1 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentAttemptModelDao.java
@@ -34,6 +34,7 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
     private UUID accountId;
     private UUID invoiceId;
     private UUID paymentId;
+    private UUID paymentMethodId;
     private PaymentStatus processingStatus;
     private DateTime effectiveDate;
     private String gatewayErrorCode;
@@ -44,12 +45,14 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
 
     public PaymentAttemptModelDao(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
                                   final UUID accountId, final UUID invoiceId,
-                                  final UUID paymentId, final PaymentStatus processingStatus, final DateTime effectiveDate,
+                                  final UUID paymentId, final UUID paymentMethodId,
+                                  final PaymentStatus processingStatus, final DateTime effectiveDate,
                                   final BigDecimal requestedAmount, final String gatewayErrorCode, final String gatewayErrorMsg) {
         super(id, createdDate, updatedDate);
         this.accountId = accountId;
         this.invoiceId = invoiceId;
         this.paymentId = paymentId;
+        this.paymentMethodId = paymentMethodId;
         this.processingStatus = processingStatus;
         this.effectiveDate = effectiveDate;
         this.requestedAmount = requestedAmount;
@@ -57,17 +60,17 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
         this.gatewayErrorMsg = gatewayErrorMsg;
     }
 
-    public PaymentAttemptModelDao(final UUID accountId, final UUID invoiceId, final UUID paymentId, final PaymentStatus paymentStatus, final DateTime effectiveDate, final BigDecimal requestedAmount) {
-        this(UUID.randomUUID(), null, null, accountId, invoiceId, paymentId, paymentStatus, effectiveDate, requestedAmount, null, null);
+    public PaymentAttemptModelDao(final UUID accountId, final UUID invoiceId, final UUID paymentId, final UUID paymentMethodId, final PaymentStatus paymentStatus, final DateTime effectiveDate, final BigDecimal requestedAmount) {
+        this(UUID.randomUUID(), null, null, accountId, invoiceId, paymentId, paymentMethodId, paymentStatus, effectiveDate, requestedAmount, null, null);
     }
 
-    public PaymentAttemptModelDao(final UUID accountId, final UUID invoiceId, final UUID paymentId, final DateTime effectiveDate, final BigDecimal requestedAmount) {
-        this(UUID.randomUUID(), null, null, accountId, invoiceId, paymentId, PaymentStatus.UNKNOWN, effectiveDate, requestedAmount, null, null);
+    public PaymentAttemptModelDao(final UUID accountId, final UUID invoiceId, final UUID paymentId, final UUID paymentMethodId, final DateTime effectiveDate, final BigDecimal requestedAmount) {
+        this(UUID.randomUUID(), null, null, accountId, invoiceId, paymentId, paymentMethodId, PaymentStatus.UNKNOWN, effectiveDate, requestedAmount, null, null);
     }
 
     public PaymentAttemptModelDao(final PaymentAttemptModelDao src, final PaymentStatus newProcessingStatus, final String gatewayErrorCode, final String gatewayErrorMsg) {
-        this(src.getId(), src.getCreatedDate(), src.getUpdatedDate(), src.getAccountId(), src.getInvoiceId(), src.getPaymentId(), newProcessingStatus,
-             src.getEffectiveDate(), src.getRequestedAmount(), gatewayErrorCode, gatewayErrorMsg);
+        this(src.getId(), src.getCreatedDate(), src.getUpdatedDate(), src.getAccountId(), src.getInvoiceId(), src.getPaymentId(), src.getPaymentMethodId(),
+             newProcessingStatus, src.getEffectiveDate(), src.getRequestedAmount(), gatewayErrorCode, gatewayErrorMsg);
     }
 
     public UUID getAccountId() {
@@ -82,6 +85,10 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
         return paymentId;
     }
 
+    public UUID getPaymentMethodId() {
+        return paymentMethodId;
+    }
+
     public PaymentStatus getProcessingStatus() {
         return processingStatus;
     }
@@ -150,6 +157,9 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
         if (paymentId != null ? !paymentId.equals(that.paymentId) : that.paymentId != null) {
             return false;
         }
+        if (paymentMethodId != null ? !paymentMethodId.equals(that.paymentMethodId) : that.paymentMethodId != null) {
+            return false;
+        }
         if (processingStatus != that.processingStatus) {
             return false;
         }
@@ -166,6 +176,7 @@ public class PaymentAttemptModelDao extends EntityBase implements EntityModelDao
         result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
         result = 31 * result + (invoiceId != null ? invoiceId.hashCode() : 0);
         result = 31 * result + (paymentId != null ? paymentId.hashCode() : 0);
+        result = 31 * result + (paymentMethodId != null ? paymentMethodId.hashCode() : 0);
         result = 31 * result + (processingStatus != null ? processingStatus.hashCode() : 0);
         result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0);
         result = 31 * result + (gatewayErrorCode != null ? gatewayErrorCode.hashCode() : 0);
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 f16ced0..3ea92e4 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
@@ -28,13 +28,12 @@ import com.ning.billing.callcontext.InternalTenantContext;
 
 public interface PaymentDao {
 
-    // STEPH do we need object returned?
-    public PaymentModelDao insertPaymentWithAttempt(PaymentModelDao paymentInfo, PaymentAttemptModelDao attempt, InternalCallContext context);
+    public PaymentModelDao insertPaymentWithFirstAttempt(PaymentModelDao paymentInfo, PaymentAttemptModelDao attempt, InternalCallContext context);
 
-    public PaymentAttemptModelDao insertNewAttemptForPayment(UUID paymentId, PaymentAttemptModelDao attempt, InternalCallContext context);
+    public PaymentAttemptModelDao updatePaymentWithNewAttempt(UUID paymentId, PaymentAttemptModelDao attempt, InternalCallContext context);
 
-    public void updateStatusAndEffectiveDateForPaymentWithAttempt(UUID paymentId, PaymentStatus paymentStatus, DateTime newEffectiveDate,
-                                                                  UUID attemptId, String gatewayErrorMsg, String gatewayErrorCode, InternalCallContext context);
+    public void updatePaymentAndAttemptOnCompletion(UUID paymentId, PaymentStatus paymentStatus,
+                                                    UUID attemptId, String gatewayErrorMsg, String gatewayErrorCode, InternalCallContext context);
 
     public PaymentAttemptModelDao getPaymentAttempt(UUID attemptId, InternalTenantContext context);
 
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 f3a8e5e..19a367c 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
@@ -40,14 +40,15 @@ public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
     @Audited(ChangeType.UPDATE)
     void updatePaymentStatus(@Bind("id") final String paymentId,
                              @Bind("paymentStatus") final String paymentStatus,
-                             @Bind("effectiveDate") final Date effectiveDate,
                              @BindBean final InternalCallContext context);
 
     @SqlUpdate
     @Audited(ChangeType.UPDATE)
-    void updatePaymentAmount(@Bind("id") final String paymentId,
-                             @Bind("amount") final BigDecimal amount,
-                             @BindBean final InternalCallContext context);
+    void updatePaymentForNewAttempt(@Bind("id") final String paymentId,
+                                    @Bind("paymentMethodId") final String paymentMethodId,
+                                    @Bind("amount") final BigDecimal amount,
+                                    @Bind("effectiveDate") final Date effectiveDate,
+                                    @BindBean final InternalCallContext context);
 
     @SqlQuery
     PaymentModelDao getLastPaymentForAccountAndPaymentMethod(@Bind("accountId") final String accountId,
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
index 2e2402a..071968b 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentAttemptSqlDao.sql.stg
@@ -2,6 +2,7 @@ group PaymentAttemptSqlDao: EntitySqlDao;
 
 tableFields(prefix) ::= <<
   <prefix>payment_id
+, <prefix>payment_method_id
 , <prefix>gateway_error_code
 , <prefix>gateway_error_msg
 , <prefix>processing_status
@@ -14,6 +15,7 @@ tableFields(prefix) ::= <<
 
 tableValues() ::= <<
   :paymentId
+, :paymentMethodId
 , :gatewayErrorCode
 , :gatewayErrorMsg
 , :processingStatus
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 b7bc670..c7121a5 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
@@ -71,16 +71,18 @@ order by effective_date desc limit 1
 
 updatePaymentStatus() ::= <<
 update payments
-set payment_status = :paymentStatus,
-effective_date = :effectiveDate
+set payment_status = :paymentStatus
 where id = :id
 <AND_CHECK_TENANT()>
 ;
 >>
 
-updatePaymentAmount() ::= <<
+
+updatePaymentForNewAttempt() ::= <<
 update <tableName()>
 set amount = :amount
+, effective_date = :effectiveDate
+, payment_method_id= :paymentMethodId
 where id = :id
 <AND_CHECK_TENANT()>
 ;
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 cc27122..6dfc718 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -55,6 +55,7 @@ CREATE TABLE payment_attempts (
     record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
     payment_id char(36) NOT NULL,
+    payment_method_id char(36) NOT NULL,
     gateway_error_code varchar(32),              
     gateway_error_msg varchar(256),
     processing_status varchar(50),
@@ -77,6 +78,7 @@ CREATE TABLE payment_attempt_history (
     id char(36) NOT NULL,
     target_record_id int(11) unsigned NOT NULL,
     payment_id char(36) NOT NULL,
+    payment_method_id char(36) NOT NULL,
     gateway_error_code varchar(32),              
     gateway_error_msg varchar(256),
     processing_status varchar(50),
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 3dba5c0..2c5e51f 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
@@ -25,8 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
 import com.ning.billing.callcontext.InternalCallContext;
@@ -40,8 +38,8 @@ public class MockPaymentDao implements PaymentDao {
     private final Map<UUID, PaymentAttemptModelDao> attempts = new HashMap<UUID, PaymentAttemptModelDao>();
 
     @Override
-    public PaymentModelDao insertPaymentWithAttempt(final PaymentModelDao paymentInfo, final PaymentAttemptModelDao attempt,
-                                                    final InternalCallContext context) {
+    public PaymentModelDao insertPaymentWithFirstAttempt(final PaymentModelDao paymentInfo, final PaymentAttemptModelDao attempt,
+                                                         final InternalCallContext context) {
         synchronized (this) {
             payments.put(paymentInfo.getId(), paymentInfo);
             attempts.put(attempt.getId(), attempt);
@@ -50,7 +48,7 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public PaymentAttemptModelDao insertNewAttemptForPayment(final UUID paymentId, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
+    public PaymentAttemptModelDao updatePaymentWithNewAttempt(final UUID paymentId, final PaymentAttemptModelDao attempt, final InternalCallContext context) {
         synchronized (this) {
             attempts.put(attempt.getId(), attempt);
         }
@@ -58,9 +56,9 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
-    public void updateStatusAndEffectiveDateForPaymentWithAttempt(final UUID paymentId, final PaymentStatus paymentStatus, final DateTime effectibeDate,  final UUID attemptId, final String gatewayErrorCode,
-                                                                  final String gatewayErrorMsg,
-                                                                  final InternalCallContext context) {
+    public void updatePaymentAndAttemptOnCompletion(final UUID paymentId, final PaymentStatus paymentStatus, final UUID attemptId, final String gatewayErrorCode,
+                                                    final String gatewayErrorMsg,
+                                                    final InternalCallContext context) {
         synchronized (this) {
             final PaymentModelDao entry = payments.remove(paymentId);
             if (entry != null) {
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 d090ef6..29a5162 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
@@ -22,15 +22,12 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.catalog.api.Duration;
 import com.ning.billing.payment.PaymentTestSuiteWithEmbeddedDB;
 import com.ning.billing.payment.api.PaymentStatus;
 import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
-import com.ning.billing.payment.provider.MockPaymentProviderPlugin;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
@@ -98,16 +95,15 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final DateTime effectiveDate = clock.getUTCNow();
 
         final PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, paymentMethodId, amount, currency, effectiveDate);
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), amount);
-        PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, internalCallContext);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), paymentMethodId, effectiveDate, amount);
+        PaymentModelDao savedPayment = paymentDao.insertPaymentWithFirstAttempt(payment, attempt, internalCallContext);
         assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0);
 
         final PaymentStatus paymentStatus = PaymentStatus.SUCCESS;
         final String gatewayErrorCode = "OK";
 
         clock.addDays(1);
-        final DateTime newEffectiveDate = clock.getUTCNow();
-        paymentDao.updateStatusAndEffectiveDateForPaymentWithAttempt(payment.getId(), paymentStatus, newEffectiveDate, attempt.getId(), gatewayErrorCode, null,  internalCallContext);
+        paymentDao.updatePaymentAndAttemptOnCompletion(payment.getId(), paymentStatus, attempt.getId(), gatewayErrorCode, null, internalCallContext);
 
         final List<PaymentModelDao> payments = paymentDao.getPaymentsForInvoice(invoiceId, internalCallContext);
         assertEquals(payments.size(), 1);
@@ -118,7 +114,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         assertEquals(savedPayment.getPaymentMethodId(), paymentMethodId);
         assertEquals(savedPayment.getAmount().compareTo(amount), 0);
         assertEquals(savedPayment.getCurrency(), currency);
-        assertEquals(savedPayment.getEffectiveDate().compareTo(newEffectiveDate), 0);
+        assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0);
         assertEquals(savedPayment.getPaymentStatus(), PaymentStatus.SUCCESS);
 
         final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(payment.getId(), internalCallContext);
@@ -143,9 +139,9 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final DateTime effectiveDate = clock.getUTCNow();
 
         final PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, paymentMethodId, amount, currency, effectiveDate);
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), amount);
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), paymentMethodId, clock.getUTCNow(), amount);
 
-        PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, attempt, internalCallContext);
+        PaymentModelDao savedPayment = paymentDao.insertPaymentWithFirstAttempt(payment, attempt, internalCallContext);
         assertEquals(savedPayment.getId(), payment.getId());
         assertEquals(savedPayment.getAccountId(), accountId);
         assertEquals(savedPayment.getInvoiceId(), invoiceId);
@@ -195,8 +191,8 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final DateTime effectiveDate = clock.getUTCNow();
 
         final PaymentModelDao payment = new PaymentModelDao(accountId, invoiceId, paymentMethodId, amount, currency, effectiveDate);
-        final PaymentAttemptModelDao firstAttempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), amount);
-        PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, firstAttempt, internalCallContext);
+        final PaymentAttemptModelDao firstAttempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), paymentMethodId, effectiveDate, amount);
+        PaymentModelDao savedPayment = paymentDao.insertPaymentWithFirstAttempt(payment, firstAttempt, internalCallContext);
 
         final PaymentModelDao lastPayment = paymentDao.getLastPaymentForPaymentMethod(accountId, paymentMethodId, internalCallContext);
         assertNotNull(lastPayment);
@@ -209,9 +205,13 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         assertEquals(lastPayment.getEffectiveDate().compareTo(effectiveDate), 0);
         assertEquals(lastPayment.getPaymentStatus(), PaymentStatus.UNKNOWN);
 
+
+        clock.addDays(3);
+        final DateTime newEffectiveDate = clock.getUTCNow();
+        final UUID newPaymentMethodId = UUID.randomUUID();
         final BigDecimal newAmount = new BigDecimal(15.23).setScale(2, RoundingMode.HALF_EVEN);
-        final PaymentAttemptModelDao secondAttempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), newAmount);
-        paymentDao.insertNewAttemptForPayment(payment.getId(), secondAttempt, internalCallContext);
+        final PaymentAttemptModelDao secondAttempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), newPaymentMethodId, newEffectiveDate, newAmount);
+        paymentDao.updatePaymentWithNewAttempt(payment.getId(), secondAttempt, internalCallContext);
 
         final List<PaymentModelDao> payments = paymentDao.getPaymentsForInvoice(invoiceId, internalCallContext);
         assertEquals(payments.size(), 1);
@@ -219,25 +219,27 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         assertEquals(savedPayment.getId(), payment.getId());
         assertEquals(savedPayment.getAccountId(), accountId);
         assertEquals(savedPayment.getInvoiceId(), invoiceId);
-        assertEquals(savedPayment.getPaymentMethodId(), paymentMethodId);
+        assertEquals(savedPayment.getPaymentMethodId(), newPaymentMethodId);
         assertEquals(savedPayment.getAmount().compareTo(newAmount), 0);
         assertEquals(savedPayment.getCurrency(), currency);
-        assertEquals(savedPayment.getEffectiveDate().compareTo(effectiveDate), 0);
+        assertEquals(savedPayment.getEffectiveDate().compareTo(newEffectiveDate), 0);
         assertEquals(savedPayment.getPaymentStatus(), PaymentStatus.UNKNOWN);
 
         final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(payment.getId(), internalCallContext);
         assertEquals(attempts.size(), 2);
         final PaymentAttemptModelDao savedAttempt1 = attempts.get(0);
         assertEquals(savedAttempt1.getPaymentId(), payment.getId());
+        assertEquals(savedAttempt1.getPaymentMethodId(), paymentMethodId);
         assertEquals(savedAttempt1.getAccountId(), accountId);
         assertEquals(savedAttempt1.getInvoiceId(), invoiceId);
-        assertEquals(savedAttempt1.getProcessingStatus(), PaymentStatus.UNKNOWN);
+        assertEquals(savedAttempt1.getInvoiceId(), invoiceId);
         assertEquals(savedAttempt1.getGatewayErrorCode(), null);
         assertEquals(savedAttempt1.getGatewayErrorMsg(), null);
         assertEquals(savedAttempt1.getRequestedAmount().compareTo(amount), 0);
 
         final PaymentAttemptModelDao savedAttempt2 = attempts.get(1);
         assertEquals(savedAttempt2.getPaymentId(), payment.getId());
+        assertEquals(savedAttempt2.getPaymentMethodId(), newPaymentMethodId);
         assertEquals(savedAttempt2.getAccountId(), accountId);
         assertEquals(savedAttempt2.getInvoiceId(), invoiceId);
         assertEquals(savedAttempt2.getProcessingStatus(), PaymentStatus.UNKNOWN);