diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentLeavingStateCallback.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentLeavingStateCallback.java
index edc6f70..9fec37d 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentLeavingStateCallback.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/payments/PaymentLeavingStateCallback.java
@@ -72,7 +72,7 @@ public abstract class PaymentLeavingStateCallback implements LeavingStateCallbac
}
// Validate the payment transactions belong to the right payment
- validatePaymentId(existingPaymentTransactions);
+ validatePaymentIdAndTransactionType(existingPaymentTransactions);
// Validate some constraints on the unicity of that paymentTransactionExternalKey
validateUniqueTransactionExternalKey(existingPaymentTransactions);
@@ -134,11 +134,15 @@ public abstract class PaymentLeavingStateCallback implements LeavingStateCallbac
}
// At this point, the payment id should have been populated for follow-up transactions (see PaymentAutomationRunner#run)
- protected void validatePaymentId(final List<PaymentTransactionModelDao> existingPaymentTransactions) throws PaymentApiException {
+ protected void validatePaymentIdAndTransactionType(final List<PaymentTransactionModelDao> existingPaymentTransactions) throws PaymentApiException {
for (final PaymentTransactionModelDao paymentTransactionModelDao : existingPaymentTransactions) {
if (!paymentTransactionModelDao.getPaymentId().equals(paymentStateContext.getPaymentId())) {
throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, paymentTransactionModelDao.getId(), "does not belong to payment " + paymentStateContext.getPaymentId());
}
+ if (paymentStateContext.getTransactionType() != null && paymentTransactionModelDao.getTransactionType() != paymentStateContext.getTransactionType()) {
+ throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, paymentTransactionModelDao.getId(), "has a transaction type of " + paymentTransactionModelDao.getTransactionType() +
+ " instead of requested " + paymentStateContext.getTransactionType());
+ }
}
}
}
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 a3cca2f..42eafdc 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
@@ -1286,6 +1286,34 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
assertTrue(spyLogger.contains("TimeoutException.*" + pluginName, Optional.of(SpyLogger.LOG_LEVEL_WARN)));
}
+
+ @Test(groups = "slow")
+ public void testSanityAcrossTransactionTypes() throws PaymentApiException {
+
+ final BigDecimal requestedAmount = BigDecimal.TEN;
+ final String paymentExternalKey = "ahhhhhhhh";
+ final String transactionExternalKey = "okkkkkkk";
+
+ final Payment pendingPayment = createPayment(TransactionType.AUTHORIZE, null, paymentExternalKey, transactionExternalKey, requestedAmount, PaymentPluginStatus.PENDING);
+ assertNotNull(pendingPayment);
+ Assert.assertEquals(pendingPayment.getExternalKey(), paymentExternalKey);
+ Assert.assertEquals(pendingPayment.getTransactions().size(), 1);
+ Assert.assertEquals(pendingPayment.getTransactions().get(0).getAmount().compareTo(requestedAmount), 0);
+ Assert.assertEquals(pendingPayment.getTransactions().get(0).getProcessedAmount().compareTo(requestedAmount), 0);
+ Assert.assertEquals(pendingPayment.getTransactions().get(0).getCurrency(), account.getCurrency());
+ Assert.assertEquals(pendingPayment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+ Assert.assertEquals(pendingPayment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PENDING);
+
+
+ try {
+ createPayment(TransactionType.PURCHASE, null, paymentExternalKey, transactionExternalKey, requestedAmount, PaymentPluginStatus.PENDING);
+ Assert.fail("PURCHASE transaction with same key should have failed");
+ } catch (final PaymentApiException expected) {
+ Assert.assertEquals(expected.getCode(), ErrorCode.PAYMENT_INVALID_PARAMETER.getCode());
+ }
+
+ }
+
private void verifyRefund(final Payment refund, final String paymentExternalKey, final String paymentTransactionExternalKey, final String refundTransactionExternalKey, final BigDecimal requestedAmount, final BigDecimal refundAmount, final TransactionStatus transactionStatus) {
Assert.assertEquals(refund.getExternalKey(), paymentExternalKey);
Assert.assertEquals(refund.getTransactions().size(), 2);