Details
diff --git a/account/src/main/resources/com/ning/billing/account/ddl.sql b/account/src/main/resources/com/ning/billing/account/ddl.sql
index 7ba749e..17e344a 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -3,7 +3,7 @@ CREATE TABLE accounts (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
id char(36) NOT NULL,
external_key varchar(128) NULL,
- email varchar(50) NOT NULL,
+ email varchar(128) NOT NULL,
name varchar(100) NOT NULL,
first_name_length int NOT NULL,
currency char(3) DEFAULT NULL,
@@ -17,7 +17,7 @@ CREATE TABLE accounts (
city varchar(50) DEFAULT NULL,
state_or_province varchar(50) DEFAULT NULL,
country varchar(50) DEFAULT NULL,
- postal_code varchar(11) DEFAULT NULL,
+ postal_code varchar(16) DEFAULT NULL,
phone varchar(25) DEFAULT NULL,
migrated bool DEFAULT false,
is_notified_for_invoices boolean NOT NULL,
@@ -29,7 +29,6 @@ CREATE TABLE accounts (
) ENGINE=innodb;
CREATE UNIQUE INDEX accounts_id ON accounts(id);
CREATE UNIQUE INDEX accounts_external_key ON accounts(external_key);
-CREATE UNIQUE INDEX accounts_email ON accounts(email);
DROP TABLE IF EXISTS account_history;
CREATE TABLE account_history (
@@ -37,7 +36,7 @@ CREATE TABLE account_history (
record_id int(11) unsigned NOT NULL,
id char(36) NOT NULL,
external_key varchar(128) NULL,
- email varchar(50) NOT NULL,
+ email varchar(128) NOT NULL,
name varchar(100) NOT NULL,
first_name_length int NOT NULL,
currency char(3) DEFAULT NULL,
@@ -51,7 +50,7 @@ CREATE TABLE account_history (
city varchar(50) DEFAULT NULL,
state_or_province varchar(50) DEFAULT NULL,
country varchar(50) DEFAULT NULL,
- postal_code varchar(11) DEFAULT NULL,
+ postal_code varchar(16) DEFAULT NULL,
phone varchar(25) DEFAULT NULL,
migrated bool DEFAULT false,
is_notified_for_invoices boolean NOT NULL,
@@ -67,7 +66,7 @@ CREATE TABLE account_emails (
record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
id char(36) NOT NULL,
account_id char(36) NOT NULL,
- email varchar(50) NOT NULL,
+ email varchar(128) NOT NULL,
created_by varchar(50) NOT NULL,
created_date datetime NOT NULL,
updated_by varchar(50) NOT NULL,
@@ -83,10 +82,10 @@ CREATE TABLE account_email_history (
record_id int(11) unsigned NOT NULL,
id char(36) NOT NULL,
account_id char(36) NOT NULL,
- email varchar(50) NOT NULL,
+ email varchar(128) NOT NULL,
change_type char(6) NOT NULL,
updated_by varchar(50) NOT NULL,
date datetime NOT NULL,
PRIMARY KEY(history_record_id)
) ENGINE=innodb;
-CREATE INDEX account_email_record_id ON account_email_history(record_id);
\ No newline at end of file
+CREATE INDEX account_email_record_id ON account_email_history(record_id);
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index dd03756..8ea1ee2 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -248,7 +248,8 @@ public enum ErrorCode {
PAYMENT_NO_SUCH_REFUND(7023, "Refund %s does not exist"),
PAYMENT_NO_SUCH_SUCCESS_PAYMENT(7024, "Payment %s did not succeed"),
PAYMENT_REFUND_AMOUNT_TOO_LARGE(7025, "Refund amount if larger than payment"),
- PAYMENT_BAD_ACCOUNT(7026, "Account %s has payments left in an unknwon state"),
+ PAYMENT_REFUND_AMOUNT_NEGATIVE_OR_NULL(7026, "Refund amount needs to be strictly positive"),
+ PAYMENT_BAD_ACCOUNT(7027, "Account %s has payments left in an unknwon state"),
PAYMENT_PLUGIN_TIMEOUT(7100, "Plugin timeout for account %s and invoice %s"),
PAYMENT_PLUGIN_ACCOUNT_INIT(7101, "Account initialization for account %s and plugin % s failed: %s"),
diff --git a/api/src/main/java/com/ning/billing/payment/api/Payment.java b/api/src/main/java/com/ning/billing/payment/api/Payment.java
index 9171213..e64d92e 100644
--- a/api/src/main/java/com/ning/billing/payment/api/Payment.java
+++ b/api/src/main/java/com/ning/billing/payment/api/Payment.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -37,6 +37,8 @@ public interface Payment {
public BigDecimal getAmount();
+ public BigDecimal getPaidAmount();
+
public DateTime getEffectiveDate();
public Currency getCurrency();
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
index 400046c..2729faa 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/invoice/DefaultInvoicePaymentApi.java
@@ -23,6 +23,7 @@ import java.util.UUID;
import org.joda.time.DateTime;
+import com.ning.billing.ErrorCode;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.invoice.api.Invoice;
import com.ning.billing.invoice.api.InvoiceApiException;
@@ -36,6 +37,7 @@ import com.ning.billing.util.callcontext.CallContext;
import com.google.inject.Inject;
public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
+
private final InvoiceDao dao;
@Inject
@@ -113,6 +115,9 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
@Override
public InvoicePayment createRefund(final UUID paymentId, final BigDecimal amount, final boolean isInvoiceAdjusted,
final UUID paymentCookieId, final CallContext context) throws InvoiceApiException {
+ if (amount.compareTo(BigDecimal.ZERO) <= 0) {
+ throw new InvoiceApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_NEGATIVE_OR_NULL);
+ }
return dao.createRefund(paymentId, amount, isInvoiceAdjusted, paymentCookieId, context);
}
}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index 94ffef9..73d6cba 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -306,13 +306,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_BY_ATTEMPT_NOT_FOUND, paymentId);
}
final BigDecimal maxRefundAmount = payment.getAmount() == null ? BigDecimal.ZERO : payment.getAmount();
- final BigDecimal requestedAmount = amount == null ? maxRefundAmount : amount;
- if (requestedAmount.compareTo(BigDecimal.ZERO) >= 0) {
- throw new InvoiceApiException(ErrorCode.REFUND_AMOUNT_IS_POSITIVE);
- }
-
- // Now that we checked signs, let's work with positive numbers, this makes things simpler
- final BigDecimal requestedPositiveAmount = requestedAmount.negate();
+ final BigDecimal requestedPositiveAmount = amount == null ? maxRefundAmount : amount;
if (requestedPositiveAmount.compareTo(maxRefundAmount) > 0) {
throw new InvoiceApiException(ErrorCode.REFUND_AMOUNT_TOO_HIGH, requestedPositiveAmount, maxRefundAmount);
}
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
index 5b3d802..dcaa40b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceDao.java
@@ -530,7 +530,7 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
final LocalDate endDate = startDate.plusMonths(1);
final BigDecimal rate1 = new BigDecimal("20.0");
- final BigDecimal refund1 = new BigDecimal("-7.00");
+ final BigDecimal refund1 = new BigDecimal("7.00");
final BigDecimal rate2 = new BigDecimal("10.0");
// Recurring item
@@ -559,28 +559,28 @@ public class TestInvoiceDao extends InvoiceDaoTestBase {
@Test(groups = "slow")
public void testAccountBalanceWithSmallRefundAndCBANoAdj() throws InvoiceApiException {
- BigDecimal refundAmount = new BigDecimal("-7.00");
+ BigDecimal refundAmount = new BigDecimal("7.00");
BigDecimal expectedBalance = new BigDecimal("-3.00");
testAccountBalanceWithRefundAndCBAInternal(false, refundAmount, expectedBalance);
}
@Test(groups = "slow")
public void testAccountBalanceWithSmallRefundAndCBAWithAdj() throws InvoiceApiException {
- BigDecimal refundAmount = new BigDecimal("-7.00");
+ BigDecimal refundAmount = new BigDecimal("7.00");
BigDecimal expectedBalance = new BigDecimal("-3.00");
testAccountBalanceWithRefundAndCBAInternal(true, refundAmount, expectedBalance);
}
@Test(groups = "slow")
public void testAccountBalanceWithLargeRefundAndCBANoAdj() throws InvoiceApiException {
- BigDecimal refundAmount = new BigDecimal("-20.00");
+ BigDecimal refundAmount = new BigDecimal("20.00");
BigDecimal expectedBalance = new BigDecimal("10.00");
testAccountBalanceWithRefundAndCBAInternal(false, refundAmount, expectedBalance);
}
@Test(groups = "slow")
public void testAccountBalanceWithLargeRefundAndCBAWithAdj() throws InvoiceApiException {
- BigDecimal refundAmount = new BigDecimal("-20.00");
+ BigDecimal refundAmount = new BigDecimal("20.00");
BigDecimal expectedBalance = BigDecimal.ZERO;
testAccountBalanceWithRefundAndCBAInternal(true, refundAmount, expectedBalance);
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
index 789ccc3..866f64d 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/AccountTimelineJson.java
@@ -109,8 +109,7 @@ public class AccountTimelineJson {
for (final Payment cur : payments) {
final String status = cur.getPaymentStatus().toString();
- final BigDecimal paidAmount = cur.getPaymentStatus() == PaymentStatus.SUCCESS ? cur.getAmount() : BigDecimal.ZERO;
- this.payments.add(new PaymentJsonWithBundleKeys(cur.getAmount(), paidAmount, account.getId().toString(),
+ this.payments.add(new PaymentJsonWithBundleKeys(cur.getAmount(), cur.getPaidAmount(), account.getId().toString(),
cur.getInvoiceId().toString(), cur.getId().toString(),
cur.getEffectiveDate(), cur.getEffectiveDate(),
cur.getAttempts().size(), cur.getCurrency().toString(), status,
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
index a74e005..a075425 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
@@ -86,7 +86,7 @@ public class PaymentJsonSimple {
public PaymentJsonSimple(final Payment src) {
this.amount = src.getAmount();
- this.paidAmount = src.getPaymentStatus() == PaymentStatus.SUCCESS ? src.getAmount() : BigDecimal.ZERO;
+ this.paidAmount = src.getPaidAmount();
this.invoiceId = src.getInvoiceId().toString();
this.accountId = src.getAccountId().toString();
this.paymentId = src.getId().toString();
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index faaccb5..a4f079d 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -25,6 +25,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Response.Status;
@@ -114,11 +115,12 @@ public class PaymentResource extends JaxRsResourceBase {
@javax.ws.rs.core.Context final UriInfo uriInfo) {
try {
+
final UUID paymentUuid = UUID.fromString(paymentId);
final Payment payment = paymentApi.getPayment(paymentUuid);
-
final Account account = accountApi.getAccountById(payment.getAccountId());
+
Refund result = paymentApi.createRefund(account, paymentUuid, json.getRefundAmount(), json.isAdjusted(), context.createContext(createdBy, reason, comment));
return uriBuilder.buildResponse(RefundResource.class, "getRefund", result.getId(), uriInfo.getBaseUri().toString());
} catch (AccountApiException e) {
@@ -128,7 +130,7 @@ public class PaymentResource extends JaxRsResourceBase {
return Response.status(Status.BAD_REQUEST).build();
}
} catch (PaymentApiException e) {
- return Response.status(Status.BAD_REQUEST).build();
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build();
}
}
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
index c206d8e..8bb07fd 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPayment.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
@@ -28,6 +28,8 @@ import com.google.common.collect.Collections2;
import com.ning.billing.catalog.api.Currency;
import com.ning.billing.payment.dao.PaymentAttemptModelDao;
import com.ning.billing.payment.dao.PaymentModelDao;
+import com.ning.billing.payment.dao.RefundModelDao;
+import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.util.entity.EntityBase;
public class DefaultPayment extends EntityBase implements Payment {
@@ -37,6 +39,7 @@ public class DefaultPayment extends EntityBase implements Payment {
private final UUID invoiceId;
private final UUID paymentMethodId;
private final BigDecimal amount;
+ private final BigDecimal paidAmount;
private final Currency currency;
private final DateTime effectiveDate;
private final Integer paymentNumber;
@@ -45,7 +48,7 @@ public class DefaultPayment extends EntityBase implements Payment {
private DefaultPayment(final UUID id, final UUID accountId, final UUID invoiceId,
- final UUID paymentMethodId, final BigDecimal amount, final Currency currency,
+ final UUID paymentMethodId, final BigDecimal amount, BigDecimal paidAmount, final Currency currency,
final DateTime effectiveDate, final Integer paymentNumber,
final PaymentStatus paymentStatus, final String paymentError, final List<PaymentAttempt> attempts) {
super(id);
@@ -53,6 +56,7 @@ public class DefaultPayment extends EntityBase implements Payment {
this.invoiceId = invoiceId;
this.paymentMethodId = paymentMethodId;
this.amount = amount;
+ this.paidAmount = paidAmount;
this.currency = currency;
this.effectiveDate = effectiveDate;
this.paymentNumber = paymentNumber;
@@ -60,12 +64,13 @@ public class DefaultPayment extends EntityBase implements Payment {
this.attempts = attempts;
}
- public DefaultPayment(final PaymentModelDao src, final List<PaymentAttemptModelDao> attempts) {
+ public DefaultPayment(final PaymentModelDao src, final List<PaymentAttemptModelDao> attempts, final List<RefundModelDao> refunds) {
this(src.getId(),
src.getAccountId(),
src.getInvoiceId(),
src.getPaymentMethodId(),
src.getAmount(),
+ toPaidAmount(src.getPaymentStatus(), src.getAmount(), refunds),
src.getCurrency(),
src.getEffectiveDate(),
src.getPaymentNumber(),
@@ -101,6 +106,11 @@ public class DefaultPayment extends EntityBase implements Payment {
}
@Override
+ public BigDecimal getPaidAmount() {
+ return paidAmount;
+ }
+
+ @Override
public DateTime getEffectiveDate() {
return effectiveDate;
}
@@ -121,6 +131,21 @@ public class DefaultPayment extends EntityBase implements Payment {
return attempts;
}
+ private final static BigDecimal toPaidAmount(final PaymentStatus paymentStatus, final BigDecimal amount, final List<RefundModelDao> refunds) {
+
+ if (paymentStatus != PaymentStatus.SUCCESS) {
+ return BigDecimal.ZERO;
+ }
+
+ BigDecimal result = amount;
+ for (RefundModelDao cur : refunds) {
+ if (cur.getRefundStatus() != RefundStatus.CREATED) {
+ result = result.subtract(cur.getAmount());
+ }
+ }
+ return result;
+ }
+
private static List<PaymentAttempt> toPaymentAttempts(final List<PaymentAttemptModelDao> attempts) {
if (attempts == null || attempts.size() == 0) {
return Collections.emptyList();
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 4968a24..1bcedf9 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -88,6 +88,9 @@ public class DefaultPaymentApi implements PaymentApi {
public Refund createRefund(Account account, UUID paymentId,
BigDecimal refundAmount, boolean isAdjusted, CallContext context)
throws PaymentApiException {
+ if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_NEGATIVE_OR_NULL);
+ }
return refundProcessor.createRefund(account, paymentId, refundAmount, isAdjusted, context);
}
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 780fea6..46f2cfd 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
@@ -51,6 +51,7 @@ import com.ning.billing.payment.dao.PaymentAttemptModelDao;
import com.ning.billing.payment.dao.PaymentDao;
import com.ning.billing.payment.dao.PaymentModelDao;
import com.ning.billing.payment.dao.PaymentSqlDao;
+import com.ning.billing.payment.dao.RefundModelDao;
import com.ning.billing.payment.dispatcher.PluginDispatcher;
import com.ning.billing.payment.plugin.api.PaymentInfoPlugin;
import com.ning.billing.payment.plugin.api.PaymentPluginApi;
@@ -143,7 +144,8 @@ public class PaymentProcessor extends ProcessorBase {
final List<Payment> result = new LinkedList<Payment>();
for (final PaymentModelDao cur : payments) {
final List<PaymentAttemptModelDao> attempts = paymentDao.getAttemptsForPayment(cur.getId());
- final Payment entry = new DefaultPayment(cur, attempts);
+ final List<RefundModelDao> refunds = paymentDao.getRefundsForPayment(cur.getId());
+ final Payment entry = new DefaultPayment(cur, attempts, refunds);
result.add(entry);
}
return result;
@@ -408,7 +410,7 @@ public class PaymentProcessor extends ProcessorBase {
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), invoice.getId(), paymentInfo.getId(), paymentStatus, clock.getUTCNow(), requestedAmount);
paymentDao.insertPaymentWithAttempt(paymentInfo, attempt, context);
- return new DefaultPayment(paymentInfo, Collections.singletonList(attempt));
+ return new DefaultPayment(paymentInfo, Collections.singletonList(attempt), Collections.<RefundModelDao>emptyList());
}
@@ -503,7 +505,7 @@ public class PaymentProcessor extends ProcessorBase {
postPaymentEvent(event, account.getId());
}
}
- return new DefaultPayment(payment, allAttempts);
+ return new DefaultPayment(payment, allAttempts, Collections.<RefundModelDao>emptyList());
}
private PaymentStatus scheduleRetryOnPluginFailure(final UUID paymentId) {
diff --git a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
index 9d31f67..33c1431 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
@@ -66,6 +66,15 @@ public abstract class ProcessorBase {
this.executor = executor;
}
+ protected PaymentPluginApi getPaymentProviderPlugin(final UUID paymentMethodId) throws PaymentApiException {
+ final PaymentMethodModelDao methodDao = paymentDao.getPaymentMethod(paymentMethodId);
+ if (methodDao == null) {
+ log.error("PaymentMethod dpes not exist", paymentMethodId);
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);
+ }
+ return pluginRegistry.getPlugin(methodDao.getPluginName());
+ }
+
protected PaymentPluginApi getPaymentProviderPlugin(final String accountKey)
throws AccountApiException, PaymentApiException {
@@ -79,20 +88,11 @@ public abstract class ProcessorBase {
}
protected PaymentPluginApi getPaymentProviderPlugin(final Account account) throws PaymentApiException {
- String paymentProviderName = null;
- if (account != null) {
- final UUID paymentMethodId = account.getPaymentMethodId();
- if (paymentMethodId == null) {
- throw new PaymentApiException(ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD, account.getId());
- }
- final PaymentMethodModelDao methodDao = paymentDao.getPaymentMethod(paymentMethodId);
- if (methodDao == null) {
- log.error("Account {} has a non existent default payment method {}!!!", account.getId(), paymentMethodId);
- throw new PaymentApiException(ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD, account.getId());
- }
- paymentProviderName = methodDao.getPluginName();
+ final UUID paymentMethodId = account.getPaymentMethodId();
+ if (paymentMethodId == null) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_NO_DEFAULT_PAYMENT_METHOD, account.getId());
}
- return pluginRegistry.getPlugin(paymentProviderName);
+ return getPaymentProviderPlugin(paymentMethodId);
}
protected void postPaymentEvent(final BusEvent ev, final UUID accountId) {
diff --git a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
index a7768c2..d5ca7e9 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
@@ -44,6 +44,7 @@ import com.ning.billing.payment.api.PaymentStatus;
import com.ning.billing.payment.api.Refund;
import com.ning.billing.payment.dao.PaymentAttemptModelDao;
import com.ning.billing.payment.dao.PaymentDao;
+import com.ning.billing.payment.dao.PaymentModelDao;
import com.ning.billing.payment.dao.RefundModelDao;
import com.ning.billing.payment.dao.RefundModelDao.RefundStatus;
import com.ning.billing.payment.plugin.api.PaymentPluginApi;
@@ -89,20 +90,25 @@ public class RefundProcessor extends ProcessorBase {
public Refund doOperation() throws PaymentApiException {
try {
- final PaymentAttemptModelDao successfulAttempt = getPaymentAttempt(paymentId);
- if (successfulAttempt == null) {
+ final PaymentModelDao payment = paymentDao.getPayment(paymentId);
+ if (payment == null) {
throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_SUCCESS_PAYMENT, paymentId);
}
- if (successfulAttempt.getRequestedAmount().compareTo(refundAmount) < 0) {
- throw new PaymentApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_TOO_LARGE);
- }
- // Look for that refund entry and count any 'similar' refund left in CREATED state (same amount, same paymentId)
+ //
+ // We are looking for multiple things:
+ // 1. Compute totalAmountRefunded based on all Refund entries that made it to the plugin.
+ // 2. If we find a CREATED entry (that did not make it to the plugin) with the same amount, we reuse the entry
+ // 3. Compute foundPluginCompletedRefunds, number of refund entries for that amount that made it to the plugin
+ //
int foundPluginCompletedRefunds = 0;
RefundModelDao refundInfo = null;
+ BigDecimal totalAmountRefunded = BigDecimal.ZERO;
List<RefundModelDao> existingRefunds = paymentDao.getRefundsForPayment(paymentId);
for (RefundModelDao cur : existingRefunds) {
- if (cur.getAmount().compareTo(refundAmount) == 0) {
+
+ final BigDecimal existingPositiveAmount = cur.getAmount();
+ if (existingPositiveAmount.compareTo(refundAmount) == 0) {
if (cur.getRefundStatus() == RefundStatus.CREATED) {
if (refundInfo == null) {
refundInfo = cur;
@@ -111,18 +117,28 @@ public class RefundProcessor extends ProcessorBase {
foundPluginCompletedRefunds++;
}
}
+ if (cur.getRefundStatus() != RefundStatus.CREATED) {
+ totalAmountRefunded = totalAmountRefunded.add(existingPositiveAmount);
+ }
}
+
+ if (payment.getAmount().subtract(totalAmountRefunded).compareTo(refundAmount) < 0) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_REFUND_AMOUNT_TOO_LARGE);
+ }
+
if (refundInfo == null) {
refundInfo = new RefundModelDao(account.getId(), paymentId, refundAmount, account.getCurrency(), isAdjusted);
paymentDao.insertRefund(refundInfo, context);
}
- final PaymentPluginApi plugin = getPaymentProviderPlugin(account);
+ final PaymentPluginApi plugin = getPaymentProviderPlugin(payment.getPaymentMethodId());
int nbExistingRefunds = plugin.getNbRefundForPaymentAmount(account, paymentId, refundAmount);
+ log.debug(String.format("found %d pluginRefunds for paymentId %s and amount %s", nbExistingRefunds, paymentId, refundAmount));
+
if (nbExistingRefunds > foundPluginCompletedRefunds) {
log.info("Found existing plugin refund for paymentId {}, skip plugin", paymentId);
} else {
- // If there is no such existng refund we create it
+ // If there is no such existing refund we create it
plugin.processRefund(account, paymentId, refundAmount);
}
paymentDao.updateRefundStatus(refundInfo.getId(), RefundStatus.PLUGIN_COMPLETED, context);
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java b/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
index be1ec0d..090b700 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestPayment.java
@@ -79,7 +79,7 @@ public class TestPayment extends TestJaxrsBase {
// Issue the refund
- RefundJson refundJson = new RefundJson(null, paymentId, paymentAmount.negate(), false);
+ RefundJson refundJson = new RefundJson(null, paymentId, paymentAmount, false);
baseJson = mapper.writeValueAsString(refundJson);
response = doPost(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());