killbill-memoizeit

Details

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 2729faa..effca13 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
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.skife.jdbi.v2.exceptions.TransactionFailedException;
 
 import com.ning.billing.ErrorCode;
 import com.ning.billing.catalog.api.Currency;
@@ -38,6 +39,8 @@ import com.google.inject.Inject;
 
 public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
 
+    private static final WithInvoiceApiException<InvoicePayment> invoicePaymentWithException = new WithInvoiceApiException<InvoicePayment>();
+
     private final InvoiceDao dao;
 
     @Inject
@@ -77,15 +80,6 @@ public class DefaultInvoicePaymentApi implements InvoicePaymentApi {
         dao.notifyOfPayment(invoicePayment, context);
     }
 
-    @Override
-    public InvoicePayment createChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException {
-        return dao.postChargeback(invoicePaymentId, amount, context);
-    }
-
-    @Override
-    public InvoicePayment createChargeback(final UUID invoicePaymentId, final CallContext context) throws InvoiceApiException {
-        return createChargeback(invoicePaymentId, null, context);
-    }
 
     @Override
     public BigDecimal getRemainingAmountPaid(final UUID invoicePaymentId) {
@@ -115,9 +109,59 @@ 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 invoicePaymentWithException.executeAndThrow(new WithInvoiceApiExceptionCallback<InvoicePayment>() {
+
+            @Override
+            public InvoicePayment doHandle() 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);
+            }
+        });
+    }
+
+    @Override
+    public InvoicePayment createChargeback(final UUID invoicePaymentId, final CallContext context) throws InvoiceApiException {
+        return createChargeback(invoicePaymentId, null, context);
+    }
+
+
+    @Override
+    public InvoicePayment createChargeback(final UUID invoicePaymentId, final BigDecimal amount, final CallContext context) throws InvoiceApiException {
+
+        return invoicePaymentWithException.executeAndThrow(new WithInvoiceApiExceptionCallback<InvoicePayment>() {
+
+            @Override
+            public InvoicePayment doHandle() throws InvoiceApiException {
+                return dao.postChargeback(invoicePaymentId, amount, context);
+            }
+
+        });
+
+    }
+
+    //
+    // Allow to safely catch TransactionFailedException exceptions and rethrow the correct InvoiceApiException exception
+    //
+    private interface WithInvoiceApiExceptionCallback<T> {
+        public T doHandle() throws InvoiceApiException;
+    }
+
+    private static final class WithInvoiceApiException<T> {
+        public T executeAndThrow(WithInvoiceApiExceptionCallback<T> callback) throws InvoiceApiException  {
+
+            try {
+                return callback.doHandle();
+            } catch (TransactionFailedException e) {
+                if (e.getCause() instanceof InvoiceApiException) {
+                    InvoiceApiException realException = (InvoiceApiException) e.getCause();
+                    throw realException;
+                } else {
+                    throw e;
+                }
+            }
         }
-        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 3f94759..68cf45c 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
@@ -385,7 +385,7 @@ public class DefaultInvoiceDao implements InvoiceDao {
                 if (payment == null) {
                     throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, invoicePaymentId.toString());
                 } else {
-                    final InvoicePayment chargeBack = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, null,
+                    final InvoicePayment chargeBack = new DefaultInvoicePayment(UUID.randomUUID(), InvoicePaymentType.CHARGED_BACK, payment.getPaymentId(),
                                                                                 payment.getInvoiceId(), context.getCreatedDate(), requestedChargedBackAmout.negate(), payment.getCurrency(), null, payment.getId());
                     invoicePaymentSqlDao.create(chargeBack, context);
                     return chargeBack;
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 2cb35fc..9eba9a9 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.getPaymentDate();
         this.chargebackAmount = chargeback.getAmount().negate();
-        this.paymentId = chargeback.getLinkedInvoicePaymentId().toString();
+        this.paymentId = chargeback.getPaymentId().toString();
         this.reason = null;
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
index c45836b..4fac93c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/ChargebackResource.java
@@ -28,7 +28,6 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
 
 import com.ning.billing.ErrorCode;
 import com.ning.billing.invoice.api.InvoiceApiException;
@@ -109,8 +108,7 @@ public class ChargebackResource extends JaxRsResourceBase {
     public Response createChargeback(final ChargebackJson json,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
-                                     @HeaderParam(HDR_COMMENT) final String comment,
-                                     @javax.ws.rs.core.Context final UriInfo uriInfo) throws InvoiceApiException {
+                                     @HeaderParam(HDR_COMMENT) final String comment) throws InvoiceApiException {
         final InvoicePayment invoicePayment = invoicePaymentApi.getInvoicePayment(UUID.fromString(json.getPaymentId()));
         if (invoicePayment == null) {
             throw new InvoiceApiException(ErrorCode.INVOICE_PAYMENT_NOT_FOUND, json.getPaymentId());
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestChargeback.java b/server/src/test/java/com/ning/billing/jaxrs/TestChargeback.java
index 0a7dcb2..c20e0fe 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestChargeback.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestChargeback.java
@@ -65,6 +65,7 @@ public class TestChargeback extends TestJaxrsBase {
         response = doGetWithUrl(location, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         verifySingleChargebackResponse(response, input);
 
+
         // Find the chargeback by account
         response = doGet(JaxrsResource.CHARGEBACKS_PATH + "/accounts/" + payment.getAccountId(), DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         verifyCollectionChargebackResponse(response, input);
@@ -74,11 +75,55 @@ public class TestChargeback extends TestJaxrsBase {
         verifyCollectionChargebackResponse(response, input);
     }
 
+
+    @Test(groups = "slow")
+    public void testMultipleChargeback() throws Exception {
+        final PaymentJsonSimple payment = createAccountWithInvoiceAndPayment();
+
+        // We get a 249.95 payment so we do 4 chargeback and then the fifth should fail
+        final ChargebackJson input = new ChargebackJson(null, null, new BigDecimal("50.00"), payment.getPaymentId(), null);
+        final String jsonInput = mapper.writeValueAsString(input);
+
+        //
+        int count = 4;
+        Response response = null;
+        while (count-- > 0) {
+            response = doPost(JaxrsResource.CHARGEBACKS_PATH, jsonInput, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+            assertEquals(response.getStatusCode(), javax.ws.rs.core.Response.Status.CREATED.getStatusCode(), response.getResponseBody());
+        }
+
+        // Last attempt should fail because this is more than the Payment
+        response = doPost(JaxrsResource.CHARGEBACKS_PATH, jsonInput, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), javax.ws.rs.core.Response.Status.BAD_REQUEST.getStatusCode(), response.getResponseBody());
+
+
+        // Find the chargeback by account
+        response = doGet(JaxrsResource.CHARGEBACKS_PATH + "/accounts/" + payment.getAccountId(), DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), javax.ws.rs.core.Response.Status.OK.getStatusCode());
+        ChargebackCollectionJson objFromJson = mapper.readValue(response.getResponseBody(), ChargebackCollectionJson.class);
+        assertEquals(objFromJson.getChargebacks().size(), 4);
+        for (int i = 0; i < objFromJson.getChargebacks().size(); i++) {
+            ChargebackJson chargeBack = objFromJson.getChargebacks().get(i);
+            assertTrue(chargeBack.getChargebackAmount().compareTo(input.getChargebackAmount()) == 0);
+            assertEquals(chargeBack.getPaymentId(), input.getPaymentId());
+        }
+
+        // Find the chargeback by payment
+        response = doGet(JaxrsResource.CHARGEBACKS_PATH + "/payments/" + payment.getPaymentId(), DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), javax.ws.rs.core.Response.Status.OK.getStatusCode());
+        objFromJson = mapper.readValue(response.getResponseBody(), ChargebackCollectionJson.class);
+        assertEquals(objFromJson.getChargebacks().size(), 4);
+
+    }
+
+
     private void verifyCollectionChargebackResponse(final Response response, final ChargebackJson input) throws IOException {
         assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
         final ChargebackCollectionJson objFromJson = mapper.readValue(response.getResponseBody(), ChargebackCollectionJson.class);
         assertEquals(objFromJson.getChargebacks().size(), 1);
-        assertTrue(objFromJson.getChargebacks().get(0).getChargebackAmount().compareTo(input.getChargebackAmount()) == 0);
+        ChargebackJson chargeBack = objFromJson.getChargebacks().get(0);
+        assertTrue(chargeBack.getChargebackAmount().compareTo(input.getChargebackAmount()) == 0);
+        assertEquals(chargeBack.getPaymentId(), input.getPaymentId());
     }
 
     private void verifySingleChargebackResponse(final Response response, final ChargebackJson input) throws IOException {
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 582a384..fc0ddf2 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -101,13 +101,15 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
                 }
             }
         }
+        if (definitionIds.size() > 0) {
+            result.addAll(tagDefinitionSqlDao.getByIds(Collections2.transform(definitionIds, new Function<UUID, String>() {
+                @Override
+                public String apply(UUID input) {
+                    return input.toString();
+                }
 
-        result.addAll(tagDefinitionSqlDao.getByIds(Collections2.transform(definitionIds, new Function<UUID, String>() {
-            @Override
-            public String apply(UUID input) {
-                return input.toString();
-            }
-        })));
+            })));
+        }
         return result;
     }
 
diff --git a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
index cd0e544..e1f4105 100644
--- a/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
+++ b/util/src/test/java/com/ning/billing/util/tag/dao/TestAuditedTagDao.java
@@ -95,6 +95,10 @@ public class TestAuditedTagDao extends UtilTestSuiteWithEmbeddedDB {
 
         final List<UUID> uuids = new ArrayList<UUID>();
 
+        // Check with a empty Collecion first
+        List<TagDefinition> result = tagDefinitionDao.getByIds(uuids);
+        assertEquals(result.size(), 0);
+
         TagDefinition defYo = tagDefinitionDao.create("yo", "defintion yo", context);
         uuids.add(defYo.getId());
         TagDefinition defBah = tagDefinitionDao.create("bah", "defintion bah", context);
@@ -102,7 +106,7 @@ public class TestAuditedTagDao extends UtilTestSuiteWithEmbeddedDB {
         TagDefinition defZoo = tagDefinitionDao.create("zoo", "defintion zoo", context);
         uuids.add(defZoo.getId());
 
-        List<TagDefinition> result = tagDefinitionDao.getByIds(uuids);
+        result = tagDefinitionDao.getByIds(uuids);
         assertEquals(result.size(), 3);
 
         // Add control tag and retry