Fluent Commerce Logo
Sign In

Cash on Delivery workflow action

How-to Guide
Extend

Author:

Valery Kornilovich

Changed on:

8 July 2024

Key Points

  • Understanding the Market: Recognizing the importance of Cash on Delivery (CoD) in markets like India, where it is a preferred payment method.
  • Global Adaptability: The workflow's design serves a global audience, providing a template that can be customised for regions where upfront payment is not the norm.
  • Seamless Integration: Ensuring the CoD process is smoothly incorporated into the existing order journey to enhance customer experience.
  • Operational Efficiency: Streamlining the CoD transaction to ensure quick and secure payment collection at the point of delivery.

Steps

Step arrow right iconUse Case

As a Consumer, I want to pay for my order items upon collection or delivery arrival.

Step arrow right iconSolution Approach

  • Place a CC or HD order over API containing the following order attribute:
1"attributes": [
2    {
3        "name": "CASH_ON_DELIVERY",
4        "type": "STRING",
5        "value": "TRUE"
6    }
7]

Language: json

Name: Order Attribute

Description:

Attribute to activate 'Cash on Delivery' functionality

  • Process the order through the normal fulfillment workflow.
  • As a final step before the orders are complete, there is a holding state where user actions are presented in the Fluent OMS app. This will enable a user to manually simulate that a payment event is received into Fluent from an external source.

Step arrow right iconChallenges / Limitiations

The main limitation here is that we can’t receive an order from a demo commerce platform such as Salesforce or Adobe as this would require an extension of these connectors. Therefore this demo scenario must be performed through API creation of orders via Postman.

Step arrow right iconWorkflow changes

Add a series of workflow changes to include a new status, user action and underpinning ruleset to enable this step at the end of the CC and HD order entity workflows.

1        {
2            "name": "CheckIfOrderIsComplete",
3            "description": "Checks if all fulfilments are in any of the configured states and sends an event",
4            "type": "ORDER",
5            "eventType": "NORMAL",
6            "rules": [
7                {
8                    "name": "{{fluent.account.id}}.order.SendEventOnVerifyingAllFulfilmentStates",
9                    "props": {
10                        "status": [
11                            "COMPLETE",
12                            "REJECTED",
13                            "EXPIRED",
14                            "ESCALATED"
15                        ],
16                        "eventName": "CheckEnablementCashOnDeliveryLogic"
17                    }
18                }
19            ],
20            "triggers": [
21                {
22                    "status": "AWAITING_CUSTOMER_COLLECTION"
23                },
24                {
25                    "status": "BOOKED"
26                },
27                {
28                    "status": "PICK_PACK"
29                }
30            ],
31            "userActions": []
32        },
33

Language: json

Name: Entry point of 'Cash on Delivery' functionality

Description:

Replace OrderComplete with CheckEnablementCashOnDeliveryLogic

1        {
2            "name": "ContinueWithoutTransaction",
3            "description": "Continue of Order processing without creating of a new transaction",
4            "type": "ORDER",
5            "subtype": "CC",
6            "eventType": "NORMAL",
7            "rules": [
8                {
9                    "name": "{{fluent.account.id}}.core.SendEvent",
10                    "props": {
11                        "eventName": "OrderComplete"
12                    }
13                }
14            ],
15            "triggers": [
16                {
17                    "status": "AWAITING_TRANSACTION"
18                }
19            ],
20            "userActions": [
21                {
22                    "context": [
23                        {
24                            "label": "Use Credit Card",
25                            "type": "PRIMARY",
26                            "modules": [
27                                "adminconsole",
28                                "servicepoint"
29                            ],
30                            "confirm": true
31                        }
32                    ],
33                    "attributes": []
34                }
35            ]
36        },
37        {
38            "name": "ContinueWithTransaction",
39            "description": "Continue of Order processing with creating of a new transaction (with PaymentType CASH by default)",
40            "type": "ORDER",
41            "subtype": "CC",
42            "eventType": "NORMAL",
43            "rules": [
44                {
45                    "name": "FLUENTRETAIL.base.CreateTransactionForOrder",
46                    "props": {}
47                },
48                {
49                    "name": "{{fluent.account.id}}.core.ScheduleEvent",
50                    "props": {
51                        "delay": 1,
52                        "eventName": "CheckTransaction"
53                    }
54                }
55            ],
56            "triggers": [
57                {
58                    "status": "AWAITING_TRANSACTION"
59                }
60            ],
61            "userActions": [
62                {
63                    "context": [
64                        {
65                            "label": "Cash On Delivery",
66                            "type": "PRIMARY",
67                            "modules": [
68                                "adminconsole",
69                                "servicepoint"
70                            ],
71                            "confirm": false
72                        }
73                    ],
74                    "attributes": [
75                        {
76                            "name": "amount",
77                            "label": "Amount",
78                            "type": "STRING",
79                            "source": "",
80                            "defaultValue": "100",
81                            "mandatory": false
82                        },
83                        {
84                            "name": "cardType",
85                            "label": "Card Type",
86                            "type": "STRING",
87                            "source": "",
88                            "defaultValue": "INTERAC",
89                            "mandatory": false
90                        },
91                        {
92                            "name": "currency",
93                            "label": "Currency",
94                            "type": "STRING",
95                            "source": "",
96                            "defaultValue": "USD",
97                            "mandatory": false
98                        },
99                        {
100                            "name": "paymentMethod",
101                            "label": "Payment Method",
102                            "type": "STRING",
103                            "source": "",
104                            "defaultValue": "CASH",
105                            "mandatory": true
106                        },
107                        {
108                            "name": "paymentProvider",
109                            "label": "Payment Provider",
110                            "type": "STRING",
111                            "source": "",
112                            "defaultValue": "AFTERPAY",
113                            "mandatory": false
114                        },
115                        {
116                            "name": "transactionCode",
117                            "label": "Transaction Code",
118                            "type": "STRING",
119                            "source": "",
120                            "defaultValue": "TRC-1234",
121                            "mandatory": false
122                        },
123                        {
124                            "name": "transactionRef",
125                            "label": "Transaction Ref",
126                            "type": "STRING",
127                            "source": "",
128                            "defaultValue": "TR-1234",
129                            "mandatory": false
130                        },
131                        {
132                            "name": "transactionType",
133                            "label": "Transaction Type",
134                            "type": "STRING",
135                            "source": "",
136                            "defaultValue": "PAYMENT",
137                            "mandatory": false
138                        }
139                    ]
140                }
141            ]
142        },
143        {
144            "name": "CheckEnablementCashOnDeliveryLogic",
145            "description": "Checking that Order has CASH_ON_DELIVERY attribute",
146            "type": "ORDER",
147            "eventType": "NORMAL",
148            "rules": [
149                {
150                    "name": "{{fluent.account.id}}.order.SendEventOnVerifyingAttributeValue",
151                    "props": {
152                        "eventName": "AwaitingTransaction",
153                        "noMatchEventName": "OrderComplete",
154                        "attributeName": "CASH_ON_DELIVERY",
155                        "attributeValue": "TRUE"
156                    }
157                }
158            ],
159            "triggers": [
160                {
161                    "status": "BOOKED"
162                },
163                {
164                    "status": "PICK_PACK"
165                },
166                {
167                    "status": "COMPLETE"
168                },
169                {
170                    "status": "AWAITING_CUSTOMER_COLLECTION"
171                }
172            ],
173            "userActions": []
174        },
175        {
176            "name": "CheckPayment",
177            "description": "Checking that Order has CASH transaction (according to attribute IS_CASH_ON_DELIVERY)",
178            "type": "ORDER",
179            "eventType": "NORMAL",
180            "rules": [
181                {
182                    "name": "{{fluent.account.id}}.order.SendEventOnVerifyingAttributeValue",
183                    "props": {
184                        "eventName": "AwaitingPayment",
185                        "noMatchEventName": "OrderComplete",
186                        "attributeName": "TRANSACTION_CASH_EXISTS",
187                        "attributeValue": "TRUE"
188                    }
189                }
190            ],
191            "triggers": [
192                {
193                    "status": "AWAITING_CUSTOMER_COLLECTION"
194                },
195                {
196                    "status": "BOOKED"
197                },
198                {
199                    "status": "PICK_PACK"
200                },
201                {
202                    "status": "AWAITING_TRANSACTION"
203                }
204            ],
205            "userActions": []
206        },
207        {
208            "name": "AwaitingPayment",
209            "description": "Changing state of Order to AWAITING_PAYMENT for orders with CASH transaction",
210            "type": "ORDER",
211            "eventType": "NORMAL",
212            "rules": [
213                {
214                    "name": "{{fluent.account.id}}.core.SetState",
215                    "props": {
216                        "status": "AWAITING_PAYMENT"
217                    }
218                }
219            ],
220            "triggers": [
221                {
222                    "status": "AWAITING_CUSTOMER_COLLECTION"
223                },
224                {
225                    "status": "PICK_PACK"
226                },
227                {
228                    "status": "BOOKED"
229                },
230                {
231                    "status": "AWAITING_TRANSACTION"
232                }
233            ],
234            "userActions": []
235        },
236        {
237            "name": "ConfirmPayment",
238            "description": "Confirmation that payment collected",
239            "type": "ORDER",
240            "subtype": "CC",
241            "eventType": "NORMAL",
242            "rules": [
243                {
244                    "name": "{{fluent.account.id}}.core.SendEvent",
245                    "props": {
246                        "eventName": "OrderComplete"
247                    }
248                }
249            ],
250            "triggers": [
251                {
252                    "status": "AWAITING_PAYMENT"
253                }
254            ],
255            "userActions": [
256                {
257                    "context": [
258                        {
259                            "label": "Paid",
260                            "type": "PRIMARY",
261                            "modules": [
262                                "servicepoint",
263                                "adminconsole"
264                            ],
265                            "confirm": true
266                        }
267                    ],
268                    "attributes": []
269                }
270            ]
271        },
272        {
273            "name": "AwaitingTransaction",
274            "description": "Change status of the Order to AWAITING_TRANSACTION",
275            "type": "ORDER",
276            "eventType": "NORMAL",
277            "rules": [
278                {
279                    "name": "{{fluent.account.id}}.core.SetState",
280                    "props": {
281                        "status": "AWAITING_TRANSACTION"
282                    }
283                }
284            ],
285            "triggers": [
286                {
287                    "status": "BOOKED"
288                },
289                {
290                    "status": "PICK_PACK"
291                },
292                {
293                    "status": "COMPLETE"
294                },
295                {
296                    "status": "AWAITING_CUSTOMER_COLLECTION"
297                }
298            ],
299            "userActions": []
300        },
301        {
302            "name": "CheckTransaction",
303            "description": "Check that the Order has transaction with type CASH",
304            "type": "ORDER",
305            "eventType": "NORMAL",
306            "rules": [
307                {
308                    "name": "{{fluent.account.id}}.{packageName}.MarkOrderAccordingToTransactionPaymentMethod",
309                    "props": {
310                        "paymentMethod": "CASH",
311                        "attributeName": "TRANSACTION_CASH_EXISTS"
312                    }
313                },
314                {
315                    "name": "{{fluent.account.id}}.core.SendEvent",
316                    "props": {
317                        "eventName": "CheckPayment"
318                    }
319                }
320            ],
321            "triggers": [
322                {
323                    "status": "AWAITING_TRANSACTION"
324                }
325            ],
326            "userActions": []
327        }
328

Language: json

Name: Example of changes in Workflow

Description:

Example of changes in Workflow

Step arrow right iconCustom Rule

The new rule MarkOrderAccordingToTransactionPaymentMethod has been added to a custom rule plugin. This rule checks if a Financial Transaction exists for Order and Payment Method equal to the specified method then adds a specified attribute to Order to mark the entity.

Property

Value

Plugin name

<yourPluginName>

Rule API Client

GraphQL

Rule Info Description

Mark the Order as {

`attributeName`
} when the Order has transaction with {
`paymentMethod`
} Payment Method

Supported Entities

ORDER

1@RuleInfo(name = "MarkOrderAccordingToTransactionPaymentMethod",
2    description = "Mark the Order as {attributeName} "
3        + "when the Order has transaction with {paymentMethod} Payment Method",
4    accepts = {
5        @EventInfo(entityType = "ORDER")
6    })
7@ParamString(name = "attributeName",
8    description = "Mark attribute name")
9@ParamString(name = "paymentMethod",
10    description = "Payment Method for checking")
11public class MarkOrderAccordingToTransactionPaymentMethod implements Rule {
12
13    @Override
14    public <C extends Context> void run(C context) {
15        String markAttributeName = context.getProp("attributeName", String.class);
16        if (StringUtils.isBlank(markAttributeName)) {
17            throw new PropertyNotFoundException(400, "attributeName is blank");
18        }
19
20        String paymentMethod = context.getProp("paymentMethod", String.class);
21        if (StringUtils.isBlank(paymentMethod)) {
22            throw new PropertyNotFoundException(400, "paymentMethod is blank");
23        }
24
25        String orderId = context.getEvent().getEntityId();
26        if (StringUtils.isBlank(orderId)) {
27            throw new RuleExecutionException("order id is blank", context.getEvent());
28        }
29
30        Data orderById =
31            OrderUtils.getOrderByIdQuery(context, orderId, false, false, false, false, false, false, false, true);
32
33        if (orderById == null || orderById.order() == null) {
34            throw NoOrderFoundException.id(orderId, context.getEvent());
35        }
36
37        if (orderById.order().financialTransactions() == null
38            || orderById.order().financialTransactions().edges() == null) {
39            return;
40        }
41
42        boolean attributeDetected = orderById.order().financialTransactions().edges().stream().anyMatch(edge ->
43            edge != null && edge.node() != null && paymentMethod.equals(edge.node().paymentMethod())
44        );
45
46        if (!attributeDetected) {
47            return;
48        }
49
50        List<AttributeInput> attributeInputList =
51            Collections.singletonList(AttributeUtils.inputOf(markAttributeName, true));
52        new OrderService(context).updateOrderAttributes(attributeInputList);
53    }
54}
55

Language: java

Name: Example of MarkOrderAccordingToTransactionPaymentMethod

Description:

MarkOrderAccordingToTransactionPaymentMethod rule

Step arrow right iconResult

As a result, we will have User Actions 'Cash on Delivery' and 'Use Credit Card' to finalize the Order.

No alt provided

Step arrow right iconRelated Sources