killbill-aplcache

payment: disallow void on capture, refund, etc. by default This

6/28/2016 3:37:49 PM

Details

diff --git a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
index da851a2..9031c87 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
+++ b/payment/src/main/resources/org/killbill/billing/payment/PaymentStates.xml
@@ -441,30 +441,6 @@
             <finalState>VOID_INIT</finalState>
         </linkStateMachine>
         <linkStateMachine>
-            <initialStateMachine>VOID</initialStateMachine>
-            <initialState>VOID_SUCCESS</initialState>
-            <finalStateMachine>VOID</finalStateMachine>
-            <finalState>VOID_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
-            <initialStateMachine>VOID</initialStateMachine>
-            <initialState>VOID_SUCCESS</initialState>
-            <finalStateMachine>CAPTURE</finalStateMachine>
-            <finalState>CAPTURE_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
-            <initialStateMachine>VOID</initialStateMachine>
-            <initialState>VOID_SUCCESS</initialState>
-            <finalStateMachine>REFUND</finalStateMachine>
-            <finalState>REFUND_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
-            <initialStateMachine>VOID</initialStateMachine>
-            <initialState>VOID_SUCCESS</initialState>
-            <finalStateMachine>CREDIT</finalStateMachine>
-            <finalState>CREDIT_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
             <initialStateMachine>CAPTURE</initialStateMachine>
             <initialState>CAPTURE_SUCCESS</initialState>
             <finalStateMachine>REFUND</finalStateMachine>
@@ -483,12 +459,6 @@
             <finalState>CHARGEBACK_INIT</finalState>
         </linkStateMachine>
         <linkStateMachine>
-            <initialStateMachine>CAPTURE</initialStateMachine>
-            <initialState>CAPTURE_SUCCESS</initialState>
-            <finalStateMachine>VOID</finalStateMachine>
-            <finalState>VOID_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
             <initialStateMachine>REFUND</initialStateMachine>
             <initialState>REFUND_SUCCESS</initialState>
             <finalStateMachine>REFUND</finalStateMachine>
@@ -501,12 +471,6 @@
             <finalState>CHARGEBACK_INIT</finalState>
         </linkStateMachine>
         <linkStateMachine>
-            <initialStateMachine>REFUND</initialStateMachine>
-            <initialState>REFUND_SUCCESS</initialState>
-            <finalStateMachine>VOID</finalStateMachine>
-            <finalState>VOID_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
             <initialStateMachine>PURCHASE</initialStateMachine>
             <initialState>PURCHASE_SUCCESS</initialState>
             <finalStateMachine>REFUND</finalStateMachine>
@@ -519,12 +483,6 @@
             <finalState>CHARGEBACK_INIT</finalState>
         </linkStateMachine>
         <linkStateMachine>
-            <initialStateMachine>CREDIT</initialStateMachine>
-            <initialState>CREDIT_SUCCESS</initialState>
-            <finalStateMachine>VOID</finalStateMachine>
-            <finalState>VOID_INIT</finalState>
-        </linkStateMachine>
-        <linkStateMachine>
             <initialStateMachine>CHARGEBACK</initialStateMachine>
             <initialState>CHARGEBACK_SUCCESS</initialState>
             <finalStateMachine>CHARGEBACK</finalStateMachine>
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 e7a1756..f95e0db 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
@@ -416,6 +416,9 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
 
     @Test(groups = "slow")
     public void testCreateSuccessAuthCaptureVoidCapture() throws PaymentApiException {
+        // Overwrite the default state machine to allow void on captures
+        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig("org/killbill/billing/payment/PermissivePaymentStates.xml");
+
         final BigDecimal authAmount = BigDecimal.TEN;
         final BigDecimal captureAmount = BigDecimal.ONE;
 
@@ -533,7 +536,82 @@ public class TestPaymentApi extends PaymentTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
+    public void testCreateSuccessAuthCaptureVoidFailed() throws PaymentApiException {
+        final BigDecimal authAmount = BigDecimal.TEN;
+        final BigDecimal captureAmount = BigDecimal.ONE;
+
+        final String paymentExternalKey = UUID.randomUUID().toString();
+        final String transactionExternalKey = UUID.randomUUID().toString();
+        final String transactionExternalKey2 = UUID.randomUUID().toString();
+        final String transactionExternalKey3 = UUID.randomUUID().toString();
+
+        final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, authAmount, Currency.AED,
+                                                               paymentExternalKey, transactionExternalKey,
+                                                               ImmutableList.<PluginProperty>of(), callContext);
+
+        assertEquals(payment.getExternalKey(), paymentExternalKey);
+        assertEquals(payment.getPaymentMethodId(), account.getPaymentMethodId());
+        assertEquals(payment.getAccountId(), account.getId());
+        assertEquals(payment.getAuthAmount().compareTo(authAmount), 0);
+        assertEquals(payment.getCapturedAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(payment.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(payment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(payment.getCurrency(), Currency.AED);
+        assertFalse(payment.isAuthVoided());
+
+        assertEquals(payment.getTransactions().size(), 1);
+        assertEquals(payment.getTransactions().get(0).getExternalKey(), transactionExternalKey);
+        assertEquals(payment.getTransactions().get(0).getPaymentId(), payment.getId());
+        assertEquals(payment.getTransactions().get(0).getAmount().compareTo(authAmount), 0);
+        assertEquals(payment.getTransactions().get(0).getCurrency(), Currency.AED);
+        assertEquals(payment.getTransactions().get(0).getProcessedAmount().compareTo(authAmount), 0);
+        assertEquals(payment.getTransactions().get(0).getProcessedCurrency(), Currency.AED);
+
+        assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.SUCCESS);
+        assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.AUTHORIZE);
+        assertNotNull(payment.getTransactions().get(0).getGatewayErrorMsg());
+        assertNotNull(payment.getTransactions().get(0).getGatewayErrorCode());
+
+        final Payment payment2 = paymentApi.createCapture(account, payment.getId(), captureAmount, Currency.AED, transactionExternalKey2,
+                                                          ImmutableList.<PluginProperty>of(), callContext);
+
+        assertEquals(payment2.getExternalKey(), paymentExternalKey);
+        assertEquals(payment2.getPaymentMethodId(), account.getPaymentMethodId());
+        assertEquals(payment2.getAccountId(), account.getId());
+        assertEquals(payment2.getAuthAmount().compareTo(authAmount), 0);
+        assertEquals(payment2.getCapturedAmount().compareTo(captureAmount), 0);
+        assertEquals(payment2.getPurchasedAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(payment2.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
+        assertEquals(payment2.getCurrency(), Currency.AED);
+        assertFalse(payment2.isAuthVoided());
+
+        assertEquals(payment2.getTransactions().size(), 2);
+        assertEquals(payment2.getTransactions().get(1).getExternalKey(), transactionExternalKey2);
+        assertEquals(payment2.getTransactions().get(1).getPaymentId(), payment.getId());
+        assertEquals(payment2.getTransactions().get(1).getAmount().compareTo(captureAmount), 0);
+        assertEquals(payment2.getTransactions().get(1).getCurrency(), Currency.AED);
+        assertEquals(payment2.getTransactions().get(1).getProcessedAmount().compareTo(captureAmount), 0);
+        assertEquals(payment2.getTransactions().get(1).getProcessedCurrency(), Currency.AED);
+
+        assertEquals(payment2.getTransactions().get(1).getTransactionStatus(), TransactionStatus.SUCCESS);
+        assertEquals(payment2.getTransactions().get(1).getTransactionType(), TransactionType.CAPTURE);
+        assertNotNull(payment2.getTransactions().get(1).getGatewayErrorMsg());
+        assertNotNull(payment2.getTransactions().get(1).getGatewayErrorCode());
+
+        try {
+            // Voiding a capture is prohibited by default
+            paymentApi.createVoid(account, payment.getId(), transactionExternalKey3, ImmutableList.<PluginProperty>of(), callContext);
+            Assert.fail();
+        } catch (final PaymentApiException e) {
+            Assert.assertEquals(e.getCode(), ErrorCode.PAYMENT_INVALID_OPERATION.getCode());
+        }
+    }
+
+    @Test(groups = "slow")
     public void testCreateSuccessAuthCaptureVoidVoid() throws PaymentApiException {
+        // Overwrite the default state machine to allow void on captures
+        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig("org/killbill/billing/payment/PermissivePaymentStates.xml");
+
         final BigDecimal authAmount = BigDecimal.TEN;
         final BigDecimal captureAmount = BigDecimal.ONE;
 
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
index 74f2237..713219a 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteNoDB.java
@@ -56,6 +56,8 @@ import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
+import static org.killbill.billing.payment.provider.MockPaymentControlProviderPlugin.PLUGIN_NAME;
+
 public abstract class PaymentTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
 
     @Inject
@@ -112,12 +114,13 @@ public abstract class PaymentTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
     protected void beforeClass() throws Exception {
         final Injector injector = Guice.createInjector(new TestPaymentModuleNoDB(configSource, getClock()));
         injector.injectMembers(this);
-
-        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig(PaymentModule.DEFAULT_STATE_MACHINE_PAYMENT_XML);
     }
 
     @BeforeMethod(groups = "fast")
     public void beforeMethod() throws Exception {
+        stateMachineConfigCache.clearPaymentStateMachineConfig(PLUGIN_NAME, internalCallContext);
+        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig(PaymentModule.DEFAULT_STATE_MACHINE_PAYMENT_XML);
+
         eventBus.start();
         paymentExecutors.initialize();
         ((MockPaymentDao) paymentDao).reset();
diff --git a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
index d32f6ce..f0f7e09 100644
--- a/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/PaymentTestSuiteWithEmbeddedDB.java
@@ -28,8 +28,8 @@ import org.killbill.billing.payment.api.PaymentApi;
 import org.killbill.billing.payment.api.PaymentGatewayApi;
 import org.killbill.billing.payment.caching.StateMachineConfigCache;
 import org.killbill.billing.payment.core.PaymentExecutors;
-import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.PaymentMethodProcessor;
+import org.killbill.billing.payment.core.PaymentProcessor;
 import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
 import org.killbill.billing.payment.dao.PaymentDao;
 import org.killbill.billing.payment.glue.PaymentModule;
@@ -50,6 +50,8 @@ import com.google.inject.Guice;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
+import static org.killbill.billing.payment.provider.MockPaymentControlProviderPlugin.PLUGIN_NAME;
+
 public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWithEmbeddedDB {
 
     @Inject
@@ -98,18 +100,19 @@ public abstract class PaymentTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
     protected void beforeClass() throws Exception {
         final Injector injector = Guice.createInjector(new TestPaymentModuleWithEmbeddedDB(configSource, getClock()));
         injector.injectMembers(this);
-
-        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig(PaymentModule.DEFAULT_STATE_MACHINE_PAYMENT_XML);
     }
 
     @BeforeMethod(groups = "slow")
     public void beforeMethod() throws Exception {
         super.beforeMethod();
+
+        stateMachineConfigCache.clearPaymentStateMachineConfig(PLUGIN_NAME, internalCallContext);
+        stateMachineConfigCache.loadDefaultPaymentStateMachineConfig(PaymentModule.DEFAULT_STATE_MACHINE_PAYMENT_XML);
+
         paymentExecutors.initialize();
         eventBus.start();
         Profiling.resetPerThreadProfilingData();
         clock.resetDeltaFromReality();
-
     }
 
     @AfterMethod(groups = "slow")
diff --git a/payment/src/test/resources/org/killbill/billing/payment/PermissivePaymentStates.xml b/payment/src/test/resources/org/killbill/billing/payment/PermissivePaymentStates.xml
new file mode 100644
index 0000000..99d4bb9
--- /dev/null
+++ b/payment/src/test/resources/org/killbill/billing/payment/PermissivePaymentStates.xml
@@ -0,0 +1,541 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  ~ License.  You may obtain a copy of the License at:
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+  ~ License for the specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<stateMachineConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                    xsi:noNamespaceSchemaLocation="StateMachineConfig.xsd">
+
+    <stateMachines>
+        <stateMachine name="BIG_BANG">
+            <states>
+                <state name="BIG_BANG_INIT"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>BIG_BANG_INIT</initialState>
+                    <operation>OP_DUMMY</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>BIG_BANG_INIT</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_DUMMY"/>
+            </operations>
+        </stateMachine>
+        <stateMachine name="AUTHORIZE">
+            <states>
+                <state name="AUTH_INIT"/>
+                <state name="AUTH_PENDING"/>
+                <state name="AUTH_SUCCESS"/>
+                <state name="AUTH_FAILED"/>
+                <state name="AUTH_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>AUTH_INIT</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>AUTH_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_INIT</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>AUTH_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_INIT</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>AUTH_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_PENDING</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>AUTH_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_PENDING</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>AUTH_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_PENDING</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>AUTH_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>AUTH_INIT</initialState>
+                    <operation>OP_AUTHORIZE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>AUTH_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_AUTHORIZE"/>
+            </operations>
+        </stateMachine>
+
+        <stateMachine name="CAPTURE">
+            <states>
+                <state name="CAPTURE_INIT"/>
+                <state name="CAPTURE_PENDING"/>
+                <state name="CAPTURE_SUCCESS"/>
+                <state name="CAPTURE_FAILED"/>
+                <state name="CAPTURE_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>CAPTURE_INIT</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>CAPTURE_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_INIT</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>CAPTURE_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_INIT</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>CAPTURE_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_PENDING</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>CAPTURE_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_PENDING</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>CAPTURE_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_PENDING</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>CAPTURE_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CAPTURE_INIT</initialState>
+                    <operation>OP_CAPTURE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>CAPTURE_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_CAPTURE"/>
+            </operations>
+        </stateMachine>
+
+        <stateMachine name="PURCHASE">
+            <states>
+                <state name="PURCHASE_INIT"/>
+                <state name="PURCHASE_PENDING"/>
+                <state name="PURCHASE_SUCCESS"/>
+                <state name="PURCHASE_FAILED"/>
+                <state name="PURCHASE_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>PURCHASE_INIT</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>PURCHASE_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_INIT</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>PURCHASE_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_INIT</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>PURCHASE_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_PENDING</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>PURCHASE_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_PENDING</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>PURCHASE_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_PENDING</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>PURCHASE_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>PURCHASE_INIT</initialState>
+                    <operation>OP_PURCHASE</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>PURCHASE_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_PURCHASE"/>
+            </operations>
+        </stateMachine>
+
+        <stateMachine name="REFUND">
+            <states>
+                <state name="REFUND_INIT"/>
+                <state name="REFUND_PENDING"/>
+                <state name="REFUND_SUCCESS"/>
+                <state name="REFUND_FAILED"/>
+                <state name="REFUND_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>REFUND_INIT</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>REFUND_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_INIT</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>REFUND_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_INIT</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>REFUND_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_PENDING</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>REFUND_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_PENDING</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>REFUND_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_PENDING</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>REFUND_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>REFUND_INIT</initialState>
+                    <operation>OP_REFUND</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>REFUND_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_REFUND"/>
+            </operations>
+        </stateMachine>
+
+        <stateMachine name="CREDIT">
+            <states>
+                <state name="CREDIT_INIT"/>
+                <state name="CREDIT_PENDING"/>
+                <state name="CREDIT_SUCCESS"/>
+                <state name="CREDIT_FAILED"/>
+                <state name="CREDIT_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>CREDIT_INIT</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>CREDIT_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_INIT</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>CREDIT_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_INIT</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>CREDIT_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_PENDING</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>CREDIT_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_PENDING</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>CREDIT_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_PENDING</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>CREDIT_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CREDIT_INIT</initialState>
+                    <operation>OP_CREDIT</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>CREDIT_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_CREDIT"/>
+            </operations>
+        </stateMachine>
+
+        <stateMachine name="VOID">
+            <states>
+                <state name="VOID_INIT"/>
+                <state name="VOID_PENDING"/>
+                <state name="VOID_SUCCESS"/>
+                <state name="VOID_FAILED"/>
+                <state name="VOID_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>VOID_INIT</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>VOID_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_INIT</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>VOID_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_INIT</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>PENDING</operationResult>
+                    <finalState>VOID_PENDING</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_PENDING</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>VOID_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_PENDING</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>VOID_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_PENDING</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>VOID_ERRORED</finalState>
+                </transition>
+                <transition>
+                    <initialState>VOID_INIT</initialState>
+                    <operation>OP_VOID</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>VOID_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_VOID"/>
+            </operations>
+        </stateMachine>
+        <stateMachine name="CHARGEBACK">
+            <states>
+                <state name="CHARGEBACK_INIT"/>
+                <state name="CHARGEBACK_SUCCESS"/>
+                <state name="CHARGEBACK_FAILED"/>
+                <state name="CHARGEBACK_ERRORED"/>
+            </states>
+            <transitions>
+                <transition>
+                    <initialState>CHARGEBACK_INIT</initialState>
+                    <operation>OP_CHARGEBACK</operation>
+                    <operationResult>SUCCESS</operationResult>
+                    <finalState>CHARGEBACK_SUCCESS</finalState>
+                </transition>
+                <transition>
+                    <initialState>CHARGEBACK_INIT</initialState>
+                    <operation>OP_CHARGEBACK</operation>
+                    <operationResult>FAILURE</operationResult>
+                    <finalState>CHARGEBACK_FAILED</finalState>
+                </transition>
+                <transition>
+                    <initialState>CHARGEBACK_INIT</initialState>
+                    <operation>OP_CHARGEBACK</operation>
+                    <operationResult>EXCEPTION</operationResult>
+                    <finalState>CHARGEBACK_ERRORED</finalState>
+                </transition>
+            </transitions>
+            <operations>
+                <operation name="OP_CHARGEBACK"/>
+            </operations>
+        </stateMachine>
+    </stateMachines>
+
+    <linkStateMachines>
+        <linkStateMachine>
+            <initialStateMachine>BIG_BANG</initialStateMachine>
+            <initialState>BIG_BANG_INIT</initialState>
+            <finalStateMachine>AUTHORIZE</finalStateMachine>
+            <finalState>AUTH_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>BIG_BANG</initialStateMachine>
+            <initialState>BIG_BANG_INIT</initialState>
+            <finalStateMachine>PURCHASE</finalStateMachine>
+            <finalState>PURCHASE_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>BIG_BANG</initialStateMachine>
+            <initialState>BIG_BANG_INIT</initialState>
+            <finalStateMachine>CREDIT</finalStateMachine>
+            <finalState>CREDIT_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>AUTHORIZE</initialStateMachine>
+            <initialState>AUTH_SUCCESS</initialState>
+            <finalStateMachine>CAPTURE</finalStateMachine>
+            <finalState>CAPTURE_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>AUTHORIZE</initialStateMachine>
+            <initialState>AUTH_SUCCESS</initialState>
+            <finalStateMachine>VOID</finalStateMachine>
+            <finalState>VOID_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>VOID</initialStateMachine>
+            <initialState>VOID_SUCCESS</initialState>
+            <finalStateMachine>VOID</finalStateMachine>
+            <finalState>VOID_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>VOID</initialStateMachine>
+            <initialState>VOID_SUCCESS</initialState>
+            <finalStateMachine>CAPTURE</finalStateMachine>
+            <finalState>CAPTURE_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>VOID</initialStateMachine>
+            <initialState>VOID_SUCCESS</initialState>
+            <finalStateMachine>REFUND</finalStateMachine>
+            <finalState>REFUND_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>VOID</initialStateMachine>
+            <initialState>VOID_SUCCESS</initialState>
+            <finalStateMachine>CREDIT</finalStateMachine>
+            <finalState>CREDIT_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CAPTURE</initialStateMachine>
+            <initialState>CAPTURE_SUCCESS</initialState>
+            <finalStateMachine>REFUND</finalStateMachine>
+            <finalState>REFUND_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CAPTURE</initialStateMachine>
+            <initialState>CAPTURE_SUCCESS</initialState>
+            <finalStateMachine>CAPTURE</finalStateMachine>
+            <finalState>CAPTURE_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CAPTURE</initialStateMachine>
+            <initialState>CAPTURE_SUCCESS</initialState>
+            <finalStateMachine>CHARGEBACK</finalStateMachine>
+            <finalState>CHARGEBACK_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CAPTURE</initialStateMachine>
+            <initialState>CAPTURE_SUCCESS</initialState>
+            <finalStateMachine>VOID</finalStateMachine>
+            <finalState>VOID_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>REFUND</initialStateMachine>
+            <initialState>REFUND_SUCCESS</initialState>
+            <finalStateMachine>REFUND</finalStateMachine>
+            <finalState>REFUND_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>REFUND</initialStateMachine>
+            <initialState>REFUND_SUCCESS</initialState>
+            <finalStateMachine>CHARGEBACK</finalStateMachine>
+            <finalState>CHARGEBACK_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>REFUND</initialStateMachine>
+            <initialState>REFUND_SUCCESS</initialState>
+            <finalStateMachine>VOID</finalStateMachine>
+            <finalState>VOID_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>PURCHASE</initialStateMachine>
+            <initialState>PURCHASE_SUCCESS</initialState>
+            <finalStateMachine>REFUND</finalStateMachine>
+            <finalState>REFUND_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>PURCHASE</initialStateMachine>
+            <initialState>PURCHASE_SUCCESS</initialState>
+            <finalStateMachine>CHARGEBACK</finalStateMachine>
+            <finalState>CHARGEBACK_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CREDIT</initialStateMachine>
+            <initialState>CREDIT_SUCCESS</initialState>
+            <finalStateMachine>VOID</finalStateMachine>
+            <finalState>VOID_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CHARGEBACK</initialStateMachine>
+            <initialState>CHARGEBACK_SUCCESS</initialState>
+            <finalStateMachine>CHARGEBACK</finalStateMachine>
+            <finalState>CHARGEBACK_INIT</finalState>
+        </linkStateMachine>
+        <linkStateMachine>
+            <initialStateMachine>CHARGEBACK</initialStateMachine>
+            <initialState>CHARGEBACK_FAILED</initialState>
+            <finalStateMachine>REFUND</finalStateMachine>
+            <finalState>REFUND_INIT</finalState>
+        </linkStateMachine>
+    </linkStateMachines>
+</stateMachineConfig>