Validate Customer ID at Pickup
Authors:
Amine Sadallah, Siarhei Vaitsiakhovich, 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 an extended new feature where the Store User can validate the Customer ID during the Customer Collection Process.
- New custom UI components and rules are needed to capture the user input and confirm the selected articles in the UI user Action screen. Then, the store/business can track and trace the proof of the shopper's collection.
- Due to security reasons, the shopper's sensitive personal information should not be stored within Fluent OMS. Therefore, the proof of collection should be stored at a third-party storage.
Prerequisites
Steps
Solution Approach
The customer collection process must include a step to validate customer identification. Some key aspects of this screen change:
- Card 1: Customer card stays in the Customer Collection Screen.

- Card 2: Validate Identification (new component) in the user action drawers:
- This contains a drop-down of various identification types (presumably housed in a new setting)
- Driver’s License
- Passport
- Student ID
- Other
- This contains a drop-down of various identification types (presumably housed in a new setting)


- Card 3: Capture Signature (new component) in the user action drawers:
- This needs to allow the capture of a signature. This requires a dialogue pop-up to enter (and re-enter if needed). This is similar to the return image capture component experience that was created.
- This signature image should be saved as a file with a name that includes the article ID.
- This signature image should be saved as a file in an external repo (like product images and return capture images)
- This signature image should be visible against the article in Fluent OMS (like the return image is visible against the return order) Note: this idea is not part of this article.

- Card 4: Article Selector (new component) in the user action drawers:
- After the user has provided Identification, validated by the Store Staff, and captured the Shopper's signature, a list of articles will be displayed so that the Store Staff can pick which article is ready for collection:
- After the user has provided Identification, validated by the Store Staff, and captured the Shopper's signature, a list of articles will be displayed so that the Store Staff can pick which article is ready for collection:

- By clicking the Submit button, all customer-provided information is stored in a third-party storage.
Technical Design Overview
To support the business solution design, the following technical areas need to be enhanced:
- A new custom UI component (by using Component SDK) -
`articlesSelector`
- Two custom rules (by using Rule SDK):
`UpdateArticleAttributesAccordingEventAttribute`
`SendEventForAllArticlesFromAttribute`
- A new Setting to list out Identification Types:
`IDENTIFICATION_TYPE`
- Update of the Language Setting. E.g.
`LANGUAGE_EN-AU`
- Update Rulesets in CC Order workflow (,
`ARTICLE_COLLECTED`
)`ArticlesCollected`
Each of these tasks will be described below in steps.
UI Component: articlesSelector
For training purposes, the signature canvas package can be downloaded here: https://www.npmjs.com/package/react-signature-canvas
After installing the React signature canvas, open up your Component SDK, and create a new file:
`IdentificationTypes.tsx`
1 return (
2 <Card
3 title={translate(
4 'fc.sf.ui.collections.articleSelector.identificationTypes.selector',
5 )}
6 >
7 <CardContent>
8 <FormControl className={classes.cardSelect} variant="outlined">
9 <InputLabel id="identification-label">
10 {translate(
11 'fc.sf.ui.collections.articleSelector.identificationTypes.title',
12 )}
13 </InputLabel>
14 <Select
15 onChange={(_event, identification: any) => {
16 setValidate(false);
17 setIdentificationType(identification.props.value);
18 }}
19 value={identificationType}
20 labelId="identification-label"
21 label={translate(
22 'fc.sf.ui.collections.articleSelector.identificationTypes.title',
23 )}
24 >
25 {identificationSetting &&
26 identificationSetting.map((item, idx) => {
27 const identificationItemText = translate(item);
28 return (
29 <MenuItem key={idx} value={identificationItemText}>
30 {identificationItemText}
31 </MenuItem>
32 );
33 })}
34 </Select>
35 </FormControl>
36 <FormControlLabel
37 className={classes.cardCheckbox}
38 value="end"
39 control={
40 <Checkbox
41 color="primary"
42 checked={validate}
43 onChange={(_event, checked) => {
44 setValidate(checked);
45 }}
46 />
47 }
48 label={translate(
49 'fc.sf.ui.collections.articleSelector.identificationTypes.validate',
50 )}
51 />
52 </CardContent>
53 </Card>
54 );
Language: tsx
Name: IdentificationTypes sample output:
Description:
This will display a dropdown list of the type of identification accepted by the Store. The list is derived from a setting. It also displays a checkbox where the store user has confirmed the ID validation.
Then create a new file:
`CanvasSignature.tsx`
1 <Card
2 title={translate('fc.sf.ui.collections.articleSelector.signature.title')}
3 >
4 <CardContent>
5 <div className={classes.sigCanvas}>
6 <SignatureCanvas
7 ref={(ref) => {
8 sigCanvas.current = ref;
9 }}
10 penColor="black"
11 backgroundColor="#eee"
12 canvasProps={{ width: 450, height: 150 }}
13 />
14 </div>
15 <div className={classes.sigBlockButton}>
16 <Button variant="contained" color="primary" onClick={clearSignature}>
17 {translate(
18 'fc.sf.ui.collections.articleSelector.signature.button.clear',
19 )}
20 </Button>
21 <Button variant="contained" color="primary" onClick={getDataUrl}>
22 {translate(
23 'fc.sf.ui.collections.articleSelector.signature.button.capture',
24 )}
25 </Button>
26 </div>
27 </CardContent>
28 </Card>
Language: tsx
Name: The CanvasSignature sample output:
Description:
This will display the Signature Canvas card with a clear button and a capture button.
Next, create a new file:
`ArticleSelector.tsx`
1 return (
2 <div className={classes.articleColumn}>
3 <IdentificationTypes onChange={getIdentificationType} />
4 <CanvasSignature onChange={getSignature} />
5 {signature && identificationType && (
6 <TableContainer component={Paper}>
7 <Table className={classes.table}>
8 <TableHead>
9 <TableRow>
10 {articles?.length ? (
11 <TableCell padding="checkbox">
12 <Checkbox
13 onChange={handleSelectAllClick}
14 color="secondary"
15 indeterminate={
16 selectedRows.length > 0 &&
17 selectedRows.length < articles.length
18 }
19 checked={
20 articles.length > 0 &&
21 selectedRows.length === articles.length
22 }
23 inputProps={{
24 'aria-label': 'select all',
25 }}
26 />
27 </TableCell>
28 ) : (
29 ''
30 )}
31 <TableCell>
32 <span>
33 {translate(
34 'fc.sf.ui.collections.articleSelector.details.list.column.storageArea.heading',
35 )}
36 </span>
37 </TableCell>
38 <TableCell>
39 <span>
40 {translate(
41 'fc.sf.ui.collections.articleSelector.details.list.column.status.heading',
42 )}
43 </span>
44 </TableCell>
45 <TableCell>
46 <span>
47 {translate(
48 'fc.sf.ui.collections.articleSelector.details.list.column.article.heading',
49 )}
50 </span>
51 </TableCell>
52 </TableRow>
53 </TableHead>
54 <TableBody>
55 {articles?.length ? (
56 articles.map((articleNode) => {
57 const isItemSelected = isSelected(articleNode);
58 return (
59 <TableRow
60 hover
61 role="checkbox"
62 tabIndex={-1}
63 key={articleNode.ref}
64 selected={isItemSelected}
65 >
66 <TableCell
67 padding="checkbox"
68 onClick={(e) => {
69 selectRow(e, articleNode);
70 }}
71 >
72 <Checkbox
73 checked={
74 !!selectedRows.find(
75 (sel) => sel.key === articleNode.ref,
76 )
77 }
78 inputProps={{
79 'aria-labelledby': '' + articleNode.ref,
80 }}
81 />
82 </TableCell>
83 <TableCell>
84 <span title={articleNode.storageArea?.name}>
85 {articleNode.storageArea?.name}
86 </span>
87 </TableCell>
88 <TableCell>
89 <span title={articleNode.status}>
90 <ContentColumn
91 data={articleNode}
92 value={'{{status}}'}
93 contentColumnSetting={
94 (contentColumnSetting.setting.status === 'ok' &&
95 contentColumnSetting.setting.result?.value) ||
96 'fc.list.status.column'
97 }
98 />
99 </span>
100 </TableCell>
101 <TableCell>
102 <span title={articleNode.ref}>
103 <CollapsibleText
104 text={articleNode.ref}
105 charCutoff={8}
106 />
107 </span>
108 </TableCell>
109 </TableRow>
110 );
111 })
112 ) : (
113 <TableRow className={classes.tableEmpty}>
114 <TableCell colSpan={3} align="center">
115 {translate(
116 'fc.sf.ui.collections.articleSelector.details.list.noRecords',
117 )}
118 </TableCell>
119 </TableRow>
120 )}
121 </TableBody>
122 </Table>
123 </TableContainer>
124 )}
125 </div>
126 );
Language: tsx
Name: The CanvasSignature sample output:
Description:
After user has provided an Identification, validated by the Store Staff and capture the Shopper's signature, a list of articles will be displayed so that the Store Staff can pick which article is ready for collection
Custom Rules
Two custom Rules need to be added:
SendEventForAllArticlesFromAttribute
Property | Value |
Plugin name | <yourPluginName> |
Rule API Client | GraphQL |
Rule Info Description | Send an event
|
Supported Entities | ORDER, FULFILMENT, ARTICLE |
Input Parameters
Parameter | Description |
eventName | The name of the event to be triggered |
Event Attributes
Attribute Name | Description |
ARTICLES | Object with information about articles in JSON format. Example: { "signature": "data:image/png;base64,iVBORw0KGgoAAAN...", "identificationType": "Passport", "articles": [ "fd7c188b-d9cf-42da-9a71-14bd11e336183d443e333-1" ] } Where
|
UpdateArticleAttributesAccordingEventAttribute
Property | Value |
Plugin name | <yourPluginName> |
Rule API Client | GraphQL |
Rule Info Description | Update Article attributes according to Event Attribute
|
Supported Entities | ARTICLE |
Event Attributes
Attribute Name | Description |
ARTICLES | Object with information about articles in JSON format. Example: { "signature": "data:image/png;base64,iVBORw0KGgoAAAN...", "identificationType": "Passport", "articles": [ "fd7c188b-d9cf-42da-9a71-14bd11e336183d443e333-1" ] } Where
|
Update Language Setting
Include the following in your language Setting. For example: Setting name: LANGUAGE_EN-AU:
1{
2 "translation": {
3 "fc.sf.ui.collections.articleSelector.signature.success.capture": "Successful",
4 "fc.sf.ui.collections.articleSelector.signature.title": "CUSTOMER SIGNATURE",
5 "fc.sf.ui.collections.articleSelector.signature.button.clear": "Clear",
6 "fc.sf.ui.collections.articleSelector.signature.button.capture": "Capture",
7 "fc.sf.ui.collections.articleSelector.details.list.column.storageArea.heading": "Storage Area",
8 "fc.sf.ui.collections.articleSelector.details.list.column.status.heading": "Status",
9 "fc.sf.ui.collections.articleSelector.details.list.column.article.heading": "Article",
10 "fc.sf.ui.collections.articleSelector.identificationTypes.selector": "IDENTIFICATION TYPE",
11 "fc.sf.ui.collections.articleSelector.identificationTypes.title": "Validate Identification",
12 "fc.sf.ui.collections.articleSelector.identificationTypes.validate": "Validated",
13 "fc.sf.ui.collections.articleSelector.identificationTypes.driversLicense": "Driver License",
14 "fc.sf.ui.collections.articleSelector.identificationTypes.passport": "Passport",
15 "fc.sf.ui.collections.articleSelector.identificationTypes.studentId": "Student ID",
16 "fc.sf.ui.collections.articleSelector.identificationTypes.other": "Other",
17
18 ...
19 }
20}
Language: json
Name: Language setting snippets
Description:
Language setting snippets
Setting: IDENTIFICATION_TYPE
Create a new Setting with the following:
Name | IDENTIFICATION_TYPE |
Value Type | JSON |
Context | ACCOUNT |
Context ID | 0 |
JSON Value | [ "fc.sf.ui.collections.articleSelector.identificationTypes.driversLicense", "fc.sf.ui.collections.articleSelector.identificationTypes.passport", "fc.sf.ui.collections.articleSelector.identificationTypes.studentId", "fc.sf.ui.collections.articleSelector.identificationTypes.other" ] |
CC Order Manifest Change
Update the Ruleset ARTICLE_COLLECTED with the following:
1{
2 "name": "ARTICLE_COLLECTED",
3 "description": "Customer collection",
4 "type": "ARTICLE",
5 "subtype": "DEFAULT",
6 "eventType": "NORMAL",
7 "rules": [
8 {
9 "name": "{{fluent.account.id}}.core.SetState",
10 "props": {
11 "status": "COLLECTED"
12 }
13 },
14 {
15 "name": "{{fluent.account.id}}.{packageName}.UpdateArticleAttributesAccordingEventAttribute",
16 "props": {}
17 },
18 {
19 "name": "{{fluent.account.id}}.{packageName}.SendEventForAllArticlesFromAttribute",
20 "props": {
21 "eventName": "ArticleCollected"
22 }
23 }
24 ],
25 "triggers": [
26 {
27 "status": "AWAITING_COLLECTION"
28 }
29 ],
30 "userActions": [
31 {
32 "context": [
33 {
34 "label": "CUSTOMER COLLECTION",
35 "type": "PRIMARY",
36 "modules": [
37 "servicepoint"
38 ],
39 "confirm": false
40 }
41 ],
42 "attributes": [
43 {
44 "name": "ARTICLES",
45 "label": "Articles",
46 "type": "articlesSelector",
47 "source": "",
48 "defaultValue": "",
49 "mandatory": true
50 }
51 ]
52 }
53 ]
54 },
Language: json
Name: ARTICLE_COLLECTED ruleset in Click and Collect (CC) order workflow
Description:
ARTICLE_COLLECTED ruleset in CC order workflow
Result
The user should able to see the article selector UI in the User Action section:


The output of the above can be seen in the third-party storage:
1"articles": {
2"edges": [
3 {
4 "node": {
5 "ref": "35e6ea8f-ee85-464c-dsdsdsds-2dsdsdsds-199_MEL-1",
6 "id": "1231",
7 "status": "COLLECTED",
8 "attributes": [
9 {
10 "name": "IDENTIFICATION_TYPE",
11 "type": "STRING",
12 "value": "fc.sf.ui.collections.articleSelector.identificationTypes.driversLicense"
13 },
14 {
15 "name": "SIGNATURE",
16 "type": "STRING",
17 "value": "data:image/png;base64,i...Jggg=="
18 }
19 ]
20 }
21 }
22]
Language: json
Name: sample output
Description:
Example of attributes