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 9058564..18f1feb 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
@@ -22,6 +22,7 @@ import javax.inject.Inject;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.payment.core.PaymentTransactionInfoPluginConverter;
+import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
import org.killbill.billing.payment.dao.PaymentDao;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
@@ -29,12 +30,17 @@ import org.killbill.billing.util.config.definition.PaymentConfig;
public class DefaultAdminPaymentApi extends DefaultApiBase implements AdminPaymentApi {
+ private final PaymentStateMachineHelper paymentSMHelper;
private final PaymentDao paymentDao;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
- public DefaultAdminPaymentApi(final PaymentConfig paymentConfig, final PaymentDao paymentDao, final InternalCallContextFactory internalCallContextFactory) {
+ public DefaultAdminPaymentApi(final PaymentConfig paymentConfig,
+ final PaymentStateMachineHelper paymentSMHelper,
+ final PaymentDao paymentDao,
+ final InternalCallContextFactory internalCallContextFactory) {
super(paymentConfig, internalCallContextFactory);
+ this.paymentSMHelper = paymentSMHelper;
this.paymentDao = paymentDao;
this.internalCallContextFactory = internalCallContextFactory;
}
@@ -42,19 +48,54 @@ public class DefaultAdminPaymentApi extends DefaultApiBase implements AdminPayme
@Override
public void fixPaymentTransactionState(final Payment payment,
final PaymentTransaction paymentTransaction,
- @Nullable final TransactionStatus transactionStatusMaybeNull,
- @Nullable final String lastSuccessPaymentState,
- final String currentPaymentStateName,
+ @Nullable final TransactionStatus transactionStatusOrNull,
+ @Nullable final String lastSuccessPaymentStateOrNull,
+ @Nullable final String currentPaymentStateNameOrNull,
final Iterable<PluginProperty> properties,
final CallContext callContext) throws PaymentApiException {
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(payment.getAccountId(), callContext);
- final TransactionStatus transactionStatus;
- if (transactionStatusMaybeNull == null) {
+ TransactionStatus transactionStatus = transactionStatusOrNull;
+ if (transactionStatusOrNull == null) {
checkNotNullParameter(paymentTransaction.getPaymentInfoPlugin(), "PaymentTransactionInfoPlugin");
transactionStatus = PaymentTransactionInfoPluginConverter.toTransactionStatus(paymentTransaction.getPaymentInfoPlugin());
- } else {
- transactionStatus = transactionStatusMaybeNull;
+ }
+
+ String currentPaymentStateName = currentPaymentStateNameOrNull;
+ if (currentPaymentStateName == null) {
+ switch (transactionStatus) {
+ case PENDING:
+ currentPaymentStateName = paymentSMHelper.getPendingStateForTransaction(paymentTransaction.getTransactionType());
+ break;
+ case SUCCESS:
+ currentPaymentStateName = paymentSMHelper.getSuccessfulStateForTransaction(paymentTransaction.getTransactionType());
+ break;
+ case PAYMENT_FAILURE:
+ currentPaymentStateName = paymentSMHelper.getFailureStateForTransaction(paymentTransaction.getTransactionType());
+ break;
+ case PLUGIN_FAILURE:
+ case UNKNOWN:
+ default:
+ currentPaymentStateName = paymentSMHelper.getErroredStateForTransaction(paymentTransaction.getTransactionType());
+ break;
+ }
+ }
+
+ String lastSuccessPaymentState = lastSuccessPaymentStateOrNull;
+ if (lastSuccessPaymentState == null &&
+ // Verify we are not updating an older transaction (only the last one has an impact on lastSuccessPaymentState)
+ paymentTransaction.getId().equals(payment.getTransactions().get(payment.getTransactions().size() - 1).getId())) {
+ if (paymentSMHelper.isSuccessState(currentPaymentStateName)) {
+ lastSuccessPaymentState = currentPaymentStateName;
+ } else {
+ for (int i = payment.getTransactions().size() - 2; i >= 0; i--) {
+ final PaymentTransaction transaction = payment.getTransactions().get(i);
+ if (TransactionStatus.SUCCESS.equals(transaction.getTransactionStatus())) {
+ lastSuccessPaymentState = paymentSMHelper.getSuccessfulStateForTransaction(transaction.getTransactionType());
+ break;
+ }
+ }
+ }
}
paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(),
diff --git a/payment/src/test/java/org/killbill/billing/payment/api/TestDefaultAdminPaymentApi.java b/payment/src/test/java/org/killbill/billing/payment/api/TestDefaultAdminPaymentApi.java
index 03f6d8a..e710d8b 100644
--- a/payment/src/test/java/org/killbill/billing/payment/api/TestDefaultAdminPaymentApi.java
+++ b/payment/src/test/java/org/killbill/billing/payment/api/TestDefaultAdminPaymentApi.java
@@ -206,4 +206,98 @@ public class TestDefaultAdminPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorCode(), "error-code");
Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorMsg(), "error-msg");
}
+
+ @Test(groups = "slow", description = "https://github.com/killbill/killbill-adyen-plugin/pull/60")
+ public void testFixPaymentTransactionStateRefundSuccessToRefundFailed() throws PaymentApiException {
+ final Payment payment = paymentApi.createPurchase(account,
+ account.getPaymentMethodId(),
+ null,
+ BigDecimal.TEN,
+ Currency.EUR,
+ UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+
+ final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao.getStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
+
+ final Payment refund = paymentApi.createRefund(account,
+ payment.getId(),
+ payment.getPurchasedAmount(),
+ payment.getCurrency(),
+ UUID.randomUUID().toString(),
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+
+ final PaymentModelDao paymentModelDao2 = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao2 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao2.getStateName(), "REFUND_SUCCESS");
+ Assert.assertEquals(paymentModelDao2.getLastSuccessStateName(), "REFUND_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao2.getTransactionStatus(), TransactionStatus.SUCCESS);
+
+ adminPaymentApi.fixPaymentTransactionState(refund,
+ refund.getTransactions().get(1),
+ TransactionStatus.PAYMENT_FAILURE,
+ null, /* Let Kill Bill figure it out */
+ null, /* Let Kill Bill figure it out */
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+
+ final PaymentModelDao paymentModelDao3 = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao3 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao3.getStateName(), "REFUND_FAILED");
+ Assert.assertEquals(paymentModelDao3.getLastSuccessStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao3.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
+ }
+
+ @Test(groups = "slow", description = "https://github.com/killbill/killbill-adyen-plugin/pull/60")
+ public void testFixPaymentTransactionStateRefundFailedToRefundSuccess() throws PaymentApiException {
+ final Payment payment = paymentApi.createPurchase(account,
+ account.getPaymentMethodId(),
+ null,
+ BigDecimal.TEN,
+ Currency.EUR,
+ UUID.randomUUID().toString(),
+ UUID.randomUUID().toString(),
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+
+ final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao.getStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
+
+ final Payment refund = paymentApi.createRefund(account,
+ payment.getId(),
+ payment.getPurchasedAmount(),
+ payment.getCurrency(),
+ UUID.randomUUID().toString(),
+ ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.ERROR.toString(), false)),
+ callContext);
+
+ final PaymentModelDao paymentModelDao2 = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao2 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao2.getStateName(), "REFUND_FAILED");
+ Assert.assertEquals(paymentModelDao2.getLastSuccessStateName(), "PURCHASE_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao2.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
+
+ adminPaymentApi.fixPaymentTransactionState(refund,
+ refund.getTransactions().get(1),
+ TransactionStatus.SUCCESS,
+ null, /* Let Kill Bill figure it out */
+ null, /* Let Kill Bill figure it out */
+ ImmutableList.<PluginProperty>of(),
+ callContext);
+
+ final PaymentModelDao paymentModelDao3 = paymentDao.getPayment(payment.getId(), internalCallContext);
+ final PaymentTransactionModelDao paymentTransactionModelDao3 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
+ Assert.assertEquals(paymentModelDao3.getStateName(), "REFUND_SUCCESS");
+ Assert.assertEquals(paymentModelDao3.getLastSuccessStateName(), "REFUND_SUCCESS");
+ Assert.assertEquals(paymentTransactionModelDao3.getTransactionStatus(), TransactionStatus.SUCCESS);
+ }
}