@cxtms/cx-schema 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/cx-core/SKILL.md +93 -0
- package/.claude/skills/cx-core/ref-entity-accounting.md +173 -0
- package/.claude/skills/cx-core/ref-entity-commodity.md +205 -0
- package/.claude/skills/cx-core/ref-entity-contact.md +153 -0
- package/.claude/skills/cx-core/ref-entity-geography.md +119 -0
- package/.claude/skills/cx-core/ref-entity-job.md +77 -0
- package/.claude/skills/cx-core/ref-entity-order-sub.md +140 -0
- package/.claude/skills/cx-core/ref-entity-order.md +168 -0
- package/.claude/skills/cx-core/ref-entity-rate.md +174 -0
- package/.claude/skills/cx-core/ref-entity-shared.md +147 -0
- package/.claude/skills/cx-core/ref-entity-warehouse.md +110 -0
- package/.claude/skills/cx-module/SKILL.md +402 -0
- package/.claude/skills/cx-module/ref-components-data.md +286 -0
- package/.claude/skills/cx-module/ref-components-display.md +394 -0
- package/.claude/skills/cx-module/ref-components-forms.md +362 -0
- package/.claude/skills/cx-module/ref-components-interactive.md +306 -0
- package/.claude/skills/cx-module/ref-components-layout.md +295 -0
- package/.claude/skills/cx-module/ref-components-specialized.md +427 -0
- package/.claude/skills/cx-workflow/SKILL.md +330 -0
- package/.claude/skills/cx-workflow/ref-accounting.md +66 -0
- package/.claude/skills/cx-workflow/ref-communication.md +161 -0
- package/.claude/skills/cx-workflow/ref-entity.md +162 -0
- package/.claude/skills/cx-workflow/ref-expressions.md +239 -0
- package/.claude/skills/cx-workflow/ref-filetransfer.md +80 -0
- package/.claude/skills/cx-workflow/ref-flow.md +180 -0
- package/.claude/skills/cx-workflow/ref-other.md +120 -0
- package/.claude/skills/cx-workflow/ref-query.md +85 -0
- package/.claude/skills/cx-workflow/ref-utilities.md +171 -0
- package/README.md +34 -34
- package/dist/cli.js +545 -35
- package/dist/cli.js.map +1 -1
- package/dist/types.d.ts +17 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/workflowValidator.d.ts +31 -0
- package/dist/workflowValidator.d.ts.map +1 -1
- package/dist/workflowValidator.js +299 -9
- package/dist/workflowValidator.js.map +1 -1
- package/package.json +4 -3
- package/schemas/schema.graphql +2077 -321
- package/schemas/workflows/flow/aggregation.json +44 -0
- package/schemas/workflows/flow/entity.json +110 -0
- package/schemas/workflows/flow/state.json +105 -0
- package/schemas/workflows/flow/transition.json +143 -0
- package/schemas/workflows/input.json +53 -7
- package/schemas/workflows/output.json +20 -0
- package/schemas/workflows/trigger.json +4 -0
- package/schemas/workflows/variable.json +2 -6
- package/schemas/workflows/workflow.json +179 -21
- package/scripts/postinstall.js +30 -1
- package/templates/module-configuration.yaml +110 -0
- package/templates/module-form.yaml +152 -0
- package/templates/module-grid.yaml +229 -0
- package/templates/module-select.yaml +139 -0
- package/templates/module.yaml +3 -3
- package/templates/workflow-api-tracking.yaml +189 -0
- package/templates/workflow-basic.yaml +76 -0
- package/templates/workflow-document.yaml +155 -0
- package/templates/workflow-entity-trigger.yaml +90 -0
- package/templates/workflow-ftp-edi.yaml +158 -0
- package/templates/workflow-ftp-tracking.yaml +161 -0
- package/templates/workflow-mcp-tool.yaml +112 -0
- package/templates/workflow-public-api.yaml +135 -0
- package/templates/workflow-scheduled.yaml +125 -0
- package/templates/workflow-utility.yaml +96 -0
- package/templates/workflow-webhook.yaml +128 -0
- package/templates/workflow.yaml +52 -12
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# {{displayName}} Workflow
|
|
2
|
+
# Generated by cx-cli create workflow --template document
|
|
3
|
+
|
|
4
|
+
workflow:
|
|
5
|
+
workflowId: "{{uuid}}"
|
|
6
|
+
name: "{{displayName}}"
|
|
7
|
+
description: "{{displayName}} document generation workflow"
|
|
8
|
+
version: "1.0"
|
|
9
|
+
workflowType: "Document"
|
|
10
|
+
executionMode: Sync
|
|
11
|
+
logLevel: Information
|
|
12
|
+
isActive: true
|
|
13
|
+
enableAudit: true
|
|
14
|
+
filePath: "{{fileName}}"
|
|
15
|
+
tags:
|
|
16
|
+
- "generated"
|
|
17
|
+
- "document"
|
|
18
|
+
|
|
19
|
+
inputs:
|
|
20
|
+
- name: orderId
|
|
21
|
+
type: text
|
|
22
|
+
props:
|
|
23
|
+
displayName: "Order ID"
|
|
24
|
+
description: "The ID of the order to generate document for"
|
|
25
|
+
required: true
|
|
26
|
+
visible: true
|
|
27
|
+
mapping: "order.orderId"
|
|
28
|
+
|
|
29
|
+
outputs:
|
|
30
|
+
- name: file
|
|
31
|
+
mapping: "GenerateDocument.Render.document"
|
|
32
|
+
- name: fileName
|
|
33
|
+
mapping: "fileName"
|
|
34
|
+
- name: fileDisposition
|
|
35
|
+
mapping: "attachment"
|
|
36
|
+
|
|
37
|
+
variables:
|
|
38
|
+
- name: fileName
|
|
39
|
+
value: "{{displayNameNoSpaces}}.pdf"
|
|
40
|
+
|
|
41
|
+
triggers:
|
|
42
|
+
- type: Manual
|
|
43
|
+
name: ManualTrigger
|
|
44
|
+
displayName: "Generate {{displayName}}"
|
|
45
|
+
|
|
46
|
+
activities:
|
|
47
|
+
- name: FetchData
|
|
48
|
+
events:
|
|
49
|
+
onActivityStarted:
|
|
50
|
+
- task: "Utilities/Log@1"
|
|
51
|
+
name: LogActivityStarted
|
|
52
|
+
inputs:
|
|
53
|
+
message: "Activity FetchData started"
|
|
54
|
+
level: Information
|
|
55
|
+
onActivityCompleted:
|
|
56
|
+
- task: "Utilities/Log@1"
|
|
57
|
+
name: LogActivityCompleted
|
|
58
|
+
inputs:
|
|
59
|
+
message: "Activity FetchData completed"
|
|
60
|
+
level: Information
|
|
61
|
+
onActivityFailed:
|
|
62
|
+
- task: "Utilities/Log@1"
|
|
63
|
+
name: LogActivityFailed
|
|
64
|
+
inputs:
|
|
65
|
+
message: "Activity FetchData failed: {{exception.message}}"
|
|
66
|
+
level: Error
|
|
67
|
+
steps:
|
|
68
|
+
- task: "Query/GraphQL"
|
|
69
|
+
name: GetOrder
|
|
70
|
+
inputs:
|
|
71
|
+
query: |
|
|
72
|
+
query($organizationId: Int!, $orderId: Int!) {
|
|
73
|
+
order(organizationId: $organizationId, orderId: $orderId) {
|
|
74
|
+
orderId
|
|
75
|
+
orderNumber
|
|
76
|
+
status
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
variables:
|
|
80
|
+
organizationId: "\{{organizationId}}"
|
|
81
|
+
orderId: "\{{inputs.orderId}}"
|
|
82
|
+
outputs:
|
|
83
|
+
- name: order
|
|
84
|
+
mapping: "order?"
|
|
85
|
+
|
|
86
|
+
- name: GenerateDocument
|
|
87
|
+
events:
|
|
88
|
+
onActivityStarted:
|
|
89
|
+
- task: "Utilities/Log@1"
|
|
90
|
+
name: LogActivityStarted
|
|
91
|
+
inputs:
|
|
92
|
+
message: "Activity GenerateDocument started"
|
|
93
|
+
level: Information
|
|
94
|
+
onActivityCompleted:
|
|
95
|
+
- task: "Utilities/Log@1"
|
|
96
|
+
name: LogActivityCompleted
|
|
97
|
+
inputs:
|
|
98
|
+
message: "Activity GenerateDocument completed"
|
|
99
|
+
level: Information
|
|
100
|
+
onActivityFailed:
|
|
101
|
+
- task: "Utilities/Log@1"
|
|
102
|
+
name: LogActivityFailed
|
|
103
|
+
inputs:
|
|
104
|
+
message: "Activity GenerateDocument failed: {{exception.message}}"
|
|
105
|
+
level: Error
|
|
106
|
+
steps:
|
|
107
|
+
- task: "Document/Render@1"
|
|
108
|
+
name: Render
|
|
109
|
+
inputs:
|
|
110
|
+
template:
|
|
111
|
+
engine: "handlebars"
|
|
112
|
+
recipe: "chrome-pdf"
|
|
113
|
+
content: |
|
|
114
|
+
<html>
|
|
115
|
+
<head>
|
|
116
|
+
<style>
|
|
117
|
+
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
118
|
+
h1 { color: #333; }
|
|
119
|
+
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
|
120
|
+
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
121
|
+
th { background-color: #f5f5f5; }
|
|
122
|
+
</style>
|
|
123
|
+
</head>
|
|
124
|
+
<body>
|
|
125
|
+
<h1>{{displayName}}</h1>
|
|
126
|
+
<p>Order: \{{orderNumber}}</p>
|
|
127
|
+
<p>Status: \{{status}}</p>
|
|
128
|
+
</body>
|
|
129
|
+
</html>
|
|
130
|
+
data:
|
|
131
|
+
orderNumber: "\{{FetchData?.GetOrder?.order?.orderNumber?}}"
|
|
132
|
+
status: "\{{FetchData?.GetOrder?.order?.status?}}"
|
|
133
|
+
outputs:
|
|
134
|
+
- name: document
|
|
135
|
+
mapping: "document?"
|
|
136
|
+
|
|
137
|
+
events:
|
|
138
|
+
onWorkflowStarted:
|
|
139
|
+
- task: "Utilities/Log@1"
|
|
140
|
+
name: LogWorkflowStarted
|
|
141
|
+
inputs:
|
|
142
|
+
message: "{{displayName}} workflow started"
|
|
143
|
+
level: Information
|
|
144
|
+
onWorkflowExecuted:
|
|
145
|
+
- task: "Utilities/Log@1"
|
|
146
|
+
name: LogWorkflowExecuted
|
|
147
|
+
inputs:
|
|
148
|
+
message: "{{displayName}} workflow completed successfully"
|
|
149
|
+
level: Information
|
|
150
|
+
onWorkflowFailed:
|
|
151
|
+
- task: "Utilities/Log@1"
|
|
152
|
+
name: LogWorkflowFailed
|
|
153
|
+
inputs:
|
|
154
|
+
message: "{{displayName}} workflow failed: {{exception.message}}"
|
|
155
|
+
level: Error
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# {{displayName}} Workflow
|
|
2
|
+
# Generated by cx-cli create workflow --template entity-trigger
|
|
3
|
+
|
|
4
|
+
workflow:
|
|
5
|
+
workflowId: "{{uuid}}"
|
|
6
|
+
name: "{{displayName}}"
|
|
7
|
+
description: "{{displayName}} entity trigger workflow"
|
|
8
|
+
version: "1.0"
|
|
9
|
+
executionMode: Sync
|
|
10
|
+
logLevel: Information
|
|
11
|
+
isActive: true
|
|
12
|
+
enableAudit: true
|
|
13
|
+
filePath: "{{fileName}}"
|
|
14
|
+
tags:
|
|
15
|
+
- "generated"
|
|
16
|
+
- "trigger"
|
|
17
|
+
|
|
18
|
+
triggers:
|
|
19
|
+
- type: "Entity"
|
|
20
|
+
entityName: "Order"
|
|
21
|
+
eventType: "Modified"
|
|
22
|
+
conditions:
|
|
23
|
+
- expression: "any([changes], [each.key] = 'Status') = true"
|
|
24
|
+
position: "After"
|
|
25
|
+
|
|
26
|
+
activities:
|
|
27
|
+
- name: Data
|
|
28
|
+
events:
|
|
29
|
+
onActivityStarted:
|
|
30
|
+
- task: "Utilities/Log@1"
|
|
31
|
+
name: LogActivityStarted
|
|
32
|
+
inputs:
|
|
33
|
+
message: "Activity Data started"
|
|
34
|
+
level: Information
|
|
35
|
+
onActivityCompleted:
|
|
36
|
+
- task: "Utilities/Log@1"
|
|
37
|
+
name: LogActivityCompleted
|
|
38
|
+
inputs:
|
|
39
|
+
message: "Activity Data completed"
|
|
40
|
+
level: Information
|
|
41
|
+
onActivityFailed:
|
|
42
|
+
- task: "Utilities/Log@1"
|
|
43
|
+
name: LogActivityFailed
|
|
44
|
+
inputs:
|
|
45
|
+
message: "Activity Data failed: {{exception.message}}"
|
|
46
|
+
level: Error
|
|
47
|
+
steps:
|
|
48
|
+
- task: "Query/GraphQL"
|
|
49
|
+
name: GetOrder
|
|
50
|
+
inputs:
|
|
51
|
+
query: |
|
|
52
|
+
query($organizationId: Int!, $orderId: Int!) {
|
|
53
|
+
order(organizationId: $organizationId, orderId: $orderId) {
|
|
54
|
+
orderId
|
|
55
|
+
orderNumber
|
|
56
|
+
status
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
variables:
|
|
60
|
+
organizationId: "\{{organizationId}}"
|
|
61
|
+
orderId: "\{{entity.orderId}}"
|
|
62
|
+
outputs:
|
|
63
|
+
- name: order
|
|
64
|
+
mapping: "order?"
|
|
65
|
+
|
|
66
|
+
- task: "Utilities/Log@1"
|
|
67
|
+
name: LogChange
|
|
68
|
+
inputs:
|
|
69
|
+
message: "{{displayName}}: Order \{{Data?.GetOrder?.order?.orderNumber?}} status changed"
|
|
70
|
+
level: Information
|
|
71
|
+
|
|
72
|
+
events:
|
|
73
|
+
onWorkflowStarted:
|
|
74
|
+
- task: "Utilities/Log@1"
|
|
75
|
+
name: LogWorkflowStarted
|
|
76
|
+
inputs:
|
|
77
|
+
message: "{{displayName}} workflow started"
|
|
78
|
+
level: Information
|
|
79
|
+
onWorkflowExecuted:
|
|
80
|
+
- task: "Utilities/Log@1"
|
|
81
|
+
name: LogWorkflowExecuted
|
|
82
|
+
inputs:
|
|
83
|
+
message: "{{displayName}} workflow completed successfully"
|
|
84
|
+
level: Information
|
|
85
|
+
onWorkflowFailed:
|
|
86
|
+
- task: "Utilities/Log@1"
|
|
87
|
+
name: LogWorkflowFailed
|
|
88
|
+
inputs:
|
|
89
|
+
message: "{{displayName}} workflow failed: {{exception.message}}"
|
|
90
|
+
level: Error
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# {{displayName}} Workflow
|
|
2
|
+
# Generated by cx-cli create workflow --template ftp-edi
|
|
3
|
+
|
|
4
|
+
workflow:
|
|
5
|
+
workflowId: "{{uuid}}"
|
|
6
|
+
name: "{{displayName}}"
|
|
7
|
+
description: "{{displayName}} - Import orders from FTP via EDI"
|
|
8
|
+
version: "1.0"
|
|
9
|
+
executionMode: Async
|
|
10
|
+
logLevel: Information
|
|
11
|
+
isActive: true
|
|
12
|
+
enableAudit: true
|
|
13
|
+
filePath: "{{fileName}}"
|
|
14
|
+
runAs: workflowAgent
|
|
15
|
+
concurrency:
|
|
16
|
+
waitTime: 0
|
|
17
|
+
tags:
|
|
18
|
+
- "generated"
|
|
19
|
+
- "ftp"
|
|
20
|
+
- "edi"
|
|
21
|
+
|
|
22
|
+
variables:
|
|
23
|
+
- name: ftpConfig
|
|
24
|
+
fromConfig:
|
|
25
|
+
configName: "apps.myApp.ftpConfig"
|
|
26
|
+
|
|
27
|
+
schedules:
|
|
28
|
+
- cron: "0/10 * * * *"
|
|
29
|
+
displayName: "{{displayName}} - Every 10 minutes"
|
|
30
|
+
|
|
31
|
+
activities:
|
|
32
|
+
- name: FtpImport
|
|
33
|
+
conditions: "[ftpConfig?.schedulingEnabled?] = true"
|
|
34
|
+
events:
|
|
35
|
+
onActivityStarted:
|
|
36
|
+
- task: "Utilities/Log@1"
|
|
37
|
+
name: LogActivityStarted
|
|
38
|
+
inputs:
|
|
39
|
+
message: "Activity FtpImport started"
|
|
40
|
+
level: Information
|
|
41
|
+
onActivityCompleted:
|
|
42
|
+
- task: "Utilities/Log@1"
|
|
43
|
+
name: LogActivityCompleted
|
|
44
|
+
inputs:
|
|
45
|
+
message: "Activity FtpImport completed"
|
|
46
|
+
level: Information
|
|
47
|
+
onActivityFailed:
|
|
48
|
+
- task: "Utilities/Log@1"
|
|
49
|
+
name: LogActivityFailed
|
|
50
|
+
inputs:
|
|
51
|
+
message: "Activity FtpImport failed: {{exception.message}}"
|
|
52
|
+
level: Error
|
|
53
|
+
steps:
|
|
54
|
+
- task: "FileTransfer/Connect@1"
|
|
55
|
+
name: SftpConnect
|
|
56
|
+
inputs:
|
|
57
|
+
host: "{{ ftpConfig?.host? }}"
|
|
58
|
+
protocol: "{{ ftpConfig?.protocol? }}"
|
|
59
|
+
username: "{{ ftpConfig?.username? }}"
|
|
60
|
+
authentication:
|
|
61
|
+
type: "password"
|
|
62
|
+
password: "{{ ftpConfig?.password? }}"
|
|
63
|
+
options:
|
|
64
|
+
timeout: 30
|
|
65
|
+
outputs:
|
|
66
|
+
- name: connection
|
|
67
|
+
mapping: "connection?"
|
|
68
|
+
- name: connectionId
|
|
69
|
+
mapping: "connectionId?"
|
|
70
|
+
|
|
71
|
+
- task: "FileTransfer/ListFiles@1"
|
|
72
|
+
name: SftpListFiles
|
|
73
|
+
inputs:
|
|
74
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
75
|
+
directory: "inbound"
|
|
76
|
+
recursive: false
|
|
77
|
+
includeDirectories: false
|
|
78
|
+
sortBy: "name"
|
|
79
|
+
sortOrder: "asc"
|
|
80
|
+
outputs:
|
|
81
|
+
- name: files
|
|
82
|
+
mapping: "files?"
|
|
83
|
+
- name: fileCount
|
|
84
|
+
mapping: "fileCount?"
|
|
85
|
+
|
|
86
|
+
- task: "foreach"
|
|
87
|
+
name: ProcessFiles
|
|
88
|
+
collection: "FtpImport?.SftpListFiles?.files?"
|
|
89
|
+
steps:
|
|
90
|
+
- task: "FileTransfer/DownloadFile@1"
|
|
91
|
+
name: SftpDownloadFile
|
|
92
|
+
inputs:
|
|
93
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
94
|
+
remotePath: "{{ item.path }}"
|
|
95
|
+
outputs:
|
|
96
|
+
- name: fileInfo
|
|
97
|
+
mapping: "fileInfo?"
|
|
98
|
+
- name: content
|
|
99
|
+
mapping: "content?"
|
|
100
|
+
|
|
101
|
+
- task: "Workflow/Execute@1"
|
|
102
|
+
name: ProcessEdi
|
|
103
|
+
inputs:
|
|
104
|
+
workflowName: "EDI Parse"
|
|
105
|
+
workflowInputs:
|
|
106
|
+
fileContent:
|
|
107
|
+
expression: "fromBase64([FtpImport?.SftpDownloadFile?.content?])"
|
|
108
|
+
outputs:
|
|
109
|
+
- name: parsedData
|
|
110
|
+
mapping: "parsedObject?"
|
|
111
|
+
|
|
112
|
+
# TODO: Map parsed EDI data to orders and import
|
|
113
|
+
- task: "Order/Import@1"
|
|
114
|
+
name: ImportOrders
|
|
115
|
+
inputs:
|
|
116
|
+
orders: "{{ orderData }}"
|
|
117
|
+
options:
|
|
118
|
+
orderMatchByFields:
|
|
119
|
+
- "orderNumber"
|
|
120
|
+
commodityMatchByFields:
|
|
121
|
+
- "description"
|
|
122
|
+
|
|
123
|
+
- task: "FileTransfer/MoveFile@1"
|
|
124
|
+
name: SftpMoveFile
|
|
125
|
+
inputs:
|
|
126
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
127
|
+
sourcePath: "{{ item.path }}"
|
|
128
|
+
destinationPath:
|
|
129
|
+
expression: "format('processed/{0}-{1}', formatDate(now(), 'yyyyMMdd_HHmmss', 'en-US'), [item.name])"
|
|
130
|
+
options:
|
|
131
|
+
createDirectories: true
|
|
132
|
+
overwrite: true
|
|
133
|
+
|
|
134
|
+
- task: "FileTransfer/Disconnect@1"
|
|
135
|
+
name: SftpDisconnect
|
|
136
|
+
conditions: "isNullOrEmpty([FtpImport?.SftpConnect?.connection?]) = false"
|
|
137
|
+
inputs:
|
|
138
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
139
|
+
|
|
140
|
+
events:
|
|
141
|
+
onWorkflowStarted:
|
|
142
|
+
- task: "Utilities/Log@1"
|
|
143
|
+
name: LogWorkflowStarted
|
|
144
|
+
inputs:
|
|
145
|
+
message: "{{displayName}} workflow started"
|
|
146
|
+
level: Information
|
|
147
|
+
onWorkflowExecuted:
|
|
148
|
+
- task: "Utilities/Log@1"
|
|
149
|
+
name: LogWorkflowExecuted
|
|
150
|
+
inputs:
|
|
151
|
+
message: "{{displayName}} workflow completed successfully"
|
|
152
|
+
level: Information
|
|
153
|
+
onWorkflowFailed:
|
|
154
|
+
- task: "Utilities/Log@1"
|
|
155
|
+
name: LogWorkflowFailed
|
|
156
|
+
inputs:
|
|
157
|
+
message: "{{displayName}} workflow failed: {{exception.message}}"
|
|
158
|
+
level: Error
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# {{displayName}} Workflow
|
|
2
|
+
# Generated by cx-cli create workflow --template ftp-tracking
|
|
3
|
+
|
|
4
|
+
workflow:
|
|
5
|
+
workflowId: "{{uuid}}"
|
|
6
|
+
name: "{{displayName}}"
|
|
7
|
+
description: "{{displayName}} - Import tracking events from FTP"
|
|
8
|
+
version: "1.0"
|
|
9
|
+
executionMode: Async
|
|
10
|
+
logLevel: Information
|
|
11
|
+
isActive: true
|
|
12
|
+
enableAudit: true
|
|
13
|
+
filePath: "{{fileName}}"
|
|
14
|
+
runAs: workflowAgent
|
|
15
|
+
concurrency:
|
|
16
|
+
waitTime: 0
|
|
17
|
+
tags:
|
|
18
|
+
- "generated"
|
|
19
|
+
- "ftp"
|
|
20
|
+
- "tracking"
|
|
21
|
+
|
|
22
|
+
variables:
|
|
23
|
+
- name: ftpConfig
|
|
24
|
+
fromConfig:
|
|
25
|
+
configName: "apps.myApp.ftpConfig"
|
|
26
|
+
|
|
27
|
+
schedules:
|
|
28
|
+
- cron: "*/30 * * * *"
|
|
29
|
+
displayName: "{{displayName}} - Every 30 minutes"
|
|
30
|
+
|
|
31
|
+
activities:
|
|
32
|
+
- name: FtpImport
|
|
33
|
+
conditions: "[ftpConfig?.schedulingEnabled?] = true"
|
|
34
|
+
events:
|
|
35
|
+
onActivityStarted:
|
|
36
|
+
- task: "Utilities/Log@1"
|
|
37
|
+
name: LogActivityStarted
|
|
38
|
+
inputs:
|
|
39
|
+
message: "Activity FtpImport started"
|
|
40
|
+
level: Information
|
|
41
|
+
onActivityCompleted:
|
|
42
|
+
- task: "Utilities/Log@1"
|
|
43
|
+
name: LogActivityCompleted
|
|
44
|
+
inputs:
|
|
45
|
+
message: "Activity FtpImport completed"
|
|
46
|
+
level: Information
|
|
47
|
+
onActivityFailed:
|
|
48
|
+
- task: "Utilities/Log@1"
|
|
49
|
+
name: LogActivityFailed
|
|
50
|
+
inputs:
|
|
51
|
+
message: "Activity FtpImport failed: {{exception.message}}"
|
|
52
|
+
level: Error
|
|
53
|
+
steps:
|
|
54
|
+
- task: "FileTransfer/Connect@1"
|
|
55
|
+
name: SftpConnect
|
|
56
|
+
inputs:
|
|
57
|
+
host: "{{ ftpConfig?.host? }}"
|
|
58
|
+
protocol: "{{ ftpConfig?.protocol? }}"
|
|
59
|
+
username: "{{ ftpConfig?.username? }}"
|
|
60
|
+
authentication:
|
|
61
|
+
type: "password"
|
|
62
|
+
password: "{{ ftpConfig?.password? }}"
|
|
63
|
+
options:
|
|
64
|
+
timeout: 30
|
|
65
|
+
outputs:
|
|
66
|
+
- name: connection
|
|
67
|
+
mapping: "connection?"
|
|
68
|
+
- name: connectionId
|
|
69
|
+
mapping: "connectionId?"
|
|
70
|
+
|
|
71
|
+
- task: "FileTransfer/ListFiles@1"
|
|
72
|
+
name: SftpListFiles
|
|
73
|
+
inputs:
|
|
74
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
75
|
+
directory: "tracking/inbound"
|
|
76
|
+
pattern: "*.json"
|
|
77
|
+
recursive: false
|
|
78
|
+
includeDirectories: false
|
|
79
|
+
sortBy: "name"
|
|
80
|
+
sortOrder: "asc"
|
|
81
|
+
outputs:
|
|
82
|
+
- name: files
|
|
83
|
+
mapping: "files?"
|
|
84
|
+
- name: fileCount
|
|
85
|
+
mapping: "fileCount?"
|
|
86
|
+
|
|
87
|
+
- task: "foreach"
|
|
88
|
+
name: ProcessFiles
|
|
89
|
+
collection: "FtpImport?.SftpListFiles?.files?"
|
|
90
|
+
steps:
|
|
91
|
+
- task: "FileTransfer/DownloadFile@1"
|
|
92
|
+
name: SftpDownloadFile
|
|
93
|
+
inputs:
|
|
94
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
95
|
+
remotePath: "{{ item.path }}"
|
|
96
|
+
outputs:
|
|
97
|
+
- name: fileInfo
|
|
98
|
+
mapping: "fileInfo?"
|
|
99
|
+
- name: content
|
|
100
|
+
mapping: "content?"
|
|
101
|
+
|
|
102
|
+
# TODO: Parse downloaded content and map to tracking events
|
|
103
|
+
- task: "Utilities/SetVariable@1"
|
|
104
|
+
name: ParseContent
|
|
105
|
+
inputs:
|
|
106
|
+
variables:
|
|
107
|
+
- name: trackingEvents
|
|
108
|
+
value: []
|
|
109
|
+
|
|
110
|
+
- task: "Order/Import@1"
|
|
111
|
+
name: ImportTrackingEvents
|
|
112
|
+
inputs:
|
|
113
|
+
orders:
|
|
114
|
+
- trackingNumber: "{{ varTrackingNumber }}"
|
|
115
|
+
orderType: "ParcelShipment"
|
|
116
|
+
trackingEvents: "{{ trackingEvents }}"
|
|
117
|
+
options:
|
|
118
|
+
orderMatchByFields:
|
|
119
|
+
- "trackingNumber"
|
|
120
|
+
trackingEventMatchByFields:
|
|
121
|
+
- "eventDate"
|
|
122
|
+
- "customValues.eventType"
|
|
123
|
+
skipIfExists: true
|
|
124
|
+
createEventDefinitions: true
|
|
125
|
+
|
|
126
|
+
- task: "FileTransfer/MoveFile@1"
|
|
127
|
+
name: SftpMoveFile
|
|
128
|
+
inputs:
|
|
129
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
130
|
+
sourcePath: "{{ item.path }}"
|
|
131
|
+
destinationPath:
|
|
132
|
+
expression: "format('tracking/processed/{0}-{1}', formatDate(now(), 'yyyyMMdd_HHmmss', 'en-US'), [item.name])"
|
|
133
|
+
options:
|
|
134
|
+
createDirectories: true
|
|
135
|
+
overwrite: true
|
|
136
|
+
|
|
137
|
+
- task: "FileTransfer/Disconnect@1"
|
|
138
|
+
name: SftpDisconnect
|
|
139
|
+
conditions: "isNullOrEmpty([FtpImport?.SftpConnect?.connection?]) = false"
|
|
140
|
+
inputs:
|
|
141
|
+
connection: "{{ FtpImport?.SftpConnect?.connection? }}"
|
|
142
|
+
|
|
143
|
+
events:
|
|
144
|
+
onWorkflowStarted:
|
|
145
|
+
- task: "Utilities/Log@1"
|
|
146
|
+
name: LogWorkflowStarted
|
|
147
|
+
inputs:
|
|
148
|
+
message: "{{displayName}} workflow started"
|
|
149
|
+
level: Information
|
|
150
|
+
onWorkflowExecuted:
|
|
151
|
+
- task: "Utilities/Log@1"
|
|
152
|
+
name: LogWorkflowExecuted
|
|
153
|
+
inputs:
|
|
154
|
+
message: "{{displayName}} workflow completed successfully"
|
|
155
|
+
level: Information
|
|
156
|
+
onWorkflowFailed:
|
|
157
|
+
- task: "Utilities/Log@1"
|
|
158
|
+
name: LogWorkflowFailed
|
|
159
|
+
inputs:
|
|
160
|
+
message: "{{displayName}} workflow failed: {{exception.message}}"
|
|
161
|
+
level: Error
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# {{displayName}} Workflow
|
|
2
|
+
# Generated by cx-cli create workflow --template mcp-tool
|
|
3
|
+
|
|
4
|
+
workflow:
|
|
5
|
+
workflowId: "{{uuid}}"
|
|
6
|
+
name: "{{displayName}}"
|
|
7
|
+
description: "{{displayName}} - MCP tool workflow"
|
|
8
|
+
version: "1.0"
|
|
9
|
+
executionMode: Sync
|
|
10
|
+
logLevel: Information
|
|
11
|
+
isActive: true
|
|
12
|
+
enableAudit: true
|
|
13
|
+
filePath: "{{fileName}}"
|
|
14
|
+
agentInstruction: |
|
|
15
|
+
Use this tool to {{displayName}}.
|
|
16
|
+
Inputs:
|
|
17
|
+
- orderId (required): The order ID to process
|
|
18
|
+
Returns:
|
|
19
|
+
- result: Processing outcome with success status
|
|
20
|
+
tags:
|
|
21
|
+
- "mcp-tool"
|
|
22
|
+
|
|
23
|
+
inputs:
|
|
24
|
+
- name: orderId
|
|
25
|
+
type: number
|
|
26
|
+
props:
|
|
27
|
+
displayName: "Order ID"
|
|
28
|
+
description: "The ID of the order to process"
|
|
29
|
+
required: true
|
|
30
|
+
|
|
31
|
+
outputs:
|
|
32
|
+
- name: result
|
|
33
|
+
mapping: "Main.SetResult.result"
|
|
34
|
+
|
|
35
|
+
activities:
|
|
36
|
+
- name: Main
|
|
37
|
+
events:
|
|
38
|
+
onActivityStarted:
|
|
39
|
+
- task: "Utilities/Log@1"
|
|
40
|
+
name: LogActivityStarted
|
|
41
|
+
inputs:
|
|
42
|
+
message: "Activity Main started"
|
|
43
|
+
level: Information
|
|
44
|
+
onActivityCompleted:
|
|
45
|
+
- task: "Utilities/Log@1"
|
|
46
|
+
name: LogActivityCompleted
|
|
47
|
+
inputs:
|
|
48
|
+
message: "Activity Main completed"
|
|
49
|
+
level: Information
|
|
50
|
+
onActivityFailed:
|
|
51
|
+
- task: "Utilities/Log@1"
|
|
52
|
+
name: LogActivityFailed
|
|
53
|
+
inputs:
|
|
54
|
+
message: "Activity Main failed: {{exception.message}}"
|
|
55
|
+
level: Error
|
|
56
|
+
steps:
|
|
57
|
+
- task: "Query/GraphQL"
|
|
58
|
+
name: GetOrder
|
|
59
|
+
inputs:
|
|
60
|
+
query: |
|
|
61
|
+
query($organizationId: Int!, $orderId: Int!) {
|
|
62
|
+
order(organizationId: $organizationId, orderId: $orderId) {
|
|
63
|
+
orderId
|
|
64
|
+
orderNumber
|
|
65
|
+
status
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
variables:
|
|
69
|
+
organizationId: "\{{int organizationId}}"
|
|
70
|
+
orderId: "\{{inputs.orderId}}"
|
|
71
|
+
outputs:
|
|
72
|
+
- name: order
|
|
73
|
+
mapping: "order?"
|
|
74
|
+
|
|
75
|
+
- task: "Utilities/Error@1"
|
|
76
|
+
name: ValidateOrder
|
|
77
|
+
conditions:
|
|
78
|
+
- expression: "isNullOrEmpty([Main?.GetOrder?.order?]) = true"
|
|
79
|
+
inputs:
|
|
80
|
+
message: "Order not found: \{{inputs.orderId}}"
|
|
81
|
+
|
|
82
|
+
# TODO: Add processing logic here
|
|
83
|
+
|
|
84
|
+
- task: "Utilities/SetVariable@1"
|
|
85
|
+
name: SetResult
|
|
86
|
+
inputs:
|
|
87
|
+
variables:
|
|
88
|
+
- name: result
|
|
89
|
+
value:
|
|
90
|
+
success: true
|
|
91
|
+
orderId: "\{{inputs.orderId}}"
|
|
92
|
+
orderNumber: "\{{Main?.GetOrder?.order?.orderNumber?}}"
|
|
93
|
+
|
|
94
|
+
events:
|
|
95
|
+
onWorkflowStarted:
|
|
96
|
+
- task: "Utilities/Log@1"
|
|
97
|
+
name: LogWorkflowStarted
|
|
98
|
+
inputs:
|
|
99
|
+
message: "{{displayName}} workflow started"
|
|
100
|
+
level: Information
|
|
101
|
+
onWorkflowExecuted:
|
|
102
|
+
- task: "Utilities/Log@1"
|
|
103
|
+
name: LogWorkflowExecuted
|
|
104
|
+
inputs:
|
|
105
|
+
message: "{{displayName}} workflow completed successfully"
|
|
106
|
+
level: Information
|
|
107
|
+
onWorkflowFailed:
|
|
108
|
+
- task: "Utilities/Log@1"
|
|
109
|
+
name: LogWorkflowFailed
|
|
110
|
+
inputs:
|
|
111
|
+
message: "{{displayName}} workflow failed: {{exception.message}}"
|
|
112
|
+
level: Error
|