@cxtms/cx-schema 1.9.24 → 1.9.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cxtms/cx-schema",
3
- "version": "1.9.24",
3
+ "version": "1.9.25",
4
4
  "description": "Schema validation package for CXTMS YAML modules",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -74,6 +74,17 @@
74
74
  "type": ["boolean", "string"],
75
75
  "description": "Skip if same EventDefinitionId already on order"
76
76
  },
77
+ "autoLinkToCommodities": {
78
+ "type": ["boolean", "string"],
79
+ "description": "Per-task override for the tms.trackingEvents.autoLinkToCommodities org config. When true, links the tracking event to all first-level commodities; when false, skips auto-linking. Ignored when commodityIds is supplied."
80
+ },
81
+ "commodityIds": {
82
+ "type": ["array", "string"],
83
+ "description": "Explicit list of commodity IDs to link the tracking event to. When provided (non-empty), overrides auto-link entirely and links only these commodities. IDs not belonging to the order are silently dropped.",
84
+ "items": {
85
+ "type": ["integer", "string"]
86
+ }
87
+ },
77
88
  "eventDefinitionValues?": {
78
89
  "type": "object",
79
90
  "description": "Values for creating a new EventDefinition if not found by name",
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "title": "TrackingEvent Tasks",
4
- "description": "Tracking event import operations",
4
+ "description": "Tracking event create and import operations",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "task": {
8
8
  "type": "string",
9
9
  "enum": [
10
+ "TrackingEvent/Create@1",
10
11
  "TrackingEvent/Import@1"
11
12
  ],
12
13
  "description": "Task type identifier"
@@ -36,11 +37,64 @@
36
37
  },
37
38
  "inputs": {
38
39
  "type": "object",
39
- "description": "TrackingEvent/Import inputs",
40
+ "description": "TrackingEvent/Create inputs (organizationId, eventDefinitionId or eventDefinitionName, orderId/commodityId/commodityIds, description, location, includeInTracking, sendEmail, eventDate, customValues, skipIfExists, eventDefinitionValues) OR TrackingEvent/Import inputs",
40
41
  "properties": {
42
+ "organizationId": {
43
+ "type": ["integer", "string"],
44
+ "description": "Organization ID (required for TrackingEvent/Create@1)"
45
+ },
41
46
  "orderId": {
47
+ "type": ["integer", "string"],
48
+ "description": "Target order ID. Required for TrackingEvent/Import@1; for TrackingEvent/Create@1 at least one of orderId, commodityId, or commodityIds must be provided."
49
+ },
50
+ "commodityId": {
51
+ "type": ["integer", "string"],
52
+ "description": "(TrackingEvent/Create@1) Single commodity to link. Can be combined with orderId and/or commodityIds."
53
+ },
54
+ "commodityIds": {
55
+ "type": ["array", "string"],
56
+ "description": "(TrackingEvent/Create@1) List of commodities to link. Can be combined with orderId and/or commodityId.",
57
+ "items": {
58
+ "type": ["integer", "string"]
59
+ }
60
+ },
61
+ "eventDefinitionId": {
62
+ "type": ["integer", "string"],
63
+ "description": "(TrackingEvent/Create@1) ID of an existing event definition. Required if eventDefinitionName is not provided."
64
+ },
65
+ "eventDefinitionName": {
66
+ "type": "string",
67
+ "description": "(TrackingEvent/Create@1) Name of the event definition. Required if eventDefinitionId is not provided. Auto-creates a new definition when combined with eventDefinitionValues."
68
+ },
69
+ "eventDate": {
70
+ "type": "string",
71
+ "description": "(TrackingEvent/Create@1) Event date (converted to UTC; defaults to current UTC time)"
72
+ },
73
+ "includeInTracking": {
74
+ "type": ["boolean", "string"],
75
+ "description": "(TrackingEvent/Create@1) Include in public tracking display"
76
+ },
77
+ "sendEmail": {
78
+ "type": ["boolean", "string"],
79
+ "description": "(TrackingEvent/Create@1) Send email notification"
80
+ },
81
+ "location": {
82
+ "type": "string",
83
+ "description": "(TrackingEvent/Create@1) Event location (overrides EventDefinition default)"
84
+ },
85
+ "description": {
42
86
  "type": "string",
43
- "description": "Target order ID (required)"
87
+ "description": "(TrackingEvent/Create@1) Event description (overrides EventDefinition default). NOTE: When specified at inputs level (not step root), this is the tracking-event description."
88
+ },
89
+ "customValues": {
90
+ "type": "object",
91
+ "description": "(TrackingEvent/Create@1) Free-form custom values stored on the event",
92
+ "additionalProperties": true
93
+ },
94
+ "eventDefinitionValues": {
95
+ "type": "object",
96
+ "description": "(TrackingEvent/Create@1) Values for creating a new EventDefinition when none matches the given name",
97
+ "additionalProperties": true
44
98
  },
45
99
  "events": {
46
100
  "type": ["array", "string"],
@@ -94,7 +148,7 @@
94
148
  },
95
149
  "skipIfExists": {
96
150
  "type": ["boolean", "string"],
97
- "description": "Skip event if duplicate found via matchByFields. Default: true"
151
+ "description": "(TrackingEvent/Import@1) Skip event if duplicate found via matchByFields. Default: true. (TrackingEvent/Create@1) Skip if an event with the same event definition already exists on the target order or commodity."
98
152
  },
99
153
  "createEventDefinitions": {
100
154
  "type": ["boolean", "string"],
@@ -77,6 +77,12 @@ Milestone/tracking event on an order or commodity.
77
77
  |-------|------|
78
78
  | `eventDefinition` | `EventDefinition` |
79
79
 
80
+ ### GraphQL Computed
81
+
82
+ | Field | Returns | Notes |
83
+ |-------|---------|-------|
84
+ | `businessDays(path: String!)` | `int?` | Business days from the date at `path` to today, using the org's business calendar. `path` is a dot-separated property path on the tracking event (e.g. `"eventDate"`, `"customValues.scheduledAt"`). Returns `null` if path doesn't resolve or value isn't a parseable date. |
85
+
80
86
  ---
81
87
 
82
88
  ## EventDefinition
@@ -109,6 +109,7 @@ These are virtual fields that filter `orderEntities` by type:
109
109
  | `getChargesByChargeType(chargeType)` | `[Charge]` | Charges filtered by type |
110
110
  | `getOrderSummary(weightUnit, volumeUnit, dimensionsUnit)` | `OrderSummary` | |
111
111
  | `lastTrackingEvent(eventDefinitionName)` | `TrackingEvent` | Most recent |
112
+ | `businessDays(path: String!)` | `int?` | Business days from the date at `path` to today, using the org's business calendar. `path` is a dot-separated property path on the order (e.g. `"customValues.leg.pickup.scheduledAt"`). Returns `null` if path doesn't resolve or value isn't a parseable date. |
112
113
  | `attachmentsSummary` | `OrderAttachmentSummaryGqlDto` | `.totalCount` (int), `.hasAny` (bool) — batched DataLoader, backed by DB view |
113
114
  | `notesSummary` | `OrderNoteSummaryGqlDto` | `.totalCount` (int), `.hasAny` (bool) — batched DataLoader, backed by DB view |
114
115
  | `notesCount(threadFilter)` | `int` | |
@@ -227,6 +227,7 @@ Colored chip/badge with dot indicator.
227
227
  | `label` | `string` | Badge text (template-parsed) |
228
228
  | `colorKey` | `string` | Color lookup key (template-parsed; defaults to lowercased label) |
229
229
  | `options.colors` | `Record<string, {label, bgcolor, dot}>` | Color map (must include `default`) |
230
+ | `onClick` | `Action[]` | Actions to dispatch when the badge is clicked. Makes the badge interactive (pointer cursor). |
230
231
 
231
232
  ```yaml
232
233
  component: badge
@@ -238,6 +239,22 @@ props:
238
239
  active: { label: "Active", bgcolor: "#e8f5e9", dot: "#4caf50" }
239
240
  inactive: { label: "Inactive", bgcolor: "#fce4ec", dot: "#f44336" }
240
241
  default: { label: "Unknown", bgcolor: "#f5f5f5", dot: "#9e9e9e" }
242
+
243
+ # Badge with click action
244
+ component: badge
245
+ name: priorityBadge
246
+ props:
247
+ label: "{{ order.priority }}"
248
+ colorKey: "{{ order.priority }}"
249
+ options:
250
+ colors:
251
+ high: { label: "High", bgcolor: "#fce4ec", dot: "#f44336" }
252
+ normal: { label: "Normal", bgcolor: "#e8f5e9", dot: "#4caf50" }
253
+ default: { label: "Unknown", bgcolor: "#f5f5f5", dot: "#9e9e9e" }
254
+ onClick:
255
+ - navigate:
256
+ route: order-detail
257
+ params: { id: "{{ order.id }}" }
241
258
  ```
242
259
 
243
260
  ---
@@ -197,11 +197,11 @@ Input priority: `stream` > `fileUrl` > `postalCodes`. Task catches exceptions an
197
197
  | `OrderCharge/Create` | Create order charge |
198
198
  | `OrderDocument/Create` | Create order document |
199
199
  | `OrderDocument/Send` | Send order document |
200
- | `OrderTrackingEvent/Create` | Create a single tracking event on an order |
200
+ | `OrderTrackingEvent/Create` | Create a single tracking event on an order. Auto-links to first-level commodities by default; override per task via `autoLinkToCommodities` or target specific commodities via `commodityIds`. |
201
201
  | `OrderEntity/ChangeCustomValue` | Change custom field value |
202
202
 
203
203
  ```yaml
204
- # Create a single tracking event
204
+ # Create a single tracking event (auto-links to first-level commodities by default)
205
205
  - task: "OrderTrackingEvent/Create@1"
206
206
  name: AddPickupEvent
207
207
  inputs:
@@ -219,6 +219,32 @@ Input priority: `stream` > `fileUrl` > `postalCodes`. Task catches exceptions an
219
219
  carrierEventCode: "PU"
220
220
  ```
221
221
 
222
+ **Auto-link to commodities.** When the event is added to an order, it is also linked to every first-level commodity (commodities where `ContainerCommodityId` is null). This behavior is governed by the org config `tms.trackingEvents.autoLinkToCommodities` (default `true`) and can be overridden per task:
223
+
224
+ ```yaml
225
+ # Force-enable auto-link even if the org config disables it
226
+ - task: "OrderTrackingEvent/Create@1"
227
+ inputs:
228
+ orderId: "{{ order.orderId }}"
229
+ organizationId: "{{ organizationId }}"
230
+ eventDefinitionName: "Arrived"
231
+ autoLinkToCommodities: true
232
+
233
+ # Link to specific commodities only (bypasses auto-link entirely)
234
+ - task: "OrderTrackingEvent/Create@1"
235
+ inputs:
236
+ orderId: "{{ order.orderId }}"
237
+ organizationId: "{{ organizationId }}"
238
+ eventDefinitionName: "Partial Delivery"
239
+ commodityIds: [101, 102, 103]
240
+ ```
241
+
242
+ | Precedence | Source | Behavior |
243
+ |---|---|---|
244
+ | 1 (highest) | `commodityIds` input | Link exactly those IDs. IDs not on the order are silently dropped. `autoLinkToCommodities` is ignored. |
245
+ | 2 | `autoLinkToCommodities` input | `true` → link all first-level commodities; `false` → link none. Overrides org config. |
246
+ | 3 (default) | `tms.trackingEvents.autoLinkToCommodities` org config | Default `true` → link first-level commodities. |
247
+
222
248
  ## Inventory
223
249
 
224
250
  | Task | Description |
@@ -235,8 +261,27 @@ Input priority: `stream` > `fileUrl` > `postalCodes`. Task catches exceptions an
235
261
  | `Country/Create`, `Country/Update`, `Country/Delete` | Country CRUD |
236
262
  | `Cities/Import` | Import cities |
237
263
  | `Rate/Update` | Update rate |
264
+ | `TrackingEvent/Create` | Create a single tracking event and link to an order, a commodity, or multiple commodities |
238
265
  | `TrackingEvent/Import` | Batch import tracking events into an order |
239
266
 
267
+ ```yaml
268
+ # Create a single tracking event linked to a commodity (or a list of commodities)
269
+ - task: "TrackingEvent/Create@1"
270
+ name: CreateCommodityEvent
271
+ inputs:
272
+ organizationId: "{{ organizationId }}"
273
+ eventDefinitionName: "Scanned"
274
+ commodityIds: [101, 102] # or commodityId for a single commodity
275
+ orderId: "{{ order.orderId }}" # optional; triggers auto-link to first-level commodities
276
+ eventDate: "{{ utcNow() }}"
277
+ location: "{{ scan.location }}"
278
+ includeInTracking: true
279
+ sendEmail: false
280
+ skipIfExists: true
281
+ ```
282
+
283
+ Use [`OrderTrackingEvent/Create@1`](#order-sub-entities) when you want per-task overrides of the commodity auto-link behavior (`autoLinkToCommodities`, `commodityIds`). `TrackingEvent/Create@1` only honors the org-wide `tms.trackingEvents.autoLinkToCommodities` default for the auto-link step.
284
+
240
285
  ```yaml
241
286
  # Batch import tracking events
242
287
  - task: "TrackingEvent/Import@1"
@@ -4,7 +4,7 @@
4
4
  - NCalc expression syntax `[variable]` (in conditions and expression directives)
5
5
  - Operators (comparison, logical, arithmetic, ternary, membership)
6
6
  - Iterator variables (`[each.*]` and `[item.*]`)
7
- - Collection functions (any, all, count, sum, first, last, distinct, select, zip, groupBy, join, etc.)
7
+ - Collection functions (any, all, count, sum, first, last, distinct, select, zip, groupBy, join, sort, etc.)
8
8
  - String functions (isNullOrEmpty, length, lower, upper, replace, format, base64, coalesce, etc.)
9
9
  - Date functions (now, parseDate, addDays, formatDate, dateFromUnix, etc.)
10
10
  - Math functions (Abs, Ceiling, Floor, Round, Min, Max, etc.)
@@ -44,7 +44,7 @@ conditions:
44
44
 
45
45
  Functions use two iterator variable names:
46
46
  - **`[each.*]`** -- used by: `any`, `all`, `sum`, `select`, `join` (3-arg), and projections over `zip(...)` output
47
- - **`[item.*]`** -- used by: `first`, `last`, `groupBy`
47
+ - **`[item.*]`** -- used by: `first`, `last`, `groupBy`, `sort`
48
48
 
49
49
  ### Collection Functions
50
50
 
@@ -68,6 +68,9 @@ Functions use two iterator variable names:
68
68
  | `zip([a], [b])` | Pair elements from two or more lists into `[{item1, item2}, ...]`. Custom keys: `zip([a], [b], 'name', 'code')`. Variadic: accepts N lists. Truncates to shortest list. Returns empty list if any input is empty/null. Falls back to `item1`, `item2`, ... when custom key count does not match list count |
69
69
  | `split([str], ' ')` | Split string by first character of separator. Returns `List<string>` |
70
70
  | `elementAt([items], 0)` | Get element at index (zero-based) from list |
71
+ | `sort([items])` | Sort items ascending by their natural value |
72
+ | `sort([items], [item.expr])` | Sort ascending by projected property using `[item.*]` accessor |
73
+ | `sort([items], [item.expr], 'asc'\|'desc')` | Sort with explicit direction. `orderBy` is an alias for `sort` |
71
74
 
72
75
  ### String Functions
73
76
 
@@ -181,7 +181,7 @@ Used in `collection:` (foreach), `mapping:` (outputs), and variable resolution.
181
181
  | `list[*].dictKey` | Wildcard traversal into Dictionary/JObject keys | `items[*].customValues.chapter_en` |
182
182
  | `list[**]` | Recursive flatten (all depths) | `containerCommodities[**]` |
183
183
  | `list[-1]` | Depth filter (leaves only) | `tree[**][-1]` |
184
- | `list[condition]` | Filter by condition | `items[status=Active]` |
184
+ | `list[condition]` | Filter by condition. LHS supports dotted nested paths | `items[status=Active]`, `activity[status.type=D]` |
185
185
  | `dict['key']` | Dictionary key access | `customValues['myField']` |
186
186
  | `list[*].{f1 f2}` | Field selector (projection) | `items[*].{name description}` |
187
187
  | `list[*].{alias:source}` | Field selector with alias | `items[*].{id:commodityId}` |