@happyvertical/smrt-manufacturing 0.53.4 → 0.53.6
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/AGENTS.md +58 -7
- package/README.md +228 -4
- package/agents/multilevel-and-runs.md +28 -0
- package/dist/collections/AssemblyCollection.d.ts +15 -0
- package/dist/collections/AssemblyCollection.d.ts.map +1 -0
- package/dist/collections/OperationCollection.d.ts +20 -0
- package/dist/collections/OperationCollection.d.ts.map +1 -0
- package/dist/collections/ProductionRunCollection.d.ts +15 -0
- package/dist/collections/ProductionRunCollection.d.ts.map +1 -0
- package/dist/collections/ProductionRunCompletionCollection.d.ts +14 -0
- package/dist/collections/ProductionRunCompletionCollection.d.ts.map +1 -0
- package/dist/collections/RoutingStepCollection.d.ts +15 -0
- package/dist/collections/RoutingStepCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +5 -0
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/index.d.ts +23 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1660 -42
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1910 -161
- package/dist/models/Assembly.d.ts +62 -0
- package/dist/models/Assembly.d.ts.map +1 -0
- package/dist/models/BillOfMaterials.d.ts +12 -4
- package/dist/models/BillOfMaterials.d.ts.map +1 -1
- package/dist/models/BomLine.d.ts +11 -5
- package/dist/models/BomLine.d.ts.map +1 -1
- package/dist/models/Operation.d.ts +59 -0
- package/dist/models/Operation.d.ts.map +1 -0
- package/dist/models/ProductionRun.d.ts +67 -0
- package/dist/models/ProductionRun.d.ts.map +1 -0
- package/dist/models/ProductionRunCompletion.d.ts +36 -0
- package/dist/models/ProductionRunCompletion.d.ts.map +1 -0
- package/dist/models/RoutingStep.d.ts +46 -0
- package/dist/models/RoutingStep.d.ts.map +1 -0
- package/dist/models/index.d.ts +5 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/operation-types.d.ts +108 -0
- package/dist/operation-types.d.ts.map +1 -0
- package/dist/production-run-types.d.ts +100 -0
- package/dist/production-run-types.d.ts.map +1 -0
- package/dist/quantity.d.ts +36 -0
- package/dist/quantity.d.ts.map +1 -0
- package/dist/services/AssemblyService.d.ts +222 -0
- package/dist/services/AssemblyService.d.ts.map +1 -0
- package/dist/services/BomService.d.ts +108 -5
- package/dist/services/BomService.d.ts.map +1 -1
- package/dist/services/OperationService.d.ts +48 -0
- package/dist/services/OperationService.d.ts.map +1 -0
- package/dist/services/ProductionRunService.d.ts +123 -0
- package/dist/services/ProductionRunService.d.ts.map +1 -0
- package/dist/services/ProductionService.d.ts +11 -0
- package/dist/services/ProductionService.d.ts.map +1 -1
- package/dist/services/RoutingService.d.ts +50 -0
- package/dist/services/RoutingService.d.ts.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/structure-walk.d.ts +77 -0
- package/dist/services/structure-walk.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +1771 -207
- package/dist/svelte/components/AssemblyForm.svelte +69 -0
- package/dist/svelte/components/AssemblyForm.svelte.d.ts +38 -0
- package/dist/svelte/components/AssemblyForm.svelte.d.ts.map +1 -0
- package/dist/svelte/components/AssemblyList.svelte +229 -0
- package/dist/svelte/components/AssemblyList.svelte.d.ts +28 -0
- package/dist/svelte/components/AssemblyList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/BomEditor.svelte +575 -0
- package/dist/svelte/components/BomEditor.svelte.d.ts +29 -0
- package/dist/svelte/components/BomEditor.svelte.d.ts.map +1 -0
- package/dist/svelte/components/BomStructureTree.svelte +164 -0
- package/dist/svelte/components/BomStructureTree.svelte.d.ts +16 -0
- package/dist/svelte/components/BomStructureTree.svelte.d.ts.map +1 -0
- package/dist/svelte/components/OperationForm.svelte +258 -0
- package/dist/svelte/components/OperationForm.svelte.d.ts +17 -0
- package/dist/svelte/components/OperationForm.svelte.d.ts.map +1 -0
- package/dist/svelte/components/OperationList.svelte +170 -0
- package/dist/svelte/components/OperationList.svelte.d.ts +17 -0
- package/dist/svelte/components/OperationList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ProductionRunList.svelte +213 -0
- package/dist/svelte/components/ProductionRunList.svelte.d.ts +18 -0
- package/dist/svelte/components/ProductionRunList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/RequirementsTree.svelte +125 -0
- package/dist/svelte/components/RequirementsTree.svelte.d.ts +13 -0
- package/dist/svelte/components/RequirementsTree.svelte.d.ts.map +1 -0
- package/dist/svelte/components/RequirementsTreeLevel.svelte +120 -0
- package/dist/svelte/components/RequirementsTreeLevel.svelte.d.ts +12 -0
- package/dist/svelte/components/RequirementsTreeLevel.svelte.d.ts.map +1 -0
- package/dist/svelte/i18n.d.ts +119 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +119 -0
- package/dist/svelte/index.d.ts +33 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +34 -0
- package/dist/svelte/types.d.ts +257 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +249 -0
- package/dist/tenant-scope.d.ts +25 -0
- package/dist/tenant-scope.d.ts.map +1 -0
- package/dist/types.d.ts +207 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -1
- package/dist/types.js.map +1 -1
- package/dist/ui.d.ts +17 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +94 -0
- package/dist/ui.js.map +1 -0
- package/package.json +41 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quantity.d.ts","sourceRoot":"","sources":["../src/quantity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAInC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,YAAc,CAAC;AAExC;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssemblyService — the link between a bill line and the thing it names.
|
|
3
|
+
*
|
|
4
|
+
* A {@link BomLine} points at a component SKU. That SKU belongs to a
|
|
5
|
+
* `Product` row in `@happyvertical/smrt-products`, and the row's subtype
|
|
6
|
+
* decides what the line means:
|
|
7
|
+
*
|
|
8
|
+
* | Component SKU belongs to | Kind | Meaning |
|
|
9
|
+
* |---|---|---|
|
|
10
|
+
* | an {@link Assembly} | `assembly` | a sub-assembly; it is built from its own active bill, if it has one |
|
|
11
|
+
* | a `Material` | `material` | a consumed input; the leaf of the structure |
|
|
12
|
+
* | any other `Product` | `bought` | an item that is bought, not built here |
|
|
13
|
+
* | nothing (unknown SKU or product) | `missing` | the line points at a record that does not exist |
|
|
14
|
+
*
|
|
15
|
+
* {@link AssemblyService.resolveComponent} answers that question for one
|
|
16
|
+
* SKU, and also returns the assembly's active bill. It is the step a
|
|
17
|
+
* multi-level explosion repeats: resolve each line's component, recurse into
|
|
18
|
+
* every `assembly` that has an `activeBom`, stop at everything else.
|
|
19
|
+
*
|
|
20
|
+
* The service also owns the **cycle refusal**: an assembly may not contain
|
|
21
|
+
* itself, directly or through sub-assemblies. {@link BomLine} and
|
|
22
|
+
* {@link BillOfMaterials} call {@link AssemblyService.assertLineAcyclic} and
|
|
23
|
+
* {@link AssemblyService.assertBillAcyclic} before every save, so the
|
|
24
|
+
* generated REST routes refuse a cycle too.
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
import { type DatabaseConfig, ValidationError } from '@happyvertical/smrt-core';
|
|
29
|
+
import { ProductCollection, SkuCollection } from '@happyvertical/smrt-products/collections';
|
|
30
|
+
import { type Product, type Sku } from '@happyvertical/smrt-products/models';
|
|
31
|
+
import { BillOfMaterialsCollection } from '../collections/BillOfMaterialsCollection.js';
|
|
32
|
+
import { BomLineCollection } from '../collections/BomLineCollection.js';
|
|
33
|
+
import { Assembly } from '../models/Assembly.js';
|
|
34
|
+
import type { BillOfMaterials } from '../models/BillOfMaterials.js';
|
|
35
|
+
import type { BomLine } from '../models/BomLine.js';
|
|
36
|
+
/**
|
|
37
|
+
* What a component SKU is, as far as building goes. See the table in the
|
|
38
|
+
* {@link AssemblyService} module documentation.
|
|
39
|
+
*/
|
|
40
|
+
export type ComponentKind = 'assembly' | 'material' | 'bought' | 'missing';
|
|
41
|
+
/**
|
|
42
|
+
* The answer to "what is this component SKU?" returned by
|
|
43
|
+
* {@link AssemblyService.resolveComponent}.
|
|
44
|
+
*/
|
|
45
|
+
export interface ResolvedComponent {
|
|
46
|
+
/** The component SKU id that was resolved. */
|
|
47
|
+
skuId: string;
|
|
48
|
+
/** What the SKU is; see {@link ComponentKind}. */
|
|
49
|
+
kind: ComponentKind;
|
|
50
|
+
/** The SKU row, or `null` when no SKU has this id. */
|
|
51
|
+
sku: Sku | null;
|
|
52
|
+
/**
|
|
53
|
+
* The product the SKU belongs to (an `Assembly`, a `Material` or a plain
|
|
54
|
+
* `Product`), or `null` when the SKU or its product does not exist.
|
|
55
|
+
*/
|
|
56
|
+
product: Product | null;
|
|
57
|
+
/** The assembly, when {@link kind} is `assembly`; otherwise `null`. */
|
|
58
|
+
assembly: Assembly | null;
|
|
59
|
+
/**
|
|
60
|
+
* The assembly's active bill (the highest active version), or `null` for
|
|
61
|
+
* an assembly that has no active bill yet and for every other kind.
|
|
62
|
+
*/
|
|
63
|
+
activeBom: BillOfMaterials | null;
|
|
64
|
+
/**
|
|
65
|
+
* `true` only for an assembly with an active bill: the component *can* be
|
|
66
|
+
* built here. Whether a shortage is built or bought is the application's
|
|
67
|
+
* decision; this only reports the fact.
|
|
68
|
+
*/
|
|
69
|
+
buildable: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** One bill line together with the component it resolves to. */
|
|
72
|
+
export interface BillStructureLine {
|
|
73
|
+
/** The bill line as stored. */
|
|
74
|
+
line: BomLine;
|
|
75
|
+
/** The line's component SKU, resolved. */
|
|
76
|
+
component: ResolvedComponent;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* One level of an assembly's structure, returned by
|
|
80
|
+
* {@link AssemblyService.getBillStructure}. Sub-assembly lines carry their
|
|
81
|
+
* own `activeBom`; pass its id back to `getBillStructure` to open the next
|
|
82
|
+
* level.
|
|
83
|
+
*/
|
|
84
|
+
export interface BillStructure {
|
|
85
|
+
/** The bill that was read. */
|
|
86
|
+
bom: BillOfMaterials;
|
|
87
|
+
/** Its lines in component-SKU order, each resolved. */
|
|
88
|
+
lines: BillStructureLine[];
|
|
89
|
+
}
|
|
90
|
+
/** One product on a cycle path reported by {@link BomCycleError}. */
|
|
91
|
+
export interface BomCyclePathEntry {
|
|
92
|
+
/** The product id (an assembly, or the bill's own product). */
|
|
93
|
+
productId: string;
|
|
94
|
+
/** The product's name, or its id when it has no name or cannot be read. */
|
|
95
|
+
name: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Thrown when saving a bill line, or saving a bill as active, would make a
|
|
99
|
+
* product contain itself. `path` starts and ends with the bill's product,
|
|
100
|
+
* listing each assembly in between: `Frame → Side panel → Frame`.
|
|
101
|
+
*/
|
|
102
|
+
export declare class BomCycleError extends ValidationError {
|
|
103
|
+
/** The bill being saved (or the bill of the line being saved). */
|
|
104
|
+
readonly bomId: string;
|
|
105
|
+
/** The cycle, from the bill's product back to itself. */
|
|
106
|
+
readonly path: BomCyclePathEntry[];
|
|
107
|
+
name: string;
|
|
108
|
+
constructor(
|
|
109
|
+
/** The bill being saved (or the bill of the line being saved). */
|
|
110
|
+
bomId: string,
|
|
111
|
+
/** The cycle, from the bill's product back to itself. */
|
|
112
|
+
path: BomCyclePathEntry[]);
|
|
113
|
+
}
|
|
114
|
+
/** Options for {@link AssemblyService.resolveComponent} and the walks built on it. */
|
|
115
|
+
export interface ResolveComponentOptions {
|
|
116
|
+
/**
|
|
117
|
+
* The tenant whose structure is being read. When given (including `null`
|
|
118
|
+
* for global records), an assembly's active bill is chosen only among
|
|
119
|
+
* bills with exactly this `tenantId`, and a SKU, product or bill line
|
|
120
|
+
* belonging to another tenant is treated as missing (global rows stay
|
|
121
|
+
* visible), whatever tenant context is active. When omitted, the active
|
|
122
|
+
* tenant context decides what is visible.
|
|
123
|
+
*/
|
|
124
|
+
tenantId?: string | null;
|
|
125
|
+
}
|
|
126
|
+
/** Options accepted by {@link AssemblyService.create}. */
|
|
127
|
+
export interface AssemblyServiceOptions {
|
|
128
|
+
/** Database config or live handle shared by every collection. */
|
|
129
|
+
db: DatabaseConfig;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolves components and refuses cycles. Construct with
|
|
133
|
+
* {@link AssemblyService.create} or {@link createAssemblyService}.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const assemblies = await AssemblyService.create({ db });
|
|
138
|
+
* const component = await assemblies.resolveComponent(line.componentSkuId);
|
|
139
|
+
* if (component.kind === 'assembly' && component.activeBom) {
|
|
140
|
+
* // a sub-assembly that can be built: walk component.activeBom next
|
|
141
|
+
* }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare class AssemblyService {
|
|
145
|
+
/** Every `Product` row, any subtype. */
|
|
146
|
+
readonly products: ProductCollection;
|
|
147
|
+
/** The SKU catalog. */
|
|
148
|
+
readonly skus: SkuCollection;
|
|
149
|
+
/** Bills of materials. */
|
|
150
|
+
readonly boms: BillOfMaterialsCollection;
|
|
151
|
+
/** Bill lines. */
|
|
152
|
+
readonly lines: BomLineCollection;
|
|
153
|
+
private constructor();
|
|
154
|
+
/** Factory — prefer {@link createAssemblyService}. */
|
|
155
|
+
static create(options: AssemblyServiceOptions): Promise<AssemblyService>;
|
|
156
|
+
/**
|
|
157
|
+
* Resolve a component SKU to what it is: an assembly (with its active bill,
|
|
158
|
+
* or `null` when it has none), a material, a bought item, or missing. Never
|
|
159
|
+
* throws for an unknown id; it reports `missing` instead.
|
|
160
|
+
*
|
|
161
|
+
* This is the documented link a multi-level explosion walks: recurse into
|
|
162
|
+
* `activeBom` while `kind === 'assembly'`, stop at every other kind. Pass
|
|
163
|
+
* the parent bill's `tenantId` so a shared assembly resolves to that
|
|
164
|
+
* tenant's bill, not another tenant's.
|
|
165
|
+
*/
|
|
166
|
+
resolveComponent(skuId: string, options?: ResolveComponentOptions): Promise<ResolvedComponent>;
|
|
167
|
+
/**
|
|
168
|
+
* The highest-version active bill for a product. With `options.tenantId`,
|
|
169
|
+
* that tenant's own bill, or else a global one; another tenant's never.
|
|
170
|
+
*/
|
|
171
|
+
findActiveBom(productId: string, options?: ResolveComponentOptions): Promise<BillOfMaterials | null>;
|
|
172
|
+
/**
|
|
173
|
+
* One row by id: through the collection's `get` without an explicit
|
|
174
|
+
* tenant, else as a list read of that tenant's and global rows.
|
|
175
|
+
*/
|
|
176
|
+
private byId;
|
|
177
|
+
/** `true` when the SKU belongs to an {@link Assembly}. */
|
|
178
|
+
isAssembly(skuId: string): Promise<boolean>;
|
|
179
|
+
/**
|
|
180
|
+
* Read one bill and resolve every line's component. Sub-assembly lines say
|
|
181
|
+
* whether they have an active bill of their own (`component.activeBom`);
|
|
182
|
+
* the caller opens the next level by passing that id back in.
|
|
183
|
+
*
|
|
184
|
+
* @throws {BomNotFoundError} when no bill has this id.
|
|
185
|
+
*/
|
|
186
|
+
getBillStructure(bomId: string): Promise<BillStructure>;
|
|
187
|
+
/**
|
|
188
|
+
* Find the path by which adding `componentSkuIds` to a bill for
|
|
189
|
+
* `productId` would make that product contain itself, or `null` when none
|
|
190
|
+
* would. The walk follows each sub-assembly's **active** bill only; a
|
|
191
|
+
* draft or superseded bill is not part of the structure. Pass the bill's
|
|
192
|
+
* `tenantId` so the walk reads that tenant's structure.
|
|
193
|
+
*/
|
|
194
|
+
findCycle(productId: string, componentSkuIds: readonly string[], options?: ResolveComponentOptions): Promise<BomCyclePathEntry[] | null>;
|
|
195
|
+
/**
|
|
196
|
+
* Refuse a bill line that would make its bill's product contain itself.
|
|
197
|
+
* A line on a draft bill is checked too, so a cycle is refused when it is
|
|
198
|
+
* written rather than when the bill is activated. A line whose bill does
|
|
199
|
+
* not exist is left to the caller.
|
|
200
|
+
*
|
|
201
|
+
* @throws {BomCycleError} naming the path.
|
|
202
|
+
*/
|
|
203
|
+
assertLineAcyclic(line: Pick<BomLine, 'bomId' | 'componentSkuId'>): Promise<void>;
|
|
204
|
+
/**
|
|
205
|
+
* Refuse saving a bill as `active` when any of its lines would make its
|
|
206
|
+
* product contain itself. Bills in any other status are not part of the
|
|
207
|
+
* structure and pass.
|
|
208
|
+
*
|
|
209
|
+
* The lines checked are the bill's own and those of any stored bill with
|
|
210
|
+
* the same natural key (`productId`, `version`, and the bill's tenant, or
|
|
211
|
+
* the active tenant when the bill has none yet): saving a new
|
|
212
|
+
* instance with that key upserts onto the stored bill and activates its
|
|
213
|
+
* lines, so they are part of what the save makes active.
|
|
214
|
+
*
|
|
215
|
+
* @throws {BomCycleError} naming the path.
|
|
216
|
+
*/
|
|
217
|
+
assertBillAcyclic(bom: Pick<BillOfMaterials, 'id' | 'productId' | 'status' | 'version' | 'tenantId'>): Promise<void>;
|
|
218
|
+
private resolveCached;
|
|
219
|
+
}
|
|
220
|
+
/** Convenience factory for {@link AssemblyService}. */
|
|
221
|
+
export declare function createAssemblyService(options: AssemblyServiceOptions): Promise<AssemblyService>;
|
|
222
|
+
//# sourceMappingURL=AssemblyService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssemblyService.d.ts","sourceRoot":"","sources":["../../src/services/AssemblyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
* - "What do I need to buy / pull to make N units?" via {@link explodeRequirements}
|
|
10
10
|
* - "Do I have enough on hand?" via {@link canProduce}
|
|
11
11
|
*
|
|
12
|
+
* Every method reads one level of the bill by default. Pass `{ levels }` to
|
|
13
|
+
* walk sub-assemblies too: a line whose component SKU belongs to an
|
|
14
|
+
* `Assembly` with an active bill is opened, to the given depth or (`'all'`)
|
|
15
|
+
* down to materials and bought items. {@link explode} returns that walk line
|
|
16
|
+
* by line with the rolled-up totals, and {@link planRequirements} nets it
|
|
17
|
+
* against stock: how much of each sub-assembly is available, how much is
|
|
18
|
+
* short, and what building the shortfall takes.
|
|
19
|
+
*
|
|
12
20
|
* Construct via {@link BomService.create} — the static factory wires up
|
|
13
21
|
* the BOM, BOM-line, and inventory collections so a single `db` (or a
|
|
14
22
|
* pre-built {@link StockService}) drives everything.
|
|
@@ -22,12 +30,16 @@
|
|
|
22
30
|
*
|
|
23
31
|
* @packageDocumentation
|
|
24
32
|
*/
|
|
25
|
-
import type
|
|
33
|
+
import { type DatabaseConfig } from '@happyvertical/smrt-core';
|
|
26
34
|
import { type StockService } from '@happyvertical/smrt-inventory';
|
|
27
35
|
import { BillOfMaterialsCollection } from '../collections/BillOfMaterialsCollection.js';
|
|
28
36
|
import { BomLineCollection } from '../collections/BomLineCollection.js';
|
|
37
|
+
import { OperationCollection } from '../collections/OperationCollection.js';
|
|
38
|
+
import { RoutingStepCollection } from '../collections/RoutingStepCollection.js';
|
|
29
39
|
import type { BomLine } from '../models/BomLine.js';
|
|
30
|
-
import
|
|
40
|
+
import type { LabourEstimate, OperationRateResolver } from '../operation-types.js';
|
|
41
|
+
import { type BomCostRollup, type CanProduceResult, type Explosion, type ExplosionOptions, type MaterialRequirement, type RequirementsPlan } from '../types.js';
|
|
42
|
+
import { AssemblyService } from './AssemblyService.js';
|
|
31
43
|
/**
|
|
32
44
|
* Callback signature for resolving the unit cost of a component SKU.
|
|
33
45
|
*
|
|
@@ -68,6 +80,12 @@ export type BomServiceOptions = {
|
|
|
68
80
|
* costs default to `0` and per-line `costUnavailable` is set.
|
|
69
81
|
*/
|
|
70
82
|
costResolver?: ComponentCostResolver;
|
|
83
|
+
/**
|
|
84
|
+
* Optional resolver that returns the hourly labour rate for an operation,
|
|
85
|
+
* used by {@link BomService.computeLabourEstimate}. When omitted, the
|
|
86
|
+
* estimate reports minutes only and flags every step `rateUnavailable`.
|
|
87
|
+
*/
|
|
88
|
+
rateResolver?: OperationRateResolver;
|
|
71
89
|
} & ({
|
|
72
90
|
db: DatabaseConfig;
|
|
73
91
|
stockService?: StockService;
|
|
@@ -92,6 +110,11 @@ export declare class BomService {
|
|
|
92
110
|
readonly lines: BomLineCollection;
|
|
93
111
|
readonly stockService: StockService;
|
|
94
112
|
private readonly costResolver;
|
|
113
|
+
readonly routingSteps: RoutingStepCollection;
|
|
114
|
+
readonly operations: OperationCollection;
|
|
115
|
+
private readonly rateResolver;
|
|
116
|
+
/** Resolves components for the multi-level walks. */
|
|
117
|
+
readonly assemblies: AssemblyService;
|
|
95
118
|
private constructor();
|
|
96
119
|
/** Factory — prefer {@link createBomService}. */
|
|
97
120
|
static create(options: BomServiceOptions): Promise<BomService>;
|
|
@@ -106,8 +129,32 @@ export declare class BomService {
|
|
|
106
129
|
* set `costUnavailable: true` on their breakdown row; the aggregate
|
|
107
130
|
* `hasMissingCosts` flag mirrors this so callers can surface a UI
|
|
108
131
|
* warning.
|
|
132
|
+
*
|
|
133
|
+
* With `{ levels }` above 1, a sub-assembly line whose bill the walk opens
|
|
134
|
+
* is costed from that bill instead of the resolver: its `unitCost` is the
|
|
135
|
+
* bill's rolled-up material cost per unit, its `components` hold that
|
|
136
|
+
* bill's lines, and a missing cost anywhere below marks it and
|
|
137
|
+
* `hasMissingCosts` (its known part still counts, so the total is a lower
|
|
138
|
+
* bound). Other lines, including sub-assemblies with no active bill, use
|
|
139
|
+
* the resolver as before.
|
|
140
|
+
*/
|
|
141
|
+
computeMaterialCost(bomId: string, options?: ExplosionOptions): Promise<BomCostRollup>;
|
|
142
|
+
/**
|
|
143
|
+
* Roll up the estimated labour to build one unit from the bill's routing:
|
|
144
|
+
* total minutes, plus cost when a `rateResolver` was supplied (hourly rate
|
|
145
|
+
* times minutes, per step). A bill with no routing returns an empty
|
|
146
|
+
* estimate with zero totals, so callers can add it to the material cost
|
|
147
|
+
* unconditionally. Retired operations still count: the routing names them.
|
|
148
|
+
*
|
|
149
|
+
* With `{ levels }` above 1, every sub-assembly the walk opens adds its own
|
|
150
|
+
* bill's routing, multiplied by the units of it one unit needs (waste
|
|
151
|
+
* included); see {@link LabourEstimate.subAssemblies}.
|
|
152
|
+
*
|
|
153
|
+
* Throws {@link BomNotFoundError} when the BOM does not exist.
|
|
109
154
|
*/
|
|
110
|
-
|
|
155
|
+
computeLabourEstimate(bomId: string, options?: ExplosionOptions): Promise<LabourEstimate>;
|
|
156
|
+
/** One bill's own routing estimate, per unit of its product. */
|
|
157
|
+
private labourFor;
|
|
111
158
|
/**
|
|
112
159
|
* Return a "shopping list" of materials needed to produce `qty` units of
|
|
113
160
|
* the parent product against the given BOM. Lines that reference the
|
|
@@ -118,10 +165,14 @@ export declare class BomService {
|
|
|
118
165
|
* {@link ProductionService.consumeMaterials} when you're ready to write
|
|
119
166
|
* stock movements.
|
|
120
167
|
*
|
|
168
|
+
* With `{ levels }` above 1, sub-assemblies with an active bill are
|
|
169
|
+
* replaced by what their bills need, waste compounding down the levels;
|
|
170
|
+
* this is {@link explode}'s `totals`.
|
|
171
|
+
*
|
|
121
172
|
* Throws {@link BomNotFoundError} when the BOM does not exist; throws a
|
|
122
173
|
* plain `Error` when `qty` is not a positive finite number.
|
|
123
174
|
*/
|
|
124
|
-
explodeRequirements(bomId: string, qty: number): Promise<MaterialRequirement[]>;
|
|
175
|
+
explodeRequirements(bomId: string, qty: number, options?: ExplosionOptions): Promise<MaterialRequirement[]>;
|
|
125
176
|
/**
|
|
126
177
|
* Check whether the requirements for producing `qty` units against the
|
|
127
178
|
* given BOM are currently satisfied by available stock. Returns
|
|
@@ -134,14 +185,66 @@ export declare class BomService {
|
|
|
134
185
|
* "where do we pull from?" is left to the caller of
|
|
135
186
|
* {@link ProductionService.consumeMaterials}).
|
|
136
187
|
*
|
|
188
|
+
* With `{ levels }` above 1 the check is {@link planRequirements}: a
|
|
189
|
+
* sub-assembly that is short and has an active bill is opened for its
|
|
190
|
+
* shortfall, and each shortage is reported on the line where it occurs,
|
|
191
|
+
* with its `level` and `path`. Stock is allocated as the walk goes, so a
|
|
192
|
+
* component used in two places is not counted twice.
|
|
193
|
+
*
|
|
137
194
|
* Throws {@link BomNotFoundError} when the BOM does not exist.
|
|
138
195
|
*/
|
|
139
|
-
canProduce(bomId: string, qty: number): Promise<CanProduceResult>;
|
|
196
|
+
canProduce(bomId: string, qty: number, options?: ExplosionOptions): Promise<CanProduceResult>;
|
|
197
|
+
/**
|
|
198
|
+
* Walk the bill for `qty` units and return every line, depth first, with
|
|
199
|
+
* its level, the path of bills above it and its quantity for the run, plus
|
|
200
|
+
* the rolled-up `totals`. Gross requirements: stock is not read.
|
|
201
|
+
*
|
|
202
|
+
* `levels` (default `1`) says how far to open sub-assemblies; see
|
|
203
|
+
* {@link ExplosionLevels}. Waste compounds: a sub-assembly line's quantity
|
|
204
|
+
* includes its own waste, and its bill's lines are multiplied by it.
|
|
205
|
+
*
|
|
206
|
+
* Throws {@link BomNotFoundError}, `BomStructureCycleError` when stored
|
|
207
|
+
* data already has a product containing itself, `BomExplosionLimitError`
|
|
208
|
+
* past the depth or line limits, and a plain `Error` for a bad `qty` or
|
|
209
|
+
* `levels`.
|
|
210
|
+
*/
|
|
211
|
+
explode(bomId: string, qty: number, options?: ExplosionOptions): Promise<Explosion>;
|
|
212
|
+
/**
|
|
213
|
+
* Net the walk against stock: for each line, the available stock (all
|
|
214
|
+
* locations) not yet allocated to an earlier line and how much is short.
|
|
215
|
+
* A sub-assembly that is short and has an active bill is opened for the
|
|
216
|
+
* shortfall only, so its lines say what building that shortfall takes;
|
|
217
|
+
* one covered by stock is not opened. Lines that are short and cannot be
|
|
218
|
+
* opened are the `shortages`, each at its own level.
|
|
219
|
+
*
|
|
220
|
+
* These are facts, not a decision: the application decides whether a
|
|
221
|
+
* short sub-assembly is built or bought. Does not mutate stock.
|
|
222
|
+
*
|
|
223
|
+
* Throws as {@link explode} does.
|
|
224
|
+
*/
|
|
225
|
+
planRequirements(bomId: string, qty: number, options?: ExplosionOptions): Promise<RequirementsPlan>;
|
|
140
226
|
/**
|
|
141
227
|
* Fetch a BOM by id or throw {@link BomNotFoundError}. Centralises the
|
|
142
228
|
* "missing BOM" error path so callers don't have to repeat the check.
|
|
143
229
|
*/
|
|
230
|
+
/**
|
|
231
|
+
* A bill's lines: its own tenant's and global ones, whatever tenant
|
|
232
|
+
* context is active (a context alone would hide a global bill's lines).
|
|
233
|
+
*/
|
|
234
|
+
private linesOf;
|
|
144
235
|
private requireBom;
|
|
236
|
+
/**
|
|
237
|
+
* Available stock of a SKU across locations, counting only the top bill's
|
|
238
|
+
* tenant's rows and global ones, whatever tenant context is active (the
|
|
239
|
+
* walk reads its structure the same way).
|
|
240
|
+
*/
|
|
241
|
+
private availableInTenant;
|
|
242
|
+
/** {@link computeMaterialCost} with `levels` above 1. */
|
|
243
|
+
private computeMultiLevelCost;
|
|
244
|
+
/** {@link computeLabourEstimate} with `levels` above 1. */
|
|
245
|
+
private computeMultiLevelLabour;
|
|
246
|
+
/** Run the {@link OperationRateResolver}; `null` when there is no rate. */
|
|
247
|
+
private resolveRate;
|
|
145
248
|
/**
|
|
146
249
|
* Run the supplied {@link ComponentCostResolver} for the given component
|
|
147
250
|
* SKU. Returns `null` when no resolver is registered or when the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BomService.d.ts","sourceRoot":"","sources":["../../src/services/BomService.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"BomService.d.ts","sourceRoot":"","sources":["../../src/services/BomService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OperationService — maintain the managed list of {@link Operation} rows:
|
|
3
|
+
* define, rename, change category or required qualification, retire and
|
|
4
|
+
* reinstate. Operations are never deleted.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
import type { DatabaseConfig } from '@happyvertical/smrt-core';
|
|
9
|
+
import { OperationCollection } from '../collections/OperationCollection.js';
|
|
10
|
+
import type { Operation } from '../models/Operation.js';
|
|
11
|
+
import { type DefineOperationInput } from '../operation-types.js';
|
|
12
|
+
/** Options accepted by {@link OperationService.create}. */
|
|
13
|
+
export interface OperationServiceOptions {
|
|
14
|
+
db: DatabaseConfig;
|
|
15
|
+
}
|
|
16
|
+
export declare class OperationService {
|
|
17
|
+
readonly operations: OperationCollection;
|
|
18
|
+
private constructor();
|
|
19
|
+
/** Factory — prefer {@link createOperationService}. */
|
|
20
|
+
static create(options: OperationServiceOptions): Promise<OperationService>;
|
|
21
|
+
/**
|
|
22
|
+
* Add an operation. The code is trimmed and must be unique per tenant;
|
|
23
|
+
* throws {@link DuplicateOperationCodeError} when it is taken (retired
|
|
24
|
+
* operations keep their code).
|
|
25
|
+
*/
|
|
26
|
+
define(input: DefineOperationInput): Promise<Operation>;
|
|
27
|
+
/** Fetch an operation or throw {@link OperationNotFoundError}. */
|
|
28
|
+
get(id: string): Promise<Operation>;
|
|
29
|
+
/** List operations; retired ones only with `includeRetired`. */
|
|
30
|
+
list(options?: {
|
|
31
|
+
includeRetired?: boolean;
|
|
32
|
+
}): Promise<Operation[]>;
|
|
33
|
+
/** Change the display name. The code does not change. */
|
|
34
|
+
rename(id: string, name: string): Promise<Operation>;
|
|
35
|
+
/** Change category and/or required qualification; an empty string clears. */
|
|
36
|
+
update(id: string, changes: {
|
|
37
|
+
category?: string;
|
|
38
|
+
requiredQualificationId?: string;
|
|
39
|
+
}): Promise<Operation>;
|
|
40
|
+
/** Retire: stays on history and routings, leaves pickers. Idempotent. */
|
|
41
|
+
retire(id: string): Promise<Operation>;
|
|
42
|
+
/** Reinstate a retired operation. Idempotent. */
|
|
43
|
+
reinstate(id: string): Promise<Operation>;
|
|
44
|
+
private setActive;
|
|
45
|
+
}
|
|
46
|
+
/** Convenience factory. */
|
|
47
|
+
export declare function createOperationService(options: OperationServiceOptions): Promise<OperationService>;
|
|
48
|
+
//# sourceMappingURL=OperationService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OperationService.d.ts","sourceRoot":"","sources":["../../src/services/OperationService.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,KAAK,oBAAoB,EAI1B,MAAM,uBAAuB,CAAC;AAE/B,2DAA2D;AAC3D,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,cAAc,CAAC;CACpB;AAED,qBAAa,gBAAgB;aACS,UAAU,EAAE,mBAAmB;IAAnE,OAAO;IAEP,uDAAuD;WAC1C,MAAM,CACjB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;IAM5B;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC;IA2B7D,kEAAkE;IAC5D,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAMzC,gEAAgE;IAC1D,IAAI,CAAC,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAI5E,yDAAyD;IACnD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAU1D,6EAA6E;IACvE,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,uBAAuB,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/D,OAAO,CAAC,SAAS,CAAC;IAWrB,yEAAyE;IACnE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAI5C,iDAAiD;IAC3C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;YAIjC,SAAS;CAQxB;AAED,2BAA2B;AAC3B,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAE3B"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProductionRunService — create production runs and report work on them as
|
|
3
|
+
* it happens: "25 to build, 12 done".
|
|
4
|
+
*
|
|
5
|
+
* Every write runs in one database transaction that first saves the run
|
|
6
|
+
* row. That save is revision-guarded, so it takes the row's lock and a
|
|
7
|
+
* concurrent writer's save fails with a revision conflict; the loser's whole
|
|
8
|
+
* transaction is retried against the committed run. Two people reporting
|
|
9
|
+
* completions at once therefore both count, and a run never goes past its
|
|
10
|
+
* target.
|
|
11
|
+
*
|
|
12
|
+
* Recording a completion moves no stock unless the caller asks. With
|
|
13
|
+
* `consume` and/or `produce`, it uses the {@link ProductionService} paths
|
|
14
|
+
* inside the same transaction as the completion, so a stock shortfall rolls
|
|
15
|
+
* the completion back too.
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
import { type DatabaseConfig } from '@happyvertical/smrt-core';
|
|
20
|
+
import { type StockService } from '@happyvertical/smrt-inventory';
|
|
21
|
+
import { BillOfMaterialsCollection } from '../collections/BillOfMaterialsCollection.js';
|
|
22
|
+
import { ProductionRunCollection } from '../collections/ProductionRunCollection.js';
|
|
23
|
+
import { ProductionRunCompletionCollection } from '../collections/ProductionRunCompletionCollection.js';
|
|
24
|
+
import type { ProductionRun } from '../models/ProductionRun.js';
|
|
25
|
+
import type { ProductionRunCompletion } from '../models/ProductionRunCompletion.js';
|
|
26
|
+
import { type CreateProductionRunInput, type RecordCompletionInput, type RecordCompletionResult } from '../production-run-types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Options accepted by {@link ProductionRunService.create}. With a
|
|
29
|
+
* `stockService`, its database is used for everything, so a completion and
|
|
30
|
+
* its stock movements share one transaction.
|
|
31
|
+
*/
|
|
32
|
+
export type ProductionRunServiceOptions = {
|
|
33
|
+
db: DatabaseConfig;
|
|
34
|
+
stockService?: undefined;
|
|
35
|
+
} | {
|
|
36
|
+
stockService: StockService;
|
|
37
|
+
db?: undefined;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Creates runs and records their progress. Construct with
|
|
41
|
+
* {@link ProductionRunService.create} or {@link createProductionRunService}.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const runs = await ProductionRunService.create({ db });
|
|
46
|
+
* const run = await runs.createRun({ productId: frame.id, targetQty: 25 });
|
|
47
|
+
* await runs.recordCompletion(run.id!, { qty: 12 });
|
|
48
|
+
* // run: 25 to build, 12 done, in_progress
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class ProductionRunService {
|
|
52
|
+
/** The stock service whose database every collection here shares. */
|
|
53
|
+
readonly stockService: StockService;
|
|
54
|
+
/** Production runs (reads; writes go through this service). */
|
|
55
|
+
readonly runs: ProductionRunCollection;
|
|
56
|
+
/** Completions (reads; writes go through this service). */
|
|
57
|
+
readonly completions: ProductionRunCompletionCollection;
|
|
58
|
+
/** Bills, to pin a run's bill. */
|
|
59
|
+
readonly boms: BillOfMaterialsCollection;
|
|
60
|
+
private constructor();
|
|
61
|
+
/** Factory — prefer {@link createProductionRunService}. */
|
|
62
|
+
static create(options: ProductionRunServiceOptions): Promise<ProductionRunService>;
|
|
63
|
+
/**
|
|
64
|
+
* Create a `planned` run of `targetQty` units, pinned to `bomId`, or to the
|
|
65
|
+
* active bill of `productId`.
|
|
66
|
+
*
|
|
67
|
+
* @throws {InvalidProductionRunInputError} for a target that is not a
|
|
68
|
+
* positive number, or when neither `bomId` nor `productId` is given.
|
|
69
|
+
* @throws {BomNotFoundError} when `bomId` does not exist.
|
|
70
|
+
* @throws {NoActiveBomForProductError} when `productId` has no active bill.
|
|
71
|
+
*/
|
|
72
|
+
createRun(input: CreateProductionRunInput): Promise<ProductionRun>;
|
|
73
|
+
/** The run, or `null` when no run has this id. */
|
|
74
|
+
get(runId: string): Promise<ProductionRun | null>;
|
|
75
|
+
/** A run's completions in the order they happened. */
|
|
76
|
+
listCompletions(runId: string): Promise<ProductionRunCompletion[]>;
|
|
77
|
+
/** Mark a `planned` run `in_progress`. */
|
|
78
|
+
start(runId: string): Promise<ProductionRun>;
|
|
79
|
+
/** Mark an open run `done`, short of its target if work stopped early. */
|
|
80
|
+
finish(runId: string): Promise<ProductionRun>;
|
|
81
|
+
/** Cancel an open run. Completions already reported stay. */
|
|
82
|
+
cancel(runId: string): Promise<ProductionRun>;
|
|
83
|
+
/**
|
|
84
|
+
* Change an open run's target. It may not go below what is already done;
|
|
85
|
+
* setting it to exactly that finishes the run.
|
|
86
|
+
*
|
|
87
|
+
* @throws {InvalidProductionRunInputError} for a target that is not a
|
|
88
|
+
* positive number or is below the completed quantity.
|
|
89
|
+
*/
|
|
90
|
+
setTarget(runId: string, targetQty: number): Promise<ProductionRun>;
|
|
91
|
+
/**
|
|
92
|
+
* Report `qty` finished units on an open run: records a dated completion,
|
|
93
|
+
* adds it to `completedQty`, moves a `planned` run to `in_progress`, and
|
|
94
|
+
* marks the run `done` when the target is reached. With `consume` and/or
|
|
95
|
+
* `produce`, also writes the stock movements through
|
|
96
|
+
* {@link ProductionService}, stamped `sourceType: 'ProductionRunCompletion'`
|
|
97
|
+
* with the completion id. Everything runs in one transaction.
|
|
98
|
+
*
|
|
99
|
+
* Consumption takes the run's bill's own lines for `qty` units: a
|
|
100
|
+
* sub-assembly on the bill is taken from stock as a component. Building
|
|
101
|
+
* that sub-assembly is its own run.
|
|
102
|
+
*
|
|
103
|
+
* @throws {ProductionRunNotFoundError}
|
|
104
|
+
* @throws {ProductionRunStateError} when the run is `done` or `cancelled`.
|
|
105
|
+
* @throws {ProductionRunOverCompletionError} when `qty` is more than the
|
|
106
|
+
* run has left.
|
|
107
|
+
* @throws {InvalidProductionRunInputError} for a bad `qty` or date.
|
|
108
|
+
* @throws `InsufficientStockError` from inventory when consuming would
|
|
109
|
+
* drive stock below zero; nothing is recorded then.
|
|
110
|
+
*/
|
|
111
|
+
recordCompletion(runId: string, input: RecordCompletionInput): Promise<RecordCompletionResult>;
|
|
112
|
+
/** Apply `apply` to an open run and save it, in one transaction. */
|
|
113
|
+
private change;
|
|
114
|
+
private load;
|
|
115
|
+
/**
|
|
116
|
+
* Run `work` in one transaction on collections bound to it, rerunning the
|
|
117
|
+
* whole transaction when it lost a revision race on the run row.
|
|
118
|
+
*/
|
|
119
|
+
private inTransaction;
|
|
120
|
+
}
|
|
121
|
+
/** Convenience factory for {@link ProductionRunService}. */
|
|
122
|
+
export declare function createProductionRunService(options: ProductionRunServiceOptions): Promise<ProductionRunService>;
|
|
123
|
+
//# sourceMappingURL=ProductionRunService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductionRunService.d.ts","sourceRoot":"","sources":["../../src/services/ProductionRunService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,EAAE,iCAAiC,EAAE,MAAM,qDAAqD,CAAC;AAExG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EACL,KAAK,wBAAwB,EAK7B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AAepC;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GACnC;IAAE,EAAE,EAAE,cAAc,CAAC;IAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,GAChD;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,EAAE,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAmBnD;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IAE7B,qEAAqE;aACrD,YAAY,EAAE,YAAY;IAC1C,+DAA+D;aAC/C,IAAI,EAAE,uBAAuB;IAC7C,2DAA2D;aAC3C,WAAW,EAAE,iCAAiC;IAC9D,kCAAkC;aAClB,IAAI,EAAE,yBAAyB;IARjD,OAAO;IAWP,2DAA2D;WAC9C,MAAM,CACjB,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,oBAAoB,CAAC;IA8BhC;;;;;;;;OAQG;IACG,SAAS,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IA+CxE,kDAAkD;IAC5C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKvD,sDAAsD;IAChD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAKxE,0CAA0C;IACpC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAQlD,0EAA0E;IACpE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMnD,6DAA6D;IACvD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMnD;;;;;;OAMG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAezE;;;;;;;;;;;;;;;;;;;OAmBG;IACG,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IAgFlC,oEAAoE;IACpE,OAAO,CAAC,MAAM;YAeA,IAAI;IAWlB;;;OAGG;IACH,OAAO,CAAC,aAAa;CActB;AAsCD,4DAA4D;AAC5D,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,oBAAoB,CAAC,CAE/B"}
|
|
@@ -100,6 +100,12 @@ export interface ConsumeMaterialsOptions {
|
|
|
100
100
|
* Optional free-form note attached to every emitted movement.
|
|
101
101
|
*/
|
|
102
102
|
note?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Optional override of the `sourceType` stamped on each movement, with
|
|
105
|
+
* the order's `id` as `sourceId`. Defaults to `'ProductionOrder'`;
|
|
106
|
+
* `ProductionRunService` passes `'ProductionRunCompletion'`.
|
|
107
|
+
*/
|
|
108
|
+
sourceType?: string;
|
|
103
109
|
}
|
|
104
110
|
/**
|
|
105
111
|
* Per-call options for {@link ProductionService.produceFinishedGoods}.
|
|
@@ -131,6 +137,11 @@ export interface ProduceFinishedGoodsOptions {
|
|
|
131
137
|
* Optional free-form note attached to the emitted movement.
|
|
132
138
|
*/
|
|
133
139
|
note?: string;
|
|
140
|
+
/**
|
|
141
|
+
* Optional override of the `sourceType` stamped on the movement. Defaults
|
|
142
|
+
* to `'ProductionOrder'`; see {@link ConsumeMaterialsOptions.sourceType}.
|
|
143
|
+
*/
|
|
144
|
+
sourceType?: string;
|
|
134
145
|
}
|
|
135
146
|
/**
|
|
136
147
|
* Options accepted by {@link ProductionService.create}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductionService.d.ts","sourceRoot":"","sources":["../../src/services/ProductionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EACV,mBAAmB,EAEnB,YAAY,EACb,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"ProductionService.d.ts","sourceRoot":"","sources":["../../src/services/ProductionService.ts"],"names":[],"mappings":"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"}
|