killbill-aplcache

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