killbill-uncached

Fix for chargebacks

6/29/2012 9:43:11 PM

Details

diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
index 4a04248..880fc2b 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoicePayment.java
@@ -27,6 +27,8 @@ import com.ning.billing.util.entity.Entity;
 public interface InvoicePayment extends Entity {
     UUID getPaymentAttemptId();
 
+    InvoicePaymentType getType();
+
     UUID getInvoiceId();
 
     DateTime getPaymentAttemptDate();
@@ -35,10 +37,11 @@ public interface InvoicePayment extends Entity {
 
     Currency getCurrency();
 
-    UUID getReversedInvoicePaymentId();
+    UUID getLinkedInvoicePaymentId();
 
-    /*
-     * @param chargeBackAmount BigDecimal pass the amount as a positive number
-     */
-    InvoicePayment asChargeBack(BigDecimal chargeBackAmount, DateTime chargeBackDate) throws InvoiceApiException;
+    public enum InvoicePaymentType {
+        ATTEMPT,
+        CHARGED_BACK,
+        REFUND
+    }
 }
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 a93ee28..eeb8c85 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
@@ -28,6 +28,7 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.api.InvoicePaymentApi;
 import com.ning.billing.invoice.dao.InvoiceDao;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
@@ -69,13 +70,13 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
 
     @Override
     public void notifyOfPaymentAttempt(final UUID invoiceId, final BigDecimal amount, final Currency currency, final UUID paymentAttemptId, final DateTime paymentAttemptDate, final CallContext context) {
-        final InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate, amount, currency);
+        final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentAttemptId, invoiceId, paymentAttemptDate, amount, currency);
         dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
     public void notifyOfPaymentAttempt(final UUID invoiceId, final UUID paymentAttemptId, final DateTime paymentAttemptDate, final CallContext context) {
-        final InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate);
+        final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentAttemptId, invoiceId, paymentAttemptDate);
         dao.notifyOfPaymentAttempt(invoicePayment, context);
     }
 
@@ -86,10 +87,7 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
 
     @Override
     public InvoicePayment processChargeback(final UUID invoicePaymentId, final CallContext context) throws InvoiceApiException {
-        // use the invoicePaymentId to get the amount remaining on the payment
-        // (preventing charge backs totalling more than the payment)
-        final BigDecimal amount = dao.getRemainingAmountPaid(invoicePaymentId);
-        return processChargeback(invoicePaymentId, amount, context);
+        return processChargeback(invoicePaymentId, null, context);
     }
 
     @Override
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 dea44c3..246ba16 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
@@ -23,6 +23,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.IDBI;
 import org.skife.jdbi.v2.Transaction;
@@ -39,9 +41,11 @@ import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceItemType;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.model.CreditAdjInvoiceItem;
 import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoice;
+import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.invoice.notification.NextBillingDatePoster;
@@ -295,20 +299,27 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     @Override
     public InvoicePayment postChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException {
+
         return invoicePaymentSqlDao.inTransaction(new Transaction<InvoicePayment, InvoicePaymentSqlDao>() {
             @Override
             public InvoicePayment inTransaction(final InvoicePaymentSqlDao transactional, final TransactionStatus status) throws Exception {
+
+                final BigDecimal maxChargedBackAmount = getRemainingAmountPaidFromTransaction(invoicePaymentId, transactional);
+                final BigDecimal requestedChargedBackAmout = (amount == null) ? maxChargedBackAmount : amount;
+                if (requestedChargedBackAmout.compareTo(BigDecimal.ZERO) < 0) {
+                    throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_IS_NEGATIVE);
+                }
+                if (requestedChargedBackAmout.compareTo(maxChargedBackAmount) > 0) {
+                    throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_TOO_HIGH, requestedChargedBackAmout, maxChargedBackAmount);
+                }
+
                 final InvoicePayment payment = invoicePaymentSqlDao.getById(invoicePaymentId.toString());
                 if (payment == null) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, invoicePaymentId.toString());
                 } else {
-                    if (amount.compareTo(BigDecimal.ZERO) < 0) {
-                        throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_IS_NEGATIVE);
-                    }
-
-                    final InvoicePayment chargeBack = payment.asChargeBack(amount, context.getCreatedDate());
+                    final InvoicePayment chargeBack = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, null,
+                            payment.getInvoiceId(), context.getCreatedDate(), requestedChargedBackAmout.negate(), payment.getCurrency(), payment.getId());
                     invoicePaymentSqlDao.create(chargeBack, context);
-
                     return chargeBack;
                 }
             }
@@ -317,8 +328,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     @Override
     public BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId) {
-        final BigDecimal amount = invoicePaymentSqlDao.getRemainingAmountPaid(invoicePaymentId.toString());
-        return amount == null ? BigDecimal.ZERO : amount;
+        return getRemainingAmountPaidFromTransaction(invoicePaymentId, invoicePaymentSqlDao);
     }
 
     @Override
@@ -400,6 +410,13 @@ public class DefaultInvoiceDao implements InvoiceDao {
     }
 
 
+    private BigDecimal getRemainingAmountPaidFromTransaction(final UUID invoicePaymentId, final InvoicePaymentSqlDao transactional) {
+        final BigDecimal amount = transactional.getRemainingAmountPaid(invoicePaymentId.toString());
+        return amount == null ? BigDecimal.ZERO : amount;
+    }
+
+
+
     private void getInvoiceItemsWithinTransaction(final List<Invoice> invoices, final InvoiceSqlDao invoiceDao) {
         for (final Invoice invoice : invoices) {
             getInvoiceItemsWithinTransaction(invoice, invoiceDao);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
index ab817b5..852660d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.java
@@ -45,6 +45,7 @@ import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.CallContextBinder;
@@ -103,16 +104,17 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
         @Override
         public InvoicePayment map(final int index, final ResultSet result, final StatementContext context) throws SQLException {
             final UUID id = getUUID(result, "id");
+            final InvoicePaymentType type = InvoicePaymentType.valueOf(result.getString("type"));
             final UUID paymentAttemptId = getUUID(result, "payment_attempt_id");
             final UUID invoiceId = getUUID(result, "invoice_id");
             final DateTime paymentAttemptDate = getDate(result, "payment_attempt_date");
             final BigDecimal amount = result.getBigDecimal("amount");
             final String currencyString = result.getString("currency");
             final Currency currency = (currencyString == null) ? null : Currency.valueOf(currencyString);
-            final UUID reversedInvoicePaymentId = getUUID(result, "reversed_invoice_Payment_id");
+            final UUID linkedInvoicePaymentId = getUUID(result, "linked_invoice_payment_id");
 
-            return new DefaultInvoicePayment(id, paymentAttemptId, invoiceId, paymentAttemptDate,
-                                             amount, currency, reversedInvoicePaymentId);
+            return new DefaultInvoicePayment(id, type, paymentAttemptId, invoiceId, paymentAttemptDate,
+                                             amount, currency, linkedInvoicePaymentId);
         }
     }
 
@@ -127,13 +129,14 @@ public interface InvoicePaymentSqlDao extends EntitySqlDao<InvoicePayment>, Tran
                     @Override
                     public void bind(final SQLStatement q, final InvoicePaymentBinder bind, final InvoicePayment payment) {
                         q.bind("id", payment.getId().toString());
+                        q.bind("type", payment.getType().toString());
                         q.bind("invoiceId", payment.getInvoiceId().toString());
                         q.bind("paymentAttemptId", uuidToString(payment.getPaymentAttemptId()));
                         q.bind("paymentAttemptDate", payment.getPaymentAttemptDate().toDate());
                         q.bind("amount", payment.getAmount());
                         final Currency currency = payment.getCurrency();
                         q.bind("currency", (currency == null) ? null : currency.toString());
-                        q.bind("reversedInvoicePaymentId", uuidToString(payment.getReversedInvoicePaymentId()));
+                        q.bind("linkedInvoicePaymentId", uuidToString(payment.getLinkedInvoicePaymentId()));
                     }
                 };
             }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
index db80be0..99e0bde 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoicePayment.java
@@ -30,25 +30,27 @@ import com.ning.billing.util.entity.EntityBase;
 
 public class DefaultInvoicePayment extends EntityBase implements InvoicePayment {
     private final UUID paymentAttemptId;
+    private final InvoicePaymentType type;
     private final UUID invoiceId;
     private final DateTime paymentDate;
     private final BigDecimal amount;
     private final Currency currency;
     private final UUID reversedInvoicePaymentId;
 
-    public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate) {
-        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, null, null, null);
+    public DefaultInvoicePayment(final InvoicePaymentType type, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate) {
+        this(UUID.randomUUID(), type, paymentAttemptId, invoiceId, paymentDate, null, null, null);
     }
 
-    public DefaultInvoicePayment(final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
+    public DefaultInvoicePayment(final InvoicePaymentType type, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
                                  final BigDecimal amount, final Currency currency) {
-        this(UUID.randomUUID(), paymentAttemptId, invoiceId, paymentDate, amount, currency, null);
+        this(UUID.randomUUID(), type, paymentAttemptId, invoiceId, paymentDate, amount, currency, null);
     }
 
-    public DefaultInvoicePayment(final UUID id, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
+    public DefaultInvoicePayment(final UUID id, final InvoicePaymentType type, final UUID paymentAttemptId, final UUID invoiceId, final DateTime paymentDate,
                                  @Nullable final BigDecimal amount, @Nullable final Currency currency,
                                  @Nullable final UUID reversedInvoicePaymentId) {
         super(id);
+        this.type = type;
         this.paymentAttemptId = paymentAttemptId;
         this.amount = amount;
         this.invoiceId = invoiceId;
@@ -58,6 +60,11 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment 
     }
 
     @Override
+    public InvoicePaymentType getType() {
+        return type;
+    }
+
+    @Override
     public UUID getPaymentAttemptId() {
         return paymentAttemptId;
     }
@@ -83,16 +90,7 @@ public class DefaultInvoicePayment extends EntityBase implements InvoicePayment 
     }
 
     @Override
-    public UUID getReversedInvoicePaymentId() {
+    public UUID getLinkedInvoicePaymentId() {
         return reversedInvoicePaymentId;
     }
-
-    @Override
-    public InvoicePayment asChargeBack(final BigDecimal chargeBackAmount, final DateTime chargeBackDate) throws InvoiceApiException {
-        if (chargeBackAmount.compareTo(amount) > 0) {
-            throw new InvoiceApiException(ErrorCode.CHARGE_BACK_AMOUNT_TOO_HIGH, chargeBackAmount, amount);
-        }
-
-        return new DefaultInvoicePayment(UUID.randomUUID(), null, invoiceId, chargeBackDate, chargeBackAmount.negate(), currency, id);
-    }
 }
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
index 8ccf73b..f201331 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoicePaymentSqlDao.sql.stg
@@ -2,26 +2,27 @@ group InvoicePayment;
 
 invoicePaymentFields(prefix) ::= <<
   <prefix>id,
+  <prefix>type,
   <prefix>invoice_id,
   <prefix>payment_attempt_id,
   <prefix>payment_attempt_date,
   <prefix>amount,
   <prefix>currency,
-  <prefix>reversed_invoice_payment_id,
+  <prefix>linked_invoice_payment_id,
   <prefix>created_by,
   <prefix>created_date
 >>
 
 create() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
-         :reversedInvoicePaymentId, :userName, :createdDate);
+  VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+         :linkedInvoicePaymentId, :userName, :createdDate);
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
-        :reversedInvoicePaymentId, :userName, :createdDate);
+  VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+        :linkedInvoicePaymentId, :userName, :createdDate);
 >>
 
 getByPaymentAttemptId() ::= <<
@@ -49,8 +50,8 @@ getPaymentsForInvoice() ::= <<
 
 notifyOfPaymentAttempt() ::= <<
   INSERT INTO invoice_payments(<invoicePaymentFields()>)
-  VALUES(:id, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
-        :reversedInvoicePaymentId, :userName, :createdDate);
+  VALUES(:id, :type, :invoiceId, :paymentAttemptId, :paymentAttemptDate, :amount, :currency,
+        :linkedInvoicePaymentId, :userName, :createdDate);
 >>
 
 getInvoicePayment() ::= <<
@@ -95,7 +96,7 @@ getRemainingAmountPaid() ::= <<
     SELECT SUM(amount)
     FROM invoice_payments
     WHERE id = :invoicePaymentId
-    OR reversed_invoice_payment_id = :invoicePaymentId;
+    OR linked_invoice_payment_id = :invoicePaymentId;
 >>
 
 getAccountIdFromInvoicePaymentId() ::= <<
@@ -110,13 +111,13 @@ getChargeBacksByAccountId() ::= <<
     FROM invoice_payments ip
     INNER JOIN invoices i ON i.id = ip.invoice_id
     WHERE i.account_id = :accountId
-    AND reversed_invoice_payment_id IS NOT NULL;
+    AND linked_invoice_payment_id IS NOT NULL;
 >>
 
 getChargebacksByAttemptPaymentId() ::= <<
     SELECT <invoicePaymentFields()>
     FROM invoice_payments
-    WHERE reversed_invoice_payment_id IN
+    WHERE linked_invoice_payment_id IN
         (SELECT id FROM invoice_payments WHERE payment_attempt_id = :paymentAttemptId);
 >>
 ;
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index 93f770a..a408d3c 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -46,16 +46,17 @@ DROP TABLE IF EXISTS invoice_payments;
 CREATE TABLE invoice_payments (
     record_id int(11) unsigned NOT NULL AUTO_INCREMENT,
     id char(36) NOT NULL,
+    type varchar(24) NOT NULL,    
     invoice_id char(36) NOT NULL,
     payment_attempt_id char(36) COLLATE utf8_bin,
     payment_attempt_date datetime NOT NULL,
     amount numeric(10,4) NOT NULL,
     currency char(3) NOT NULL,
-    reversed_invoice_payment_id char(36) DEFAULT NULL,
+    linked_invoice_payment_id char(36) DEFAULT NULL,
     created_by varchar(50) NOT NULL,
     created_date datetime NOT NULL,
     PRIMARY KEY(record_id)
 ) ENGINE=innodb;
 CREATE UNIQUE INDEX invoice_payments_id ON invoice_payments(id);
 CREATE INDEX invoice_payments_attempt ON invoice_payments(payment_attempt_id);
-CREATE INDEX invoice_payments_reversals ON invoice_payments(reversed_invoice_payment_id);
+CREATE INDEX invoice_payments_reversals ON invoice_payments(linked_invoice_payment_id);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
index d4feb57..7087cd3 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/api/MockInvoicePaymentApi.java
@@ -26,6 +26,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
 import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.util.callcontext.CallContext;
 
@@ -91,13 +92,13 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi {
 
     @Override
     public void notifyOfPaymentAttempt(final UUID invoiceId, final BigDecimal amountOutstanding, final Currency currency, final UUID paymentAttemptId, final DateTime paymentAttemptDate, final CallContext context) {
-        final InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate, amountOutstanding, currency);
+        final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentAttemptId, invoiceId, paymentAttemptDate, amountOutstanding, currency);
         notifyOfPaymentAttempt(invoicePayment, context);
     }
 
     @Override
     public void notifyOfPaymentAttempt(final UUID invoiceId, final UUID paymentAttemptId, final DateTime paymentAttemptDate, final CallContext context) {
-        final InvoicePayment invoicePayment = new DefaultInvoicePayment(paymentAttemptId, invoiceId, paymentAttemptDate);
+        final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentAttemptId, invoiceId, paymentAttemptDate);
         notifyOfPaymentAttempt(invoicePayment, context);
     }
 
@@ -107,11 +108,13 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi {
         for (final InvoicePayment payment : invoicePayments) {
             if (payment.getId() == invoicePaymentId) {
                 existingPayment = payment;
+                break;
             }
         }
 
         if (existingPayment != null) {
-            invoicePayments.add(existingPayment.asChargeBack(amount, DateTime.now(DateTimeZone.UTC)));
+            invoicePayments.add(new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, null, null, DateTime.now(DateTimeZone.UTC), amount,
+                    Currency.USD, existingPayment.getId()));
         }
 
         return existingPayment;
@@ -141,7 +144,7 @@ public class MockInvoicePaymentApi implements InvoicePaymentApi {
                 amount = amount.add(payment.getAmount());
             }
 
-            if (payment.getReversedInvoicePaymentId().equals(invoicePaymentId)) {
+            if (payment.getLinkedInvoicePaymentId().equals(invoicePaymentId)) {
                 amount = amount.add(payment.getAmount());
             }
         }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 36d42fd..098f653 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -45,6 +45,7 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.model.CreditAdjInvoiceItem;
 import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoice;
@@ -113,7 +114,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final BigDecimal paymentAmount = new BigDecimal("11.00");
         final UUID paymentAttemptId = UUID.randomUUID();
 
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoiceId, clock.getUTCNow().plusDays(12), paymentAmount, Currency.USD), context);
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT,paymentAttemptId, invoiceId, clock.getUTCNow().plusDays(12), paymentAmount, Currency.USD), context);
 
         final Invoice retrievedInvoice = invoiceDao.getById(invoiceId);
         assertNotNull(retrievedInvoice);
@@ -140,7 +141,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final BigDecimal paymentAmount = new BigDecimal("14.0");
 
         invoiceDao.create(invoice, context);
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(paymentAttemptId, invoice.getId(), paymentAttemptDate, paymentAmount, Currency.USD), context);
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentAttemptId, invoice.getId(), paymentAttemptDate, paymentAmount, Currency.USD), context);
 
         invoice = invoiceDao.getById(invoice.getId());
         assertEquals(invoice.getPaidAmount().compareTo(paymentAmount), 0);
@@ -157,7 +158,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         final DateTime paymentAttemptDate = new DateTime(2011, 6, 24, 12, 14, 36, 0);
 
         invoiceDao.create(invoice, context);
-        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(UUID.randomUUID(), invoice.getId(), paymentAttemptDate), context);
+        invoiceDao.notifyOfPaymentAttempt(new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice.getId(), paymentAttemptDate), context);
 
         invoice = invoiceDao.getById(invoice.getId());
         assertEquals(invoice.getLastPaymentAttempt().compareTo(paymentAttemptDate), 0);
@@ -470,7 +471,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         invoiceItemSqlDao.create(item2, context);
 
         final BigDecimal payment1 = new BigDecimal("48.0");
-        final InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        final InvoicePayment payment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT,UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
         invoicePaymentDao.create(payment, context);
 
         final BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -537,7 +538,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         invoiceDao.create(invoice1, context);
 
         final BigDecimal payment1 = new BigDecimal("48.0");
-        final InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        final InvoicePayment payment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
         invoicePaymentDao.create(payment, context);
 
         final BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -577,7 +578,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         // Pay the whole thing
         final BigDecimal payment1 = amount1.add(rate1);
-        final InvoicePayment payment = new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
+        final InvoicePayment payment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), payment1, Currency.USD);
         invoicePaymentDao.create(payment, context);
         balance = invoiceDao.getAccountBalance(accountId);
         assertEquals(balance.compareTo(new BigDecimal("0.00")), 0);
@@ -600,7 +601,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         assertEquals(cba.compareTo(new BigDecimal("10.00")), 0);
 
         // partial REFUND on the payment (along with CBA generated by the system)
-        final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), UUID.randomUUID(), invoice1.getId(), new DateTime(), rate2.negate(), Currency.USD, payment.getId());
+        final InvoicePayment refund = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), new DateTime(), rate2.negate(), Currency.USD, payment.getId());
         invoicePaymentDao.create(refund, context);
         final CreditBalanceAdjInvoiceItem cbaItem2 = new CreditBalanceAdjInvoiceItem(invoice1.getId(), accountId, new DateTime(), rate2.negate(), Currency.USD);
         invoiceItemSqlDao.create(cbaItem2, context);
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java
index ce941b9..699b12b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/ChargeBackTests.java
@@ -159,7 +159,7 @@ public class ChargeBackTests {
         final List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByAccountId(invoice.getAccountId());
         assertNotNull(chargebacks);
         assertEquals(chargebacks.size(), 1);
-        assertEquals(chargebacks.get(0).getReversedInvoicePaymentId(), payment.getId());
+        assertEquals(chargebacks.get(0).getLinkedInvoicePaymentId(), payment.getId());
     }
 
     @Test
@@ -180,7 +180,7 @@ public class ChargeBackTests {
         final List<InvoicePayment> chargebacks = invoicePaymentApi.getChargebacksByPaymentAttemptId(payment.getPaymentAttemptId());
         assertNotNull(chargebacks);
         assertEquals(chargebacks.size(), 1);
-        assertEquals(chargebacks.get(0).getReversedInvoicePaymentId(), payment.getId());
+        assertEquals(chargebacks.get(0).getLinkedInvoicePaymentId(), payment.getId());
     }
 
     private Invoice createAndPersistInvoice(final BigDecimal amount) {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index 7b271c8..b4d106c 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -47,6 +47,7 @@ import com.ning.billing.invoice.MockBillingEventSet;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoicePayment.InvoicePaymentType;
 import com.ning.billing.invoice.generator.DefaultInvoiceGenerator;
 import com.ning.billing.invoice.generator.InvoiceGenerator;
 import com.ning.billing.invoice.model.CreditBalanceAdjInvoiceItem;
@@ -809,7 +810,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         invoices.add(invoice1);
 
         // pay the invoice
-        invoice1.addPayment(new DefaultInvoicePayment(UUID.randomUUID(), invoice1.getId(), april25, TEN, Currency.USD));
+        invoice1.addPayment(new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, UUID.randomUUID(), invoice1.getId(), april25, TEN, Currency.USD));
         assertEquals(invoice1.getBalance().compareTo(ZERO), 0);
 
         // change the plan (i.e. repair) on start date
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java
index f9b681f..70385a6 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/ChargebackJson.java
@@ -49,7 +49,7 @@ public class ChargebackJson {
         this.requestedDate = null;
         this.effectiveDate = chargeback.getPaymentAttemptDate();
         this.chargebackAmount = chargeback.getAmount().negate();
-        this.paymentId = chargeback.getReversedInvoicePaymentId().toString();
+        this.paymentId = chargeback.getLinkedInvoicePaymentId().toString();
         this.reason = null;
     }