killbill-memoizeit
Changes
payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java 2(+1 -1)
payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlInitiated.java 71(+54 -17)
Details
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultAdminPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultAdminPaymentApi.java
index a256c61..7b57166 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultAdminPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultAdminPaymentApi.java
@@ -17,8 +17,6 @@
package org.killbill.billing.payment.api;
-import java.util.UUID;
-
import javax.annotation.Nullable;
import javax.inject.Inject;
@@ -51,9 +49,9 @@ public class DefaultAdminPaymentApi implements AdminPaymentApi {
throws PaymentApiException {
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(payment.getAccountId(), callContext);
- paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), payment.getId(), paymentTransaction.getTransactionType(),
- currentPaymentStateName, lastSuccessPaymentState, paymentTransaction.getId(),
- transactionStatus, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(),
- paymentTransaction.getGatewayErrorCode(), paymentTransaction.getGatewayErrorMsg(), internalCallContext);
+ paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), null, payment.getId(), paymentTransaction.getTransactionType(),
+ currentPaymentStateName, lastSuccessPaymentState, paymentTransaction.getId(),
+ transactionStatus, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(),
+ paymentTransaction.getGatewayErrorCode(), paymentTransaction.getGatewayErrorMsg(), internalCallContext);
}
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
index 29a722e..592dcd5 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/janitor/IncompletePaymentTransactionTask.java
@@ -241,7 +241,7 @@ public class IncompletePaymentTransactionTask extends CompletionTaskBase<Payment
payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionStatus(), transactionStatus);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(payment.getAccountId(), callContext);
- paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, lastSuccessPaymentState,
+ paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), paymentTransaction.getAttemptId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, lastSuccessPaymentState,
paymentTransaction.getId(), transactionStatus, processedAmount, processedCurrency, gatewayErrorCode, gatewayError, internalCallContext);
return true;
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlInitiated.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlInitiated.java
index 9a87984..fe13f20 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlInitiated.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/control/DefaultControlInitiated.java
@@ -17,11 +17,14 @@
package org.killbill.billing.payment.core.sm.control;
+import java.util.List;
+
import org.joda.time.DateTime;
import org.killbill.automaton.OperationException;
import org.killbill.automaton.State;
import org.killbill.automaton.State.LeavingStateCallback;
import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.core.sm.PaymentStateContext;
import org.killbill.billing.payment.core.sm.PluginControlPaymentAutomatonRunner;
@@ -38,6 +41,10 @@ import com.google.common.collect.ImmutableList;
public class DefaultControlInitiated implements LeavingStateCallback {
+ private static final ImmutableList<TransactionStatus> TRANSIENT_TRANSACTION_STATUSES = ImmutableList.<TransactionStatus>builder().add(TransactionStatus.PENDING)
+ .add(TransactionStatus.UNKNOWN)
+ .build();
+
private final PluginControlPaymentAutomatonRunner pluginControlPaymentAutomatonRunner;
private final PaymentStateControlContext stateContext;
private final State initialState;
@@ -59,6 +66,31 @@ public class DefaultControlInitiated implements LeavingStateCallback {
public void leavingState(final State state) throws OperationException {
final DateTime utcNow = pluginControlPaymentAutomatonRunner.getClock().getUTCNow();
+ // Retrieve the associated payment transaction, if any
+ PaymentTransactionModelDao paymentTransactionModelDaoCandidate = null;
+ if (stateContext.getTransactionId() != null) {
+ paymentTransactionModelDaoCandidate = paymentDao.getPaymentTransaction(stateContext.getTransactionId(), stateContext.getInternalCallContext());
+ Preconditions.checkNotNull(paymentTransactionModelDaoCandidate, "paymentTransaction cannot be null for id " + stateContext.getTransactionId());
+ } else if (stateContext.getPaymentTransactionExternalKey() != null) {
+ final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getPaymentTransactionsByExternalKey(stateContext.getPaymentTransactionExternalKey(), stateContext.getInternalCallContext());
+ if (!paymentTransactionModelDaos.isEmpty()) {
+ paymentTransactionModelDaoCandidate = paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1);
+ }
+ } else if (stateContext.getPaymentId() != null) {
+ final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getTransactionsForPayment(stateContext.getPaymentId(), stateContext.getInternalCallContext());
+ Preconditions.checkArgument(!paymentTransactionModelDaos.isEmpty(), "paymentTransactions cannot be empty for id " + stateContext.getPaymentId());
+ paymentTransactionModelDaoCandidate = paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1);
+ } else if (stateContext.getPaymentExternalKey() != null) {
+ final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(stateContext.getPaymentExternalKey(), stateContext.getInternalCallContext());
+ if (payment != null) {
+ final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getTransactionsForPayment(payment.getId(), stateContext.getInternalCallContext());
+ if (!paymentTransactionModelDaos.isEmpty()) {
+ paymentTransactionModelDaoCandidate = paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1);
+ }
+ }
+ }
+ final PaymentTransactionModelDao paymentTransactionModelDao = paymentTransactionModelDaoCandidate != null && TRANSIENT_TRANSACTION_STATUSES.contains(paymentTransactionModelDaoCandidate.getTransactionStatus()) ? paymentTransactionModelDaoCandidate : null;
+
if (stateContext.getPaymentId() != null && stateContext.getPaymentExternalKey() == null) {
final PaymentModelDao payment = paymentDao.getPayment(stateContext.getPaymentId(), stateContext.getInternalCallContext());
Preconditions.checkNotNull(payment, "payment cannot be null for id " + stateContext.getPaymentId());
@@ -67,9 +99,8 @@ public class DefaultControlInitiated implements LeavingStateCallback {
} else if (stateContext.getPaymentExternalKey() == null) {
stateContext.setPaymentExternalKey(UUIDs.randomUUID().toString());
}
- if (stateContext.getTransactionId() != null && stateContext.getPaymentTransactionExternalKey() == null) {
- final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(stateContext.getTransactionId(), stateContext.getInternalCallContext());
- Preconditions.checkNotNull(paymentTransactionModelDao, "paymentTransaction cannot be null for id " + stateContext.getTransactionId());
+
+ if (paymentTransactionModelDao != null) {
stateContext.setPaymentTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey());
} else if (stateContext.getPaymentTransactionExternalKey() == null) {
stateContext.setPaymentTransactionExternalKey(UUIDs.randomUUID().toString());
@@ -82,20 +113,26 @@ public class DefaultControlInitiated implements LeavingStateCallback {
if (state.getName().equals(initialState.getName()) || state.getName().equals(retriedState.getName())) {
try {
- //
- // We don't serialize any properties at this stage to avoid serializing sensitive information.
- // However, if after going through the control plugins, the attempt end up in RETRIED state,
- // the properties will be serialized in the enteringState callback (any plugin that sets a
- // retried date is responsible to correctly remove sensitive information such as CVV, ...)
- //
- final byte[] serializedProperties = PluginPropertySerializer.serialize(ImmutableList.<PluginProperty>of());
- final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(stateContext.getAccount().getId(), stateContext.getPaymentMethodId(),
- utcNow, utcNow, stateContext.getPaymentExternalKey(), stateContext.getTransactionId(),
- stateContext.getPaymentTransactionExternalKey(), transactionType, initialState.getName(),
- stateContext.getAmount(), stateContext.getCurrency(),
- stateContext.getPaymentControlPluginNames(), serializedProperties);
-
- pluginControlPaymentAutomatonRunner.getPaymentDao().insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext());
+ final PaymentAttemptModelDao attempt;
+ if (paymentTransactionModelDao != null && paymentTransactionModelDao.getAttemptId() != null) {
+ attempt = pluginControlPaymentAutomatonRunner.getPaymentDao().getPaymentAttempt(paymentTransactionModelDao.getAttemptId(), stateContext.getInternalCallContext());
+ Preconditions.checkNotNull(attempt, "attempt cannot be null for id " + paymentTransactionModelDao.getAttemptId());
+ } else {
+ //
+ // We don't serialize any properties at this stage to avoid serializing sensitive information.
+ // However, if after going through the control plugins, the attempt end up in RETRIED state,
+ // the properties will be serialized in the enteringState callback (any plugin that sets a
+ // retried date is responsible to correctly remove sensitive information such as CVV, ...)
+ //
+ final byte[] serializedProperties = PluginPropertySerializer.serialize(ImmutableList.<PluginProperty>of());
+
+ attempt = new PaymentAttemptModelDao(stateContext.getAccount().getId(), stateContext.getPaymentMethodId(),
+ utcNow, utcNow, stateContext.getPaymentExternalKey(), stateContext.getTransactionId(),
+ stateContext.getPaymentTransactionExternalKey(), transactionType, initialState.getName(),
+ stateContext.getAmount(), stateContext.getCurrency(),
+ stateContext.getPaymentControlPluginNames(), serializedProperties);
+ pluginControlPaymentAutomatonRunner.getPaymentDao().insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext());
+ }
stateContext.setAttemptId(attempt.getId());
} catch (final PluginPropertySerializerException e) {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
index c6545dc..6800bbe 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentAutomatonDAOHelper.java
@@ -128,6 +128,7 @@ public class PaymentAutomatonDAOHelper {
final String lastSuccessPaymentState = paymentSMHelper.isSuccessState(currentPaymentStateName) ? currentPaymentStateName : null;
paymentDao.updatePaymentAndTransactionOnCompletion(paymentStateContext.getAccount().getId(),
+ paymentStateContext.getAttemptId(),
paymentStateContext.getPaymentId(),
paymentStateContext.getTransactionType(),
currentPaymentStateName,
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
index 3be74e7..0e67704 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
@@ -297,7 +297,7 @@ public class DefaultPaymentDao implements PaymentDao {
}
@Override
- public void updatePaymentAndTransactionOnCompletion(final UUID accountId, final UUID paymentId, final TransactionType transactionType,
+ public void updatePaymentAndTransactionOnCompletion(final UUID accountId, @Nullable final UUID attemptId, final UUID paymentId, final TransactionType transactionType,
final String currentPaymentStateName, @Nullable final String lastPaymentSuccessStateName,
final UUID transactionId, final TransactionStatus transactionStatus,
final BigDecimal processedAmount, final Currency processedCurrency,
@@ -308,10 +308,16 @@ public class DefaultPaymentDao implements PaymentDao {
@Override
public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
final InternalCallContext contextWithUpdatedDate = contextWithUpdatedDate(context);
- entitySqlDaoWrapperFactory.become(TransactionSqlDao.class).updateTransactionStatus(transactionId.toString(),
- processedAmount, processedCurrency == null ? null : processedCurrency.toString(),
- transactionStatus == null ? null : transactionStatus.toString(),
- gatewayErrorCode, gatewayErrorMsg, contextWithUpdatedDate);
+ final TransactionSqlDao transactional = entitySqlDaoWrapperFactory.become(TransactionSqlDao.class);
+ final PaymentTransactionModelDao paymentTransactionModelDao = transactional.getById(transactionId.toString(), context);
+ transactional.updateTransactionStatus(transactionId.toString(),
+ attemptId == null ? (paymentTransactionModelDao.getAttemptId() == null ? null : paymentTransactionModelDao.getAttemptId().toString()) : attemptId.toString(),
+ processedAmount,
+ processedCurrency == null ? null : processedCurrency.toString(),
+ transactionStatus == null ? null : transactionStatus.toString(),
+ gatewayErrorCode,
+ gatewayErrorMsg,
+ contextWithUpdatedDate);
if (lastPaymentSuccessStateName != null) {
entitySqlDaoWrapperFactory.become(PaymentSqlDao.class).updateLastSuccessPaymentStateName(paymentId.toString(), currentPaymentStateName, lastPaymentSuccessStateName, contextWithUpdatedDate);
} else {
@@ -321,7 +327,6 @@ public class DefaultPaymentDao implements PaymentDao {
return null;
}
});
-
}
@Override
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
index 4c3eeee..dc1f8f7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
@@ -56,7 +56,7 @@ public interface PaymentDao {
public PaymentTransactionModelDao updatePaymentWithNewTransaction(UUID paymentId, PaymentTransactionModelDao paymentTransaction, InternalCallContext context);
- public void updatePaymentAndTransactionOnCompletion(UUID accountId, UUID paymentId, TransactionType transactionType, String currentPaymentStateName, String lastPaymentSuccessStateName, UUID transactionId,
+ public void updatePaymentAndTransactionOnCompletion(UUID accountId, UUID attemptId, UUID paymentId, TransactionType transactionType, String currentPaymentStateName, String lastPaymentSuccessStateName, UUID transactionId,
TransactionStatus paymentStatus, BigDecimal processedAmount, Currency processedCurrency,
String gatewayErrorCode, String gatewayErrorMsg, InternalCallContext context);
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
index d31d589..d85ac3a 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/TransactionSqlDao.java
@@ -1,5 +1,6 @@
/*
- * Copyright 2014 Groupon, Inc
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 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
@@ -41,6 +42,7 @@ public interface TransactionSqlDao extends EntitySqlDao<PaymentTransactionModelD
@SqlUpdate
@Audited(ChangeType.UPDATE)
void updateTransactionStatus(@Bind("id") final String transactionId,
+ @Bind("attemptId") final String attemptId,
@Bind("processedAmount") final BigDecimal processedAmount,
@Bind("processedCurrency") final String processedCurrency,
@Bind("transactionStatus") final String transactionStatus,
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
index 3a91dc9..c00aee0 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/TransactionSqlDao.sql.stg
@@ -60,6 +60,7 @@ where transaction_external_key = :transactionExternalKey
updateTransactionStatus() ::= <<
update <tableName()>
set transaction_status = :transactionStatus
+, attempt_id = :attemptId
, processed_amount = :processedAmount
, processed_currency = :processedCurrency
, gateway_error_code = :gatewayErrorCode
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
index a00a2c2..c9aadbe 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApi.java
@@ -1359,7 +1359,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
// Update the payment/transaction by hand to simulate a PENDING state.
final PaymentTransaction paymentTransaction = initialPayment.getTransactions().get(0);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), initialPayment.getId(), TransactionType.AUTHORIZE, "AUTH_PENDING", "AUTH_PENDING",
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, initialPayment.getId(), TransactionType.AUTHORIZE, "AUTH_PENDING", "AUTH_PENDING",
paymentTransaction.getId(), TransactionStatus.PENDING, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(),
null, null, internalCallContext);
@@ -1435,7 +1435,7 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
ImmutableList.<PluginProperty>of(), callContext);
// Hack the Database to make it look like it was a failure
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, "AUTH_ERRORED", null,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, "AUTH_ERRORED", null,
payment.getTransactions().get(0).getId(), TransactionStatus.PLUGIN_FAILURE, null, null, null, null, internalCallContext);
final PaymentSqlDao paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
paymentSqlDao.updateLastSuccessPaymentStateName(payment.getId().toString(), "AUTH_ERRORED", null, internalCallContext);
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
index acb1be0..be3d8d8 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestPaymentApiWithControl.java
@@ -32,11 +32,15 @@ import org.killbill.billing.control.plugin.api.PriorPaymentControlResult;
import org.killbill.billing.osgi.api.OSGIServiceDescriptor;
import org.killbill.billing.osgi.api.OSGIServiceRegistration;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
+import org.killbill.billing.payment.plugin.api.PaymentPluginStatus;
import org.killbill.billing.payment.provider.DefaultNoOpPaymentMethodPlugin;
import org.killbill.billing.payment.provider.MockPaymentProviderPlugin;
import org.killbill.billing.payment.retry.DefaultFailureCallResult;
import org.killbill.billing.payment.retry.DefaultOnSuccessPaymentControlResult;
+import org.killbill.commons.request.Request;
+import org.killbill.commons.request.RequestData;
import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -86,6 +90,14 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
}
},
testPaymentControlPluginApi);
+
+ // Required for re-entrant locks to work
+ Request.setPerThreadRequestData(new RequestData(UUID.randomUUID().toString()));
+ }
+
+ @AfterMethod(groups = "slow")
+ public void tearDown() throws Exception {
+ Request.resetPerThreadRequestData();
}
// Verify Payment control API can be used to change the paymentMethodId on the fly and this is reflected in the created Payment.
@@ -101,6 +113,66 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
}
@Test(groups = "slow")
+ public void testCreateAuthPendingWithControlCompleteWithControl() throws PaymentApiException {
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+ final Iterable<PluginProperty> pendingPluginProperties = ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.PENDING, false));
+
+ Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(), pendingPluginProperties, PAYMENT_OPTIONS, callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNotNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+
+ payment = paymentApi.createAuthorizationWithPaymentControl(account, payment.getPaymentMethodId(), payment.getId(), requestedAmount, payment.getCurrency(), payment.getExternalKey(),
+ payment.getTransactions().get(0).getExternalKey(), ImmutableList.<PluginProperty>of(), PAYMENT_OPTIONS, callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(requestedAmount), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNotNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+ }
+
+ @Test(groups = "slow")
+ public void testCreateAuthPendingWithControlCompleteNoControl() throws PaymentApiException {
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+ final Iterable<PluginProperty> pendingPluginProperties = ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.PENDING, false));
+
+ Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(), pendingPluginProperties, PAYMENT_OPTIONS, callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNotNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+
+ payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), payment.getId(), requestedAmount, payment.getCurrency(), payment.getExternalKey(),
+ payment.getTransactions().get(0).getExternalKey(), ImmutableList.<PluginProperty>of(), callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(requestedAmount), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNotNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+ }
+
+ @Test(groups = "slow")
+ public void testCreateAuthPendingNoControlCompleteWithControl() throws PaymentApiException {
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+ final Iterable<PluginProperty> pendingPluginProperties = ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.PENDING, false));
+
+ Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, requestedAmount, Currency.USD, UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(), pendingPluginProperties, callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+
+ payment = paymentApi.createAuthorizationWithPaymentControl(account, payment.getPaymentMethodId(), payment.getId(), requestedAmount, payment.getCurrency(), payment.getExternalKey(),
+ payment.getTransactions().get(0).getExternalKey(), ImmutableList.<PluginProperty>of(), PAYMENT_OPTIONS, callContext);
+ Assert.assertEquals(payment.getAuthAmount().compareTo(requestedAmount), 0);
+ Assert.assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+ Assert.assertEquals(payment.getTransactions().size(), 1);
+ Assert.assertNotNull(((DefaultPaymentTransaction) payment.getTransactions().get(0)).getAttemptId());
+ }
+
+ @Test(groups = "slow")
public void testCreateAuthWithControlCaptureNoControl() throws PaymentApiException {
final BigDecimal requestedAmount = BigDecimal.TEN;
@@ -174,7 +246,7 @@ public class TestPaymentApiWithControl extends PaymentTestSuiteWithEmbeddedDB {
@Override
public Iterable<PluginProperty> getAdjustedPluginProperties() {
- return ImmutableList.of();
+ return null;
}
};
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
index 106c179..ffb44d2 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
@@ -98,7 +98,7 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
Assert.assertEquals(transactions.size(), 1);
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.CAPTURE).toString();
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), paymentId, TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), transactions.get(0).getAttemptId(), paymentId, TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
transactions.get(0).getId(), TransactionStatus.SUCCESS, BigDecimal.ONE, Currency.BRL,
"foo", "bar", internalCallContext);
@@ -117,7 +117,7 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
Assert.assertEquals(transactions.size(), 1);
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.CAPTURE).toString();
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), paymentId, TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), transactions.get(0).getAttemptId(), paymentId, TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
transactions.get(0).getId(), TransactionStatus.SUCCESS, BigDecimal.ONE, Currency.BRL,
"foo", "bar", internalCallContext);
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
index 3f314c8..0798535 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
@@ -221,7 +221,7 @@ public class MockPaymentDao implements PaymentDao {
}
@Override
- public void updatePaymentAndTransactionOnCompletion(final UUID accountId, final UUID paymentId, final TransactionType transactionType,
+ public void updatePaymentAndTransactionOnCompletion(final UUID accountId, final UUID attemptId, final UUID paymentId, final TransactionType transactionType,
final String currentPaymentStateName, final String lastSuccessPaymentStateName, final UUID transactionId,
final TransactionStatus paymentStatus, final BigDecimal processedAmount, final Currency processedCurrency,
final String gatewayErrorCode, final String gatewayErrorMsg, final InternalCallContext context) {
@@ -232,6 +232,7 @@ public class MockPaymentDao implements PaymentDao {
}
final PaymentTransactionModelDao transaction = transactions.get(transactionId);
if (transaction != null) {
+ transaction.setAttemptId(attemptId);
transaction.setTransactionStatus(paymentStatus);
transaction.setProcessedAmount(processedAmount);
transaction.setProcessedCurrency(processedCurrency);
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
index ac1860e..2c93d7f 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
@@ -65,6 +65,7 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final String gatewayErrorCode = UUID.randomUUID().toString().substring(0, 5);
final String gatewayErrorMsg = UUID.randomUUID().toString();
paymentDao.updatePaymentAndTransactionOnCompletion(accountId,
+ specifiedSecondPaymentTransactionModelDao.getAttemptId(),
specifiedSecondPaymentTransactionModelDao.getPaymentId(),
specifiedFirstPaymentTransactionModelDao.getTransactionType(),
"SOME_ERRORED_STATE",
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index 878ee98..e988651 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -169,7 +169,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(savedPayment.getId(), internalCallContext);
assertEquals(transactions.size(), 2);
- paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", "AUTH_SUCCESS", transactionModelDao2.getId(), TransactionStatus.SUCCESS,
+ paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedTransactionModelDao2.getAttemptId(), savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", "AUTH_SUCCESS", transactionModelDao2.getId(), TransactionStatus.SUCCESS,
BigDecimal.ONE, Currency.USD, null, "nothing", internalCallContext);
final PaymentModelDao savedPayment4 = paymentDao.getPayment(savedPayment.getId(), internalCallContext);
@@ -192,7 +192,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertNull(savedTransactionModelDao4.getGatewayErrorCode());
assertEquals(savedTransactionModelDao4.getGatewayErrorMsg(), "nothing");
- paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", null, transactionModelDao2.getId(), TransactionStatus.SUCCESS,
+ paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedTransactionModelDao2.getAttemptId(), savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", null, transactionModelDao2.getId(), TransactionStatus.SUCCESS,
BigDecimal.ONE, Currency.USD, null, "nothing", internalCallContext);
final PaymentModelDao savedPayment4Again = paymentDao.getPayment(savedPayment.getId(), internalCallContext);
@@ -200,7 +200,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(savedPayment4Again.getStateName(), "AUTH_ABORTED");
assertEquals(savedPayment4Again.getLastSuccessStateName(), "AUTH_SUCCESS");
- paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", "AUTH_SUCCESS", transactionModelDao2.getId(), TransactionStatus.SUCCESS,
+ paymentDao.updatePaymentAndTransactionOnCompletion(accountId, savedTransactionModelDao2.getAttemptId(), savedPayment.getId(), savedTransactionModelDao2.getTransactionType(), "AUTH_ABORTED", "AUTH_SUCCESS", transactionModelDao2.getId(), TransactionStatus.SUCCESS,
BigDecimal.ONE, Currency.USD, null, "nothing", internalCallContext);
final PaymentModelDao savedPayment4Final = paymentDao.getPayment(savedPayment.getId(), internalCallContext);
@@ -304,7 +304,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final Iterable<PaymentTransactionModelDao> transactions1 = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.PENDING), newTime, initialTime, 0L, 3L);
for (PaymentTransactionModelDao paymentTransaction : transactions1) {
final String newPaymentState = "XXX_FAILED";
- paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, payment.getLastSuccessStateName(),
+ paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), paymentTransaction.getAttemptId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, payment.getLastSuccessStateName(),
paymentTransaction.getId(), TransactionStatus.PAYMENT_FAILURE, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(),
paymentTransaction.getGatewayErrorCode(), paymentTransaction.getGatewayErrorMsg(), internalCallContext);
}
@@ -322,7 +322,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
final Iterable<PaymentTransactionModelDao> transactions2 = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.PENDING), clock.getUTCNow(), initialTime, 0L, 1L);
for (PaymentTransactionModelDao paymentTransaction : transactions2) {
final String newPaymentState = "XXX_FAILED";
- paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, payment.getLastSuccessStateName(),
+ paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), paymentTransaction.getAttemptId(), payment.getId(), paymentTransaction.getTransactionType(), newPaymentState, payment.getLastSuccessStateName(),
paymentTransaction.getId(), TransactionStatus.PAYMENT_FAILURE, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(),
paymentTransaction.getGatewayErrorCode(), paymentTransaction.getGatewayErrorMsg(), internalCallContext);
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
index ccf0a1c..982e35f 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestJanitor.java
@@ -290,7 +290,7 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
// Artificially move the transaction status to UNKNOWN
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
payment.getTransactions().get(0).getId(), TransactionStatus.UNKNOWN, requestedAmount, account.getCurrency(),
"foo", "bar", internalCallContext);
testListener.assertListenerStatus();
@@ -322,7 +322,7 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
// Artificially move the transaction status to UNKNOWN
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
payment.getTransactions().get(0).getId(), TransactionStatus.UNKNOWN, requestedAmount, account.getCurrency(),
"foo", "bar", internalCallContext);
testListener.assertListenerStatus();
@@ -367,7 +367,7 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
// Artificially move the transaction status to UNKNOWN
final String paymentStateName = paymentSMHelper.getErroredStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT_PLUGIN_ERROR);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
payment.getTransactions().get(0).getId(), TransactionStatus.UNKNOWN, requestedAmount, account.getCurrency(),
"foo", "bar", internalCallContext);
testListener.assertListenerStatus();
@@ -400,7 +400,7 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
// Artificially move the transaction status to PENDING
final String paymentStateName = paymentSMHelper.getPendingStateForTransaction(TransactionType.AUTHORIZE).toString();
testListener.pushExpectedEvent(NextEvent.PAYMENT);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
payment.getTransactions().get(0).getId(), TransactionStatus.PENDING, requestedAmount, account.getCurrency(),
"loup", "chat", internalCallContext);
testListener.assertListenerStatus();
@@ -439,7 +439,7 @@ public class TestJanitor extends PaymentTestSuiteWithEmbeddedDB {
testListener.pushExpectedEvent(NextEvent.PAYMENT);
- paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
+ paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName,
payment.getTransactions().get(0).getId(), TransactionStatus.PENDING, requestedAmount, account.getCurrency(),
"loup", "chat", internalCallContext);
testListener.assertListenerStatus();