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