@substrat-run/engine-workorder 0.2.0 → 0.3.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/README.md +20 -25
- package/dist/index.d.ts +28 -103
- package/dist/index.d.ts.map +1 -1
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -7,36 +7,27 @@ machine, append-only reporting, and a billable snapshot frozen at completion.
|
|
|
7
7
|
It deliberately knows nothing about pricing (the vertical's job) or invoicing (a
|
|
8
8
|
sibling engine, reached only via events).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## What it owns
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- **The state machine cannot skip states.**
|
|
15
|
-
`planned → in_progress → completed → closed`; invalid transitions throw. No caller
|
|
16
|
-
can complete a planned order or restart a completed one.
|
|
17
|
-
- **Time and material are append-only.** There is no update or delete operation for
|
|
18
|
-
reported entries; corrections are compensating entries, never silent edits.
|
|
12
|
+
- **The state machine cannot skip states** — `planned → in_progress → completed → closed`.
|
|
13
|
+
- **Time and material are append-only** — corrections are compensating entries, never edits.
|
|
19
14
|
- **Attribution comes from the ambient principal**, never from the input.
|
|
20
|
-
- **Every mutation emits a fat event** — `workorder.completed` carries the full
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## The pricing boundary
|
|
15
|
+
- **Every mutation emits a fat event** — `workorder.completed` carries the full billable
|
|
16
|
+
snapshot, so consumers never query back.
|
|
24
17
|
|
|
25
|
-
|
|
26
|
-
each with provenance (`sourceType`, `sourceId`) back to the reported entry — validates
|
|
27
|
-
them with exact decimal arithmetic, sums the total, and freezes the snapshot into the
|
|
28
|
-
`workorder.completed` payload.
|
|
18
|
+
## Install
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
`report-material`, `complete`, `close`) are default bindings. For custom flows, call
|
|
34
|
-
the exported in-scope functions inside your own operations — same transaction, your
|
|
35
|
-
permission check:
|
|
20
|
+
```sh
|
|
21
|
+
pnpm add @substrat-run/engine-workorder
|
|
22
|
+
```
|
|
36
23
|
|
|
37
24
|
```ts
|
|
38
|
-
import { createWorkOrder, PERM } from '@substrat-run/engine-workorder';
|
|
25
|
+
import { createWorkOrder, PERM, workorderModule } from '@substrat-run/engine-workorder';
|
|
39
26
|
|
|
27
|
+
host.registerModule(workorderModule);
|
|
28
|
+
|
|
29
|
+
// Note: the engine registers no `workorder/create` operation. Creation is an
|
|
30
|
+
// in-scope function, because the vertical must price and label the order first.
|
|
40
31
|
host.defineOperation('acme/ticket-to-order', async (ctx, input) => {
|
|
41
32
|
assertAllowed(await ctx.check(PERM.create));
|
|
42
33
|
return createWorkOrder(ctx, {
|
|
@@ -48,8 +39,12 @@ host.defineOperation('acme/ticket-to-order', async (ctx, input) => {
|
|
|
48
39
|
});
|
|
49
40
|
```
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
**https://substrat.ahlstrand.es/engines/workorder/** — the domain model and invariants, the
|
|
45
|
+
full operation/permission surface, event contracts, and how to compose or extend it.
|
|
46
|
+
|
|
47
|
+
The docs site is the single source of truth; this README deliberately doesn't restate it.
|
|
53
48
|
|
|
54
49
|
## Related packages
|
|
55
50
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,21 +2,21 @@ import { z } from 'zod';
|
|
|
2
2
|
import { type EntityRef, type Money } from '@substrat-run/contracts';
|
|
3
3
|
import { type ModuleRegistration, type OperationContext } from '@substrat-run/kernel';
|
|
4
4
|
export declare const PERM: {
|
|
5
|
-
create: string & z.
|
|
6
|
-
read: string & z.
|
|
7
|
-
assign: string & z.
|
|
8
|
-
report: string & z.
|
|
9
|
-
complete: string & z.
|
|
10
|
-
close: string & z.
|
|
5
|
+
create: string & z.core.$brand<"PermissionKey">;
|
|
6
|
+
read: string & z.core.$brand<"PermissionKey">;
|
|
7
|
+
assign: string & z.core.$brand<"PermissionKey">;
|
|
8
|
+
report: string & z.core.$brand<"PermissionKey">;
|
|
9
|
+
complete: string & z.core.$brand<"PermissionKey">;
|
|
10
|
+
close: string & z.core.$brand<"PermissionKey">;
|
|
11
11
|
};
|
|
12
12
|
export declare const workorderManifest: {
|
|
13
|
-
id: string & z.
|
|
13
|
+
id: string & z.core.$brand<"ModuleId">;
|
|
14
|
+
version: string;
|
|
15
|
+
kernelContract: string;
|
|
14
16
|
permissions: {
|
|
15
|
-
key: string & z.
|
|
17
|
+
key: string & z.core.$brand<"PermissionKey">;
|
|
16
18
|
description: string;
|
|
17
19
|
}[];
|
|
18
|
-
version: string;
|
|
19
|
-
kernelContract: string;
|
|
20
20
|
events: {
|
|
21
21
|
emits: {
|
|
22
22
|
type: string;
|
|
@@ -33,7 +33,7 @@ export declare const workorderManifest: {
|
|
|
33
33
|
};
|
|
34
34
|
attachmentTargets: {
|
|
35
35
|
entityType: string;
|
|
36
|
-
readPermission: string & z.
|
|
36
|
+
readPermission: string & z.core.$brand<"PermissionKey">;
|
|
37
37
|
}[];
|
|
38
38
|
entitlementKey: string;
|
|
39
39
|
entityRelations?: {
|
|
@@ -54,13 +54,13 @@ export declare const workorderManifest: {
|
|
|
54
54
|
ui?: {
|
|
55
55
|
routes?: {
|
|
56
56
|
path: string;
|
|
57
|
-
permission: string & z.BRAND<"PermissionKey">;
|
|
58
57
|
screen: string;
|
|
58
|
+
permission: string & z.core.$brand<"PermissionKey">;
|
|
59
59
|
}[] | undefined;
|
|
60
60
|
nav?: {
|
|
61
|
-
permission: string & z.BRAND<"PermissionKey">;
|
|
62
61
|
label: string;
|
|
63
62
|
to: string;
|
|
63
|
+
permission: string & z.core.$brand<"PermissionKey">;
|
|
64
64
|
icon?: string | undefined;
|
|
65
65
|
}[] | undefined;
|
|
66
66
|
entityViews?: {
|
|
@@ -68,14 +68,14 @@ export declare const workorderManifest: {
|
|
|
68
68
|
view: string;
|
|
69
69
|
}[] | undefined;
|
|
70
70
|
widgets?: {
|
|
71
|
-
permission: string & z.BRAND<"PermissionKey">;
|
|
72
71
|
slot: string;
|
|
73
72
|
component: string;
|
|
73
|
+
permission: string & z.core.$brand<"PermissionKey">;
|
|
74
74
|
}[] | undefined;
|
|
75
75
|
settingsPanels?: {
|
|
76
|
-
permission: string & z.BRAND<"PermissionKey">;
|
|
77
76
|
label: string;
|
|
78
77
|
component: string;
|
|
78
|
+
permission: string & z.core.$brand<"PermissionKey">;
|
|
79
79
|
}[] | undefined;
|
|
80
80
|
} | undefined;
|
|
81
81
|
};
|
|
@@ -89,108 +89,33 @@ export declare const billableLine: z.ZodObject<{
|
|
|
89
89
|
qty: z.ZodString;
|
|
90
90
|
unit: z.ZodString;
|
|
91
91
|
unitPrice: z.ZodObject<{
|
|
92
|
-
amount: z.ZodBranded<z.ZodString, "MoneyAmount">;
|
|
93
|
-
currency: z.ZodBranded<z.ZodString, "CurrencyCode">;
|
|
94
|
-
},
|
|
95
|
-
amount: string & z.BRAND<"MoneyAmount">;
|
|
96
|
-
currency: string & z.BRAND<"CurrencyCode">;
|
|
97
|
-
}, {
|
|
98
|
-
amount: string;
|
|
99
|
-
currency: string;
|
|
100
|
-
}>;
|
|
92
|
+
amount: z.core.$ZodBranded<z.ZodString, "MoneyAmount", "out">;
|
|
93
|
+
currency: z.core.$ZodBranded<z.ZodString, "CurrencyCode", "out">;
|
|
94
|
+
}, z.core.$strip>;
|
|
101
95
|
lineTotal: z.ZodObject<{
|
|
102
|
-
amount: z.ZodBranded<z.ZodString, "MoneyAmount">;
|
|
103
|
-
currency: z.ZodBranded<z.ZodString, "CurrencyCode">;
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
amount: string;
|
|
109
|
-
currency: string;
|
|
96
|
+
amount: z.core.$ZodBranded<z.ZodString, "MoneyAmount", "out">;
|
|
97
|
+
currency: z.core.$ZodBranded<z.ZodString, "CurrencyCode", "out">;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
sourceType: z.ZodEnum<{
|
|
100
|
+
time: "time";
|
|
101
|
+
material: "material";
|
|
110
102
|
}>;
|
|
111
|
-
sourceType: z.ZodEnum<["time", "material"]>;
|
|
112
103
|
sourceId: z.ZodString;
|
|
113
|
-
},
|
|
114
|
-
article: string;
|
|
115
|
-
description: string;
|
|
116
|
-
qty: string;
|
|
117
|
-
unit: string;
|
|
118
|
-
unitPrice: {
|
|
119
|
-
amount: string & z.BRAND<"MoneyAmount">;
|
|
120
|
-
currency: string & z.BRAND<"CurrencyCode">;
|
|
121
|
-
};
|
|
122
|
-
lineTotal: {
|
|
123
|
-
amount: string & z.BRAND<"MoneyAmount">;
|
|
124
|
-
currency: string & z.BRAND<"CurrencyCode">;
|
|
125
|
-
};
|
|
126
|
-
sourceType: "time" | "material";
|
|
127
|
-
sourceId: string;
|
|
128
|
-
}, {
|
|
129
|
-
article: string;
|
|
130
|
-
description: string;
|
|
131
|
-
qty: string;
|
|
132
|
-
unit: string;
|
|
133
|
-
unitPrice: {
|
|
134
|
-
amount: string;
|
|
135
|
-
currency: string;
|
|
136
|
-
};
|
|
137
|
-
lineTotal: {
|
|
138
|
-
amount: string;
|
|
139
|
-
currency: string;
|
|
140
|
-
};
|
|
141
|
-
sourceType: "time" | "material";
|
|
142
|
-
sourceId: string;
|
|
143
|
-
}>;
|
|
104
|
+
}, z.core.$strip>;
|
|
144
105
|
export type BillableLine = z.infer<typeof billableLine>;
|
|
145
106
|
export declare const createWorkOrderInput: z.ZodObject<{
|
|
146
107
|
facility: z.ZodObject<{
|
|
147
108
|
entityType: z.ZodString;
|
|
148
109
|
entityId: z.ZodString;
|
|
149
|
-
},
|
|
150
|
-
entityType: string;
|
|
151
|
-
entityId: string;
|
|
152
|
-
}, {
|
|
153
|
-
entityType: string;
|
|
154
|
-
entityId: string;
|
|
155
|
-
}>;
|
|
110
|
+
}, z.core.$strip>;
|
|
156
111
|
customer: z.ZodObject<{
|
|
157
112
|
entityType: z.ZodString;
|
|
158
113
|
entityId: z.ZodString;
|
|
159
|
-
},
|
|
160
|
-
entityType: string;
|
|
161
|
-
entityId: string;
|
|
162
|
-
}, {
|
|
163
|
-
entityType: string;
|
|
164
|
-
entityId: string;
|
|
165
|
-
}>;
|
|
114
|
+
}, z.core.$strip>;
|
|
166
115
|
kind: z.ZodString;
|
|
167
116
|
title: z.ZodString;
|
|
168
117
|
description: z.ZodOptional<z.ZodString>;
|
|
169
|
-
},
|
|
170
|
-
facility: {
|
|
171
|
-
entityType: string;
|
|
172
|
-
entityId: string;
|
|
173
|
-
};
|
|
174
|
-
customer: {
|
|
175
|
-
entityType: string;
|
|
176
|
-
entityId: string;
|
|
177
|
-
};
|
|
178
|
-
kind: string;
|
|
179
|
-
title: string;
|
|
180
|
-
description?: string | undefined;
|
|
181
|
-
}, {
|
|
182
|
-
facility: {
|
|
183
|
-
entityType: string;
|
|
184
|
-
entityId: string;
|
|
185
|
-
};
|
|
186
|
-
customer: {
|
|
187
|
-
entityType: string;
|
|
188
|
-
entityId: string;
|
|
189
|
-
};
|
|
190
|
-
kind: string;
|
|
191
|
-
title: string;
|
|
192
|
-
description?: string | undefined;
|
|
193
|
-
}>;
|
|
118
|
+
}, z.core.$strip>;
|
|
194
119
|
export type CreateWorkOrderInput = z.infer<typeof createWorkOrderInput>;
|
|
195
120
|
interface OrderRow {
|
|
196
121
|
id: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAQL,KAAK,SAAS,EACd,KAAK,KAAK,EACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAQ9B,eAAO,MAAM,IAAI;;;;;;;CAOhB,CAAC;AAEF,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/engine-workorder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Substrat engine: work orders + time + material — one engine, one state machine, append-only reporting",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -25,15 +25,18 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"zod": "^
|
|
29
|
-
"@substrat-run/
|
|
30
|
-
"@substrat-run/
|
|
28
|
+
"zod": "^4.4.3",
|
|
29
|
+
"@substrat-run/contracts": "^0.4.0",
|
|
30
|
+
"@substrat-run/kernel": "^0.4.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"typescript": "^5.6.0"
|
|
33
|
+
"typescript": "^5.6.0",
|
|
34
|
+
"vitest": "^3.0.0",
|
|
35
|
+
"@substrat-run/engine-test-kit": "^0.0.2"
|
|
34
36
|
},
|
|
35
37
|
"scripts": {
|
|
36
38
|
"build": "tsc -p tsconfig.json",
|
|
37
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
40
|
+
"test": "vitest run"
|
|
38
41
|
}
|
|
39
42
|
}
|