killbill-aplcache
Changes
osgi-bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java 23(+9 -14)
Details
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
index d4541e7..6d6844a 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApi.java
@@ -33,14 +33,14 @@ public interface PaymentPluginApi {
/**
* Charge a specific amount in the Gateway. Required.
*
- * @param pluginPaymentMethodKey payment method key to charge
* @param kbPaymentId killbill payment id (for reference)
+ * @param kbPaymentMethodId killbill payment method id
* @param amount amount to charge
* @param context call context
* @return information about the payment in the gateway
* @throws PaymentPluginApiException
*/
- public PaymentInfoPlugin processPayment(String pluginPaymentMethodKey, UUID kbPaymentId, BigDecimal amount, CallContext context)
+ public PaymentInfoPlugin processPayment(UUID kbPaymentId, UUID kbPaymentMethodId, BigDecimal amount, CallContext context)
throws PaymentPluginApiException;
/**
@@ -72,34 +72,30 @@ public interface PaymentPluginApi {
* Add a payment method for a Killbill account in the gateway. Optional.
*
* @param paymentMethodProps payment method details
- * @param kbAccountId killbill account id
* @param setDefault set it as the default payment method in the gateway
* @param context call context
- * @return payment method key in the gateway
* @throws PaymentPluginApiException
*/
- public String addPaymentMethod(PaymentMethodPlugin paymentMethodProps, UUID kbAccountId, boolean setDefault, CallContext context)
+ public void addPaymentMethod(UUID kbPaymentMethodId, PaymentMethodPlugin paymentMethodProps, boolean setDefault, CallContext context)
throws PaymentPluginApiException;
/**
* Delete a payment method in the gateway. Optional.
*
- * @param pluginPaymentMethodKey payment method key to delete
- * @param kbAccountId killbill account id
+ * @param kbPaymentMethodId killbill payment method id
* @param context call context
* @throws PaymentPluginApiException
*/
- public void deletePaymentMethod(String pluginPaymentMethodKey, UUID kbAccountId, CallContext context)
+ public void deletePaymentMethod(UUID kbPaymentMethodId, CallContext context)
throws PaymentPluginApiException;
/**
* Set a payment method as default in the gateway. Optional.
*
- * @param pluginPaymentMethodKey payment method key to update
- * @param kbAccountId killbill account id
+ * @param kbPaymentMethodId killbill payment method id
* @param context call context
* @throws PaymentPluginApiException
*/
- public void setDefaultPaymentMethod(String pluginPaymentMethodKey, UUID kbAccountId, CallContext context)
+ public void setDefaultPaymentMethod(UUID kbPaymentMethodId, CallContext context)
throws PaymentPluginApiException;
}
diff --git a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
index 607be20..91c106c 100644
--- a/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
+++ b/api/src/main/java/com/ning/billing/payment/plugin/api/PaymentPluginApiException.java
@@ -16,6 +16,8 @@
package com.ning.billing.payment.plugin.api;
+import com.ning.billing.BillingExceptionBase;
+
public class PaymentPluginApiException extends Exception {
private static final long serialVersionUID = 15642965L;
@@ -27,6 +29,11 @@ public class PaymentPluginApiException extends Exception {
this.errorType = errorType;
}
+ public PaymentPluginApiException(final String errorType, BillingExceptionBase billingExceptionBase) {
+ this.errorMessage = billingExceptionBase.getMessage();
+ this.errorType = errorType;
+ }
+
public String getErrorType() {
return errorType;
}
diff --git a/osgi-bundles/hello/src/main/java/com/ning/billing/osgi/bundles/hello/HelloActivator.java b/osgi-bundles/hello/src/main/java/com/ning/billing/osgi/bundles/hello/HelloActivator.java
index c0019d4..667d450 100644
--- a/osgi-bundles/hello/src/main/java/com/ning/billing/osgi/bundles/hello/HelloActivator.java
+++ b/osgi-bundles/hello/src/main/java/com/ning/billing/osgi/bundles/hello/HelloActivator.java
@@ -136,7 +136,7 @@ public class HelloActivator implements BundleActivator {
}
@Override
- public PaymentInfoPlugin processPayment(final String pluginPaymentMethodKey, final UUID kbPaymentId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+ public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
return null;
}
@@ -151,17 +151,17 @@ public class HelloActivator implements BundleActivator {
}
@Override
- public String addPaymentMethod(final PaymentMethodPlugin paymentMethodProps, final UUID kbAccountId, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
- return null;
+ public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
}
@Override
- public void deletePaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
}
@Override
- public void setDefaultPaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
}
+
}, props);
}
diff --git a/osgi-bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java b/osgi-bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
index 6c25605..c763d95 100644
--- a/osgi-bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
+++ b/osgi-bundles/jruby/src/main/java/com/ning/billing/osgi/bundles/jruby/JRubyPaymentPlugin.java
@@ -71,14 +71,14 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi
}
@Override
- public PaymentInfoPlugin processPayment(final String pluginPaymentMethodKey, final UUID kbPaymentId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+ public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
checkValidPaymentPlugin();
checkPluginIsRunning();
final Ruby runtime = getRuntime();
pluginInstance.callMethod("charge",
- JavaEmbedUtils.javaToRuby(runtime, pluginPaymentMethodKey),
JavaEmbedUtils.javaToRuby(runtime, kbPaymentId.toString()),
+ JavaEmbedUtils.javaToRuby(runtime, kbPaymentMethodId.toString()),
JavaEmbedUtils.javaToRuby(runtime, amount.longValue() * 100));
// TODO
@@ -111,41 +111,36 @@ public class JRubyPaymentPlugin extends JRubyPlugin implements PaymentPluginApi
}
@Override
- public String addPaymentMethod(final PaymentMethodPlugin paymentMethodProps, final UUID kbAccountId, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+ public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
checkValidPaymentPlugin();
checkPluginIsRunning();
final Ruby runtime = getRuntime();
pluginInstance.callMethod("add_payment_method",
- JavaEmbedUtils.javaToRuby(runtime, kbAccountId.toString()),
+ JavaEmbedUtils.javaToRuby(runtime, kbPaymentMethodId.toString()),
JavaEmbedUtils.javaToRuby(runtime, paymentMethodProps));
if (setDefault) {
- setDefaultPaymentMethod(paymentMethodProps.getExternalPaymentMethodId(), kbAccountId, context);
+ setDefaultPaymentMethod(kbPaymentMethodId, context);
}
-
- // TODO
- return null;
}
@Override
- public void deletePaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
checkValidPaymentPlugin();
checkPluginIsRunning();
final Ruby runtime = getRuntime();
pluginInstance.callMethod("delete_payment_method",
- JavaEmbedUtils.javaToRuby(runtime, pluginPaymentMethodKey),
- JavaEmbedUtils.javaToRuby(runtime, kbAccountId.toString()));
+ JavaEmbedUtils.javaToRuby(runtime, kbPaymentMethodId.toString()));
}
@Override
- public void setDefaultPaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
checkValidPaymentPlugin();
checkPluginIsRunning();
final Ruby runtime = getRuntime();
pluginInstance.callMethod("set_default_payment_method",
- JavaEmbedUtils.javaToRuby(runtime, pluginPaymentMethodKey),
- JavaEmbedUtils.javaToRuby(runtime, kbAccountId.toString()));
+ JavaEmbedUtils.javaToRuby(runtime, kbPaymentMethodId.toString()));
}
}
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 cc7e6c1..e5c2855 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
@@ -86,9 +86,9 @@ public class PaymentMethodProcessor extends ProcessorBase {
try {
pluginApi = pluginRegistry.getPlugin(pluginName);
pm = new DefaultPaymentMethod(account.getId(), pluginName, paymentMethodProps);
- final String externalId = pluginApi.addPaymentMethod(paymentMethodProps, account.getId(), setDefault, context.toCallContext());
+ pluginApi.addPaymentMethod(pm.getId(), paymentMethodProps, setDefault, context.toCallContext());
final PaymentMethodModelDao pmModel = new PaymentMethodModelDao(pm.getId(), pm.getCreatedDate(), pm.getUpdatedDate(),
- pm.getAccountId(), pm.getPluginName(), pm.isActive(), externalId);
+ pm.getAccountId(), pm.getPluginName(), pm.isActive());
paymentDao.insertPaymentMethod(pmModel, context);
if (setDefault) {
@@ -195,7 +195,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
}
}
final PaymentPluginApi pluginApi = getPluginApi(paymentMethodId, context);
- pluginApi.deletePaymentMethod(paymentMethodModel.getExternalId(), account.getId(), context.toCallContext());
+ pluginApi.deletePaymentMethod(paymentMethodId, context.toCallContext());
paymentDao.deletedPaymentMethod(paymentMethodId, context);
return null;
} catch (PaymentPluginApiException e) {
@@ -222,7 +222,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
try {
final PaymentPluginApi pluginApi = getPluginApi(paymentMethodId, context);
- pluginApi.setDefaultPaymentMethod(paymentMethodModel.getExternalId(), account.getId(), context.toCallContext());
+ pluginApi.setDefaultPaymentMethod(paymentMethodId, context.toCallContext());
accountInternalApi.updatePaymentMethod(account.getId(), paymentMethodId, context);
return null;
} catch (PaymentPluginApiException e) {
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 47ffca1..bff7a2b 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
@@ -13,6 +13,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
+
package com.ning.billing.payment.core;
import java.math.BigDecimal;
@@ -148,47 +149,47 @@ public class PaymentProcessor extends ProcessorBase {
return result;
}
- public void process_AUTO_PAY_OFF_removal(final Account account, final InternalCallContext context) throws PaymentApiException {
+ public void process_AUTO_PAY_OFF_removal(final Account account, final InternalCallContext context) throws PaymentApiException {
try {
voidPluginDispatcher.dispatchWithAccountLock(new CallableWithAccountLock<Void>(locker,
- account.getExternalKey(),
- new WithAccountLockCallback<Void>() {
-
- @Override
- public Void doOperation() throws PaymentApiException {
-
- final List<PaymentModelDao> payments = paymentDao.getPaymentsForAccount(account.getId(), context);
- final Collection<PaymentModelDao> paymentsToBeCompleted = Collections2.filter(payments, new Predicate<PaymentModelDao>() {
- @Override
- public boolean apply(final PaymentModelDao in) {
- // Payments left in AUTO_PAY_OFF or for which we did not retry enough
- return (in.getPaymentStatus() == PaymentStatus.AUTO_PAY_OFF ||
- in.getPaymentStatus() == PaymentStatus.PAYMENT_FAILURE ||
- in.getPaymentStatus() == PaymentStatus.PLUGIN_FAILURE);
- }
- });
- // Insert one retry event for each payment left in AUTO_PAY_OFF
- for (PaymentModelDao cur : paymentsToBeCompleted) {
- switch(cur.getPaymentStatus()) {
- case AUTO_PAY_OFF:
- autoPayoffRetryService.scheduleRetry(cur.getId(), clock.getUTCNow());
- break;
- case PAYMENT_FAILURE:
- scheduleRetryOnPaymentFailure(cur.getId(), context);
- break;
- case PLUGIN_FAILURE:
- scheduleRetryOnPluginFailure(cur.getId(), context);
- break;
- default:
- // Impossible...
- throw new RuntimeException("Unexpected case " + cur.getPaymentStatus());
- }
-
- }
- return null;
- }
- }));
+ account.getExternalKey(),
+ new WithAccountLockCallback<Void>() {
+
+ @Override
+ public Void doOperation() throws PaymentApiException {
+
+ final List<PaymentModelDao> payments = paymentDao.getPaymentsForAccount(account.getId(), context);
+ final Collection<PaymentModelDao> paymentsToBeCompleted = Collections2.filter(payments, new Predicate<PaymentModelDao>() {
+ @Override
+ public boolean apply(final PaymentModelDao in) {
+ // Payments left in AUTO_PAY_OFF or for which we did not retry enough
+ return (in.getPaymentStatus() == PaymentStatus.AUTO_PAY_OFF ||
+ in.getPaymentStatus() == PaymentStatus.PAYMENT_FAILURE ||
+ in.getPaymentStatus() == PaymentStatus.PLUGIN_FAILURE);
+ }
+ });
+ // Insert one retry event for each payment left in AUTO_PAY_OFF
+ for (PaymentModelDao cur : paymentsToBeCompleted) {
+ switch (cur.getPaymentStatus()) {
+ case AUTO_PAY_OFF:
+ autoPayoffRetryService.scheduleRetry(cur.getId(), clock.getUTCNow());
+ break;
+ case PAYMENT_FAILURE:
+ scheduleRetryOnPaymentFailure(cur.getId(), context);
+ break;
+ case PLUGIN_FAILURE:
+ scheduleRetryOnPluginFailure(cur.getId(), context);
+ break;
+ default:
+ // Impossible...
+ throw new RuntimeException("Unexpected case " + cur.getPaymentStatus());
+ }
+
+ }
+ return null;
+ }
+ }));
} catch (TimeoutException e) {
throw new PaymentApiException(ErrorCode.UNEXPECTED_ERROR, "Unexpected timeout for payment creation (AUTO_PAY_OFF)");
}
@@ -213,43 +214,43 @@ public class PaymentProcessor extends ProcessorBase {
// Note that at this point, we don't know the exact invoice balance (see getAndValidatePaymentAmount() below).
// This means that events will be posted for null and zero dollar invoices (e.g. trials).
final PaymentErrorInternalEvent event = new DefaultPaymentErrorEvent(account.getId(), invoiceId, null,
- ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD.toString(), context.getUserToken(),
- context.getAccountRecordId(), context.getTenantRecordId());
+ ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD.toString(), context.getUserToken(),
+ context.getAccountRecordId(), context.getTenantRecordId());
postPaymentEvent(event, account.getId(), context);
throw e;
}
try {
return paymentPluginDispatcher.dispatchWithAccountLock(new CallableWithAccountLock<Payment>(locker,
- account.getExternalKey(),
- new WithAccountLockCallback<Payment>() {
-
- @Override
- public Payment doOperation() throws PaymentApiException {
-
-
- try {
- final Invoice invoice = invoiceApi.getInvoiceById(invoiceId, context);
-
- if (invoice.isMigrationInvoice()) {
- log.error("Received invoice for payment that is a migration invoice - don't know how to handle those yet: {}", invoice);
- return null;
- }
-
- final boolean isAccountAutoPayOff = isAccountAutoPayOff(account.getId(), context);
- setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(account.getId(), paymentMethodId, isAccountAutoPayOff, context, isInstantPayment);
-
- final BigDecimal requestedAmount = getAndValidatePaymentAmount(invoice, inputAmount, isInstantPayment);
- if (!isInstantPayment && isAccountAutoPayOff) {
- return processNewPaymentForAutoPayOffWithAccountLocked(paymentMethodId, account, invoice, requestedAmount, context);
- } else {
- return processNewPaymentWithAccountLocked(paymentMethodId, plugin, account, invoice, requestedAmount, isInstantPayment, context);
- }
- } catch (InvoiceApiException e) {
- throw new PaymentApiException(e);
- }
- }
- }));
+ account.getExternalKey(),
+ new WithAccountLockCallback<Payment>() {
+
+ @Override
+ public Payment doOperation() throws PaymentApiException {
+
+
+ try {
+ final Invoice invoice = invoiceApi.getInvoiceById(invoiceId, context);
+
+ if (invoice.isMigrationInvoice()) {
+ log.error("Received invoice for payment that is a migration invoice - don't know how to handle those yet: {}", invoice);
+ return null;
+ }
+
+ final boolean isAccountAutoPayOff = isAccountAutoPayOff(account.getId(), context);
+ setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(account.getId(), paymentMethodId, isAccountAutoPayOff, context, isInstantPayment);
+
+ final BigDecimal requestedAmount = getAndValidatePaymentAmount(invoice, inputAmount, isInstantPayment);
+ if (!isInstantPayment && isAccountAutoPayOff) {
+ return processNewPaymentForAutoPayOffWithAccountLocked(paymentMethodId, account, invoice, requestedAmount, context);
+ } else {
+ return processNewPaymentWithAccountLocked(paymentMethodId, plugin, account, invoice, requestedAmount, isInstantPayment, context);
+ }
+ } catch (InvoiceApiException e) {
+ throw new PaymentApiException(e);
+ }
+ }
+ }));
} catch (TimeoutException e) {
if (isInstantPayment) {
throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_TIMEOUT, account.getId(), invoiceId);
@@ -266,37 +267,36 @@ public class PaymentProcessor extends ProcessorBase {
private void setUnsaneAccount_AUTO_PAY_OFFWithAccountLock(final UUID accountId, final UUID paymentMethodId, final boolean isAccountAutoPayOff,
final InternalCallContext context, final boolean isInstantPayment)
- throws PaymentApiException {
+ throws PaymentApiException {
final PaymentModelDao lastPaymentForPaymentMethod = paymentDao.getLastPaymentForPaymentMethod(accountId, paymentMethodId, context);
final boolean isLastPaymentForPaymentMethodBad = lastPaymentForPaymentMethod != null &&
- (lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.PLUGIN_FAILURE_ABORTED ||
- lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.UNKNOWN);
+ (lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.PLUGIN_FAILURE_ABORTED ||
+ lastPaymentForPaymentMethod.getPaymentStatus() == PaymentStatus.UNKNOWN);
if (isLastPaymentForPaymentMethodBad &&
- !isInstantPayment &&
- !isAccountAutoPayOff) {
+ !isInstantPayment &&
+ !isAccountAutoPayOff) {
log.warn(String.format("Setting account %s into AUTO_PAY_OFF because of bad payment %s", accountId, lastPaymentForPaymentMethod.getId()));
setAccountAutoPayOff(accountId, context);
}
}
-
private BigDecimal getAndValidatePaymentAmount(final Invoice invoice, @Nullable final BigDecimal inputAmount, final boolean isInstantPayment)
- throws PaymentApiException {
+ throws PaymentApiException {
if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0) {
throw new PaymentApiException(ErrorCode.PAYMENT_NULL_INVOICE, invoice.getId());
}
if (isInstantPayment &&
- inputAmount != null &&
- invoice.getBalance().compareTo(inputAmount) < 0) {
+ inputAmount != null &&
+ invoice.getBalance().compareTo(inputAmount) < 0) {
throw new PaymentApiException(ErrorCode.PAYMENT_AMOUNT_DENIED,
- invoice.getId(), inputAmount.floatValue(), invoice.getBalance().floatValue());
+ invoice.getId(), inputAmount.floatValue(), invoice.getBalance().floatValue());
}
- final BigDecimal result = inputAmount != null ? inputAmount : invoice.getBalance();
+ final BigDecimal result = inputAmount != null ? inputAmount : invoice.getBalance();
return result.setScale(2, RoundingMode.HALF_UP);
}
@@ -334,41 +334,41 @@ public class PaymentProcessor extends ProcessorBase {
final PaymentPluginApi plugin = getPaymentProviderPlugin(account, context);
voidPluginDispatcher.dispatchWithAccountLock(new CallableWithAccountLock<Void>(locker,
- account.getExternalKey(),
- new WithAccountLockCallback<Void>() {
-
- @Override
- public Void doOperation() throws PaymentApiException {
- try {
- // Fetch again with account lock this time
- final PaymentModelDao payment = paymentDao.getPayment(paymentId, context);
- boolean foundExpectedState = false;
- for (final PaymentStatus cur : expectedPaymentStates) {
- if (payment.getPaymentStatus() == cur) {
- foundExpectedState = true;
- break;
- }
- }
- if (!foundExpectedState) {
- log.info("Aborted retry for payment {} because it is {} state", paymentId, payment.getPaymentStatus());
- return null;
- }
-
- final Invoice invoice = invoiceApi.getInvoiceById(payment.getInvoiceId(), context);
- if (invoice.isMigrationInvoice()) {
- return null;
- }
- if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0) {
- log.info("Aborted retry for payment {} because invoice has been paid", paymentId);
- return null;
- }
- processRetryPaymentWithAccountLocked(plugin, account, invoice, payment, invoice.getBalance(), context);
- return null;
- } catch (InvoiceApiException e) {
- throw new PaymentApiException(e);
- }
- }
- }));
+ account.getExternalKey(),
+ new WithAccountLockCallback<Void>() {
+
+ @Override
+ public Void doOperation() throws PaymentApiException {
+ try {
+ // Fetch again with account lock this time
+ final PaymentModelDao payment = paymentDao.getPayment(paymentId, context);
+ boolean foundExpectedState = false;
+ for (final PaymentStatus cur : expectedPaymentStates) {
+ if (payment.getPaymentStatus() == cur) {
+ foundExpectedState = true;
+ break;
+ }
+ }
+ if (!foundExpectedState) {
+ log.info("Aborted retry for payment {} because it is {} state", paymentId, payment.getPaymentStatus());
+ return null;
+ }
+
+ final Invoice invoice = invoiceApi.getInvoiceById(payment.getInvoiceId(), context);
+ if (invoice.isMigrationInvoice()) {
+ return null;
+ }
+ if (invoice.getBalance().compareTo(BigDecimal.ZERO) <= 0) {
+ log.info("Aborted retry for payment {} because invoice has been paid", paymentId);
+ return null;
+ }
+ processRetryPaymentWithAccountLocked(plugin, account, invoice, payment, invoice.getBalance(), context);
+ return null;
+ } catch (InvoiceApiException e) {
+ throw new PaymentApiException(e);
+ }
+ }
+ }));
} catch (AccountApiException e) {
log.error(String.format("Failed to retry payment for paymentId %s", paymentId), e);
} catch (PaymentApiException e) {
@@ -401,7 +401,7 @@ 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 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);
return processPaymentWithAccountLocked(plugin, account, invoice, payment, attempt, false, context);
@@ -409,7 +409,7 @@ public class PaymentProcessor extends ProcessorBase {
private Payment processPaymentWithAccountLocked(final PaymentPluginApi plugin, final Account account, final Invoice invoice,
- final PaymentModelDao paymentInput, final PaymentAttemptModelDao attemptInput, final boolean isInstantPayment, final InternalCallContext context) throws PaymentApiException {
+ final PaymentModelDao paymentInput, final PaymentAttemptModelDao attemptInput, final boolean isInstantPayment, final InternalCallContext context) throws PaymentApiException {
List<PaymentAttemptModelDao> allAttempts = null;
@@ -424,53 +424,53 @@ public class PaymentProcessor extends ProcessorBase {
PaymentStatus paymentStatus;
try {
- final PaymentInfoPlugin paymentPluginInfo = plugin.processPayment(account.getExternalKey(), paymentInput.getId(), attemptInput.getRequestedAmount(), context.toCallContext());
+ final PaymentInfoPlugin paymentPluginInfo = plugin.processPayment(paymentInput.getId(), paymentInput.getPaymentMethodId(), attemptInput.getRequestedAmount(), context.toCallContext());
switch (paymentPluginInfo.getStatus()) {
- case PROCESSED:
- // Update Payment/PaymentAttempt status
- paymentStatus = PaymentStatus.SUCCESS;
- paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), null, attemptInput.getId(), context);
-
- // Fetch latest objects
- allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
-
- payment = paymentDao.getPayment(paymentInput.getId(), context);
- invoiceApi.notifyOfPayment(invoice.getId(),
- payment.getAmount(),
- paymentStatus == PaymentStatus.SUCCESS ? payment.getCurrency() : null,
- payment.getId(),
- payment.getEffectiveDate(),
- context);
-
- // Create Bus event
- event = new DefaultPaymentInfoEvent(account.getId(),
- invoice.getId(), payment.getId(), payment.getAmount(), payment.getPaymentNumber(), paymentStatus,
- context.getUserToken(), payment.getEffectiveDate(),
- context.getAccountRecordId(), context.getTenantRecordId());
- break;
-
- case ERROR:
- allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
- // Schedule if non instant payment and max attempt for retry not reached yet
- if (!isInstantPayment) {
- paymentStatus = scheduleRetryOnPaymentFailure(paymentInput.getId(), context);
- } else {
- paymentStatus = PaymentStatus.PAYMENT_FAILURE_ABORTED;
- }
+ case PROCESSED:
+ // Update Payment/PaymentAttempt status
+ paymentStatus = PaymentStatus.SUCCESS;
+ paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), null, attemptInput.getId(), context);
+
+ // Fetch latest objects
+ allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
+
+ payment = paymentDao.getPayment(paymentInput.getId(), context);
+ invoiceApi.notifyOfPayment(invoice.getId(),
+ payment.getAmount(),
+ payment.getCurrency(),
+ payment.getId(),
+ payment.getEffectiveDate(),
+ context);
+
+ // Create Bus event
+ event = new DefaultPaymentInfoEvent(account.getId(),
+ invoice.getId(), payment.getId(), payment.getAmount(), payment.getPaymentNumber(), paymentStatus,
+ context.getUserToken(), payment.getEffectiveDate(),
+ context.getAccountRecordId(), context.getTenantRecordId());
+ break;
+
+ case ERROR:
+ allAttempts = paymentDao.getAttemptsForPayment(paymentInput.getId(), context);
+ // Schedule if non instant payment and max attempt for retry not reached yet
+ if (!isInstantPayment) {
+ paymentStatus = scheduleRetryOnPaymentFailure(paymentInput.getId(), context);
+ } else {
+ paymentStatus = PaymentStatus.PAYMENT_FAILURE_ABORTED;
+ }
- paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(), attemptInput.getId(), context);
+ paymentDao.updateStatusForPaymentWithAttempt(paymentInput.getId(), paymentStatus, paymentPluginInfo.getGatewayErrorCode(), paymentPluginInfo.getGatewayError(), attemptInput.getId(), context);
- log.info(String.format("Could not process payment for account %s, invoice %s, error = %s",
- account.getId(), invoice.getId(), paymentPluginInfo.getGatewayError()));
+ log.info(String.format("Could not process payment for account %s, invoice %s, error = %s",
+ account.getId(), invoice.getId(), paymentPluginInfo.getGatewayError()));
- event = new DefaultPaymentErrorEvent(account.getId(), invoice.getId(), paymentInput.getId(), paymentPluginInfo.getGatewayError(), context.getUserToken(),
- context.getAccountRecordId(), context.getTenantRecordId());
- throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), paymentPluginInfo.getGatewayError());
+ event = new DefaultPaymentErrorEvent(account.getId(), invoice.getId(), paymentInput.getId(), paymentPluginInfo.getGatewayError(), context.getUserToken(),
+ context.getAccountRecordId(), context.getTenantRecordId());
+ throw new PaymentApiException(ErrorCode.PAYMENT_CREATE_PAYMENT, account.getId(), paymentPluginInfo.getGatewayError());
- default:
- final String formatError = String.format("Plugin return status %s for payment %s", paymentPluginInfo.getStatus(), paymentInput.getId());
- // This caught right below as a retryable Plugin failure
- throw new PaymentPluginApiException("", formatError);
+ default:
+ final String formatError = String.format("Plugin return status %s for payment %s", paymentPluginInfo.getStatus(), paymentInput.getId());
+ // This caught right below as a retryable Plugin failure
+ throw new PaymentPluginApiException("", formatError);
}
} catch (PaymentPluginApiException e) {
@@ -496,15 +496,15 @@ public class PaymentProcessor extends ProcessorBase {
private PaymentStatus scheduleRetryOnPluginFailure(final UUID paymentId, final InternalTenantContext context) {
final List<PaymentAttemptModelDao> allAttempts = paymentDao.getAttemptsForPayment(paymentId, context);
- final int retryAttempt = getNumberAttemptsInState(paymentId, allAttempts, PaymentStatus.UNKNOWN, PaymentStatus.PLUGIN_FAILURE);
+ final int retryAttempt = getNumberAttemptsInState(allAttempts, PaymentStatus.UNKNOWN, PaymentStatus.PLUGIN_FAILURE);
final boolean isScheduledForRetry = pluginFailureRetryService.scheduleRetry(paymentId, retryAttempt);
return isScheduledForRetry ? PaymentStatus.PLUGIN_FAILURE : PaymentStatus.PLUGIN_FAILURE_ABORTED;
}
private PaymentStatus scheduleRetryOnPaymentFailure(final UUID paymentId, final InternalTenantContext context) {
final List<PaymentAttemptModelDao> allAttempts = paymentDao.getAttemptsForPayment(paymentId, context);
- final int retryAttempt = getNumberAttemptsInState(paymentId, allAttempts,
- PaymentStatus.UNKNOWN, PaymentStatus.PAYMENT_FAILURE);
+ final int retryAttempt = getNumberAttemptsInState(allAttempts,
+ PaymentStatus.UNKNOWN, PaymentStatus.PAYMENT_FAILURE);
final boolean isScheduledForRetry = failedPaymentRetryService.scheduleRetry(paymentId, retryAttempt);
@@ -514,7 +514,7 @@ public class PaymentProcessor extends ProcessorBase {
return isScheduledForRetry ? PaymentStatus.PAYMENT_FAILURE : PaymentStatus.PAYMENT_FAILURE_ABORTED;
}
- private int getNumberAttemptsInState(final UUID paymentId, final List<PaymentAttemptModelDao> allAttempts, final PaymentStatus... statuses) {
+ private int getNumberAttemptsInState(final List<PaymentAttemptModelDao> allAttempts, final PaymentStatus... statuses) {
if (allAttempts == null || allAttempts.size() == 0) {
return 0;
}
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 e2d8be2..0d7cdd9 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
@@ -32,18 +32,16 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
private UUID accountId;
private String pluginName;
private Boolean isActive;
- private String externalId;
public PaymentMethodModelDao() { /* For the DAO mapper */ }
public PaymentMethodModelDao(final UUID id, @Nullable final DateTime createdDate, @Nullable final DateTime updatedDate,
final UUID accountId, final String pluginName,
- final Boolean isActive, final String externalId) {
+ final Boolean isActive) {
super(id, createdDate, updatedDate);
this.accountId = accountId;
this.pluginName = pluginName;
this.isActive = isActive;
- this.externalId = externalId;
}
public UUID getAccountId() {
@@ -63,10 +61,6 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
return isActive;
}
- public String getExternalId() {
- return externalId;
- }
-
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
@@ -74,7 +68,6 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
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();
}
@@ -105,9 +98,6 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
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;
}
@@ -120,7 +110,6 @@ public class PaymentMethodModelDao extends EntityBase implements EntityModelDao<
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/provider/DefaultNoOpPaymentProviderPlugin.java b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
index 1ef781a..8c5437c 100644
--- a/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
+++ b/payment/src/main/java/com/ning/billing/payment/provider/DefaultNoOpPaymentProviderPlugin.java
@@ -88,7 +88,7 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
}
@Override
- public PaymentInfoPlugin processPayment(final String pluginPaymentMethodKey, final UUID kbPaymentId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
+ public PaymentInfoPlugin processPayment(final UUID kbPaymentId, final UUID kbPaymentMethodId, final BigDecimal amount, final CallContext context) throws PaymentPluginApiException {
if (makeNextInvoiceFailWithException.getAndSet(false)) {
throw new PaymentPluginApiException("", "test error");
}
@@ -109,25 +109,23 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
}
@Override
- public String addPaymentMethod(final PaymentMethodPlugin paymentMethodProps, final UUID kbAccountId, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
+ public void addPaymentMethod(final UUID kbPaymentMethodId, final PaymentMethodPlugin paymentMethodProps, final boolean setDefault, final CallContext context) throws PaymentPluginApiException {
final PaymentMethodPlugin realWithID = new DefaultNoOpPaymentMethodPlugin(paymentMethodProps);
- List<PaymentMethodPlugin> pms = paymentMethods.get(kbAccountId.toString());
+ List<PaymentMethodPlugin> pms = paymentMethods.get(kbPaymentMethodId.toString());
if (pms == null) {
pms = new LinkedList<PaymentMethodPlugin>();
- paymentMethods.put(kbAccountId.toString(), pms);
+ paymentMethods.put(kbPaymentMethodId.toString(), pms);
}
pms.add(realWithID);
-
- return realWithID.getExternalPaymentMethodId();
}
@Override
- public void deletePaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void deletePaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
PaymentMethodPlugin toBeDeleted = null;
- final List<PaymentMethodPlugin> pms = paymentMethods.get(kbAccountId.toString());
+ final List<PaymentMethodPlugin> pms = paymentMethods.get(kbPaymentMethodId.toString());
if (pms != null) {
for (final PaymentMethodPlugin cur : pms) {
- if (cur.getExternalPaymentMethodId().equals(kbAccountId.toString())) {
+ if (cur.getExternalPaymentMethodId().equals(kbPaymentMethodId.toString())) {
toBeDeleted = cur;
break;
}
@@ -140,7 +138,7 @@ public class DefaultNoOpPaymentProviderPlugin implements NoOpPaymentPluginApi {
}
@Override
- public void setDefaultPaymentMethod(final String pluginPaymentMethodKey, final UUID kbAccountId, final CallContext context) throws PaymentPluginApiException {
+ public void setDefaultPaymentMethod(final UUID kbPaymentMethodId, final CallContext context) throws PaymentPluginApiException {
}
@Override
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 a242999..0186f2b 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
@@ -12,7 +12,6 @@ tableFields(prefix) ::= <<
<prefix>account_id
, <prefix>plugin_name
, <prefix>is_active
-, <prefix>external_id
, <prefix>created_by
, <prefix>created_date
, <prefix>updated_by
@@ -23,7 +22,6 @@ tableValues() ::= <<
:accountId
, :pluginName
, :isActive
-, :externalId
, :createdBy
, :createdDate
, :updatedBy
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 7c13e26..7d054d5 100644
--- a/payment/src/main/resources/com/ning/billing/payment/ddl.sql
+++ b/payment/src/main/resources/com/ning/billing/payment/ddl.sql
@@ -100,7 +100,6 @@ CREATE TABLE payment_methods (
account_id char(36) NOT NULL,
plugin_name varchar(20) DEFAULT NULL,
is_active bool DEFAULT true,
- external_id varchar(64),
created_by varchar(50) NOT NULL,
created_date datetime NOT NULL,
updated_by varchar(50) NOT NULL,
@@ -121,7 +120,6 @@ CREATE TABLE payment_method_history (
account_id char(36) NOT NULL,
plugin_name varchar(20) DEFAULT NULL,
is_active bool DEFAULT true,
- external_id varchar(64),
change_type char(6) NOT NULL,
created_by varchar(50) NOT NULL,
created_date datetime NOT 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 23d5bda..a17fcac 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
@@ -248,7 +248,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final String externalPaymentId = UUID.randomUUID().toString();
final PaymentMethodModelDao method = new PaymentMethodModelDao(paymentMethodId, null, null,
- accountId, pluginName, isActive, externalPaymentId);
+ accountId, pluginName, isActive);
PaymentMethodModelDao savedMethod = paymentDao.insertPaymentMethod(method, internalCallContext);
assertEquals(savedMethod.getId(), paymentMethodId);
@@ -263,7 +263,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(savedMethod.getAccountId(), accountId);
assertEquals(savedMethod.getPluginName(), pluginName);
assertEquals(savedMethod.isActive(), isActive);
- assertEquals(savedMethod.getExternalId(), externalPaymentId);
paymentDao.deletedPaymentMethod(paymentMethodId, internalCallContext);
diff --git a/payment/src/test/java/com/ning/billing/payment/provider/TestExternalPaymentProviderPlugin.java b/payment/src/test/java/com/ning/billing/payment/provider/TestExternalPaymentProviderPlugin.java
index 390b84c..45c36e5 100644
--- a/payment/src/test/java/com/ning/billing/payment/provider/TestExternalPaymentProviderPlugin.java
+++ b/payment/src/test/java/com/ning/billing/payment/provider/TestExternalPaymentProviderPlugin.java
@@ -50,10 +50,10 @@ public class TestExternalPaymentProviderPlugin extends PaymentTestSuiteNoDB {
@Test(groups = "fast")
public void testProcessPayment() throws Exception {
- final String pluginPaymentMethodKey = UUID.randomUUID().toString();
final UUID paymentId = UUID.randomUUID();
+ final UUID paymentMethodId = UUID.randomUUID();
final BigDecimal amount = BigDecimal.TEN;
- final PaymentInfoPlugin paymentInfoPlugin = plugin.processPayment(pluginPaymentMethodKey, paymentId, amount, callContext);
+ final PaymentInfoPlugin paymentInfoPlugin = plugin.processPayment(paymentId, paymentMethodId, amount, callContext);
Assert.assertEquals(paymentInfoPlugin.getAmount(), amount);
Assert.assertEquals(Seconds.secondsBetween(paymentInfoPlugin.getCreatedDate(), clock.getUTCNow()).getSeconds(), 0);
@@ -74,16 +74,18 @@ public class TestExternalPaymentProviderPlugin extends PaymentTestSuiteNoDB {
@Test(groups = "fast", expectedExceptions = PaymentPluginApiException.class)
public void testRefundTooLarge() throws Exception {
final UUID paymentId = UUID.randomUUID();
- plugin.processPayment(UUID.randomUUID().toString(), paymentId, BigDecimal.ZERO, callContext);
+ final UUID paymentMethodId = UUID.randomUUID();
+ plugin.processPayment(paymentId, paymentMethodId, BigDecimal.ZERO, callContext);
plugin.processRefund(paymentId, BigDecimal.ONE, callContext);
}
@Test(groups = "fast")
public void testRefundTooLargeMultipleTimes() throws Exception {
- final String pluginPaymentKey = UUID.randomUUID().toString();
final UUID paymentId = UUID.randomUUID();
- plugin.processPayment(UUID.randomUUID().toString(), paymentId, BigDecimal.TEN, callContext);
+ final UUID paymentMethodId = UUID.randomUUID();
+
+ plugin.processPayment(paymentId, paymentMethodId, BigDecimal.TEN, callContext);
final Account account = Mockito.mock(Account.class);
for (int i = 0; i < 10; i++) {