killbill-memoizeit

Details

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