killbill-memoizeit

payment: refresh payment methods correctly Make sure not

7/26/2012 6:11:51 PM

Details

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 c5b331e..eafb5ac 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2012 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
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 197d8b9..a95c98e 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2012 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
index 3bbae04..9105f58 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
@@ -17,6 +17,7 @@ package com.ning.billing.payment.core;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -135,13 +136,16 @@ public class PaymentMethodProcessor extends ProcessorBase {
                         return result;
                     }
 
+                    final List<PaymentMethodModelDao> finalPaymentMethods = new ArrayList<PaymentMethodModelDao>();
                     for (final PaymentMethodPlugin cur : pluginPms) {
                         final PaymentMethod input = new DefaultPaymentMethod(account.getId(), pluginName, cur);
-                        final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(input.getId(), input.getAccountId(), input.getPluginName(), input.isActive(), input.getPluginDetail().getExternalPaymentMethodId());
-                        // STEPH we should insert within one batch
-                        paymentDao.insertPaymentMethod(pmModel, context);
                         result.add(input);
+
+                        final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(input.getId(), input.getAccountId(), input.getPluginName(), input.isActive(), input.getPluginDetail().getExternalPaymentMethodId());
+                        finalPaymentMethods.add(pmModel);
                     }
+
+                    paymentDao.refreshPaymentMethods(account.getId(), finalPaymentMethods, context);
                 } catch (PaymentPluginApiException e) {
                     // STEPH all errors should also take a pluginName
                     throw new PaymentApiException(ErrorCode.PAYMENT_REFRESH_PAYMENT_METHOD, account.getId(), e.getErrorMessage());
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
index a749627..943a858 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/AuditedPaymentDao.java
@@ -16,6 +16,7 @@
 package com.ning.billing.payment.dao;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
@@ -177,19 +178,61 @@ public class AuditedPaymentDao implements PaymentDao {
     @Override
     public PaymentMethodModelDao insertPaymentMethod(final PaymentMethodModelDao paymentMethod, final CallContext context) {
         return paymentMethodSqlDao.inTransaction(new Transaction<PaymentMethodModelDao, PaymentMethodSqlDao>() {
-
             @Override
             public PaymentMethodModelDao inTransaction(final PaymentMethodSqlDao transactional, final TransactionStatus status)
                     throws Exception {
-                transactional.insertPaymentMethod(paymentMethod, context);
-                final PaymentMethodModelDao savedPaymentMethod = transactional.getPaymentMethod(paymentMethod.getId().toString());
-                final Long recordId = transactional.getRecordId(savedPaymentMethod.getId().toString());
-                final EntityHistory<PaymentMethodModelDao> history = new EntityHistory<PaymentMethodModelDao>(savedPaymentMethod.getId(), recordId, savedPaymentMethod, ChangeType.INSERT);
-                transactional.insertHistoryFromTransaction(history, context);
-                final Long historyRecordId = transactional.getHistoryRecordId(recordId);
-                final EntityAudit audit = new EntityAudit(TableName.PAYMENT_METHODS, historyRecordId, ChangeType.INSERT);
-                transactional.insertAuditFromTransaction(audit, context);
-                return savedPaymentMethod;
+                return insertPaymentMethodInTransaction(transactional, paymentMethod, context);
+            }
+        });
+    }
+
+    private PaymentMethodModelDao insertPaymentMethodInTransaction(final PaymentMethodSqlDao transactional, final PaymentMethodModelDao paymentMethod, final CallContext context) {
+        transactional.insertPaymentMethod(paymentMethod, context);
+        final PaymentMethodModelDao savedPaymentMethod = transactional.getPaymentMethod(paymentMethod.getId().toString());
+        final Long recordId = transactional.getRecordId(savedPaymentMethod.getId().toString());
+        final EntityHistory<PaymentMethodModelDao> history = new EntityHistory<PaymentMethodModelDao>(savedPaymentMethod.getId(), recordId, savedPaymentMethod, ChangeType.INSERT);
+        transactional.insertHistoryFromTransaction(history, context);
+        final Long historyRecordId = transactional.getHistoryRecordId(recordId);
+        final EntityAudit audit = new EntityAudit(TableName.PAYMENT_METHODS, historyRecordId, ChangeType.INSERT);
+        transactional.insertAuditFromTransaction(audit, context);
+        return savedPaymentMethod;
+    }
+
+    @Override
+    public void refreshPaymentMethods(final UUID accountId, final List<PaymentMethodModelDao> paymentMethods, final CallContext context) {
+        paymentMethodSqlDao.inTransaction(new Transaction<Void, PaymentMethodSqlDao>() {
+
+            @Override
+            public Void inTransaction(final PaymentMethodSqlDao transactional, final TransactionStatus status) throws Exception {
+                final List<PaymentMethodModelDao> existingPaymentMethods = getPaymentMethodsInTransaction(transactional, accountId);
+
+                for (final PaymentMethodModelDao finalPaymentMethod : paymentMethods) {
+                    boolean isExistingPaymentMethod = false;
+
+                    for (final PaymentMethodModelDao existingPaymentMethod : existingPaymentMethods) {
+                        if (existingPaymentMethod.equals(finalPaymentMethod)) {
+                            // We already have it - nothing to do
+                            isExistingPaymentMethod = true;
+                            break;
+                        } else if (existingPaymentMethod.equalsButActive(finalPaymentMethod)) {
+                            // We already have it but its status has changed - update it accordingly
+                            if (finalPaymentMethod.isActive()) {
+                                undeletedPaymentMethodInTransaction(transactional, existingPaymentMethod.getId());
+                            } else {
+                                deletedPaymentMethodInTransaction(transactional, existingPaymentMethod.getId());
+                            }
+                            isExistingPaymentMethod = true;
+                            break;
+                        }
+                        // Otherwise, we don't have it
+                    }
+
+                    if (!isExistingPaymentMethod) {
+                        insertPaymentMethodInTransaction(transactional, finalPaymentMethod, context);
+                    }
+                }
+
+                return null;
             }
         });
     }
@@ -276,36 +319,41 @@ public class AuditedPaymentDao implements PaymentDao {
         });
     }
 
-
-
     @Override
     public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId) {
-        return paymentMethodSqlDao.inTransaction(new Transaction<PaymentMethodModelDao, PaymentMethodSqlDao>() {
-            @Override
-            public PaymentMethodModelDao inTransaction(final PaymentMethodSqlDao transactional, final TransactionStatus status)
-                    throws Exception {
-                return transactional.getPaymentMethod(paymentMethodId.toString());
-            }
-        });
+        return getPaymentMethodInTransaction(paymentMethodSqlDao, paymentMethodId);
+    }
+
+    private PaymentMethodModelDao getPaymentMethodInTransaction(final PaymentMethodSqlDao transactional, final UUID paymentMethodId) {
+        return transactional.getPaymentMethod(paymentMethodId.toString());
     }
 
     @Override
     public List<PaymentMethodModelDao> getPaymentMethods(final UUID accountId) {
-        return paymentMethodSqlDao.inTransaction(new Transaction<List<PaymentMethodModelDao>, PaymentMethodSqlDao>() {
-            @Override
-            public List<PaymentMethodModelDao> inTransaction(final PaymentMethodSqlDao transactional, final TransactionStatus status)
-                    throws Exception {
-                return transactional.getPaymentMethods(accountId.toString());
-            }
-        });
+        return getPaymentMethodsInTransaction(paymentMethodSqlDao, accountId);
+    }
 
+    private List<PaymentMethodModelDao> getPaymentMethodsInTransaction(final PaymentMethodSqlDao transactional, final UUID accountId) {
+        return transactional.getPaymentMethods(accountId.toString());
     }
 
     @Override
     public void deletedPaymentMethod(final UUID paymentMethodId) {
-        paymentMethodSqlDao.markPaymentMethodAsDeleted(paymentMethodId.toString());
+        deletedPaymentMethodInTransaction(paymentMethodSqlDao, paymentMethodId);
+    }
+
+    private void deletedPaymentMethodInTransaction(final PaymentMethodSqlDao transactional, final UUID paymentMethodId) {
+        transactional.markPaymentMethodAsDeleted(paymentMethodId.toString());
     }
 
+    @Override
+    public void undeletedPaymentMethod(final UUID paymentMethodId) {
+        undeletedPaymentMethodInTransaction(paymentMethodSqlDao, paymentMethodId);
+    }
+
+    private void undeletedPaymentMethodInTransaction(final PaymentMethodSqlDao transactional, final UUID paymentMethodId) {
+        transactional.unmarkPaymentMethodAsDeleted(paymentMethodId.toString());
+    }
 
     @Override
     public List<PaymentModelDao> getPaymentsForInvoice(final UUID invoiceId) {
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 4d24526..9a1d7bb 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
@@ -53,9 +53,13 @@ public interface PaymentDao {
 
     public PaymentMethodModelDao insertPaymentMethod(final PaymentMethodModelDao paymentMethod, final CallContext context);
 
+    public void refreshPaymentMethods(final UUID accountId, final List<PaymentMethodModelDao> paymentMethods, final CallContext context);
+
     public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId);
 
     public List<PaymentMethodModelDao> getPaymentMethods(final UUID accountId);
 
     public void deletedPaymentMethod(final UUID paymentMethodId);
+
+    public void undeletedPaymentMethod(final UUID paymentMethodId);
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
index cbf98ea..30aa125 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodModelDao.java
@@ -50,4 +50,61 @@ public class PaymentMethodModelDao extends EntityBase {
     public String getExternalId() {
         return externalId;
     }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("PaymentMethodModelDao");
+        sb.append("{accountId=").append(accountId);
+        sb.append(", pluginName='").append(pluginName).append('\'');
+        sb.append(", isActive=").append(isActive);
+        sb.append(", externalId='").append(externalId).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final PaymentMethodModelDao that = (PaymentMethodModelDao) o;
+
+        if (!equalsButActive(that)) {
+            return false;
+        }
+
+        if (isActive != null ? !isActive.equals(that.isActive) : that.isActive != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public boolean equalsButActive(final PaymentMethodModelDao that) {
+        if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
+            return false;
+        }
+        if (externalId != null ? !externalId.equals(that.externalId) : that.externalId != null) {
+            return false;
+        }
+        if (pluginName != null ? !pluginName.equals(that.pluginName) : that.pluginName != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = accountId != null ? accountId.hashCode() : 0;
+        result = 31 * result + (pluginName != null ? pluginName.hashCode() : 0);
+        result = 31 * result + (isActive != null ? isActive.hashCode() : 0);
+        result = 31 * result + (externalId != null ? externalId.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodSqlDao.java b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodSqlDao.java
index dc85154..3065883 100644
--- a/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodSqlDao.java
+++ b/payment/src/main/java/com/ning/billing/payment/dao/PaymentMethodSqlDao.java
@@ -52,6 +52,9 @@ public interface PaymentMethodSqlDao extends Transactional<PaymentMethodSqlDao>,
     @SqlUpdate
     void markPaymentMethodAsDeleted(@Bind("id") final String paymentMethodId);
 
+    @SqlUpdate
+    void unmarkPaymentMethodAsDeleted(@Bind("id") final String paymentMethodId);
+
     @SqlQuery
     PaymentMethodModelDao getPaymentMethod(@Bind("id") final String paymentMethodId);
 
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
index 62a0501..75662f3 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
@@ -23,6 +23,12 @@ markPaymentMethodAsDeleted() ::= <<
     WHERE  id = :id;
 >>
 
+unmarkPaymentMethodAsDeleted() ::= <<
+    UPDATE payment_methods
+    SET is_active = 1
+    WHERE  id = :id;
+>>
+
 getPaymentMethod() ::= <<
     SELECT <paymentMethodFields()>
       FROM payment_methods
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 3946116..9713bfa 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
@@ -128,6 +128,23 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
+    public void refreshPaymentMethods(final UUID accountId, final List<PaymentMethodModelDao> newPaymentMethods, final CallContext context) {
+        synchronized (this) {
+            final Iterator<PaymentMethodModelDao> it = paymentMethods.iterator();
+            while (it.hasNext()) {
+                final PaymentMethodModelDao cur = it.next();
+                if (cur.getAccountId().equals(accountId)) {
+                    it.remove();
+                }
+            }
+
+            for (final PaymentMethodModelDao paymentMethodModelDao : paymentMethods) {
+                insertPaymentMethod(paymentMethodModelDao, context);
+            }
+        }
+    }
+
+    @Override
     public PaymentMethodModelDao getPaymentMethod(final UUID paymentMethodId) {
         for (final PaymentMethodModelDao cur : paymentMethods) {
             if (cur.getId().equals(paymentMethodId)) {
@@ -161,6 +178,11 @@ public class MockPaymentDao implements PaymentDao {
     }
 
     @Override
+    public void undeletedPaymentMethod(final UUID paymentMethodId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public RefundModelDao insertRefund(RefundModelDao refundInfo,
             CallContext context) {
         return null;