killbill-memoizeit

Details

diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentStatus.java b/api/src/main/java/com/ning/billing/payment/api/PaymentStatus.java
index 151447c..cb27428 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentStatus.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentStatus.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright 2010-2011 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
@@ -30,9 +30,5 @@ public enum PaymentStatus {
     /* Exception from plugin, state is unknown and needs to be retried */
     PLUGIN_FAILURE,
     /* Exception from plugin, we already retried a maximum of time */
-    PLUGIN_FAILURE_ABORTED,
-    /* PaymentAttenmpt timedout; When TimedoutPaymentRetry kicks in, it check moves the state to TIMEDOUT if this is still in UNKNWON state */
-    TIMEDOUT,
-    /* Status for Payment and PaymentAttempt all TimedoutPaymentRetry failed */
-    TIMEDOUT_ABORTED,
+    PLUGIN_FAILURE_ABORTED
 }
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 e0e64f4..02b6cb4 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
@@ -93,7 +93,6 @@ public class PaymentProcessor extends ProcessorBase {
     private final PluginDispatcher<Void> voidPluginDispatcher;
 
     private static final Logger log = LoggerFactory.getLogger(PaymentProcessor.class);
-    private static final Joiner JOINER = Joiner.on(", ");
 
     @Inject
     public PaymentProcessor(final PaymentProviderPluginRegistry pluginRegistry,
@@ -232,13 +231,10 @@ public class PaymentProcessor extends ProcessorBase {
                     }
 
                     final boolean isAccountAutoPayOff = isAccountAutoPayOff(account.getId());
-                    final boolean isBadAccount = setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(account.getId(), isAccountAutoPayOff, context, isInstantPayment);
-                    if (isBadAccount && isInstantPayment) {
-                        throw new PaymentApiException(ErrorCode.PAYMENT_BAD_ACCOUNT, account.getId());
-                    }
+                    setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(account.getId(), paymentMethodId, isAccountAutoPayOff, context, isInstantPayment);
 
                     final BigDecimal requestedAmount = getAndValidatePaymentAmount(invoice, inputAmount, isInstantPayment);
-                    if (isAccountAutoPayOff) {
+                    if (!isInstantPayment && isAccountAutoPayOff) {
                         return processNewPaymentForAutoPayOffWithAccountLocked(paymentMethodId, account, invoice, requestedAmount, context);
                     } else {
                         return processNewPaymentWithAccountLocked(paymentMethodId, plugin, account, invoice, requestedAmount, isInstantPayment, context);
@@ -260,40 +256,28 @@ public class PaymentProcessor extends ProcessorBase {
     }
 
 
-    private boolean setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(final UUID accountId, final boolean isAccountAutoPayOff, final CallContext context, final boolean isInstantPayment)
-    throws PaymentApiException  {
-        final List<PaymentModelDao> payments =  paymentDao.getPaymentsForAccount(accountId);
 
-        final Collection<PaymentModelDao> badPayments = Collections2.filter(payments, new Predicate<PaymentModelDao>() {
 
-            @Override
-            public boolean apply(PaymentModelDao input) {
-                return (input.getPaymentStatus() != PaymentStatus.SUCCESS &&
-                        input.getPaymentStatus() != PaymentStatus.PAYMENT_FAILURE &&
-                        input.getPaymentStatus() != PaymentStatus.AUTO_PAY_OFF);
-            }
-        });
 
-        if (badPayments.size() > 0) {
-            if (!isInstantPayment && !isAccountAutoPayOff) {
-                JOINER.join(Collections2.transform(badPayments, new Function<PaymentModelDao, String>() {
+    private void setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(final UUID accountId, final UUID paymentMethodId, final boolean isAccountAutoPayOff, final CallContext context, final boolean isInstantPayment)
+    throws PaymentApiException  {
 
-                    @Override
-                    public String apply(PaymentModelDao input) {
-                        return String.format("%s [%s]", input.getId(), input.getPaymentStatus());
-                    }
-                }));
-                log.warn(String.format("Setting account %s into AUTO_PAY_OFF because of bad payments : %s", accountId, JOINER.toString()));
-                try {
-                    tagUserApi.addTag(accountId, ObjectType.ACCOUNT, ControlTagType.AUTO_PAY_OFF.getId(), context);
-                } catch (TagApiException e) {
-                    log.error("Failed to add AUTO_PAY_OFF on account " + accountId, e);
-                    throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, "Failed to add AUTO_PAY_OFF on account " + accountId);
-                }
+        final PaymentModelDao lastPaymentForPaymentMethod = paymentDao.getLastPaymentForPaymentMethod(accountId, paymentMethodId);
+        final boolean isLastPaymentForPaymentMethodBad = lastPaymentForPaymentMethod != null &&
+        (lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.PLUGIN_FAILURE_ABORTED ||
+                lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.UNKNOWN);
+
+
+        if (isLastPaymentForPaymentMethodBad &&
+                !isInstantPayment &&
+                !isAccountAutoPayOff) {
+            log.warn(String.format("Setting account %s into AUTO_PAY_OFF because of bad payment %s", accountId, lastPaymentForPaymentMethod.getId()));
+            try {
+                tagUserApi.addTag(accountId, ObjectType.ACCOUNT, ControlTagType.AUTO_PAY_OFF.getId(), context);
+            } catch (TagApiException e) {
+                log.error("Failed to add AUTO_PAY_OFF on account " + accountId, e);
+                throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, "Failed to add AUTO_PAY_OFF on account " + accountId);
             }
-            return true;
-        } else {
-            return false;
         }
     }
 
@@ -321,7 +305,7 @@ public class PaymentProcessor extends ProcessorBase {
     }
 
     public void retryPluginFailure(final UUID paymentId) {
-        retryFailedPaymentInternal(paymentId, PaymentStatus.PLUGIN_FAILURE, PaymentStatus.TIMEDOUT);
+        retryFailedPaymentInternal(paymentId, PaymentStatus.PLUGIN_FAILURE);
     }
 
     public void retryFailedPayment(final UUID paymentId) {
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 b75f21c..cad796e 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
@@ -372,6 +372,11 @@ public class AuditedPaymentDao implements PaymentDao {
     }
 
     @Override
+    public PaymentModelDao getLastPaymentForPaymentMethod(final UUID accountId, final UUID paymentMethodId) {
+        return paymentSqlDao.getLastPaymentForAccountAndPaymentMethod(accountId.toString(), paymentMethodId.toString());
+    }
+
+    @Override
     public PaymentModelDao getPayment(final UUID paymentId) {
         return paymentSqlDao.getPayment(paymentId.toString());
     }
@@ -385,4 +390,5 @@ public class AuditedPaymentDao implements PaymentDao {
     public List<PaymentAttemptModelDao> getAttemptsForPayment(final UUID paymentId) {
         return paymentAttemptSqlDao.getPaymentAttempts(paymentId.toString());
     }
+
 }
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 b4e7797..78c4630 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
@@ -38,6 +38,8 @@ public interface PaymentDao {
 
     public List<PaymentModelDao> getPaymentsForAccount(final UUID accountId);
 
+    public PaymentModelDao getLastPaymentForPaymentMethod(final UUID accountId, final UUID paymentMethodId);
+
     public PaymentModelDao getPayment(final UUID paymentId);
 
     public List<PaymentAttemptModelDao> getAttemptsForPayment(final UUID paymentId);
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 a669904..1cfe4cb 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
@@ -65,6 +65,9 @@ public interface PaymentSqlDao extends Transactional<PaymentSqlDao>, UpdatableEn
     PaymentModelDao getPayment(@Bind("id") final String paymentId);
 
     @SqlQuery
+    PaymentModelDao getLastPaymentForAccountAndPaymentMethod(@Bind("accountId") final String accountId, @Bind("paymentMethodId") final String paymentMethodId);
+
+    @SqlQuery
     List<PaymentModelDao> getPaymentsForInvoice(@Bind("invoiceId") final String invoiceId);
 
     @SqlQuery
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 e9630e3..a5f84b0 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
@@ -29,6 +29,14 @@ getPayment() ::= <<
     WHERE id = :id;
 >>
 
+getLastPaymentForAccountAndPaymentMethod() ::= <<
+    SELECT <paymentFields()>
+    , record_id as payment_number
+      FROM payments
+    WHERE account_id = :accountId AND payment_method_id = :paymentMethodId
+    ORDER BY effective_date desc limit 1;
+>> 
+
 getPaymentsForInvoice() ::= <<
     SELECT <paymentFields()>
     , record_id as payment_number
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 3811f8c..b8b14bc 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
@@ -196,4 +196,10 @@ public class MockPaymentDao implements PaymentDao {
     public List<RefundModelDao> getRefundsForAccount(UUID accountId) {
         return Collections.emptyList();
     }
+
+    @Override
+    public PaymentModelDao getLastPaymentForPaymentMethod(UUID accountId,
+            UUID paymentMethodId) {
+        return 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 27196ca..5f3951b 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
@@ -230,6 +230,19 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final PaymentAttemptModelDao firstAttempt = new PaymentAttemptModelDao(accountId, invoiceId, payment.getId(), clock.getUTCNow(), amount);
         PaymentModelDao savedPayment = paymentDao.insertPaymentWithAttempt(payment, firstAttempt, context);
 
+
+        final PaymentModelDao lastPayment = paymentDao.getLastPaymentForPaymentMethod(accountId, paymentMethodId);
+        assertNotNull(lastPayment);
+        assertEquals(lastPayment.getId(), payment.getId());
+        assertEquals(lastPayment.getAccountId(), accountId);
+        assertEquals(lastPayment.getInvoiceId(), invoiceId);
+        assertEquals(lastPayment.getPaymentMethodId(), paymentMethodId);
+        assertEquals(lastPayment.getAmount().compareTo(amount), 0);
+        assertEquals(lastPayment.getCurrency(), currency);
+        assertEquals(lastPayment.getEffectiveDate().compareTo(effectiveDate), 0);
+        assertEquals(lastPayment.getPaymentStatus(), PaymentStatus.UNKNOWN);
+
+
         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, context);