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);