killbill-memoizeit

Fixes #357

7/22/2015 10:25:46 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java
new file mode 100644
index 0000000..83d65e5
--- /dev/null
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/json/ComboPaymentTransactionJson.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014-2015 Groupon, Inc
+ * Copyright 2014-2015 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.jaxrs.json;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ComboPaymentTransactionJson extends JsonBase {
+
+    private final AccountJson account;
+    private final PaymentMethodJson paymentMethod;
+    private final PaymentTransactionJson transaction;
+
+    @JsonCreator
+    public ComboPaymentTransactionJson(@JsonProperty("account") final AccountJson account,
+                                       @JsonProperty("paymentMethod") final PaymentMethodJson paymentMethod,
+                                       @JsonProperty("transaction") final PaymentTransactionJson transaction,
+                                       @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+        super(auditLogs);
+        this.account = account;
+        this.paymentMethod = paymentMethod;
+        this.transaction = transaction;
+    }
+
+    public AccountJson getAccount() {
+        return account;
+    }
+
+    public PaymentMethodJson getPaymentMethod() {
+        return paymentMethod;
+    }
+
+    public PaymentTransactionJson getTransaction() {
+        return transaction;
+    }
+
+    @Override
+    public String toString() {
+        return "ComboPaymentTransactionJson{" +
+               "account=" + account +
+               ", paymentMethod=" + paymentMethod +
+               ", transaction=" + transaction +
+               '}';
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ComboPaymentTransactionJson)) {
+            return false;
+        }
+
+        final ComboPaymentTransactionJson that = (ComboPaymentTransactionJson) o;
+
+        if (account != null ? !account.equals(that.account) : that.account != null) {
+            return false;
+        }
+        if (paymentMethod != null ? !paymentMethod.equals(that.paymentMethod) : that.paymentMethod != null) {
+            return false;
+        }
+        return !(transaction != null ? !transaction.equals(that.transaction) : that.transaction != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = account != null ? account.hashCode() : 0;
+        result = 31 * result + (paymentMethod != null ? paymentMethod.hashCode() : 0);
+        result = 31 * result + (transaction != null ? transaction.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index 43b3464..11c37c0 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -37,6 +37,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
 import org.killbill.billing.ObjectType;
@@ -44,14 +45,20 @@ import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountUserApi;
 import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.jaxrs.json.AccountJson;
+import org.killbill.billing.jaxrs.json.ComboPaymentTransactionJson;
 import org.killbill.billing.jaxrs.json.PaymentJson;
+import org.killbill.billing.jaxrs.json.PaymentMethodJson;
 import org.killbill.billing.jaxrs.json.PaymentTransactionJson;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
 import org.killbill.billing.payment.api.Payment;
 import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.PaymentMethod;
+import org.killbill.billing.payment.api.PaymentOptions;
 import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.util.api.AuditUserApi;
 import org.killbill.billing.util.api.CustomFieldUserApi;
 import org.killbill.billing.util.api.TagUserApi;
@@ -264,6 +271,57 @@ public class PaymentResource extends JaxRsResourceBase {
     }
 
     @Timed
+    @POST
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @ApiOperation(value = "Combo api to create a new payment transaction on a existing (or not) account ")
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid data for Account or PaymentMethod")})
+    public Response createPayment(final ComboPaymentTransactionJson json,
+                                  @QueryParam(QUERY_PAYMENT_CONTROL_PLUGIN_NAME) final List<String> paymentControlPluginNames,
+                                  @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
+                                  @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,
+                                  @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+
+        verifyNonNullOrEmpty(json, "ComboPaymentTransactionJson body should be specified");
+
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+        final Account account = getOrCreateAccount(json.getAccount(), callContext);
+
+        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
+        final UUID paymentMethodId = getOrCreatePaymentMethod(account, json.getPaymentMethod(), pluginProperties, callContext);
+
+        final PaymentTransactionJson paymentTransactionJson = json.getTransaction();
+        final TransactionType transactionType = TransactionType.valueOf(paymentTransactionJson.getTransactionType());
+        final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
+        final Payment result;
+
+        final UUID paymentId = null; // If we need to specify a paymentId (e.g 3DS authorization, we can use regular API, no need for combo call)
+        switch (transactionType) {
+            case AUTHORIZE:
+                result = paymentApi.createAuthorizationWithPaymentControl(account, paymentMethodId, paymentId, paymentTransactionJson.getAmount(), account.getCurrency(),
+                                                                          paymentTransactionJson.getPaymentExternalKey(), paymentTransactionJson.getTransactionExternalKey(),
+                                                                          pluginProperties, paymentOptions, callContext);
+                break;
+            case PURCHASE:
+                result = paymentApi.createPurchaseWithPaymentControl(account, paymentMethodId, paymentId, paymentTransactionJson.getAmount(), account.getCurrency(),
+                                                                     paymentTransactionJson.getPaymentExternalKey(), paymentTransactionJson.getTransactionExternalKey(),
+                                                                     pluginProperties, paymentOptions, callContext);
+                break;
+            case CREDIT:
+                result = paymentApi.createCreditWithPaymentControl(account, paymentMethodId, paymentId, paymentTransactionJson.getAmount(), account.getCurrency(),
+                                                                   paymentTransactionJson.getPaymentExternalKey(), paymentTransactionJson.getTransactionExternalKey(),
+                                                                   pluginProperties, paymentOptions, callContext);
+                break;
+            default:
+                return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
+        }
+        return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", result.getId());
+    }
+
+    @Timed
     @DELETE
     @Path("/{paymentId:" + UUID_PATTERN + "}/")
     @Consumes(APPLICATION_JSON)
@@ -328,4 +386,43 @@ public class PaymentResource extends JaxRsResourceBase {
         return ObjectType.PAYMENT;
     }
 
+    private Account getOrCreateAccount(final AccountJson accountJson, final CallContext callContext) throws AccountApiException {
+        // Attempt to retrieve by accountId if specified
+        if (accountJson.getAccountId() != null) {
+            try {
+                return accountUserApi.getAccountById(UUID.fromString(accountJson.getAccountId()), callContext);
+            } catch (AccountApiException ignore) {
+            }
+        }
+
+        verifyNonNullOrEmpty(accountJson.getExternalKey(), "Account externalKey should be specified");
+        try {
+            // Attempt to retrieve by account externalKey
+            return accountUserApi.getAccountByKey(accountJson.getExternalKey(), callContext);
+        } catch (AccountApiException ignore) {
+        }
+        // Finally create if does not exist
+        return accountUserApi.createAccount(accountJson.toAccountData(), callContext);
+    }
+
+    private UUID getOrCreatePaymentMethod(final Account account, final PaymentMethodJson paymentMethodJson, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) throws PaymentApiException {
+        // Attempt to retrieve by paymentMethodId if specified
+        if (paymentMethodJson.getPaymentMethodId() != null) {
+            try {
+                return paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodJson.getPaymentMethodId()), false, false, pluginProperties, callContext).getId();
+            } catch (PaymentApiException ignore) {
+            }
+        }
+
+        verifyNonNullOrEmpty(paymentMethodJson.getExternalKey(), "PaymentMethod externalKey should be specified");
+        try {
+            // Attempt to retrieve by paymentMethod externalKey
+            return paymentApi.getPaymentMethodByExternalKey(paymentMethodJson.getExternalKey(), false, false, pluginProperties, callContext).getId();
+        } catch (PaymentApiException ignore) {
+        }
+        final PaymentMethod paymentData = paymentMethodJson.toPaymentMethod(account.getId().toString());
+        // Finally create if does not exist
+        return paymentApi.addPaymentMethod(account, paymentMethodJson.getExternalKey(), paymentMethodJson.getPluginName(), paymentMethodJson.isDefault(),
+                                           paymentData.getPluginDetail(), pluginProperties, callContext);
+    }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 1c11ac8..a885e76 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -24,16 +24,17 @@ import javax.annotation.Nullable;
 
 import org.killbill.billing.client.KillBillClientException;
 import org.killbill.billing.client.model.Account;
-import org.killbill.billing.client.model.InvoicePayments;
+import org.killbill.billing.client.model.ComboPaymentTransaction;
 import org.killbill.billing.client.model.Payment;
 import org.killbill.billing.client.model.PaymentMethod;
 import org.killbill.billing.client.model.PaymentMethodPluginDetail;
-import org.killbill.billing.client.model.Payments;
 import org.killbill.billing.client.model.PaymentTransaction;
+import org.killbill.billing.client.model.Payments;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
 
 public class TestPayment extends TestJaxrsBase {
 
@@ -47,6 +48,32 @@ public class TestPayment extends TestJaxrsBase {
         testCreateRetrievePayment(account, nonDefaultPaymentMethod.getPaymentMethodId(), UUID.randomUUID().toString(), 2);
     }
 
+    @Test(groups = "slow")
+    public void testComboAuthorization() throws Exception {
+        final Account accountJson = getAccount();
+        final PaymentMethodPluginDetail info = new PaymentMethodPluginDetail();
+        info.setProperties(null);
+
+        final String paymentMethodExternalKey = UUID.randomUUID().toString();
+        final PaymentMethod paymentMethodJson = new PaymentMethod(null, paymentMethodExternalKey, null, true, PLUGIN_NAME, info);
+
+        final String paymentExternalKey = UUID.randomUUID().toString();
+        final String authTransactionExternalKey = UUID.randomUUID().toString();
+        final PaymentTransaction authTransactionJson = new PaymentTransaction();
+        authTransactionJson.setAmount(BigDecimal.TEN);
+        authTransactionJson.setCurrency(accountJson.getCurrency());
+        authTransactionJson.setPaymentExternalKey(paymentExternalKey);
+        authTransactionJson.setTransactionExternalKey(authTransactionExternalKey);
+        authTransactionJson.setTransactionType("AUTHORIZE");
+
+        final ComboPaymentTransaction comboPaymentTransaction = new ComboPaymentTransaction(accountJson, paymentMethodJson, authTransactionJson);
+
+        final Payment payment = killBillClient.createPayment(comboPaymentTransaction, ImmutableMap.<String, String>of(), createdBy, reason, comment);
+        verifyComboPayment(payment, paymentExternalKey,
+                      BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, 1);
+
+    }
+
     public void testCreateRetrievePayment(final Account account, @Nullable final UUID paymentMethodId,
                                           final String PaymentExternalKey, final int PaymentNb) throws Exception {
         // Authorization
@@ -59,7 +86,7 @@ public class TestPayment extends TestJaxrsBase {
         authTransaction.setTransactionType("AUTHORIZE");
         final Payment authPayment = killBillClient.createPayment(account.getAccountId(), paymentMethodId, authTransaction, createdBy, reason, comment);
         verifyPayment(account, paymentMethodId, authPayment, PaymentExternalKey, authTransactionExternalKey,
-                            BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, PaymentNb);
+                      BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, 1, PaymentNb);
 
         // Capture 1
         final String capture1TransactionExternalKey = UUID.randomUUID().toString();
@@ -71,20 +98,20 @@ public class TestPayment extends TestJaxrsBase {
         captureTransaction.setTransactionExternalKey(capture1TransactionExternalKey);
         final Payment capturedPayment1 = killBillClient.captureAuthorization(captureTransaction, createdBy, reason, comment);
         verifyPayment(account, paymentMethodId, capturedPayment1, PaymentExternalKey, authTransactionExternalKey,
-                            BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ZERO, 2, PaymentNb);
+                      BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ZERO, 2, PaymentNb);
         verifyPaymentTransaction(authPayment.getPaymentId(), capturedPayment1.getTransactions().get(1),
-                                       PaymentExternalKey, capture1TransactionExternalKey,
-                                       account, captureTransaction.getAmount(), "CAPTURE");
+                                 PaymentExternalKey, capture1TransactionExternalKey,
+                                 account, captureTransaction.getAmount(), "CAPTURE");
 
         // Capture 2
         final String capture2TransactionExternalKey = UUID.randomUUID().toString();
         captureTransaction.setTransactionExternalKey(capture2TransactionExternalKey);
         final Payment capturedPayment2 = killBillClient.captureAuthorization(captureTransaction, createdBy, reason, comment);
         verifyPayment(account, paymentMethodId, capturedPayment2, PaymentExternalKey, authTransactionExternalKey,
-                            BigDecimal.TEN, new BigDecimal("2"), BigDecimal.ZERO, 3, PaymentNb);
+                      BigDecimal.TEN, new BigDecimal("2"), BigDecimal.ZERO, 3, PaymentNb);
         verifyPaymentTransaction(authPayment.getPaymentId(), capturedPayment2.getTransactions().get(2),
-                                       PaymentExternalKey, capture2TransactionExternalKey,
-                                       account, captureTransaction.getAmount(), "CAPTURE");
+                                 PaymentExternalKey, capture2TransactionExternalKey,
+                                 account, captureTransaction.getAmount(), "CAPTURE");
 
         // Refund
         final String refundTransactionExternalKey = UUID.randomUUID().toString();
@@ -96,16 +123,16 @@ public class TestPayment extends TestJaxrsBase {
         refundTransaction.setTransactionExternalKey(refundTransactionExternalKey);
         final Payment refundPayment = killBillClient.refundPayment(refundTransaction, createdBy, reason, comment);
         verifyPayment(account, paymentMethodId, refundPayment, PaymentExternalKey, authTransactionExternalKey,
-                            BigDecimal.TEN, new BigDecimal("2"), new BigDecimal("2"), 4, PaymentNb);
+                      BigDecimal.TEN, new BigDecimal("2"), new BigDecimal("2"), 4, PaymentNb);
         verifyPaymentTransaction(authPayment.getPaymentId(), refundPayment.getTransactions().get(3),
-                                       PaymentExternalKey, refundTransactionExternalKey,
-                                       account, refundTransaction.getAmount(), "REFUND");
+                                 PaymentExternalKey, refundTransactionExternalKey,
+                                 account, refundTransaction.getAmount(), "REFUND");
     }
 
     private void verifyPayment(final Account account, @Nullable final UUID paymentMethodId, final Payment Payment,
-                                     final String PaymentExternalKey, final String authTransactionExternalKey,
-                                     final BigDecimal authAmount, final BigDecimal capturedAmount,
-                                     final BigDecimal refundedAmount, final int nbTransactions, final int PaymentNb) throws KillBillClientException {
+                               final String PaymentExternalKey, final String authTransactionExternalKey,
+                               final BigDecimal authAmount, final BigDecimal capturedAmount,
+                               final BigDecimal refundedAmount, final int nbTransactions, final int PaymentNb) throws KillBillClientException {
         Assert.assertEquals(Payment.getAccountId(), account.getAccountId());
         Assert.assertEquals(Payment.getPaymentMethodId(), Objects.firstNonNull(paymentMethodId, account.getPaymentMethodId()));
         Assert.assertNotNull(Payment.getPaymentId());
@@ -118,7 +145,7 @@ public class TestPayment extends TestJaxrsBase {
         Assert.assertEquals(Payment.getTransactions().size(), nbTransactions);
 
         verifyPaymentTransaction(Payment.getPaymentId(), Payment.getTransactions().get(0),
-                                       PaymentExternalKey, authTransactionExternalKey, account, authAmount, "AUTHORIZE");
+                                 PaymentExternalKey, authTransactionExternalKey, account, authAmount, "AUTHORIZE");
 
         final Payments Payments = killBillClient.getPayments();
         Assert.assertEquals(Payments.size(), PaymentNb);
@@ -132,9 +159,31 @@ public class TestPayment extends TestJaxrsBase {
         Assert.assertEquals(paymentsForAccount.get(PaymentNb - 1), Payment);
     }
 
+    private void verifyComboPayment(final Payment Payment,
+                                    final String paymentExternalKey,
+                                    final BigDecimal authAmount,
+                                    final BigDecimal capturedAmount,
+                                    final BigDecimal refundedAmount,
+                                    final int nbTransactions,
+                                    final int PaymentNb) throws KillBillClientException {
+
+        Assert.assertNotNull(Payment.getPaymentId());
+        Assert.assertNotNull(Payment.getPaymentNumber());
+        Assert.assertEquals(Payment.getPaymentExternalKey(), paymentExternalKey);
+        Assert.assertEquals(Payment.getAuthAmount().compareTo(authAmount), 0);
+        Assert.assertEquals(Payment.getCapturedAmount().compareTo(capturedAmount), 0);
+        Assert.assertEquals(Payment.getRefundedAmount().compareTo(refundedAmount), 0);
+        Assert.assertEquals(Payment.getTransactions().size(), nbTransactions);
+
+        final Payments Payments = killBillClient.getPayments();
+        Assert.assertEquals(Payments.size(), PaymentNb);
+        Assert.assertEquals(Payments.get(PaymentNb - 1), Payment);
+
+    }
+
     private void verifyPaymentTransaction(final UUID PaymentId, final PaymentTransaction PaymentTransaction,
-                                                final String PaymentExternalKey, final String TransactionExternalKey,
-                                                final Account account, @Nullable final BigDecimal amount, final String transactionType) {
+                                          final String PaymentExternalKey, final String TransactionExternalKey,
+                                          final Account account, @Nullable final BigDecimal amount, final String transactionType) {
         Assert.assertEquals(PaymentTransaction.getPaymentId(), PaymentId);
         Assert.assertNotNull(PaymentTransaction.getTransactionId());
         Assert.assertEquals(PaymentTransaction.getTransactionType(), transactionType);