cxtms 1.9.13

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 (215) hide show
  1. package/README.md +384 -0
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +4784 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/extractUtils.d.ts +11 -0
  7. package/dist/extractUtils.d.ts.map +1 -0
  8. package/dist/extractUtils.js +19 -0
  9. package/dist/extractUtils.js.map +1 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +11 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/types.d.ts +129 -0
  15. package/dist/types.d.ts.map +1 -0
  16. package/dist/types.js +6 -0
  17. package/dist/types.js.map +1 -0
  18. package/dist/utils/schemaLoader.d.ts +17 -0
  19. package/dist/utils/schemaLoader.d.ts.map +1 -0
  20. package/dist/utils/schemaLoader.js +134 -0
  21. package/dist/utils/schemaLoader.js.map +1 -0
  22. package/dist/validator.d.ts +72 -0
  23. package/dist/validator.d.ts.map +1 -0
  24. package/dist/validator.js +432 -0
  25. package/dist/validator.js.map +1 -0
  26. package/dist/workflowValidator.d.ts +103 -0
  27. package/dist/workflowValidator.d.ts.map +1 -0
  28. package/dist/workflowValidator.js +753 -0
  29. package/dist/workflowValidator.js.map +1 -0
  30. package/package.json +51 -0
  31. package/schemas/actions/all.json +27 -0
  32. package/schemas/actions/clipboard.json +46 -0
  33. package/schemas/actions/confirm.json +21 -0
  34. package/schemas/actions/consoleLog.json +16 -0
  35. package/schemas/actions/dialog.json +25 -0
  36. package/schemas/actions/fileDownload.json +16 -0
  37. package/schemas/actions/forEach.json +31 -0
  38. package/schemas/actions/if.json +12 -0
  39. package/schemas/actions/mutation.json +25 -0
  40. package/schemas/actions/navigate.json +18 -0
  41. package/schemas/actions/navigateBack.json +22 -0
  42. package/schemas/actions/navigateBackOrClose.json +21 -0
  43. package/schemas/actions/notification.json +19 -0
  44. package/schemas/actions/openBarcodeScanner.json +104 -0
  45. package/schemas/actions/query.json +32 -0
  46. package/schemas/actions/refresh.json +13 -0
  47. package/schemas/actions/resetDirtyState.json +22 -0
  48. package/schemas/actions/setFields.json +21 -0
  49. package/schemas/actions/setStore.json +13 -0
  50. package/schemas/actions/validateForm.json +15 -0
  51. package/schemas/actions/workflow.json +24 -0
  52. package/schemas/components/README.md +147 -0
  53. package/schemas/components/appComponent.json +58 -0
  54. package/schemas/components/barcodeScanner.json +69 -0
  55. package/schemas/components/button.json +123 -0
  56. package/schemas/components/calendar.json +489 -0
  57. package/schemas/components/card.json +176 -0
  58. package/schemas/components/collection.json +54 -0
  59. package/schemas/components/dataGrid.json +119 -0
  60. package/schemas/components/datasource.json +151 -0
  61. package/schemas/components/dropdown.json +57 -0
  62. package/schemas/components/field-collection.json +618 -0
  63. package/schemas/components/field.json +265 -0
  64. package/schemas/components/form.json +234 -0
  65. package/schemas/components/index.json +71 -0
  66. package/schemas/components/layout.json +69 -0
  67. package/schemas/components/module.json +167 -0
  68. package/schemas/components/navDropdown.json +36 -0
  69. package/schemas/components/navbar.json +78 -0
  70. package/schemas/components/navbarItem.json +28 -0
  71. package/schemas/components/navbarLink.json +36 -0
  72. package/schemas/components/row.json +31 -0
  73. package/schemas/components/slot.json +30 -0
  74. package/schemas/components/tab.json +34 -0
  75. package/schemas/components/tabs.json +35 -0
  76. package/schemas/components/timeline.json +172 -0
  77. package/schemas/components/timelineGrid.json +328 -0
  78. package/schemas/fields/README.md +66 -0
  79. package/schemas/fields/attachment.json +156 -0
  80. package/schemas/fields/autocomplete-googleplaces.json +130 -0
  81. package/schemas/fields/checkbox.json +82 -0
  82. package/schemas/fields/date.json +88 -0
  83. package/schemas/fields/datetime.json +75 -0
  84. package/schemas/fields/email.json +75 -0
  85. package/schemas/fields/index.json +53 -0
  86. package/schemas/fields/number.json +91 -0
  87. package/schemas/fields/password.json +70 -0
  88. package/schemas/fields/radio.json +94 -0
  89. package/schemas/fields/rangedatetime.json +56 -0
  90. package/schemas/fields/select-async.json +334 -0
  91. package/schemas/fields/select.json +115 -0
  92. package/schemas/fields/tel.json +79 -0
  93. package/schemas/fields/text.json +86 -0
  94. package/schemas/fields/textarea.json +95 -0
  95. package/schemas/fields/time.json +91 -0
  96. package/schemas/fields/url.json +74 -0
  97. package/schemas/schema.graphql +12248 -0
  98. package/schemas/schemas.json +610 -0
  99. package/schemas/workflows/activity.json +96 -0
  100. package/schemas/workflows/common/condition.json +48 -0
  101. package/schemas/workflows/common/expression.json +76 -0
  102. package/schemas/workflows/common/mapping.json +173 -0
  103. package/schemas/workflows/common/step.json +38 -0
  104. package/schemas/workflows/flow/aggregation.json +44 -0
  105. package/schemas/workflows/flow/entity.json +129 -0
  106. package/schemas/workflows/flow/state.json +105 -0
  107. package/schemas/workflows/flow/transition.json +143 -0
  108. package/schemas/workflows/input.json +122 -0
  109. package/schemas/workflows/output.json +61 -0
  110. package/schemas/workflows/schedule.json +26 -0
  111. package/schemas/workflows/tasks/accounting-transaction.json +95 -0
  112. package/schemas/workflows/tasks/action-event.json +65 -0
  113. package/schemas/workflows/tasks/all.json +152 -0
  114. package/schemas/workflows/tasks/appmodule.json +56 -0
  115. package/schemas/workflows/tasks/attachment.json +97 -0
  116. package/schemas/workflows/tasks/authentication.json +86 -0
  117. package/schemas/workflows/tasks/caching.json +68 -0
  118. package/schemas/workflows/tasks/charge.json +92 -0
  119. package/schemas/workflows/tasks/commodity.json +92 -0
  120. package/schemas/workflows/tasks/contact-address.json +72 -0
  121. package/schemas/workflows/tasks/contact-payment-method.json +72 -0
  122. package/schemas/workflows/tasks/contact.json +82 -0
  123. package/schemas/workflows/tasks/csv.json +81 -0
  124. package/schemas/workflows/tasks/document-render.json +105 -0
  125. package/schemas/workflows/tasks/document-send.json +84 -0
  126. package/schemas/workflows/tasks/edi.json +157 -0
  127. package/schemas/workflows/tasks/email-send.json +110 -0
  128. package/schemas/workflows/tasks/error.json +72 -0
  129. package/schemas/workflows/tasks/export.json +90 -0
  130. package/schemas/workflows/tasks/filetransfer.json +102 -0
  131. package/schemas/workflows/tasks/flow-transition.json +68 -0
  132. package/schemas/workflows/tasks/foreach.json +69 -0
  133. package/schemas/workflows/tasks/generic.json +47 -0
  134. package/schemas/workflows/tasks/graphql.json +78 -0
  135. package/schemas/workflows/tasks/httpRequest.json +161 -0
  136. package/schemas/workflows/tasks/import.json +64 -0
  137. package/schemas/workflows/tasks/inventory.json +67 -0
  138. package/schemas/workflows/tasks/job.json +88 -0
  139. package/schemas/workflows/tasks/log.json +73 -0
  140. package/schemas/workflows/tasks/map.json +58 -0
  141. package/schemas/workflows/tasks/movement.json +54 -0
  142. package/schemas/workflows/tasks/note.json +59 -0
  143. package/schemas/workflows/tasks/number.json +65 -0
  144. package/schemas/workflows/tasks/order-tracking-event.json +109 -0
  145. package/schemas/workflows/tasks/order.json +139 -0
  146. package/schemas/workflows/tasks/payment.json +85 -0
  147. package/schemas/workflows/tasks/pdf-document.json +60 -0
  148. package/schemas/workflows/tasks/postal-codes.json +92 -0
  149. package/schemas/workflows/tasks/resolve-timezone.json +65 -0
  150. package/schemas/workflows/tasks/setVariable.json +76 -0
  151. package/schemas/workflows/tasks/switch.json +75 -0
  152. package/schemas/workflows/tasks/template.json +73 -0
  153. package/schemas/workflows/tasks/tracking-event.json +137 -0
  154. package/schemas/workflows/tasks/transmission.json +185 -0
  155. package/schemas/workflows/tasks/unzip-file.json +68 -0
  156. package/schemas/workflows/tasks/user.json +70 -0
  157. package/schemas/workflows/tasks/validation.json +99 -0
  158. package/schemas/workflows/tasks/while.json +53 -0
  159. package/schemas/workflows/tasks/workflow-execute.json +82 -0
  160. package/schemas/workflows/trigger.json +90 -0
  161. package/schemas/workflows/variable.json +46 -0
  162. package/schemas/workflows/workflow.json +335 -0
  163. package/scripts/postinstall.js +291 -0
  164. package/scripts/setup-vscode.js +80 -0
  165. package/skills/cxtms-developer/SKILL.md +118 -0
  166. package/skills/cxtms-developer/ref-cli-auth.md +120 -0
  167. package/skills/cxtms-developer/ref-entity-accounting.md +180 -0
  168. package/skills/cxtms-developer/ref-entity-commodity.md +239 -0
  169. package/skills/cxtms-developer/ref-entity-contact.md +163 -0
  170. package/skills/cxtms-developer/ref-entity-geography.md +154 -0
  171. package/skills/cxtms-developer/ref-entity-job.md +77 -0
  172. package/skills/cxtms-developer/ref-entity-notification.md +85 -0
  173. package/skills/cxtms-developer/ref-entity-order-sub.md +160 -0
  174. package/skills/cxtms-developer/ref-entity-order.md +183 -0
  175. package/skills/cxtms-developer/ref-entity-organization.md +41 -0
  176. package/skills/cxtms-developer/ref-entity-rate.md +182 -0
  177. package/skills/cxtms-developer/ref-entity-shared.md +176 -0
  178. package/skills/cxtms-developer/ref-entity-warehouse.md +115 -0
  179. package/skills/cxtms-developer/ref-graphql-query.md +309 -0
  180. package/skills/cxtms-module-builder/SKILL.md +477 -0
  181. package/skills/cxtms-module-builder/ref-components-data.md +293 -0
  182. package/skills/cxtms-module-builder/ref-components-display.md +411 -0
  183. package/skills/cxtms-module-builder/ref-components-forms.md +369 -0
  184. package/skills/cxtms-module-builder/ref-components-interactive.md +317 -0
  185. package/skills/cxtms-module-builder/ref-components-layout.md +390 -0
  186. package/skills/cxtms-module-builder/ref-components-specialized.md +477 -0
  187. package/skills/cxtms-workflow-builder/SKILL.md +438 -0
  188. package/skills/cxtms-workflow-builder/ref-accounting.md +66 -0
  189. package/skills/cxtms-workflow-builder/ref-communication.md +169 -0
  190. package/skills/cxtms-workflow-builder/ref-entity.md +342 -0
  191. package/skills/cxtms-workflow-builder/ref-expressions-ncalc.md +128 -0
  192. package/skills/cxtms-workflow-builder/ref-expressions-template.md +161 -0
  193. package/skills/cxtms-workflow-builder/ref-filetransfer.md +80 -0
  194. package/skills/cxtms-workflow-builder/ref-flow.md +210 -0
  195. package/skills/cxtms-workflow-builder/ref-other.md +157 -0
  196. package/skills/cxtms-workflow-builder/ref-query.md +105 -0
  197. package/skills/cxtms-workflow-builder/ref-utilities.md +417 -0
  198. package/templates/module-configuration.yaml +44 -0
  199. package/templates/module-form.yaml +152 -0
  200. package/templates/module-grid.yaml +229 -0
  201. package/templates/module-select.yaml +139 -0
  202. package/templates/module.yaml +84 -0
  203. package/templates/workflow-api-tracking.yaml +189 -0
  204. package/templates/workflow-basic.yaml +76 -0
  205. package/templates/workflow-document.yaml +155 -0
  206. package/templates/workflow-entity-trigger.yaml +90 -0
  207. package/templates/workflow-ftp-edi.yaml +158 -0
  208. package/templates/workflow-ftp-tracking.yaml +161 -0
  209. package/templates/workflow-mcp-tool.yaml +112 -0
  210. package/templates/workflow-public-api.yaml +135 -0
  211. package/templates/workflow-scheduled-execute.yaml +75 -0
  212. package/templates/workflow-scheduled.yaml +125 -0
  213. package/templates/workflow-utility.yaml +96 -0
  214. package/templates/workflow-webhook.yaml +128 -0
  215. package/templates/workflow.yaml +140 -0
@@ -0,0 +1,342 @@
1
+ # Entity CRUD Tasks Reference
2
+
3
+ ## Contents
4
+ - Entity/Change task (generic entity modification in Before triggers)
5
+ - Order tasks (Create, Update, Delete, Get, Copy, Split, Import, etc.)
6
+ - Contact tasks (Create, Update, Delete)
7
+ - ContactAddress tasks (Create, Update, Delete, Import)
8
+ - ContactPaymentMethod tasks (Create, Update, SendChargedAmount, VerifyChargedAmount)
9
+ - Commodity tasks (Create, Update, Split, Repack, Unpack)
10
+ - CommodityTrackingNumber tasks (Create, Update, Delete)
11
+ - Job tasks (Create, Update, Delete, Assign, Unassign)
12
+ - Charge tasks (Create, Update, Delete, DynamicUpdate, Calculate)
13
+ - Discount task (Update)
14
+ - Order sub-entity tasks (OrderCommodity, OrderCharge, OrderDocument, OrderTrackingEvent, OrderEntity)
15
+ - Inventory tasks (InventoryItem Create, Update, Delete)
16
+ - Other entity tasks (Movement, Country, Cities, Rate, TrackingEvent/Import)
17
+ - Note tasks (Create, Update, Delete, Import, Export, RenameThread)
18
+ - AccountingTransaction/ApplyCredit task
19
+
20
+ All entity tasks follow the `Namespace/Operation@Version` pattern. Outputs are stored as `ActivityName.StepName.outputKey`.
21
+
22
+ ## PostalCodes
23
+
24
+ | Task | Description |
25
+ |------|-------------|
26
+ | `PostalCodes/Import@1` | Import postal codes from file URL, stream, or inline data |
27
+
28
+ ### PostalCodes/Import@1
29
+
30
+ Imports postal codes (CSV, JSON, Excel). Supports upsert via `matchByFields`.
31
+
32
+ ```yaml
33
+ - task: "PostalCodes/Import@1"
34
+ name: ImportPostalCodes
35
+ inputs:
36
+ organizationId: "{{ int inputs.organizationId }}"
37
+ fileUrl: "{{ inputs.fileUrl }}"
38
+ matchByFields: ["code", "countryCode"]
39
+ outputs:
40
+ - name: importResult
41
+ mapping: "result?"
42
+ ```
43
+
44
+ **Inputs:** `organizationId` (int, required), `fileUrl` (string?), `fileType` (FileType?), `stream` (Stream?), `postalCodes` (List?), `matchByFields` (string[]?)
45
+ **Outputs:** `result.success`, `result.added`, `result.updated`, `result.errors`, `result.totalProcessed`, `result.hasErrors`
46
+ Input priority: `stream` > `fileUrl` > `postalCodes`. Task catches exceptions and returns them in `result.errors`.
47
+
48
+ ## Generic Entity Change
49
+
50
+ | Task | Description |
51
+ |------|-------------|
52
+ | `Entity/Change` | Generic entity change — modify custom values on the tracked entity. Designed for **Before** triggers where the entity hasn't been persisted yet. |
53
+
54
+ ```yaml
55
+ - task: "Entity/Change@1"
56
+ name: SetDefaults
57
+ inputs:
58
+ changes:
59
+ customValues:
60
+ region: "{{ parseAddress(Order.ShipToAddress).state }}"
61
+ lastModifiedBy: "{{ currentUser.name }}"
62
+ ```
63
+
64
+ > **Note**: Async "Before" triggers are forbidden. Before triggers must use `executionMode: Sync`.
65
+
66
+ ## Order
67
+
68
+ | Task | Description |
69
+ |------|-------------|
70
+ | `Order/Create` | Create a new order |
71
+ | `Order/Update` (v1, v2) | Update order fields |
72
+ | `Order/Delete` | Delete an order |
73
+ | `Order/Get` | Get order by ID |
74
+ | `Order/Copy` | Copy/duplicate an order |
75
+ | `Order/Split` | Split order into multiple |
76
+ | `Order/Purge` | Purge order data |
77
+ | `Order/Import` | Import order from external data |
78
+ | `Order/RecalculateCharges` | Recalculate all charges |
79
+ | `Order/GenerateTrackingNumber` | Generate tracking number |
80
+ | `Order/GetCargoMovementByPalletQuery` | Query cargo movements by pallet |
81
+
82
+ ```yaml
83
+ - task: "Order/Create@1"
84
+ name: CreateOrder
85
+ inputs:
86
+ orderType: "ParcelShipment"
87
+ entity:
88
+ customer: "{{ inputs.customerId }}"
89
+ status: "Draft"
90
+ outputs:
91
+ - name: order
92
+ mapping: "order"
93
+ ```
94
+
95
+ ```yaml
96
+ - task: "Order/Update@2"
97
+ name: UpdateOrder
98
+ inputs:
99
+ orderId: "{{ inputs.orderId }}"
100
+ entity:
101
+ status: "Active"
102
+ notes: "Updated by workflow"
103
+ ```
104
+
105
+ **Order/Import commodity fields**: When importing commodities, you can supply `packageTypeName` (string) instead of `packageTypeId`. The import handler resolves the name to an ID using an N+1-safe per-import cache (one DB query per unique package type name).
106
+
107
+ ## Contact
108
+
109
+ | Task | Description |
110
+ |------|-------------|
111
+ | `Contact/Create` | Create contact |
112
+ | `Contact/Update` | Update contact |
113
+ | `Contact/Delete` | Delete contact |
114
+
115
+ ## Contact Address
116
+
117
+ | Task | Description |
118
+ |------|-------------|
119
+ | `ContactAddress/Create` | Create address |
120
+ | `ContactAddress/Update` | Update address |
121
+ | `ContactAddress/Delete` | Delete address |
122
+ | `ContactAddress/Import` | Bulk import addresses |
123
+
124
+ ## Contact Payment Method
125
+
126
+ | Task | Description |
127
+ |------|-------------|
128
+ | `ContactPaymentMethod/Create` | Create payment method |
129
+ | `ContactPaymentMethod/Update` | Update payment method |
130
+ | `ContactPaymentMethod/SendChargedAmount` | Send charged amount notification |
131
+ | `ContactPaymentMethod/VerifyChargedAmount` | Verify charged amount |
132
+
133
+ ## Commodity
134
+
135
+ | Task | Description |
136
+ |------|-------------|
137
+ | `Commodity/Create` | Create commodity |
138
+ | `Commodity/Update` (v1, v2) | Update commodity |
139
+ | `Commodity/Split` | Split commodity into multiple |
140
+ | `Commodity/Repack` | Repack commodities |
141
+ | `Commodity/Unpack` | Unpack commodity |
142
+
143
+ ## Commodity Tracking Number
144
+
145
+ | Task | Description |
146
+ |------|-------------|
147
+ | `CommodityTrackingNumber/Create` | Create tracking number |
148
+ | `CommodityTrackingNumber/Update` | Update tracking number |
149
+ | `CommodityTrackingNumber/Delete` | Delete tracking number |
150
+
151
+ ## Job
152
+
153
+ | Task | Description |
154
+ |------|-------------|
155
+ | `Job/Create` | Create job |
156
+ | `Job/Update` | Update job |
157
+ | `Job/Delete` | Delete job |
158
+ | `Job/Assign` | Assign job to user/driver |
159
+ | `Job/Unassign` | Unassign job |
160
+
161
+ ## Charge
162
+
163
+ | Task | Description |
164
+ |------|-------------|
165
+ | `Charge/Create` | Create charge |
166
+ | `Charge/Update` | Update charge |
167
+ | `Charge/Delete` | Delete charge |
168
+ | `Charge/DynamicUpdate` | Dynamic update (partial fields) |
169
+ | `Charge/Calculate` | Calculate charge amount |
170
+
171
+ ```yaml
172
+ - task: "Charge/Create@1"
173
+ name: CreateCharge
174
+ inputs:
175
+ orderId: "{{ inputs.orderId }}"
176
+ chargeType: "Freight"
177
+ amount: "{{ Data.GetRate.rate.amount }}"
178
+ currency: "USD"
179
+ outputs:
180
+ - name: charge
181
+ mapping: "charge"
182
+ ```
183
+
184
+ ## Discount
185
+
186
+ | Task | Description |
187
+ |------|-------------|
188
+ | `Discount/Update` | Update discount |
189
+
190
+ ## Order Sub-Entities
191
+
192
+ | Task | Description |
193
+ |------|-------------|
194
+ | `OrderCommodity/Create` | Link commodity to order |
195
+ | `OrderCommodity/Update` | Update order-commodity link |
196
+ | `OrderCommodity/Delete` | Remove commodity from order |
197
+ | `OrderCharge/Create` | Create order charge |
198
+ | `OrderDocument/Create` | Create order document |
199
+ | `OrderDocument/Send` | Send order document |
200
+ | `OrderTrackingEvent/Create` | Create a single tracking event on an order |
201
+ | `OrderEntity/ChangeCustomValue` | Change custom field value |
202
+
203
+ ```yaml
204
+ # Create a single tracking event
205
+ - task: "OrderTrackingEvent/Create@1"
206
+ name: AddPickupEvent
207
+ inputs:
208
+ orderId: "{{ inputs.orderId }}"
209
+ organizationId: "{{ inputs.organizationId }}"
210
+ eventDefinitionName: "Picked Up"
211
+ eventDate: "{{ utcNow() }}"
212
+ description: "Package picked up from shipper"
213
+ location: "{{ order.shipFromAddress?.city }}"
214
+ includeInTracking: true
215
+ sendEmail: false
216
+ skipIfExists: true
217
+ customValues?:
218
+ carrierId: "{{ carrier.contactId }}"
219
+ carrierEventCode: "PU"
220
+ ```
221
+
222
+ ## Inventory
223
+
224
+ | Task | Description |
225
+ |------|-------------|
226
+ | `InventoryItem/Create` | Create inventory item |
227
+ | `InventoryItem/Update` | Update inventory item |
228
+ | `InventoryItem/Delete` | Delete inventory item |
229
+
230
+ ## Other
231
+
232
+ | Task | Description |
233
+ |------|-------------|
234
+ | `Movement/Create` | Create cargo movement |
235
+ | `Country/Create`, `Country/Update`, `Country/Delete` | Country CRUD |
236
+ | `Cities/Import` | Import cities |
237
+ | `Rate/Update` | Update rate |
238
+ | `TrackingEvent/Import` | Batch import tracking events into an order |
239
+
240
+ ```yaml
241
+ # Batch import tracking events
242
+ - task: "TrackingEvent/Import@1"
243
+ name: ImportEvents
244
+ inputs:
245
+ orderId: "{{ order.orderId }}"
246
+ events: "{{ trackingEvents }}"
247
+ matchByFields:
248
+ - "eventDate"
249
+ - "customValues.eventType"
250
+ - "customValues.locationId"
251
+ skipIfExists: true
252
+ createEventDefinitions: true
253
+ matchByEventDefinition:
254
+ - "customValues.carrierId"
255
+ - "customValues.carrierEventCode"
256
+ eventDefinitionDefaults:
257
+ includeInTracking: true
258
+ outputs:
259
+ - name: result
260
+ mapping: "result?"
261
+ ```
262
+
263
+ Each event in the `events` array: `eventDefinitionName` (required), `eventDate`, `description`, `location`, `includeInTracking`, `sendEmail`, `isInactive`, `customValues` (object).
264
+
265
+ Output `result`: `{ added, updated, skipped, failed, total, errors[] }`.
266
+
267
+ ## Note
268
+
269
+ | Task | Description |
270
+ |------|-------------|
271
+ | `Note/Create` | Create note in a thread |
272
+ | `Note/Update` | Update note content |
273
+ | `Note/Delete` | Delete a note |
274
+ | `Note/Import` | Bulk import notes |
275
+ | `Note/Export` | Export notes for an entity |
276
+ | `Note/RenameThread` | Rename a note thread |
277
+
278
+ ## Transmission
279
+
280
+ | Task | Description |
281
+ |------|-------------|
282
+ | `Transmission/Create` | Create transmission record linked to orders |
283
+ | `Transmission/Update` | Update transmission fields (dynamic) |
284
+ | `Transmission/Delete` | Delete transmission record |
285
+
286
+ Records inbound/outbound message transmissions (EDI, API, Email, Webhook) linked to orders.
287
+
288
+ ```yaml
289
+ - task: "Transmission/Create@1"
290
+ name: CreateTransmission
291
+ inputs:
292
+ organizationId: "{{ int organizationId }}"
293
+ transmission:
294
+ orderIds: "{{ orderIds }}"
295
+ channel: "EDI"
296
+ direction: "Outbound"
297
+ messageType: "214"
298
+ sender: "{{ senderISA }}"
299
+ receiver: "{{ receiverISA }}"
300
+ status: "Pending"
301
+ endpoint: "{{ endpoint }}"
302
+ protocol: "SFTP"
303
+ outputs:
304
+ - name: transmission
305
+ mapping: "transmission"
306
+ ```
307
+
308
+ ```yaml
309
+ - task: "Transmission/Update@1"
310
+ name: UpdateTransmission
311
+ inputs:
312
+ organizationId: "{{ int organizationId }}"
313
+ transmissionId: "{{ int Main?.CreateTransmission?.transmission?.id? }}"
314
+ transmission:
315
+ status: "Sent"
316
+ completedAt: "{{ now() }}"
317
+ ```
318
+
319
+ ```yaml
320
+ - task: "Transmission/Delete@1"
321
+ name: DeleteTransmission
322
+ inputs:
323
+ organizationId: "{{ int organizationId }}"
324
+ transmissionId: "{{ int inputs.transmissionId }}"
325
+ outputs:
326
+ - name: success
327
+ mapping: "success"
328
+ ```
329
+
330
+ **Create inputs:** `organizationId` (int, required), `transmission` object — `orderIds` (required, at least one), `channel`, `direction` (Inbound/Outbound), `messageType`, `sender`, `receiver`, `status`, `endpoint`, `protocol`, `correlationId` (auto-generated if omitted), `parentId`, `httpStatus`, `byteSize`, `retryCount`, `maxRetries`, `nextRetryAt`, `errorCode`, `errorMessage`, `customValues`, `headers`, `payloadRef`, `scheduledAt`, `startedAt`, `completedAt`, `durationMs`.
331
+
332
+ **Create outputs:** `transmission` (full TransmissionDto).
333
+ **Update inputs:** `organizationId`, `transmissionId`, `transmission` (dynamic partial fields).
334
+ **Delete outputs:** `success` (boolean).
335
+
336
+ **Status enum:** Pending, InProgress, Sent, Received, Delivered, Acknowledged, Rejected, Error, RetryScheduled, Cancelled, Expired, Accepted.
337
+
338
+ ## Accounting Transaction (Additional)
339
+
340
+ | Task | Description |
341
+ |------|-------------|
342
+ | `AccountingTransaction/ApplyCredit` | Apply credit memo to invoices |
@@ -0,0 +1,128 @@
1
+ # NCalc Expressions & Functions
2
+
3
+ ## Contents
4
+ - NCalc expression syntax `[variable]` (in conditions and expression directives)
5
+ - Operators (comparison, logical, arithmetic, ternary, membership)
6
+ - Iterator variables (`[each.*]` and `[item.*]`)
7
+ - Collection functions (any, all, count, sum, first, last, distinct, groupBy, join, etc.)
8
+ - String functions (isNullOrEmpty, length, lower, upper, replace, format, base64, etc.)
9
+ - Date functions (now, parseDate, addDays, formatDate, dateFromUnix, etc.)
10
+ - Math functions (Abs, Ceiling, Floor, Round, Min, Max, etc.)
11
+ - Domain functions (convertWeight, convertDimension)
12
+
13
+ For template expressions `{{ path }}` used in step inputs, see [ref-expressions-template.md](ref-expressions-template.md).
14
+
15
+ ## NCalc Expressions: `[variable]` (in conditions and expression directives)
16
+
17
+ Used in `conditions[].expression`, `switch` case `when`, and `expression:` value directives. Variables use **square bracket** `[name]` syntax.
18
+
19
+ ```yaml
20
+ conditions:
21
+ - expression: "[status] = 'Active' AND [amount] > 100"
22
+ - expression: "isNullOrEmpty([Data.GetOrder.order?]) = false"
23
+ - expression: "any([changes], [each.key] = 'Status') = true"
24
+ ```
25
+
26
+ **Parameter resolution rules**:
27
+ - Empty strings are converted to `null` (so `""` is treated as no value)
28
+ - Numeric strings are auto-converted to `decimal` when needed (e.g., `[price] > 100` works even if price is the string `"150"`)
29
+ - Dot paths resolve deep: `[Activity.Step.output.nested.field]`
30
+ - Optional suffix `?` prevents errors: `[order.customer?.name?]`
31
+
32
+ ### Operators
33
+
34
+ | Type | Operators |
35
+ |------|-----------|
36
+ | Comparison | `=`, `!=`, `<>`, `<`, `>`, `<=`, `>=` |
37
+ | Logical | `AND`, `OR`, `NOT` (also `&&`, `\|\|`, `!`) |
38
+ | Arithmetic | `+`, `-`, `*`, `/`, `%` |
39
+ | Ternary | `if(condition, trueVal, falseVal)` |
40
+ | Membership | `in(value, val1, val2, ...)` |
41
+
42
+ ### Iterator Variables
43
+
44
+ Functions use two iterator variable names:
45
+ - **`[each.*]`** -- used by: `any`, `all`, `sum`, `join` (3-arg)
46
+ - **`[item.*]`** -- used by: `first`, `last`, `groupBy`
47
+
48
+ ### Collection Functions
49
+
50
+ | Function | Description |
51
+ |----------|-------------|
52
+ | `any([items], [each.prop] = 'val')` | True if any item matches expression. Without expression: checks if collection contains the value |
53
+ | `all([items], [each.prop] > 0)` | True if all items match. Returns `false` for null/empty collections |
54
+ | `count([items])` | Count items in list or JToken. Returns `0` for non-collections |
55
+ | `sum([items], [each.amount])` | Sum values as `decimal`. Optional `[each.*]` accessor. Skips nulls |
56
+ | `first([items])` or `first([items], [item.name])` | First item or evaluate expression on first item. Returns `""` if empty |
57
+ | `last([items])` or `last([items], [item.name])` | Last item or evaluate expression on last item. Returns `""` if empty |
58
+ | `distinct([items])` | Remove duplicates. Uses deep comparison for dictionaries |
59
+ | `reverse([items])` | Reverse collection or string |
60
+ | `contains([source], 'needle')` | String contains, JArray contains, list contains, or dict key/value contains |
61
+ | `removeEmpty([items])` | Remove null and whitespace-only items |
62
+ | `concat([list1], [list2], ...)` | Concatenate multiple collections into flat list. Variadic args. Skips nulls |
63
+ | `groupBy([items], [item.cat])` | Group by one or more key expressions. Returns `[{key, items}]`. Multi-key: keys joined with `\|` |
64
+ | `join([items], [each.name], ',')` | Join collection with `[each.*]` accessor and separator (3-arg) |
65
+ | `join([items], ',')` | Join collection directly with separator (2-arg) |
66
+ | `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
67
+ | `elementAt([items], 0)` | Get element at index (zero-based) from list |
68
+
69
+ ### String Functions
70
+
71
+ | Function | Description |
72
+ |----------|-------------|
73
+ | `isNullOrEmpty([var])` | True if null, empty string, or empty list |
74
+ | `length([var])` | String length or collection count. `0` for null strings and non-collections |
75
+ | `lower([name])` / `upper([code])` | Case conversion. Handles string, JToken, any `.ToString()` |
76
+ | `left([code], 3)` / `right([code], 3)` | Left/right N characters. Returns full string if shorter than N |
77
+ | `substring([str], 0, 5)` | Extract substring starting at position for given length |
78
+ | `replace([str], 'old', 'new')` | String replacement. Returns null if any arg is null |
79
+ | `trim([value])` | Trim whitespace. Returns `""` for null |
80
+ | `format('{0}-{1}', [prefix], [id])` | String.Format style. Variadic args. Returns null if format is null |
81
+ | `base64([value])` / `fromBase64([encoded])` | Base64 encode/decode. Handles string, byte[], JToken |
82
+ | `bool([value])` | Convert to boolean: null->`false`, empty string->`false`, "true"/"false"->parsed, non-zero number->`true`, any object->`true` |
83
+ | `transliterate([value])` | Unicode to ASCII (Unidecode). Returns `""` for null |
84
+ | `transliterateUa([value])` | Ukrainian-specific transliteration. Returns `""` for null |
85
+ | `parseAddress([address])` | Parse address -> `{StreetNumber, StreetName}`. Handles US and EU formats |
86
+
87
+ ### Date Functions
88
+
89
+ | Function | Description |
90
+ |----------|-------------|
91
+ | `parseDate([str])` | Parse date string to DateTime. Supports common formats (ISO, US, etc.) |
92
+ | `now()` | Current UTC `DateTime` |
93
+ | `now('yyyy-MM-dd', 'en-US')` | Formatted current time as string |
94
+ | `addDays([date], 30)` | Add days (decimal, can be negative). Accepts DateTime, DateTimeOffset, string |
95
+ | `addHours([date], 2)` | Add hours (decimal, can be negative). Same type handling |
96
+ | `formatDate([date], 'dd/MM/yyyy', 'en-US')` | Format date with culture. Accepts DateTime or string |
97
+ | `dateFromUnix([unixTime])` | Unix timestamp (seconds) -> `DateTimeOffset`. Accepts int, long, decimal, string |
98
+ | `dateToUtc([date])` or `dateToUtc([date], 'en-US')` | Convert to UTC. Optional culture for string parsing |
99
+ | `toLocalTime([date], 'America/Chicago')` | Convert UTC datetime to local time in IANA timezone. Returns `null` if date or timezone is invalid |
100
+
101
+ ### Business Date Math (in Lucene filter expressions)
102
+
103
+ The filter engine (`FilterBy`) supports business-aware date math units in Lucene date expressions:
104
+
105
+ | Unit | Aliases | Description |
106
+ |------|---------|-------------|
107
+ | `BHOUR` | `BHOURS` | Add/subtract business hours (respects weekly schedule + holidays) |
108
+ | `BDAY` | `BDAYS` | Add/subtract business days (skips non-working days) |
109
+
110
+ **Usage**: These units are used in **Lucene filter strings** (not NCalc expressions). They require an `IBusinessDateMathResolver` and are resolved via the organization's business calendar.
111
+
112
+ ```
113
+ dueDate: [NOW TO NOW+3BDAYS]
114
+ pickupDate: [* TO NOW-8BHOURS]
115
+ ```
116
+
117
+ ### Math Functions (NCalc built-in)
118
+
119
+ `Abs(x)`, `Ceiling(x)`, `Floor(x)`, `Round(x, decimals)`, `Min(x, y)`, `Max(x, y)`, `Pow(x, y)`, `Sqrt(x)`, `Truncate(x)`
120
+
121
+ Custom: `ceiling([value])` -- same as `Ceiling` but handles type conversion to double.
122
+
123
+ ### Domain Functions
124
+
125
+ | Function | Description |
126
+ |----------|-------------|
127
+ | `convertWeight([weight], 'Kg', 'Lb')` | Weight unit conversion. Returns `decimal` rounded to 5 places |
128
+ | `convertDimension([length], 'Cm', 'In')` | Dimension unit conversion. Returns `decimal` rounded to 3 places |
@@ -0,0 +1,161 @@
1
+ # Template Expressions & Value Directives
2
+
3
+ ## Contents
4
+ - Template expression syntax `{{ path }}` (in step inputs)
5
+ - Type converters (int, decimal, bool, fromJson, toJson, etc.)
6
+ - Value directives (expression, coalesce, foreach, switch, extends, $raw, $eval, encrypt/decrypt)
7
+ - Property path syntax (dot paths, array indexing, wildcards, filters, projections)
8
+
9
+ There are **two distinct syntaxes** for referencing variables, used in different contexts. This file covers **template expressions** used in step inputs. For NCalc conditions and functions, see [ref-expressions-ncalc.md](ref-expressions-ncalc.md).
10
+
11
+ ## Template Expressions: `{{ path }}` (in step inputs)
12
+
13
+ Used in step `inputs` values. Resolves variable paths from scoped variables.
14
+
15
+ ```yaml
16
+ inputs:
17
+ orderId: "{{ inputs.orderId }}" # Simple reference
18
+ url: "{{ chopinConfig.baseUrl }}/api/v1" # String interpolation
19
+ order: "{{ Data.GetOrder.order }}" # Raw object (single {{ }})
20
+ name: "Order {{ Data.GetOrder.order.orderNumber }}" # String interpolation (multiple)
21
+ ```
22
+
23
+ **Key behavior**: A single `{{ path }}` returns the **raw object** (preserving type). Multiple `{{ }}` in a string returns string interpolation (each resolved value is `.ToString()`).
24
+
25
+ ### Type Converters (prefix in {{ }})
26
+
27
+ ```yaml
28
+ organizationId: "{{ int organizationId }}"
29
+ amount: "{{ decimal totalAmount }}"
30
+ isActive: "{{ bool isActive }}"
31
+ flag: "{{ boolOrFalse someFlag }}" # null -> false
32
+ flagOn: "{{ boolOrTrue someFlag }}" # null -> true
33
+ notes: "{{ emptyIfNull notes }}" # null -> ""
34
+ notes: "{{ nullIfEmpty notes }}" # "" or whitespace -> null
35
+ config: "{{ fromJson configJsonString }}" # JSON string -> dict/array
36
+ payload: "{{ toJson someObject }}" # object -> JSON string
37
+ name: "{{ trim value }}"
38
+ search: "{{ luceneString query }}" # escape & quote for Lucene
39
+ ```
40
+
41
+ | Converter | Returns | Null handling |
42
+ |-----------|---------|---------------|
43
+ | `string` | `string` | null. Reads `Stream` to string if value is Stream |
44
+ | `int` | `int` | Throws on null |
45
+ | `decimal` | `decimal` | Throws on null |
46
+ | `bool` | `bool` | Throws on null |
47
+ | `boolOrFalse` | `bool` | `false` if null |
48
+ | `boolOrTrue` | `bool` | `true` if null |
49
+ | `datetime` | `DateTime` | Throws on null |
50
+ | `emptyIfNull` | same type | `""` if null, `0` for int?, `0m` for decimal? |
51
+ | `nullIfEmpty` | same type | `null` if empty/whitespace string or empty collection |
52
+ | `luceneString` | `string` | null |
53
+ | `transliterate` | `string` | null (Unicode -> ASCII via Unidecode) |
54
+ | `transliterateUa` | `string` | null (Ukrainian-specific rules) |
55
+ | `fromJson` | `dict` or `array` | null. Empty string -> empty dict |
56
+ | `toJson` | `string` | `""` if null |
57
+ | `trim` | `string` | null |
58
+ | `toLocalTime` | `DateTime` or `string` | null. Syntax: `{{ toLocalTime path 'TimezoneId' 'format?' }}` |
59
+
60
+ ### Value Directives (in YAML input mappings)
61
+
62
+ **`expression`** -- Evaluate NCalc expression as a value:
63
+ ```yaml
64
+ amount:
65
+ expression: "[price] * [quantity]"
66
+ ```
67
+
68
+ **`coalesce`** -- First non-null value from a list:
69
+ ```yaml
70
+ displayName:
71
+ coalesce:
72
+ - "{{ customer.name? }}"
73
+ - "{{ customer.email? }}"
74
+ - "Unknown"
75
+ ```
76
+
77
+ **`foreach`** (value context) -- Transform collections inline:
78
+ ```yaml
79
+ commodities:
80
+ foreach: "sourceCommodities"
81
+ item: "item" # default: "item"
82
+ conditions: "[item.isActive] = true" # optional NCalc filter per item
83
+ continueOnError: false # optional, skip errors
84
+ mapping: # dict -> List<dict>, string -> List<object>
85
+ name: "{{ item.name }}"
86
+ quantity: "{{ item.qty }}"
87
+ ```
88
+
89
+ **`switch`** (value context) -- Value-based switch (case-insensitive match):
90
+ ```yaml
91
+ perLb:
92
+ switch: "{{ contact.commissionTier }}"
93
+ cases:
94
+ "tier1": "{{ rate.customValues.commission_per_lb_tier1 }}"
95
+ "tier2": "{{ rate.customValues.commission_per_lb_tier2 }}"
96
+ default: "0"
97
+ ```
98
+
99
+ **`extends`** -- Extend/merge an existing object or array:
100
+ ```yaml
101
+ orderData:
102
+ extends: "{{ existingOrder }}" # base object or array
103
+ defaultIfNull: {} # fallback if extends is null
104
+ mapping: # dict: merge overrides. array: append items
105
+ status: "Updated"
106
+ notes: "{{ newNotes }}"
107
+ ```
108
+
109
+ **`resolve`** -- Entity ID lookup by querying a GraphQL collection:
110
+ ```yaml
111
+ customerId:
112
+ resolve:
113
+ entity: "Contact" # Entity type (auto-pluralized for query)
114
+ filter: "name:{{ customerName }}" # Lucene filter (template-parsed)
115
+ field: "contactId" # Field to return (default: <entity>Id)
116
+ ```
117
+ Results are batched and cached per unique `entity|filter|field` combination by `ResolvePreProcessor` before step execution. Cache misses return `null`. Useful inside `foreach` mappings where many items reference the same entity — only one query per unique filter value.
118
+
119
+ **`$raw`** -- Prevent template parsing (pass as-is):
120
+ ```yaml
121
+ template:
122
+ $raw: "This {{ won't }} be parsed"
123
+ ```
124
+
125
+ **`$eval`** -- Parse JSON string then evaluate as template:
126
+ ```yaml
127
+ dynamicConfig:
128
+ $eval: "{{ configJsonString }}"
129
+ ```
130
+
131
+ **`decrypt`** / **`encrypt`** -- AES-CBC encryption (optional key/IV, has defaults):
132
+ ```yaml
133
+ apiKey:
134
+ decrypt:
135
+ encryptedValue: "{{ encryptedApiKey }}"
136
+ key: "{{ encryptionKey }}" # optional Base64 AES key
137
+ initializationVector: "{{ iv }}" # optional Base64 IV
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Property Path Syntax (in collection, mapping, variable paths)
143
+
144
+ Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
145
+
146
+ | Pattern | Description | Example |
147
+ |---------|-------------|---------|
148
+ | `a.b.c` | Dot-separated nested path | `order.customer.name` |
149
+ | `prop?` | Optional access (null if missing) | `order.customer?.name?` |
150
+
151
+ > **Note**: Object-type task inputs (e.g., `headers`, `columnMappings`) are automatically null-safe at the engine level. Omitting an optional object input from YAML returns `null` without errors. The `?` suffix remains required in template expression paths and NCalc conditions.
152
+ | `list[0]` | Array index | `items[0]` |
153
+ | `list[^1]` | Index from end (last item) | `items[^1]` |
154
+ | `list[*]` | Flatten/wildcard (all items) | `containers[*].commodities` |
155
+ | `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
156
+ | `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
157
+ | `list[condition]` | Filter by condition | `items[status=Active]` |
158
+ | `dict['key']` | Dictionary key access | `customValues['myField']` |
159
+ | `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
160
+ | `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |
161
+ | `list[*].{alias:_.parent}` | Field selector referencing parent | `items[*].{parentId:_.orderId}` |