Fluent Commerce Logo
Sign In

Authors:

Valery Kornilovich, Randy Chan

Changed on:

4 July 2024

Key Points

  • This article gives System Integrator (SI) Partners and Businesses a high-level idea of where new features can be built on top of the OMS reference solution to support the customer's requirement within Fluent OMS.
  • This idea/solution will provide a new feature where the Store User can take a photo of the returning item and attach it as part of the returnOrder entity.
  • The source code will not be provided in this article.

Steps

Step arrow right iconUse Case

As a Store associate, I would like to take a photo of the returned item during the return in-store process.

As a Return Storeman in the warehouse, I would like to take a photo of the returned item during the return process.

Step arrow right iconSolution Approach


  • The image capture process needs to occur on this standard screen: return entry/creation screen.
  • Camera icon/button against each return order item. 
  • Pressing this icon/button will present a modal on top of the screen.
  • This modal will contain the image capture component.
  • Once a photo is captured, the user is presented with the still image.
  • The user can choose to ‘ok’ or ‘retake’. Retake removes the previous image and can be replaced by a new image. 'ok' adds the image to that order line.
  • The user enters all the standard return details (condition, reason, etc.).
No alt provided

Step arrow right iconTechnical Design Overview

To support the business solution design, the following technical areas need to be enhanced:

  • Extend the custom UI component (by using Component SDK) -
    `ReturnItemsExtended`
  • Customize rule (to save Attributes with image data) -
    `CreateReturnOrderFromOrder`
  • Setting -
    `RETURN_IMAGE_OPTIONS`

Step arrow right iconExtend on the custom UI Component: ReturnItemsExtended

For training purposes, the camera package can be downloaded here: https://www.npmjs.com/package/react-html5-camera-photo

Create a new file:

`PhotoCapture.tsx.`

This class will provide the PhotoCapture button function.

1  const showModal = (imageUri?: string) => {
2    pushModal({
3      title: translate(
4        'fc.sf.ui.returns.orders.createReturnOrder.list.returnItem.takePicture',
5      ),
6      body: (
7        <div style={{ padding: '20px' }}>
8          {imageUri ? (
9            <img src={imageUri} alt="" className={classes.returnPopupImg} />
10          ) : (
11            <Camera
12              onTakePhotoAnimationDone={handleTakePhotoAnimationDone}
13              onCameraError={() => {
14                setDataUri('');
15              }}
16              idealResolution={{
17                width: 640,
18                height: 480,
19              }}
20              imageType={imageType}
21              imageCompression={+imageCompression}
22              isDisplayStartCameraError={true}
23            />
24          )}
25
26          {imageUri && (
27            <div className={classes.returnPopupBtns}>
28              <Button
29                onClick={() => {
30                  updateDataUri();
31                }}
32                variant="contained"
33                color="primary"
34              >
35                {translate(
36                  'fc.sf.ui.returns.orders.createReturnOrder.list.returnItem.retake',
37                )}
38              </Button>
39              <Button onClick={clearModals} variant="contained" color="primary">
40                {translate(
41                  'fc.sf.ui.returns.orders.createReturnOrder.list.returnItem.ok',
42                )}
43              </Button>
44            </div>
45          )}
46        </div>
47      ),
48    });
49  };

Language: tsx

Name: PhotoCapture.tsx showModal snippet

Description:

PhotoCapture.tsx showModal snippet

1  return (
2    <>
3      <>
4        <IconButton
5          onClick={() => {
6            showModal(dataUri);
7          }}
8        >
9          <AddAPhoto />
10        </IconButton>
11
12        {dataUri && <img src={dataUri} alt="" className={classes.returnImg} />}
13      </>
14    </>
15  );

Language: tsx

Name: PhotoCapture.tsx return snippet

Description:

PhotoCapture.tsx return snippet

Next, add PhotoCapture details into ReturnItemsExtended.tsx

1//when there is an update, add the details into the item attribute
2      if (returnItem.photo && selectedReturnItem) {
3        selectedReturnItem.attributes = [          {            name: 'returnImage',            value: returnItem.photo,            type: 'STRING',          },        ];
4      }
5     
6     
7// dcreate thshis const as part of the class,
8  const imageCaptureAttr: TranslatableAttribute = {
9    type: 'component',
10    label:
11      'i18n:fc.sf.ui.returns.orders.createReturnOrder.list.returnItem.imageCapture',
12    labelFallback: 'Capture',
13    options: {
14      component: 'fc.photo.capture',
15      props: {
16        id: '{{node.state.orderItemRef}}',
17        onChange: handleImgChange,
18        data: dataWithState?.orderById.items,
19      },
20    },
21    align: 'center',
22  };     
23  
24 // when there is a change: 
25   const handleImgChange = (event: PhotoCaptureEvent) => {
26    const returnItem = state.returnItems.find(
27      (i) => i.orderItemRef === event.id,
28    );
29    if (!returnItem) {
30      console.error(
31        'Error handling quantity selector change: Could not find item with ref ' +
32          event.id,
33      );
34      return;
35    }
36    const returnItemUpdate = { ...returnItem };
37    returnItemUpdate.photo = event.value;
38
39    dispatch({ type: 'update', value: returnItemUpdate });
40  };
41     

Language: tsx

Name: add PhotoCapture details into ReturnItemsExtended.tsx

Description:

add PhotoCapture details into ReturnItemsExtended.tsx


Step arrow right iconCustom Rule

The new rule CreateReturnOrderFromOrder has been added to a custom rule plugin. It's an enhanced version of the basic rule from module-order. Additional code accepts new EventAttributes supported by UI changes and saves them.

Property

Value

Plugin name

<yourPluginName>

Rule API Client

GraphQL

Rule Info Description

Creates a return entity to begin the process of refunding the returned items.

Supported Entities

ORDER

1//event attribute changes
2@EventAttribute(name = "returnItems",
3    type = "RETURN_ITEMS")
4@EventAttribute(name = "pickupLocation")
5@EventAttribute(name = "lodgedLocation")
6@EventAttribute(name = "destinationLocation")
7@EventAttribute(name = "type")
8
9//save information about lodged location if it present in "lodgedLocation" or "pickupLocation" 
10        boolean hasLodgedLocation = false;
11        String lodgedLocation = null;
12
13        lodgedLocation = tryGetValueForKeyOrNull(pickupLocationMap, "lodgedLocation", "pickupLocation", String.class);
14        if (!isEmptyOrBlank(lodgedLocation)) {
15            hasLodgedLocation = true;
16        }
17            
18...
19        if (!hasLodgedLocation) {
20            lodgedLocation = tryGetValueForKeyOrNull(event.getAttributes(), "lodgedLocation", "", String.class);
21            hasLodgedLocation = !isEmptyOrBlank(lodgedLocation);
22        }
23
24
25//save attributes at the end of createReturnItem
26        // append attributes
27        List attributes = tryGetValueForKeyOrNull(returnItemMap, "attributes", "", List.class);
28        if (attributes != null) {
29            List<Attribute> attributesConverted = ValueConverter.convertList(attributes, Attribute.class);
30            returnItemBuilder.attributes(attributesConverted.stream()
31                .map(a -> AttributeInput.builder().name(a.getName()).value(a.getValue()).type(a.getType()).build())
32                .collect(Collectors.toList()));
33        }
34

Language: java

Name: Example required of changes in CreateReturnOrderFromOrder

Description:

Modified CreateReturnOrderFromOrder rule

Step arrow right iconUpdate order workflow

Rule CreateReturnOrderFromOrder was updated and added a new type returnItemsImage. To use it workflow has to be updated.

1{
2      "name": "ReturnOrder",
3      "description": "This ruleset is triggered when an event has been sent to initiate a Return against an Order. ",
4      "type": "ORDER",
5      "subtype": "HD",
6      "eventType": "NORMAL",
7      "rules": [
8        {
9          "name": "{{fluent.account.id}}.order.ValidateReturnQty",
10          "props": null
11        },
12        {
13          "name": "{{fluent.account.id}}.{packageName}.CreateReturnOrderFromOrder",
14          "props": null
15        },
16        {
17          "name": "{{fluent.account.id}}.core.SetState",
18          "props": {
19          "status": "RETURN_CREATED"
20          }
21        }
22      ],
23      "triggers": [
24        {
25          "status": "COMPLETE"
26        },
27        {
28          "status": "RETURN_CREATED"
29        },
30        {
31          "status": "RETURN_COMPLETE"
32        }
33      ],
34      "userActions": [
35        {
36          "context": [
37            {
38              "label": "Submit Return",
39              "type": "PRIMARY",
40              "modules": [
41                "adminconsole",
42                "store",
43                "servicepoint"
44              ],
45              "confirm": false
46            }
47          ],
48          "attributes": [
49            {
50              "name": "returnItems",
51              "label": "Items",
52              "type": "returnItemsImage",
53              "source": "",
54              "defaultValue": "",
55              "mandatory": true
56            },
57            {
58              "name": "pickupLocation",
59              "label": "Pickup Location",
60              "type": "ADDRESS",
61              "source": "",
62              "defaultValue": "",
63              "mandatory": false
64            },
65            {
66              "name": "lodgedLocation",
67              "label": "Lodged Location",
68              "type": "STRING",
69              "source": "",
70              "defaultValue": "",
71              "mandatory": false
72            },
73            {
74              "name": "type",
75              "label": "Return Type",
76              "type": "STRING",
77              "source": "",
78              "options": {
79                "active": [
80                  {
81                    "name": "Default",
82                    "value": "DEFAULT"
83                  }
84                ]
85              },
86              "defaultValue": "",
87              "mandatory": false
88            }
89          ]
90        }
91      ]
92    }

Language: json

Name: Home Delivery (HD)

Description:

HD workflow changes

1{
2  "name": "ReturnOrder",
3  "description": "Validate if the item can be returned and create the return order",
4  "type": "ORDER",
5  "subtype": "CC",
6  "eventType": "NORMAL",
7  "rules": [
8	{
9	  "name": "{{fluent.account.id}}.order.ValidateReturnQty",
10	  "props": null
11	},
12	{
13	  "name": "{{fluent.account.id}}.{packageName}.CreateReturnOrderFromOrder",
14	  "props": null
15	},
16	{
17	  "name": "{{fluent.account.id}}.core.SetState",
18	  "props": {
19		"status": "RETURN_CREATED"
20	  }
21	}
22  ],
23  "triggers": [
24	{
25	  "status": "COMPLETE"
26	},
27	{
28	  "status": "RETURN_CREATED"
29	},
30	{
31	  "status": "RETURN_COMPLETE"
32	}
33  ],
34  "userActions": [
35	{
36	  "context": [
37		{
38		  "label": "Submit Return",
39		  "type": "PRIMARY",
40		  "modules": [
41			"adminconsole",
42			"store",
43			"servicepoint"
44		  ],
45		  "confirm": false
46		}
47	  ],
48	  "attributes": [
49		{
50		  "name": "returnItems",
51		  "label": "Items",
52		  "type": "returnItemsImage",
53		  "source": "",
54		  "defaultValue": "",
55		  "mandatory": true
56		},
57		{
58		  "name": "pickupLocation",
59		  "label": "Pickup Location",
60		  "type": "ADDRESS",
61		  "source": "",
62		  "defaultValue": "",
63		  "mandatory": false
64		},
65		{
66		  "name": "lodgedLocation",
67		  "label": "Lodged Location",
68		  "type": "STRING",
69		  "source": "",
70		  "defaultValue": "",
71		  "mandatory": false
72		},
73		{
74		  "name": "type",
75		  "label": "Return Type",
76		  "type": "STRING",
77		  "source": "",
78		  "options": {
79			"active": [
80			  {
81				"name": "Default",
82				"value": "DEFAULT"
83			  }
84			]
85		  },
86		  "defaultValue": "",
87		  "mandatory": false
88		}
89	  ]
90	}
91  ]
92}

Language: json

Name: Click and Collect (CC)

Description:

CC workflow changes

Step arrow right iconSetting - RETURN_IMAGE_OPTIONS

1{
2    "imageType": "jpg",
3    "imageCompression": "0.3"
4}

Language: json

Name: RETURN_IMAGE_OPTIONS

Description:

Type: JSON

This setting is for image type and image compression.
imageType can contain ‘jpg’ or ‘png’ type.

imageCompression can contain a number from 0 to 1. 0 - is a maximum compression, 1 - is an original image. imageCompression works only with ‘jpg’ imageType.

Step arrow right iconResult

The result of the return image functionality enables Store Users to capture a photo of the item being returned. This photo is then attached to the returnOrder entity, providing a visual confirmation of the item's condition at the time of return. This feature enhances the return process by adding a layer of transparency and accountability, which can be beneficial for both the customer and the business.


 Valery Kornilovich

Valery Kornilovich

Contributors:
Randy Chan

Knowledge Tracks Related To This Topic

Copyright © 2024 Fluent Retail Pty Ltd (trading as Fluent Commerce). All rights reserved. No materials on this docs.fluentcommerce.com site may be used in any way and/or for any purpose without prior written authorisation from Fluent Commerce. Current customers and partners shall use these materials strictly in accordance with the terms and conditions of their written agreements with Fluent Commerce or its affiliates.

Fluent Logo