# Conditional Transaction Demo
This demo simulates a partial backend of an e-commerce application including four services:
* payment
* membership
* inventory
* supplier

**Note** Please go through the dependency-free-transaction-demo first, before proceeding with this demo. 

## Background
Many e-commerce sites have membership concept, which will level up when a customer makes a certain amount of purchase.
Moreover, as goods are sold and the stock drops to a certain level, the e-commerce company needs to fetch more goods from
its suppliers. Both scenarios introduce conditional transactions. 

## Workflow
```
                  /---> if total purchase >= 1K, level up membership
start ---> make payment ---> dispatch product from inventory ---> end
                                              \---> if product stock < 10, replenish product from supplier 
```
The conditions are business logic and belong to business service. Therefore, the decision to level up membership is made
in payment service and the decision to replenish products is made in inventory service. Saga is to be informed of service
decision by adding an additional element `sagaChildren` in service response JSON to indicate which services are to be invoked
next as shown below.
```json
{
  "customerId": "mike",
  "body": "Payment made with id xxx for customer mike",
  "sagaChildren": ["inventory"] 
}
```

If `sagaChildren` is empty or not provided in service response, saga will invoke all of its child services. To invoke none
of them, explicitly return `"sagaChildren": ["none"]`.

If any of the sub-transaction specified in sagaChildren fails, all completed sub-transactions will be compensated as usual,
when the recovery policy if backward recovery. 

## Running Demo
1. run the following command to create docker images in saga project root folder.
	```
	mvn package -DskipTests -Pdocker -Pdemo
	```

2. stop application
   ```
   ./conditional-transaction-demo.sh down
   ```

## User Requests
The request JSON to ensure the workflow order looks like the following:
```json
{
  "policy": "BackwardRecovery",
  "requests": [
    {
      "id": "payment",
      "type": "rest",
      "serviceName": "payment.servicecomb.io:8080",
      "transaction": {
        "method": "post",
        "path": "/payment",
        "params": {
          "form": {
            "customerId": "mike",
            "purchaseAmount": 400
          }
        }
      },
      "compensation": {
        "method": "put",
        "path": "/payment",
        "params": {
          "form": {
            "customerId": "mike"
          }
        }
      }
    },
    {
      "id": "membership",
      "type": "rest",
      "serviceName": "membership.servicecomb.io:8080",
      "parents": [
        "payment"
      ],
      "transaction": {
        "method": "post",
        "path": "/membership",
        "params": {
          "form": {
            "customerId": "mike"
          }
        }
      },
      "compensation": {
        "method": "put",
        "path": "/membership",
        "params": {
          "form": {
            "customerId": "mike"
          }
        }
      }
    },
    {
      "id": "inventory",
      "type": "rest",
      "serviceName": "inventory.servicecomb.io:8080",
      "parents": [
        "payment"
      ],
      "transaction": {
        "method": "post",
        "path": "/inventory",
        "params": {
          "form": {
            "customerId": "mike"
          }
        }
      },
      "compensation": {
        "method": "put",
        "path": "/inventory",
        "params": {
          "form": {
            "customerId": "mike"
          }
        }
      }
    },
    {
      "id": "supplier",
      "type": "rest",
      "serviceName": "supplier.servicecomb.io:8080",
      "parents": [
        "inventory"
      ],
      "transaction": {
        "method": "post",
        "path": "/supplier",
        "params": {
          "form": {
            "customerId": "servicecomb_mall"
          }
        }
      },
      "compensation": {
        "method": "put",
        "path": "/supplier",
        "params": {
          "form": {
            "customerId": "servicecomb_mall"
          }
        }
      }
    }
  ]
}

```

To send the above JSON request to Saga, use [postman](https://www.getpostman.com/postman) with POST request to url `http://<docker.host.ip>:8083/requests`

Each request to payment service will increase user mike's total purchase by $400. The 3<sup>rd</sup> request will trigger 
membership level up.

The initial product stock is 11 in inventory and each request to inventory service will deduct product stock by 1. 
So the 2<sup>nd</sup> request will trigger product replenishment from supplier.

**Note** transactions and compensations implemented by services must be idempotent. In this demo, we did not enforce that
for simplicity.

To see all events generated by Saga, visit `http://<docker.host.ip>:8083/events` with postman.

## Debugging
Take the [spring-demo debugging](../saga-spring-demo#debugging) as a reference.
