@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.
Files changed (106) hide show
  1. package/AGENTS.md +58 -7
  2. package/README.md +228 -4
  3. package/agents/multilevel-and-runs.md +28 -0
  4. package/dist/collections/AssemblyCollection.d.ts +15 -0
  5. package/dist/collections/AssemblyCollection.d.ts.map +1 -0
  6. package/dist/collections/OperationCollection.d.ts +20 -0
  7. package/dist/collections/OperationCollection.d.ts.map +1 -0
  8. package/dist/collections/ProductionRunCollection.d.ts +15 -0
  9. package/dist/collections/ProductionRunCollection.d.ts.map +1 -0
  10. package/dist/collections/ProductionRunCompletionCollection.d.ts +14 -0
  11. package/dist/collections/ProductionRunCompletionCollection.d.ts.map +1 -0
  12. package/dist/collections/RoutingStepCollection.d.ts +15 -0
  13. package/dist/collections/RoutingStepCollection.d.ts.map +1 -0
  14. package/dist/collections/index.d.ts +5 -0
  15. package/dist/collections/index.d.ts.map +1 -1
  16. package/dist/index.d.ts +23 -5
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1660 -42
  19. package/dist/index.js.map +1 -1
  20. package/dist/manifest.json +1910 -161
  21. package/dist/models/Assembly.d.ts +62 -0
  22. package/dist/models/Assembly.d.ts.map +1 -0
  23. package/dist/models/BillOfMaterials.d.ts +12 -4
  24. package/dist/models/BillOfMaterials.d.ts.map +1 -1
  25. package/dist/models/BomLine.d.ts +11 -5
  26. package/dist/models/BomLine.d.ts.map +1 -1
  27. package/dist/models/Operation.d.ts +59 -0
  28. package/dist/models/Operation.d.ts.map +1 -0
  29. package/dist/models/ProductionRun.d.ts +67 -0
  30. package/dist/models/ProductionRun.d.ts.map +1 -0
  31. package/dist/models/ProductionRunCompletion.d.ts +36 -0
  32. package/dist/models/ProductionRunCompletion.d.ts.map +1 -0
  33. package/dist/models/RoutingStep.d.ts +46 -0
  34. package/dist/models/RoutingStep.d.ts.map +1 -0
  35. package/dist/models/index.d.ts +5 -0
  36. package/dist/models/index.d.ts.map +1 -1
  37. package/dist/operation-types.d.ts +108 -0
  38. package/dist/operation-types.d.ts.map +1 -0
  39. package/dist/production-run-types.d.ts +100 -0
  40. package/dist/production-run-types.d.ts.map +1 -0
  41. package/dist/quantity.d.ts +36 -0
  42. package/dist/quantity.d.ts.map +1 -0
  43. package/dist/services/AssemblyService.d.ts +222 -0
  44. package/dist/services/AssemblyService.d.ts.map +1 -0
  45. package/dist/services/BomService.d.ts +108 -5
  46. package/dist/services/BomService.d.ts.map +1 -1
  47. package/dist/services/OperationService.d.ts +48 -0
  48. package/dist/services/OperationService.d.ts.map +1 -0
  49. package/dist/services/ProductionRunService.d.ts +123 -0
  50. package/dist/services/ProductionRunService.d.ts.map +1 -0
  51. package/dist/services/ProductionService.d.ts +11 -0
  52. package/dist/services/ProductionService.d.ts.map +1 -1
  53. package/dist/services/RoutingService.d.ts +50 -0
  54. package/dist/services/RoutingService.d.ts.map +1 -0
  55. package/dist/services/index.d.ts +5 -0
  56. package/dist/services/index.d.ts.map +1 -1
  57. package/dist/services/structure-walk.d.ts +77 -0
  58. package/dist/services/structure-walk.d.ts.map +1 -0
  59. package/dist/smrt-knowledge.json +1771 -207
  60. package/dist/svelte/components/AssemblyForm.svelte +69 -0
  61. package/dist/svelte/components/AssemblyForm.svelte.d.ts +38 -0
  62. package/dist/svelte/components/AssemblyForm.svelte.d.ts.map +1 -0
  63. package/dist/svelte/components/AssemblyList.svelte +229 -0
  64. package/dist/svelte/components/AssemblyList.svelte.d.ts +28 -0
  65. package/dist/svelte/components/AssemblyList.svelte.d.ts.map +1 -0
  66. package/dist/svelte/components/BomEditor.svelte +575 -0
  67. package/dist/svelte/components/BomEditor.svelte.d.ts +29 -0
  68. package/dist/svelte/components/BomEditor.svelte.d.ts.map +1 -0
  69. package/dist/svelte/components/BomStructureTree.svelte +164 -0
  70. package/dist/svelte/components/BomStructureTree.svelte.d.ts +16 -0
  71. package/dist/svelte/components/BomStructureTree.svelte.d.ts.map +1 -0
  72. package/dist/svelte/components/OperationForm.svelte +258 -0
  73. package/dist/svelte/components/OperationForm.svelte.d.ts +17 -0
  74. package/dist/svelte/components/OperationForm.svelte.d.ts.map +1 -0
  75. package/dist/svelte/components/OperationList.svelte +170 -0
  76. package/dist/svelte/components/OperationList.svelte.d.ts +17 -0
  77. package/dist/svelte/components/OperationList.svelte.d.ts.map +1 -0
  78. package/dist/svelte/components/ProductionRunList.svelte +213 -0
  79. package/dist/svelte/components/ProductionRunList.svelte.d.ts +18 -0
  80. package/dist/svelte/components/ProductionRunList.svelte.d.ts.map +1 -0
  81. package/dist/svelte/components/RequirementsTree.svelte +125 -0
  82. package/dist/svelte/components/RequirementsTree.svelte.d.ts +13 -0
  83. package/dist/svelte/components/RequirementsTree.svelte.d.ts.map +1 -0
  84. package/dist/svelte/components/RequirementsTreeLevel.svelte +120 -0
  85. package/dist/svelte/components/RequirementsTreeLevel.svelte.d.ts +12 -0
  86. package/dist/svelte/components/RequirementsTreeLevel.svelte.d.ts.map +1 -0
  87. package/dist/svelte/i18n.d.ts +119 -0
  88. package/dist/svelte/i18n.d.ts.map +1 -0
  89. package/dist/svelte/i18n.js +119 -0
  90. package/dist/svelte/index.d.ts +33 -0
  91. package/dist/svelte/index.d.ts.map +1 -0
  92. package/dist/svelte/index.js +34 -0
  93. package/dist/svelte/types.d.ts +257 -0
  94. package/dist/svelte/types.d.ts.map +1 -0
  95. package/dist/svelte/types.js +249 -0
  96. package/dist/tenant-scope.d.ts +25 -0
  97. package/dist/tenant-scope.d.ts.map +1 -0
  98. package/dist/types.d.ts +207 -3
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +13 -1
  101. package/dist/types.js.map +1 -1
  102. package/dist/ui.d.ts +17 -0
  103. package/dist/ui.d.ts.map +1 -0
  104. package/dist/ui.js +94 -0
  105. package/dist/ui.js.map +1 -0
  106. 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 { DatabaseConfig } from '@happyvertical/smrt-core';
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 { type BomCostRollup, type CanProduceResult, type MaterialRequirement } from '../types.js';
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
- computeMaterialCost(bomId: string): Promise<BomCostRollup>;
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;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAExE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,KAAK,aAAa,EAGlB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAEzB,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAClC,cAAc,EAAE,MAAM,KACnB,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;CACtC,GAAG,CACA;IAAE,EAAE,EAAE,cAAc,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,GACnD;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,EAAE,CAAC,EAAE,cAAc,CAAA;CAAE,CACtD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU;aAEH,IAAI,EAAE,yBAAyB;aAC/B,KAAK,EAAE,iBAAiB;aACxB,YAAY,EAAE,YAAY;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY;IAJ/B,OAAO;IAOP,iDAAiD;WACpC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAepE;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAwChE;;;;;;;;;;;;OAYG;IACG,mBAAmB,CACvB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,EAAE,CAAC;IA0BjC;;;;;;;;;;;;;OAaG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuCvE;;;OAGG;YACW,UAAU;IAOxB;;;;OAIG;YACW,WAAW;CAO1B;AA8BD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,UAAU,CAAC,CAErB;AAID,YAAY,EAAE,OAAO,EAAE,CAAC"}
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":"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"}
1
+ {"version":3,"file":"ProductionService.d.ts","sourceRoot":"","sources":["../../src/services/ProductionService.ts"],"names":[],"mappings":"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"}