@cxtms/cx-schema 1.1.0 → 1.2.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.
Files changed (54) hide show
  1. package/.claude/skills/cx-core/SKILL.md +93 -0
  2. package/.claude/skills/cx-core/ref-entity-accounting.md +173 -0
  3. package/.claude/skills/cx-core/ref-entity-commodity.md +205 -0
  4. package/.claude/skills/cx-core/ref-entity-contact.md +153 -0
  5. package/.claude/skills/cx-core/ref-entity-geography.md +119 -0
  6. package/.claude/skills/cx-core/ref-entity-job.md +77 -0
  7. package/.claude/skills/cx-core/ref-entity-order-sub.md +140 -0
  8. package/.claude/skills/cx-core/ref-entity-order.md +168 -0
  9. package/.claude/skills/cx-core/ref-entity-rate.md +174 -0
  10. package/.claude/skills/cx-core/ref-entity-shared.md +147 -0
  11. package/.claude/skills/cx-core/ref-entity-warehouse.md +110 -0
  12. package/.claude/skills/cx-module/SKILL.md +402 -0
  13. package/.claude/skills/cx-module/ref-components-data.md +286 -0
  14. package/.claude/skills/cx-module/ref-components-display.md +394 -0
  15. package/.claude/skills/cx-module/ref-components-forms.md +362 -0
  16. package/.claude/skills/cx-module/ref-components-interactive.md +306 -0
  17. package/.claude/skills/cx-module/ref-components-layout.md +295 -0
  18. package/.claude/skills/cx-module/ref-components-specialized.md +427 -0
  19. package/.claude/skills/cx-workflow/SKILL.md +330 -0
  20. package/.claude/skills/cx-workflow/ref-accounting.md +66 -0
  21. package/.claude/skills/cx-workflow/ref-communication.md +161 -0
  22. package/.claude/skills/cx-workflow/ref-entity.md +162 -0
  23. package/.claude/skills/cx-workflow/ref-expressions.md +239 -0
  24. package/.claude/skills/cx-workflow/ref-filetransfer.md +80 -0
  25. package/.claude/skills/cx-workflow/ref-flow.md +180 -0
  26. package/.claude/skills/cx-workflow/ref-other.md +120 -0
  27. package/.claude/skills/cx-workflow/ref-query.md +85 -0
  28. package/.claude/skills/cx-workflow/ref-utilities.md +192 -0
  29. package/dist/cli.js +252 -33
  30. package/dist/cli.js.map +1 -1
  31. package/package.json +3 -2
  32. package/schemas/workflows/tasks/action-event.json +65 -0
  33. package/schemas/workflows/tasks/all.json +126 -26
  34. package/schemas/workflows/tasks/appmodule.json +56 -0
  35. package/schemas/workflows/tasks/attachment.json +4 -1
  36. package/schemas/workflows/tasks/authentication.json +72 -0
  37. package/schemas/workflows/tasks/caching.json +68 -0
  38. package/schemas/workflows/tasks/charge.json +3 -1
  39. package/schemas/workflows/tasks/commodity.json +3 -0
  40. package/schemas/workflows/tasks/contact-address.json +72 -0
  41. package/schemas/workflows/tasks/contact-payment-method.json +72 -0
  42. package/schemas/workflows/tasks/edi.json +65 -0
  43. package/schemas/workflows/tasks/filetransfer.json +102 -0
  44. package/schemas/workflows/tasks/flow-transition.json +68 -0
  45. package/schemas/workflows/tasks/httpRequest.json +23 -0
  46. package/schemas/workflows/tasks/import.json +64 -0
  47. package/schemas/workflows/tasks/inventory.json +67 -0
  48. package/schemas/workflows/tasks/movement.json +54 -0
  49. package/schemas/workflows/tasks/note.json +59 -0
  50. package/schemas/workflows/tasks/number.json +65 -0
  51. package/schemas/workflows/tasks/order.json +8 -1
  52. package/schemas/workflows/tasks/pdf-document.json +60 -0
  53. package/schemas/workflows/tasks/user.json +70 -0
  54. package/scripts/postinstall.js +2 -2
@@ -0,0 +1,162 @@
1
+ # Entity CRUD Tasks Reference
2
+
3
+ All entity tasks follow the `Namespace/Operation@Version` pattern. Outputs are stored as `ActivityName.StepName.outputKey`.
4
+
5
+ ## Generic Entity Change
6
+
7
+ | Task | Description |
8
+ |------|-------------|
9
+ | `Entity/Change` | Generic entity change (works for any entity type) |
10
+
11
+ ## Order
12
+
13
+ | Task | Description |
14
+ |------|-------------|
15
+ | `Order/Create` | Create a new order |
16
+ | `Order/Update` (v1, v2) | Update order fields |
17
+ | `Order/Delete` | Delete an order |
18
+ | `Order/Get` | Get order by ID |
19
+ | `Order/Copy` | Copy/duplicate an order |
20
+ | `Order/Split` | Split order into multiple |
21
+ | `Order/Purge` | Purge order data |
22
+ | `Order/Import` | Import order from external data |
23
+ | `Order/RecalculateCharges` | Recalculate all charges |
24
+ | `Order/GenerateTrackingNumber` | Generate tracking number |
25
+ | `Order/GetCargoMovementByPalletQuery` | Query cargo movements by pallet |
26
+
27
+ ```yaml
28
+ - task: "Order/Create@1"
29
+ name: CreateOrder
30
+ inputs:
31
+ orderType: "ParcelShipment"
32
+ entity:
33
+ customer: "{{ inputs.customerId }}"
34
+ status: "Draft"
35
+ outputs:
36
+ - name: order
37
+ mapping: "order"
38
+ ```
39
+
40
+ ```yaml
41
+ - task: "Order/Update@2"
42
+ name: UpdateOrder
43
+ inputs:
44
+ orderId: "{{ inputs.orderId }}"
45
+ entity:
46
+ status: "Active"
47
+ notes: "Updated by workflow"
48
+ ```
49
+
50
+ ## Contact
51
+
52
+ | Task | Description |
53
+ |------|-------------|
54
+ | `Contact/Create` | Create contact |
55
+ | `Contact/Update` | Update contact |
56
+ | `Contact/Delete` | Delete contact |
57
+
58
+ ## Contact Address
59
+
60
+ | Task | Description |
61
+ |------|-------------|
62
+ | `ContactAddress/Create` | Create address |
63
+ | `ContactAddress/Update` | Update address |
64
+ | `ContactAddress/Delete` | Delete address |
65
+ | `ContactAddress/Import` | Bulk import addresses |
66
+
67
+ ## Contact Payment Method
68
+
69
+ | Task | Description |
70
+ |------|-------------|
71
+ | `ContactPaymentMethod/Create` | Create payment method |
72
+ | `ContactPaymentMethod/Update` | Update payment method |
73
+ | `ContactPaymentMethod/SendChargedAmount` | Send charged amount notification |
74
+ | `ContactPaymentMethod/VerifyChargedAmount` | Verify charged amount |
75
+
76
+ ## Commodity
77
+
78
+ | Task | Description |
79
+ |------|-------------|
80
+ | `Commodity/Create` | Create commodity |
81
+ | `Commodity/Update` (v1, v2) | Update commodity |
82
+ | `Commodity/Split` | Split commodity into multiple |
83
+ | `Commodity/Repack` | Repack commodities |
84
+ | `Commodity/Unpack` | Unpack commodity |
85
+
86
+ ## Commodity Tracking Number
87
+
88
+ | Task | Description |
89
+ |------|-------------|
90
+ | `CommodityTrackingNumber/Create` | Create tracking number |
91
+ | `CommodityTrackingNumber/Update` | Update tracking number |
92
+ | `CommodityTrackingNumber/Delete` | Delete tracking number |
93
+
94
+ ## Job
95
+
96
+ | Task | Description |
97
+ |------|-------------|
98
+ | `Job/Create` | Create job |
99
+ | `Job/Update` | Update job |
100
+ | `Job/Delete` | Delete job |
101
+ | `Job/Assign` | Assign job to user/driver |
102
+ | `Job/Unassign` | Unassign job |
103
+
104
+ ## Charge
105
+
106
+ | Task | Description |
107
+ |------|-------------|
108
+ | `Charge/Create` | Create charge |
109
+ | `Charge/Update` | Update charge |
110
+ | `Charge/Delete` | Delete charge |
111
+ | `Charge/DynamicUpdate` | Dynamic update (partial fields) |
112
+ | `Charge/Calculate` | Calculate charge amount |
113
+
114
+ ```yaml
115
+ - task: "Charge/Create@1"
116
+ name: CreateCharge
117
+ inputs:
118
+ orderId: "{{ inputs.orderId }}"
119
+ chargeType: "Freight"
120
+ amount: "{{ Data.GetRate.rate.amount }}"
121
+ currency: "USD"
122
+ outputs:
123
+ - name: charge
124
+ mapping: "charge"
125
+ ```
126
+
127
+ ## Discount
128
+
129
+ | Task | Description |
130
+ |------|-------------|
131
+ | `Discount/Update` | Update discount |
132
+
133
+ ## Order Sub-Entities
134
+
135
+ | Task | Description |
136
+ |------|-------------|
137
+ | `OrderCommodity/Create` | Link commodity to order |
138
+ | `OrderCommodity/Update` | Update order-commodity link |
139
+ | `OrderCommodity/Delete` | Remove commodity from order |
140
+ | `OrderCharge/Create` | Create order charge |
141
+ | `OrderDocument/Create` | Create order document |
142
+ | `OrderDocument/Send` | Send order document |
143
+ | `OrderTrackingEvent/Create` | Create tracking event |
144
+ | `OrderEntity/ChangeCustomValue` | Change custom field value |
145
+
146
+ ## Inventory
147
+
148
+ | Task | Description |
149
+ |------|-------------|
150
+ | `InventoryItem/Create` | Create inventory item |
151
+ | `InventoryItem/Update` | Update inventory item |
152
+ | `InventoryItem/Delete` | Delete inventory item |
153
+
154
+ ## Other
155
+
156
+ | Task | Description |
157
+ |------|-------------|
158
+ | `Movement/Create` | Create cargo movement |
159
+ | `Country/Create`, `Country/Update`, `Country/Delete` | Country CRUD |
160
+ | `Cities/Import` | Import cities |
161
+ | `Rate/Update` | Update rate |
162
+ | `TrackingEvent/Import` | Import tracking events |
@@ -0,0 +1,239 @@
1
+ # Variable References & Expressions
2
+
3
+ There are **two distinct syntaxes** for referencing variables, used in different contexts.
4
+
5
+ ## Template Expressions: `{{ path }}` (in step inputs)
6
+
7
+ Used in step `inputs` values. Resolves variable paths from scoped variables.
8
+
9
+ ```yaml
10
+ inputs:
11
+ orderId: "{{ inputs.orderId }}" # Simple reference
12
+ url: "{{ chopinConfig.baseUrl }}/api/v1" # String interpolation
13
+ order: "{{ Data.GetOrder.order }}" # Raw object (single {{ }})
14
+ name: "Order {{ Data.GetOrder.order.orderNumber }}" # String interpolation (multiple)
15
+ ```
16
+
17
+ **Key behavior**: A single `{{ path }}` returns the **raw object** (preserving type). Multiple `{{ }}` in a string returns string interpolation (each resolved value is `.ToString()`).
18
+
19
+ ### Type Converters (prefix in {{ }})
20
+
21
+ ```yaml
22
+ organizationId: "{{ int organizationId }}"
23
+ amount: "{{ decimal totalAmount }}"
24
+ isActive: "{{ bool isActive }}"
25
+ flag: "{{ boolOrFalse someFlag }}" # null -> false
26
+ flagOn: "{{ boolOrTrue someFlag }}" # null -> true
27
+ notes: "{{ emptyIfNull notes }}" # null -> ""
28
+ notes: "{{ nullIfEmpty notes }}" # "" or whitespace -> null
29
+ config: "{{ fromJson configJsonString }}" # JSON string -> dict/array
30
+ payload: "{{ toJson someObject }}" # object -> JSON string
31
+ name: "{{ trim value }}"
32
+ search: "{{ luceneString query }}" # escape & quote for Lucene
33
+ ```
34
+
35
+ | Converter | Returns | Null handling |
36
+ |-----------|---------|---------------|
37
+ | `string` | `string` | null. Reads `Stream` to string if value is Stream |
38
+ | `int` | `int` | Throws on null |
39
+ | `decimal` | `decimal` | Throws on null |
40
+ | `bool` | `bool` | Throws on null |
41
+ | `boolOrFalse` | `bool` | `false` if null |
42
+ | `boolOrTrue` | `bool` | `true` if null |
43
+ | `datetime` | `DateTime` | Throws on null |
44
+ | `emptyIfNull` | same type | `""` if null, `0` for int?, `0m` for decimal? |
45
+ | `nullIfEmpty` | same type | `null` if empty/whitespace string or empty collection |
46
+ | `luceneString` | `string` | null |
47
+ | `transliterate` | `string` | null (Unicode -> ASCII via Unidecode) |
48
+ | `transliterateUa` | `string` | null (Ukrainian-specific rules) |
49
+ | `fromJson` | `dict` or `array` | null. Empty string -> empty dict |
50
+ | `toJson` | `string` | `""` if null |
51
+ | `trim` | `string` | null |
52
+
53
+ ### Value Directives (in YAML input mappings)
54
+
55
+ **`expression`** -- Evaluate NCalc expression as a value:
56
+ ```yaml
57
+ amount:
58
+ expression: "[price] * [quantity]"
59
+ ```
60
+
61
+ **`coalesce`** -- First non-null value from a list:
62
+ ```yaml
63
+ displayName:
64
+ coalesce:
65
+ - "{{ customer.name? }}"
66
+ - "{{ customer.email? }}"
67
+ - "Unknown"
68
+ ```
69
+
70
+ **`foreach`** (value context) -- Transform collections inline:
71
+ ```yaml
72
+ commodities:
73
+ foreach: "sourceCommodities"
74
+ item: "item" # default: "item"
75
+ conditions: "[item.isActive] = true" # optional NCalc filter per item
76
+ continueOnError: false # optional, skip errors
77
+ mapping: # dict -> List<dict>, string -> List<object>
78
+ name: "{{ item.name }}"
79
+ quantity: "{{ item.qty }}"
80
+ ```
81
+
82
+ **`switch`** (value context) -- Value-based switch (case-insensitive match):
83
+ ```yaml
84
+ perLb:
85
+ switch: "{{ contact.commissionTier }}"
86
+ cases:
87
+ "tier1": "{{ rate.customValues.commission_per_lb_tier1 }}"
88
+ "tier2": "{{ rate.customValues.commission_per_lb_tier2 }}"
89
+ default: "0"
90
+ ```
91
+
92
+ **`extends`** -- Extend/merge an existing object or array:
93
+ ```yaml
94
+ orderData:
95
+ extends: "{{ existingOrder }}" # base object or array
96
+ defaultIfNull: {} # fallback if extends is null
97
+ mapping: # dict: merge overrides. array: append items
98
+ status: "Updated"
99
+ notes: "{{ newNotes }}"
100
+ ```
101
+
102
+ **`$raw`** -- Prevent template parsing (pass as-is):
103
+ ```yaml
104
+ template:
105
+ $raw: "This {{ won't }} be parsed"
106
+ ```
107
+
108
+ **`$eval`** -- Parse JSON string then evaluate as template:
109
+ ```yaml
110
+ dynamicConfig:
111
+ $eval: "{{ configJsonString }}"
112
+ ```
113
+
114
+ **`decrypt`** / **`encrypt`** -- AES-CBC encryption (optional key/IV, has defaults):
115
+ ```yaml
116
+ apiKey:
117
+ decrypt:
118
+ encryptedValue: "{{ encryptedApiKey }}"
119
+ key: "{{ encryptionKey }}" # optional Base64 AES key
120
+ initializationVector: "{{ iv }}" # optional Base64 IV
121
+ ```
122
+
123
+ ---
124
+
125
+ ## NCalc Expressions: `[variable]` (in conditions and expression directives)
126
+
127
+ Used in `conditions[].expression`, `switch` case `when`, and `expression:` value directives. Variables use **square bracket** `[name]` syntax.
128
+
129
+ ```yaml
130
+ conditions:
131
+ - expression: "[status] = 'Active' AND [amount] > 100"
132
+ - expression: "isNullOrEmpty([Data.GetOrder.order?]) = false"
133
+ - expression: "any([changes], [each.key] = 'Status') = true"
134
+ ```
135
+
136
+ **Parameter resolution rules**:
137
+ - Empty strings are converted to `null` (so `""` is treated as no value)
138
+ - Numeric strings are auto-converted to `decimal` when needed (e.g., `[price] > 100` works even if price is the string `"150"`)
139
+ - Dot paths resolve deep: `[Activity.Step.output.nested.field]`
140
+ - Optional suffix `?` prevents errors: `[order.customer?.name?]`
141
+
142
+ ### Operators
143
+
144
+ | Type | Operators |
145
+ |------|-----------|
146
+ | Comparison | `=`, `!=`, `<>`, `<`, `>`, `<=`, `>=` |
147
+ | Logical | `AND`, `OR`, `NOT` (also `&&`, `\|\|`, `!`) |
148
+ | Arithmetic | `+`, `-`, `*`, `/`, `%` |
149
+ | Ternary | `if(condition, trueVal, falseVal)` |
150
+ | Membership | `in(value, val1, val2, ...)` |
151
+
152
+ ### Iterator Variables
153
+
154
+ Functions use two iterator variable names:
155
+ - **`[each.*]`** -- used by: `any`, `all`, `sum`, `join` (3-arg)
156
+ - **`[item.*]`** -- used by: `first`, `last`, `groupBy`
157
+
158
+ ### Collection Functions
159
+
160
+ | Function | Description |
161
+ |----------|-------------|
162
+ | `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value |
163
+ | `all([items], [each.prop] > 0)` | True if all items match. Returns `false` for null/empty collections |
164
+ | `count([items])` | Count items in list or JToken. Returns `0` for non-collections |
165
+ | `sum([items], [each.amount])` | Sum values as `decimal`. Optional `[each.*]` accessor. Skips nulls |
166
+ | `first([items])` or `first([items], [item.name])` | First item or evaluate expression on first item. Returns `""` if empty |
167
+ | `last([items])` or `last([items], [item.name])` | Last item or evaluate expression on last item. Returns `""` if empty |
168
+ | `distinct([items])` | Remove duplicates. Uses deep comparison for dictionaries |
169
+ | `reverse([items])` | Reverse collection or string |
170
+ | `contains([source], 'needle')` | String contains, JArray contains, list contains, or dict key/value contains |
171
+ | `removeEmpty([items])` | Remove null and whitespace-only items |
172
+ | `concat([list1], [list2], ...)` | Concatenate multiple collections into flat list. Variadic args. Skips nulls |
173
+ | `groupBy([items], [item.cat])` | Group by one or more key expressions. Returns `[{key, items}]`. Multi-key: keys joined with `\|` |
174
+ | `join([items], [each.name], ',')` | Join collection with `[each.*]` accessor and separator (3-arg) |
175
+ | `join([items], ',')` | Join collection directly with separator (2-arg) |
176
+ | `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
177
+
178
+ ### String Functions
179
+
180
+ | Function | Description |
181
+ |----------|-------------|
182
+ | `isNullOrEmpty([var])` | True if null, empty string, or empty list |
183
+ | `length([var])` | String length or collection count. `0` for null strings and non-collections |
184
+ | `lower([name])` / `upper([code])` | Case conversion. Handles string, JToken, any `.ToString()` |
185
+ | `left([code], 3)` / `right([code], 3)` | Left/right N characters. Returns full string if shorter than N |
186
+ | `replace([str], 'old', 'new')` | String replacement. Returns null if any arg is null |
187
+ | `trim([value])` | Trim whitespace. Returns `""` for null |
188
+ | `format('{0}-{1}', [prefix], [id])` | String.Format style. Variadic args. Returns null if format is null |
189
+ | `base64([value])` / `fromBase64([encoded])` | Base64 encode/decode. Handles string, byte[], JToken |
190
+ | `bool([value])` | Convert to boolean: null->`false`, empty string->`false`, "true"/"false"->parsed, non-zero number->`true`, any object->`true` |
191
+ | `transliterate([value])` | Unicode to ASCII (Unidecode). Returns `""` for null |
192
+ | `transliterateUa([value])` | Ukrainian-specific transliteration. Returns `""` for null |
193
+ | `parseAddress([address])` | Parse address -> `{StreetNumber, StreetName}`. Handles US and EU formats |
194
+
195
+ ### Date Functions
196
+
197
+ | Function | Description |
198
+ |----------|-------------|
199
+ | `now()` | Current UTC `DateTime` |
200
+ | `now('yyyy-MM-dd', 'en-US')` | Formatted current time as string |
201
+ | `addDays([date], 30)` | Add days (decimal, can be negative). Accepts DateTime, DateTimeOffset, string |
202
+ | `addHours([date], 2)` | Add hours (decimal, can be negative). Same type handling |
203
+ | `formatDate([date], 'dd/MM/yyyy', 'en-US')` | Format date with culture. Accepts DateTime or string |
204
+ | `dateFromUnix([unixTime])` | Unix timestamp (seconds) -> `DateTimeOffset`. Accepts int, long, decimal, string |
205
+ | `dateToUtc([date])` or `dateToUtc([date], 'en-US')` | Convert to UTC. Optional culture for string parsing |
206
+
207
+ ### Math Functions (NCalc built-in)
208
+
209
+ `Abs(x)`, `Ceiling(x)`, `Floor(x)`, `Round(x, decimals)`, `Min(x, y)`, `Max(x, y)`, `Pow(x, y)`, `Sqrt(x)`, `Truncate(x)`
210
+
211
+ Custom: `ceiling([value])` -- same as `Ceiling` but handles type conversion to double.
212
+
213
+ ### Domain Functions
214
+
215
+ | Function | Description |
216
+ |----------|-------------|
217
+ | `convertWeight([weight], 'Kg', 'Lb')` | Weight unit conversion. Returns `decimal` rounded to 5 places |
218
+ | `convertDimension([length], 'Cm', 'In')` | Dimension unit conversion. Returns `decimal` rounded to 3 places |
219
+
220
+ ---
221
+
222
+ ## Property Path Syntax (in collection, mapping, variable paths)
223
+
224
+ Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
225
+
226
+ | Pattern | Description | Example |
227
+ |---------|-------------|---------|
228
+ | `a.b.c` | Dot-separated nested path | `order.customer.name` |
229
+ | `prop?` | Optional access (null if missing) | `order.customer?.name?` |
230
+ | `list[0]` | Array index | `items[0]` |
231
+ | `list[^1]` | Index from end (last item) | `items[^1]` |
232
+ | `list[*]` | Flatten/wildcard (all items) | `containers[*].commodities` |
233
+ | `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
234
+ | `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
235
+ | `list[condition]` | Filter by condition | `items[status=Active]` |
236
+ | `dict['key']` | Dictionary key access | `customValues['myField']` |
237
+ | `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
238
+ | `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |
239
+ | `list[*].{alias:_.parent}` | Field selector referencing parent | `items[*].{parentId:_.orderId}` |
@@ -0,0 +1,80 @@
1
+ # File Transfer Tasks Reference
2
+
3
+ SFTP/FTP file transfer operations. Use `FileTransfer/Connect` to establish a session, perform file operations, then `FileTransfer/Disconnect`.
4
+
5
+ ## Connection Lifecycle
6
+
7
+ ```yaml
8
+ activities:
9
+ - name: Transfer
10
+ steps:
11
+ - task: "FileTransfer/Connect@1"
12
+ name: Connect
13
+ inputs:
14
+ host: "{{ sftpConfig.host }}"
15
+ port: "{{ sftpConfig.port }}"
16
+ username: "{{ sftpConfig.username }}"
17
+ password: "{{ sftpConfig.password }}"
18
+ protocol: "sftp"
19
+ outputs:
20
+ - name: connection
21
+ mapping: "connection"
22
+
23
+ - task: "FileTransfer/ListFiles@1"
24
+ name: ListFiles
25
+ inputs:
26
+ connection: "{{ Transfer.Connect.connection }}"
27
+ path: "/incoming"
28
+ outputs:
29
+ - name: files
30
+ mapping: "files"
31
+
32
+ - task: foreach
33
+ name: ProcessFiles
34
+ collection: "Transfer.ListFiles.files"
35
+ item: "file"
36
+ steps:
37
+ - task: "FileTransfer/DownloadFile@1"
38
+ name: Download
39
+ inputs:
40
+ connection: "{{ Transfer.Connect.connection }}"
41
+ path: "{{ file.path }}"
42
+ outputs:
43
+ - name: content
44
+ mapping: "content"
45
+
46
+ - task: "FileTransfer/MoveFile@1"
47
+ name: Archive
48
+ inputs:
49
+ connection: "{{ Transfer.Connect.connection }}"
50
+ sourcePath: "{{ file.path }}"
51
+ destinationPath: "/processed/{{ file.name }}"
52
+
53
+ - task: "FileTransfer/Disconnect@1"
54
+ name: Disconnect
55
+ inputs:
56
+ connection: "{{ Transfer.Connect.connection }}"
57
+ ```
58
+
59
+ ## Available Tasks
60
+
61
+ | Task | Description |
62
+ |------|-------------|
63
+ | `FileTransfer/Connect` | Establish SFTP/FTP connection |
64
+ | `FileTransfer/Disconnect` | Close connection |
65
+ | `FileTransfer/ListFiles` | List files in remote directory |
66
+ | `FileTransfer/DownloadFile` | Download file content |
67
+ | `FileTransfer/UploadFile` | Upload file to remote |
68
+ | `FileTransfer/MoveFile` | Move/rename remote file |
69
+ | `FileTransfer/DeleteFile` | Delete remote file |
70
+
71
+ ## Upload Example
72
+
73
+ ```yaml
74
+ - task: "FileTransfer/UploadFile@1"
75
+ name: Upload
76
+ inputs:
77
+ connection: "{{ Transfer.Connect.connection }}"
78
+ path: "/outgoing/report.csv"
79
+ content: "{{ GenerateReport.Export.file }}"
80
+ ```
@@ -0,0 +1,180 @@
1
+ # Flow Workflow YAML Reference
2
+
3
+ Flow workflows are declarative state machines for entity lifecycle management. Use `workflowType: Flow` in the workflow section.
4
+
5
+ ## Top-Level Structure
6
+
7
+ ```yaml
8
+ workflow:
9
+ workflowId: "<uuid>"
10
+ name: "Flow Workflow Name"
11
+ workflowType: Flow # Required - identifies this as a Flow workflow
12
+ executionMode: Async
13
+ isActive: true
14
+ priority: 75 # 0-100, default 50
15
+ tags: ["tag1"]
16
+ agentInstruction: "AI guidance" # Optional
17
+ concurrency:
18
+ enabled: true
19
+ group: "groupName"
20
+ waitTime: 30
21
+
22
+ entity: # Required for Flow (replaces activities)
23
+ name: <EntityName>
24
+ type: <EntityType> # Required for Order, AccountingTransaction, Contact
25
+ includes: [<navigation-paths>] # Optional
26
+ query: "<graphql-query>" # Optional
27
+
28
+ states: [...] # Required, at least 1 state
29
+ transitions: [...] # Required, at least 1 transition
30
+ aggregations: [...] # Optional
31
+ ```
32
+
33
+ ## Entity Section
34
+
35
+ Specifies which entity's lifecycle this flow manages.
36
+
37
+ ### Valid Entity Names
38
+ Order, Commodity, AccountingTransaction, Workflow, OrganizationConfig, Contact, AppModule, Attachment, OrderCommodity, TrackingEvent, JobOrder
39
+
40
+ ### Entity Types (required for specific entities)
41
+
42
+ **Order** requires type: Brokerage, ParcelShipment, Quote, WarehouseReceipt, AirShipmentOrder, OceanShipmentOrder, LoadOrder, DeliveryOrder
43
+ **AccountingTransaction** requires type: Invoice, Bill, CreditMemo
44
+ **Contact** requires type: Customer, Carrier, Vendor, Driver, Employee
45
+
46
+ ```yaml
47
+ entity:
48
+ name: Order
49
+ type: ParcelShipment
50
+ includes:
51
+ - Commodities
52
+ - Customer
53
+ - Charges
54
+ query: "{ commodities { id, quantity }, customer { name, email } }"
55
+ ```
56
+
57
+ ## States Section
58
+
59
+ Each state represents a status in the entity lifecycle.
60
+
61
+ ```yaml
62
+ states:
63
+ - name: Draft # Required, unique
64
+ stage: Entry # Optional grouping label
65
+ isInitial: true # At most 1 initial state
66
+ - name: Active
67
+ stage: Processing
68
+ - name: AwaitingPickup
69
+ parent: Active # Hierarchical state
70
+ - name: InTransit
71
+ parent: Active
72
+ onEnter: # Steps on entering this state
73
+ - task: "Email/Send"
74
+ inputs:
75
+ template: in_transit_notification
76
+ onExit: # Steps on exiting this state
77
+ - task: "Utilities/Log@1"
78
+ inputs:
79
+ message: "Leaving InTransit"
80
+ - name: Delivered
81
+ stage: Complete
82
+ isFinal: true # Terminal state, no outgoing transitions
83
+ requireConfirmation: true # User must confirm before entering
84
+ query: "{ charges { id, amount } }" # State-specific data query
85
+ ```
86
+
87
+ ### State Rules
88
+ - **name**: Required, must be unique across all states
89
+ - **isInitial**: At most one state can be initial
90
+ - **isFinal**: Final states cannot be transition sources
91
+ - **parent**: References another state; parent cannot be initial or final; children inherit parent transitions
92
+
93
+ ## Transitions Section
94
+
95
+ Define how entities move between states.
96
+
97
+ ```yaml
98
+ transitions:
99
+ - name: submit # Required, unique
100
+ displayName: "Submit Order" # Optional UI label
101
+ from: Draft # Single state
102
+ to: Submitted # Must be a leaf state (no children)
103
+ trigger: manual # manual | auto | event
104
+
105
+ - name: auto_approve
106
+ from: Submitted
107
+ to: Approved
108
+ trigger: auto # Evaluated automatically
109
+ priority: 10 # Higher = checked first (default 50)
110
+ conditions:
111
+ - expression: "Order.Amount < 1000"
112
+
113
+ - name: payment_received
114
+ from: AwaitingPayment
115
+ to: Paid
116
+ trigger: event # External event-driven
117
+ eventName: PaymentConfirmed # Required when trigger is 'event'
118
+
119
+ - name: bulk_transition
120
+ from: # Array of source states
121
+ - Draft
122
+ - Submitted
123
+ to: Cancelled
124
+ trigger: manual
125
+
126
+ - name: force_cancel
127
+ from: "*" # Wildcard: any non-final state
128
+ to: Cancelled
129
+ trigger: manual
130
+ steps: # Steps during transition
131
+ - task: "Utilities/Log@1"
132
+ inputs:
133
+ message: "Force cancelled"
134
+ ```
135
+
136
+ ### Trigger Types
137
+ - **manual**: User-initiated or API call
138
+ - **auto**: Automatic evaluation based on conditions; sorted by priority descending
139
+ - **event**: External event-driven; requires `eventName`
140
+
141
+ ### From States
142
+ - Single state: `from: Draft`
143
+ - Multiple states: `from: [Draft, Submitted]`
144
+ - Wildcard (any non-final state): `from: "*"`
145
+
146
+ ### Execution Order
147
+ 1. Validate transition from current state
148
+ 2. Execute `onExit` steps (from source state)
149
+ 3. Execute transition `steps`
150
+ 4. Update entity status
151
+ 5. Execute `onEnter` steps (on target state)
152
+
153
+ ## Aggregations Section
154
+
155
+ Reusable data queries for conditions.
156
+
157
+ ```yaml
158
+ aggregations:
159
+ - name: allItemsReceived # Required, unique
160
+ expression: "all(Order.Commodities, item.ReceivedQuantity >= item.Quantity)"
161
+ - name: totalWeight
162
+ expression: "sum(Order.Commodities, item.Weight)"
163
+ - name: hasAnyDamaged
164
+ expression: "any(Order.Commodities, item.IsDamaged)"
165
+ - name: itemCount
166
+ expression: "count(Order.Commodities)"
167
+ - name: chargesByType
168
+ expression: "sum(Order.Charges, item.Amount)"
169
+ parameter: chargeType # Optional parameter
170
+ ```
171
+
172
+ ### Valid Aggregation Functions
173
+ - **all(collection, predicate)** - All items match
174
+ - **any(collection, predicate)** - At least one matches
175
+ - **sum(collection, selector)** - Sum values
176
+ - **count(collection)** - Count items
177
+ - **first(collection)** - First item
178
+ - **last(collection)** - Last item
179
+ - **distinct(collection, selector)** - Unique values
180
+ - **groupBy(collection, selector)** - Group by value