@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,249 @@
1
+ /**
2
+ * Serializable view types and pure helpers for the manufacturing components.
3
+ *
4
+ * Components take plain view objects (not model instances) so hosts can pass
5
+ * data across the server/client boundary.
6
+ */
7
+ import { M } from './i18n.js';
8
+ function textOf(value) {
9
+ return typeof value === 'string' ? value.trim() : '';
10
+ }
11
+ /** Map an operation's state onto `StatusBadge` default color-scheme keys. */
12
+ export function operationStatusBadgeKey(isActive) {
13
+ return isActive ? 'active' : 'inactive';
14
+ }
15
+ /** Trim a form draft and check the required fields: code and name. */
16
+ export function validateOperationForm(draft) {
17
+ const code = textOf(draft.code);
18
+ const name = textOf(draft.name);
19
+ const invalid = [];
20
+ if (!code)
21
+ invalid.push('code');
22
+ if (!name)
23
+ invalid.push('name');
24
+ if (invalid.length > 0)
25
+ return { ok: false, invalid };
26
+ return {
27
+ ok: true,
28
+ values: {
29
+ code,
30
+ name,
31
+ category: textOf(draft.category),
32
+ requiredQualificationId: textOf(draft.requiredQualificationId),
33
+ },
34
+ };
35
+ }
36
+ /**
37
+ * Build an {@link AssemblyView} from an `Assembly` plus the facts the list
38
+ * shows that live on its neighbours: its SKU codes and its active bill.
39
+ */
40
+ export function toAssemblyView(assembly, related = {}) {
41
+ return {
42
+ id: assembly.id ?? '',
43
+ name: assembly.name,
44
+ partReference: assembly.partReference ?? '',
45
+ skuCodes: [...(related.skuCodes ?? [])],
46
+ price: Number(assembly.price ?? 0),
47
+ estimatedLabourMinutes: Number(assembly.estimatedLabourMinutes ?? 0),
48
+ activeBomVersion: related.activeBomVersion ?? null,
49
+ };
50
+ }
51
+ /** Adapt one resolved bill line for {@link BomEditor}. */
52
+ export function toBomEditorLine(entry) {
53
+ const { line, component } = entry;
54
+ const skuCode = component.sku?.code ?? '';
55
+ return {
56
+ id: line.id ?? '',
57
+ componentSkuId: line.componentSkuId,
58
+ componentName: component.product?.name || skuCode || line.componentSkuId,
59
+ skuCode,
60
+ kind: component.kind,
61
+ qtyPerUnit: Number(line.qtyPerUnit ?? 0),
62
+ uom: line.uom,
63
+ wastePercent: Number(line.wastePercent ?? 0),
64
+ notes: line.notes ?? '',
65
+ subBomId: component.activeBom?.id ?? null,
66
+ };
67
+ }
68
+ /**
69
+ * Adapt a whole bill from `AssemblyService.getBillStructure` for
70
+ * {@link BomEditor}, keeping its line order.
71
+ */
72
+ export function toBomEditorLines(structure) {
73
+ return structure.lines.map(toBomEditorLine);
74
+ }
75
+ function toNumber(raw) {
76
+ if (typeof raw === 'number')
77
+ return raw;
78
+ const trimmed = raw.trim();
79
+ return trimmed === '' ? Number.NaN : Number(trimmed);
80
+ }
81
+ /**
82
+ * Check one line's input: a component must be chosen, the quantity must be a
83
+ * number greater than zero, the unit must not be empty, and the waste percent
84
+ * must be a number of zero or more (empty counts as zero).
85
+ */
86
+ export function validateBomLineInput(input) {
87
+ const invalid = [];
88
+ const componentSkuId = input.componentSkuId.trim();
89
+ const qtyPerUnit = toNumber(input.qtyPerUnit);
90
+ const uom = input.uom.trim();
91
+ const wasteRaw = typeof input.wastePercent === 'string' && input.wastePercent.trim() === ''
92
+ ? 0
93
+ : toNumber(input.wastePercent);
94
+ if (!componentSkuId)
95
+ invalid.push('componentSkuId');
96
+ if (!Number.isFinite(qtyPerUnit) || qtyPerUnit <= 0)
97
+ invalid.push('qtyPerUnit');
98
+ if (!uom)
99
+ invalid.push('uom');
100
+ if (!Number.isFinite(wasteRaw) || wasteRaw < 0)
101
+ invalid.push('wastePercent');
102
+ if (invalid.length > 0)
103
+ return { ok: false, invalid };
104
+ return {
105
+ ok: true,
106
+ value: { componentSkuId, qtyPerUnit, uom, wastePercent: wasteRaw },
107
+ };
108
+ }
109
+ /** The message key naming a {@link ComponentKind} in words. */
110
+ export function componentKindLabelKey(kind) {
111
+ switch (kind) {
112
+ case 'assembly':
113
+ return M['manufacturing.kind.assembly'];
114
+ case 'material':
115
+ return M['manufacturing.kind.material'];
116
+ case 'bought':
117
+ return M['manufacturing.kind.bought'];
118
+ default:
119
+ return M['manufacturing.kind.missing'];
120
+ }
121
+ }
122
+ /** Split a labour estimate into whole hours and the remaining minutes. */
123
+ export function splitLabourMinutes(minutes) {
124
+ const whole = Math.max(0, Math.round(minutes));
125
+ return { hours: Math.floor(whole / 60), minutes: whole % 60 };
126
+ }
127
+ /** Adapt a `ProductionRun` to a {@link ProductionRunView}, with the host's label. */
128
+ export function toProductionRunView(run, label) {
129
+ return {
130
+ id: run.id,
131
+ label,
132
+ targetQty: Number(run.targetQty),
133
+ completedQty: Number(run.completedQty),
134
+ status: run.status,
135
+ };
136
+ }
137
+ /** The message key naming a run status in words. */
138
+ export function productionRunStatusLabelKey(status) {
139
+ switch (status) {
140
+ case 'planned':
141
+ return M['manufacturing.production_run_status.planned'];
142
+ case 'in_progress':
143
+ return M['manufacturing.production_run_status.in_progress'];
144
+ case 'done':
145
+ return M['manufacturing.production_run_status.done'];
146
+ default:
147
+ return M['manufacturing.production_run_status.cancelled'];
148
+ }
149
+ }
150
+ /** The `StatusBadge` tone for a run status. */
151
+ export function productionRunStatusTone(status) {
152
+ switch (status) {
153
+ case 'in_progress':
154
+ return 'info';
155
+ case 'done':
156
+ return 'success';
157
+ case 'cancelled':
158
+ return 'warning';
159
+ default:
160
+ return 'neutral';
161
+ }
162
+ }
163
+ /** `true` while a run can still take completions. */
164
+ export function isProductionRunOpen(status) {
165
+ return status === 'planned' || status === 'in_progress';
166
+ }
167
+ /**
168
+ * Check a typed completion quantity against what the run has left (the
169
+ * service checks again under its lock).
170
+ */
171
+ export function validateCompletionQty(raw, run) {
172
+ const text = raw.trim();
173
+ const qty = text === '' ? Number.NaN : Number(text);
174
+ if (!Number.isFinite(qty) || qty <= 0)
175
+ return { ok: false, reason: 'invalid' };
176
+ // Whole millionths compared exactly, as ProductionRunService does
177
+ // (QUANTITY_DECIMALS = 6, MAX_QUANTITY = 999,999,999).
178
+ const millionths = (value) => Number(value.toFixed(6).replace('.', ''));
179
+ const rounded = Number(qty.toFixed(6));
180
+ if (rounded <= 0 || rounded > 999_999_999)
181
+ return { ok: false, reason: 'invalid' };
182
+ const remaining = millionths(run.targetQty) - millionths(run.completedQty);
183
+ if (millionths(rounded) > remaining)
184
+ return { ok: false, reason: 'too_many' };
185
+ return { ok: true, qty: rounded };
186
+ }
187
+ function isPlanned(line) {
188
+ return 'short' in line;
189
+ }
190
+ /**
191
+ * Nest the depth-first lines of an {@link Explosion} or a
192
+ * {@link RequirementsPlan} for `RequirementsTree`.
193
+ */
194
+ export function toRequirementTree(source) {
195
+ const roots = [];
196
+ const open = [];
197
+ for (const line of source.lines) {
198
+ const view = {
199
+ key: [...line.path.map((entry) => entry.bomId), line.lineId].join('/'),
200
+ level: line.level,
201
+ name: line.name,
202
+ skuCode: line.skuCode,
203
+ kind: line.kind,
204
+ required: line.totalQty,
205
+ uom: line.uom,
206
+ available: isPlanned(line) ? line.available : null,
207
+ short: isPlanned(line) ? line.short : null,
208
+ buildable: line.buildable,
209
+ children: [],
210
+ };
211
+ open.length = Math.min(open.length, line.level - 1);
212
+ const parent = open[line.level - 2];
213
+ if (line.level > 1 && parent)
214
+ parent.children.push(view);
215
+ else
216
+ roots.push(view);
217
+ open[line.level - 1] = view;
218
+ }
219
+ return roots;
220
+ }
221
+ /**
222
+ * The totals of an {@link Explosion} or a {@link RequirementsPlan}: every line
223
+ * not opened, summed per component SKU (first unit kept).
224
+ */
225
+ export function toRequirementTotals(source) {
226
+ const totals = new Map();
227
+ for (const line of source.lines) {
228
+ if (line.expanded)
229
+ continue;
230
+ const short = isPlanned(line) ? line.short : null;
231
+ const existing = totals.get(line.componentSkuId);
232
+ if (existing) {
233
+ existing.required += line.totalQty;
234
+ if (existing.short !== null && short !== null)
235
+ existing.short += short;
236
+ }
237
+ else {
238
+ totals.set(line.componentSkuId, {
239
+ componentSkuId: line.componentSkuId,
240
+ name: line.name,
241
+ skuCode: line.skuCode,
242
+ required: line.totalQty,
243
+ uom: line.uom,
244
+ short,
245
+ });
246
+ }
247
+ }
248
+ return Array.from(totals.values());
249
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Reading a structure in its owner's tenant: the owner's rows and global
3
+ * ones, whatever tenant context is active.
4
+ *
5
+ * Under a tenant context the tenancy interceptor narrows every read to that
6
+ * tenant, which hides global rows (a shared material, a global bill, global
7
+ * stock); without a context it narrows nothing, which shows every tenant's
8
+ * rows. Neither is a bill's structure. {@link readOwnAndGlobal} runs list
9
+ * reads through `withTenantGlobalRead` (tenant rows plus global rows, refused
10
+ * for a tenant the active context may not read), and callers keep
11
+ * {@link isOwnOrGlobal} rows, which also covers tenancy being disabled.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /**
16
+ * Run `read` so its list reads return `owner`'s rows and global ones. For a
17
+ * global owner (`null`), reads see the active tenant's rows and global ones,
18
+ * and callers keep the global rows.
19
+ */
20
+ export declare function readOwnAndGlobal<T>(owner: string | null, read: () => Promise<T>): Promise<T>;
21
+ /** `true` for a global row or one of `owner`'s rows. */
22
+ export declare function isOwnOrGlobal(row: {
23
+ tenantId?: string | null;
24
+ }, owner: string | null): boolean;
25
+ //# sourceMappingURL=tenant-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-scope.d.ts","sourceRoot":"","sources":["../src/tenant-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACrB,OAAO,CAAC,CAAC,CAAC,CAGZ;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAC3B,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACjC,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAGT"}
package/dist/types.d.ts CHANGED
@@ -7,6 +7,8 @@
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
+ import type { LabourEstimate } from './operation-types.js';
11
+ import type { ComponentKind } from './services/AssemblyService.js';
10
12
  /**
11
13
  * Lifecycle state of a {@link BillOfMaterials}.
12
14
  *
@@ -50,6 +52,13 @@ export interface BomLineCost {
50
52
  * flag lets UIs warn the user that the cost rollup is incomplete.
51
53
  */
52
54
  costUnavailable: boolean;
55
+ /**
56
+ * Multi-level only: the active bill this sub-assembly line was rolled up
57
+ * from. `unitCost` is then that bill's material cost per unit.
58
+ */
59
+ subBomId?: string;
60
+ /** Multi-level only: the sub-assembly bill's own lines, rolled up the same way. */
61
+ components?: BomLineCost[];
53
62
  }
54
63
  /**
55
64
  * Aggregate cost rollup returned by {@link BomService.computeMaterialCost}.
@@ -64,8 +73,9 @@ export interface BomCostRollup {
64
73
  /** Per-line breakdown. Empty array when the BOM has no lines. */
65
74
  lineBreakdown: BomLineCost[];
66
75
  /**
67
- * `true` when at least one line's unit cost could not be resolved.
68
- * Callers should treat `totalCost` as a lower bound in that case.
76
+ * `true` when at least one line's unit cost could not be resolved, at any
77
+ * level walked. Callers should treat `totalCost` as a lower bound in that
78
+ * case.
69
79
  */
70
80
  hasMissingCosts: boolean;
71
81
  }
@@ -83,14 +93,36 @@ export interface MaterialRequirement {
83
93
  }
84
94
  /**
85
95
  * A single shortage discovered by {@link BomService.canProduce}.
96
+ *
97
+ * A single-level check (the default) reports one entry per component SKU
98
+ * with the run's total and the SKU's whole available stock. A multi-level
99
+ * check (`{ levels }`) reports each shortage on the line where it occurs, so
100
+ * the same SKU can appear once per place it is used, and adds `level`,
101
+ * `path`, `uom` and `buildable`.
86
102
  */
87
103
  export interface MaterialShortage {
88
104
  /** Plain string reference to the missing component {@link Sku}. */
89
105
  componentSkuId: string;
90
106
  /** Total quantity required for the requested production run. */
91
107
  requested: number;
92
- /** Available stock across all locations (`available` state). */
108
+ /**
109
+ * Available stock across all locations (`available` state). In a
110
+ * multi-level check, the part of it not already allocated to lines planned
111
+ * earlier in the walk.
112
+ */
93
113
  available: number;
114
+ /** Multi-level only: the level of the line that is short (1 = the bill's own lines). */
115
+ level?: number;
116
+ /** Multi-level only: the bills from the top down to the one the line is on. */
117
+ path?: ExplosionPathEntry[];
118
+ /** Multi-level only: the line's unit of measure. */
119
+ uom?: string;
120
+ /**
121
+ * Multi-level only: `true` for a sub-assembly with an active bill that the
122
+ * walk did not open because the `levels` limit was reached. It is short,
123
+ * but could be built.
124
+ */
125
+ buildable?: boolean;
94
126
  }
95
127
  /**
96
128
  * Result returned by {@link BomService.canProduce}.
@@ -126,4 +158,176 @@ export declare class NoActiveBomForProductError extends Error {
126
158
  name: string;
127
159
  constructor(productId: string);
128
160
  }
161
+ /**
162
+ * How many bill levels a walk reads. `1` is the bill's own lines only (the
163
+ * single-level behaviour every method keeps by default); `2` also opens each
164
+ * sub-assembly's active bill; and so on. `'all'` walks down to materials,
165
+ * bought items and assemblies without an active bill, up to
166
+ * {@link MAX_EXPLOSION_DEPTH} levels.
167
+ */
168
+ export type ExplosionLevels = number | 'all';
169
+ /** Options for the multi-level forms of the {@link BomService} methods. */
170
+ export interface ExplosionOptions {
171
+ /** How deep to walk. Default `1`. See {@link ExplosionLevels}. */
172
+ levels?: ExplosionLevels;
173
+ }
174
+ /**
175
+ * The deepest structure a walk opens. A numeric `levels` above it is refused;
176
+ * `'all'` on a structure deeper than this fails with
177
+ * {@link BomExplosionLimitError} rather than running unbounded.
178
+ */
179
+ export declare const MAX_EXPLOSION_DEPTH = 32;
180
+ /**
181
+ * The most lines one walk returns. A structure that shares sub-assemblies
182
+ * widely can multiply out; past this a walk fails with
183
+ * {@link BomExplosionLimitError}.
184
+ */
185
+ export declare const MAX_EXPLOSION_LINES = 10000;
186
+ /** One bill on the way down a multi-level walk. */
187
+ export interface ExplosionPathEntry {
188
+ /** The bill. */
189
+ bomId: string;
190
+ /** The product the bill makes. */
191
+ productId: string;
192
+ /** The product's name, or its id when it has none or cannot be read. */
193
+ name: string;
194
+ }
195
+ /**
196
+ * One bill line in a multi-level walk, in depth-first order: an expanded
197
+ * sub-assembly is followed by its own bill's lines.
198
+ */
199
+ export interface ExplodedLine {
200
+ /** The `BomLine` id. */
201
+ lineId: string;
202
+ /** The bill the line is on. */
203
+ bomId: string;
204
+ /** 1 for the top bill's own lines, 2 for a sub-assembly's lines, ... */
205
+ level: number;
206
+ /** The bills from the top down to the one this line is on (`level` entries). */
207
+ path: ExplosionPathEntry[];
208
+ /** The component SKU. */
209
+ componentSkuId: string;
210
+ /** What the component is (see `AssemblyService.resolveComponent`). */
211
+ kind: ComponentKind;
212
+ /** The component product's name; `''` when it cannot be resolved. */
213
+ name: string;
214
+ /** The component SKU's code; `''` when it cannot be resolved. */
215
+ skuCode: string;
216
+ /** Quantity per unit of the parent, as on the line (before waste). */
217
+ qtyPerUnit: number;
218
+ /** Waste percent on the line. */
219
+ wastePercent: number;
220
+ /** Quantity per unit of the parent including this line's waste. */
221
+ effectiveQtyPerUnit: number;
222
+ /** The line's own unit of measure; never converted. */
223
+ uom: string;
224
+ /**
225
+ * Quantity needed for the run: the parent's quantity times
226
+ * `effectiveQtyPerUnit`, so waste compounds down the levels.
227
+ */
228
+ totalQty: number;
229
+ /** `true` for a sub-assembly with an active bill (it can be built here). */
230
+ buildable: boolean;
231
+ /** The sub-assembly's active bill id, or `null`. */
232
+ subBomId: string | null;
233
+ /** `true` when the sub-assembly's bill was opened: its lines follow this one. */
234
+ expanded: boolean;
235
+ }
236
+ /** Result of {@link BomService.explode}: the gross multi-level requirements. */
237
+ export interface Explosion {
238
+ /** The top bill. */
239
+ bomId: string;
240
+ /** The product the top bill makes. */
241
+ productId: string;
242
+ /** Units of the top product the run makes. */
243
+ qty: number;
244
+ /** The `levels` the walk used. */
245
+ levels: ExplosionLevels;
246
+ /** Every line walked, depth first. */
247
+ lines: ExplodedLine[];
248
+ /**
249
+ * The rolled-up shopping list: every line that was not expanded (materials,
250
+ * bought items, missing components, sub-assemblies without an active bill
251
+ * or past the `levels` limit), summed per component SKU. As in the
252
+ * single-level form, a SKU listed in two units keeps the first unit.
253
+ */
254
+ totals: MaterialRequirement[];
255
+ }
256
+ /**
257
+ * One line of {@link RequirementsPlan}. `totalQty` is the *net* quantity: the
258
+ * run's quantity for the top bill's lines, and only a sub-assembly's
259
+ * shortfall for the lines of its bill.
260
+ */
261
+ export interface PlannedLine extends ExplodedLine {
262
+ /**
263
+ * Available stock of the component (all locations) not already allocated
264
+ * to lines planned earlier in the walk, so stock used once is not counted
265
+ * twice.
266
+ */
267
+ available: number;
268
+ /** `totalQty` minus what `available` covers; `0` when covered. */
269
+ short: number;
270
+ }
271
+ /**
272
+ * Result of {@link BomService.planRequirements}: facts for deciding what to
273
+ * build, buy or pull. A sub-assembly that is short and has an active bill is
274
+ * opened for its shortfall only; whether the application builds or buys it is
275
+ * the application's decision.
276
+ */
277
+ export interface RequirementsPlan {
278
+ /** The top bill. */
279
+ bomId: string;
280
+ /** The product the top bill makes. */
281
+ productId: string;
282
+ /** Units of the top product the run makes. */
283
+ qty: number;
284
+ /** The `levels` the walk used. */
285
+ levels: ExplosionLevels;
286
+ /** Every line planned, depth first. */
287
+ lines: PlannedLine[];
288
+ /**
289
+ * Every line that is short and was not opened (a material, a bought item,
290
+ * a missing component, or a sub-assembly with no active bill or past the
291
+ * `levels` limit), reported at its own level.
292
+ */
293
+ shortages: MaterialShortage[];
294
+ /** `true` when `shortages` is empty. */
295
+ ok: boolean;
296
+ }
297
+ /** One sub-assembly's labour in a multi-level {@link LabourEstimate}. */
298
+ export interface SubAssemblyLabour {
299
+ /** The line naming the sub-assembly. */
300
+ lineId: string;
301
+ /** The sub-assembly's component SKU. */
302
+ componentSkuId: string;
303
+ /** The sub-assembly's name. */
304
+ name: string;
305
+ /** The level of the line naming it (1 = on the top bill). */
306
+ level: number;
307
+ /** The bills from the top down to the one the line is on. */
308
+ path: ExplosionPathEntry[];
309
+ /**
310
+ * Units of the sub-assembly per unit of the top product, waste compounded
311
+ * through every level above.
312
+ */
313
+ unitsPerUnit: number;
314
+ /** The sub-assembly bill's own routing, per unit of the sub-assembly. */
315
+ estimate: LabourEstimate;
316
+ }
317
+ /**
318
+ * Thrown when a multi-level walk would exceed {@link MAX_EXPLOSION_DEPTH}
319
+ * levels (with `levels: 'all'`) or {@link MAX_EXPLOSION_LINES} lines.
320
+ */
321
+ export declare class BomExplosionLimitError extends Error {
322
+ /** The bill the walk started from. */
323
+ readonly bomId: string;
324
+ /** Which limit was reached. */
325
+ readonly limit: 'depth' | 'lines';
326
+ name: string;
327
+ constructor(
328
+ /** The bill the walk started from. */
329
+ bomId: string,
330
+ /** Which limit was reached. */
331
+ limit: 'depth' | 'lines');
332
+ }
129
333
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,EAAE,CAAA;CAAE,GAC3B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAEjD;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAGb,KAAK,EAAE,MAAM;IAFhC,IAAI,SAAsB;gBAEP,KAAK,EAAE,MAAM;CAG1C;AAED;;;;;GAKG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;aAGvB,SAAS,EAAE,MAAM;IAFpC,IAAI,SAAgC;gBAEjB,SAAS,EAAE,MAAM;CAM9C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -15,7 +15,19 @@ var NoActiveBomForProductError = class extends Error {
15
15
  productId;
16
16
  name = "NoActiveBomForProductError";
17
17
  };
18
+ var MAX_EXPLOSION_DEPTH = 32;
19
+ var MAX_EXPLOSION_LINES = 1e4;
20
+ var BomExplosionLimitError = class extends Error {
21
+ constructor(bomId, limit) {
22
+ super(limit === "depth" ? `Bill ${bomId} is nested deeper than 32 levels.` : `Bill ${bomId} explodes to more than ${MAX_EXPLOSION_LINES} lines.`);
23
+ this.bomId = bomId;
24
+ this.limit = limit;
25
+ }
26
+ bomId;
27
+ limit;
28
+ name = "BomExplosionLimitError";
29
+ };
18
30
  //#endregion
19
- export { BomNotFoundError, NoActiveBomForProductError };
31
+ export { BomExplosionLimitError, BomNotFoundError, MAX_EXPLOSION_DEPTH, MAX_EXPLOSION_LINES, NoActiveBomForProductError };
20
32
 
21
33
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["/**\n * Shared types and error classes for `@happyvertical/smrt-manufacturing`.\n *\n * Strictly industry-neutral. The same vocabulary serves apparel, furniture,\n * automotive, CPG, electronics, food production, custom hardware, and any\n * other vertical that builds finished goods from raw inputs by recipe.\n *\n * @packageDocumentation\n */\n\n/**\n * Lifecycle state of a {@link BillOfMaterials}.\n *\n * - `draft` — under construction; not yet released for production. Cost\n * rollups can still be computed, but the BOM should not yet be referenced\n * by a production order.\n * - `active` — currently in use. New production orders should reference the\n * active BOM for a given product.\n * - `superseded` — an older revision that has been replaced by a newer\n * `active` BOM. Historical production orders may still reference the\n * superseded row for audit, but no new orders should pick it up.\n */\nexport type BomStatus = 'draft' | 'active' | 'superseded';\n\n/**\n * Per-line cost breakdown returned by {@link BomService.computeMaterialCost}.\n * Lets callers surface \"here's where the $42 came from\" UIs without\n * recomputing on the client.\n */\nexport interface BomLineCost {\n /**\n * Plain string reference to a component SKU id. The `Sku` model\n * itself lives in `@happyvertical/smrt-products`; inventory only\n * tracks stock motion against that id.\n */\n componentSkuId: string;\n /** Quantity per produced unit (pre-waste). */\n qtyPerUnit: number;\n /** Waste percent applied to this line (`0` if none). */\n wastePercent: number;\n /** Effective quantity used per produced unit, including waste. */\n effectiveQty: number;\n /** Latest known unit cost, or `0` if unavailable. */\n unitCost: number;\n /** Effective unit-cost contribution to the rolled-up total. */\n lineCost: number;\n /** Unit of measure as declared on the line (`'yards'`, `'each'`, ...). */\n uom: string;\n /**\n * `true` when the unit cost could not be resolved from upstream\n * `smrt-products`. The line still contributes `0` to the total; the\n * flag lets UIs warn the user that the cost rollup is incomplete.\n */\n costUnavailable: boolean;\n}\n\n/**\n * Aggregate cost rollup returned by {@link BomService.computeMaterialCost}.\n */\nexport interface BomCostRollup {\n /** BOM that was rolled up. */\n bomId: string;\n /** Total material cost per produced unit. */\n totalCost: number;\n /** ISO 4217 currency code. Defaults to `'USD'`. */\n currency: string;\n /** Per-line breakdown. Empty array when the BOM has no lines. */\n lineBreakdown: BomLineCost[];\n /**\n * `true` when at least one line's unit cost could not be resolved.\n * Callers should treat `totalCost` as a lower bound in that case.\n */\n hasMissingCosts: boolean;\n}\n\n/**\n * A single entry on a requirements explosion. Multiple BOM lines pointing\n * at the same component SKU are summed.\n */\nexport interface MaterialRequirement {\n /** Plain string reference to the required component {@link Sku}. */\n componentSkuId: string;\n /** Total quantity needed across the full production run (waste included). */\n totalQty: number;\n /** Unit of measure carried over from the originating BOM line(s). */\n uom: string;\n}\n\n/**\n * A single shortage discovered by {@link BomService.canProduce}.\n */\nexport interface MaterialShortage {\n /** Plain string reference to the missing component {@link Sku}. */\n componentSkuId: string;\n /** Total quantity required for the requested production run. */\n requested: number;\n /** Available stock across all locations (`available` state). */\n available: number;\n}\n\n/**\n * Result returned by {@link BomService.canProduce}.\n *\n * `ok: true` means every material requirement is currently covered by\n * available stock; `ok: false` means at least one component is short.\n */\nexport type CanProduceResult =\n | { ok: true; shortages: [] }\n | { ok: false; shortages: MaterialShortage[] };\n\n/**\n * Thrown when a service operation needs to resolve a BOM by id but the row\n * does not exist. Carries the requested id so callers can surface a\n * meaningful message.\n */\nexport class BomNotFoundError extends Error {\n override name = 'BomNotFoundError';\n\n constructor(public readonly bomId: string) {\n super(`Bill of Materials not found: ${bomId}`);\n }\n}\n\n/**\n * Thrown when a production-order operation needs a BOM to plan against but\n * no active BOM is currently registered for the production order's\n * `productId`. The caller should either link a BOM by passing one in\n * explicitly or activate one for the given product.\n */\nexport class NoActiveBomForProductError extends Error {\n override name = 'NoActiveBomForProductError';\n\n constructor(public readonly productId: string) {\n super(\n `No active Bill of Materials found for product: ${productId}. ` +\n `Activate a BOM for this product or pass one explicitly.`,\n );\n }\n}\n"],"mappings":";AAmHO,IAAM,mBAAN,cAA+B,MAAM;CAG1C,YAA4B,OAAe;EACzC,MAAM,gCAAgC,OAAO;EADnB,KAAA,QAAA;CAE5B;CAF4B;CAFnB,OAAO;AAKlB;AAQO,IAAM,6BAAN,cAAyC,MAAM;CAGpD,YAA4B,WAAmB;EAC7C,MACE,kDAAkD,UAAS,0DAE7D;EAJ0B,KAAA,YAAA;CAK5B;CAL4B;CAFnB,OAAO;AAQlB"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["/**\n * Shared types and error classes for `@happyvertical/smrt-manufacturing`.\n *\n * Strictly industry-neutral. The same vocabulary serves apparel, furniture,\n * automotive, CPG, electronics, food production, custom hardware, and any\n * other vertical that builds finished goods from raw inputs by recipe.\n *\n * @packageDocumentation\n */\n\nimport type { LabourEstimate } from './operation-types.js';\nimport type { ComponentKind } from './services/AssemblyService.js';\n\n/**\n * Lifecycle state of a {@link BillOfMaterials}.\n *\n * - `draft` — under construction; not yet released for production. Cost\n * rollups can still be computed, but the BOM should not yet be referenced\n * by a production order.\n * - `active` — currently in use. New production orders should reference the\n * active BOM for a given product.\n * - `superseded` — an older revision that has been replaced by a newer\n * `active` BOM. Historical production orders may still reference the\n * superseded row for audit, but no new orders should pick it up.\n */\nexport type BomStatus = 'draft' | 'active' | 'superseded';\n\n/**\n * Per-line cost breakdown returned by {@link BomService.computeMaterialCost}.\n * Lets callers surface \"here's where the $42 came from\" UIs without\n * recomputing on the client.\n */\nexport interface BomLineCost {\n /**\n * Plain string reference to a component SKU id. The `Sku` model\n * itself lives in `@happyvertical/smrt-products`; inventory only\n * tracks stock motion against that id.\n */\n componentSkuId: string;\n /** Quantity per produced unit (pre-waste). */\n qtyPerUnit: number;\n /** Waste percent applied to this line (`0` if none). */\n wastePercent: number;\n /** Effective quantity used per produced unit, including waste. */\n effectiveQty: number;\n /** Latest known unit cost, or `0` if unavailable. */\n unitCost: number;\n /** Effective unit-cost contribution to the rolled-up total. */\n lineCost: number;\n /** Unit of measure as declared on the line (`'yards'`, `'each'`, ...). */\n uom: string;\n /**\n * `true` when the unit cost could not be resolved from upstream\n * `smrt-products`. The line still contributes `0` to the total; the\n * flag lets UIs warn the user that the cost rollup is incomplete.\n */\n costUnavailable: boolean;\n /**\n * Multi-level only: the active bill this sub-assembly line was rolled up\n * from. `unitCost` is then that bill's material cost per unit.\n */\n subBomId?: string;\n /** Multi-level only: the sub-assembly bill's own lines, rolled up the same way. */\n components?: BomLineCost[];\n}\n\n/**\n * Aggregate cost rollup returned by {@link BomService.computeMaterialCost}.\n */\nexport interface BomCostRollup {\n /** BOM that was rolled up. */\n bomId: string;\n /** Total material cost per produced unit. */\n totalCost: number;\n /** ISO 4217 currency code. Defaults to `'USD'`. */\n currency: string;\n /** Per-line breakdown. Empty array when the BOM has no lines. */\n lineBreakdown: BomLineCost[];\n /**\n * `true` when at least one line's unit cost could not be resolved, at any\n * level walked. Callers should treat `totalCost` as a lower bound in that\n * case.\n */\n hasMissingCosts: boolean;\n}\n\n/**\n * A single entry on a requirements explosion. Multiple BOM lines pointing\n * at the same component SKU are summed.\n */\nexport interface MaterialRequirement {\n /** Plain string reference to the required component {@link Sku}. */\n componentSkuId: string;\n /** Total quantity needed across the full production run (waste included). */\n totalQty: number;\n /** Unit of measure carried over from the originating BOM line(s). */\n uom: string;\n}\n\n/**\n * A single shortage discovered by {@link BomService.canProduce}.\n *\n * A single-level check (the default) reports one entry per component SKU\n * with the run's total and the SKU's whole available stock. A multi-level\n * check (`{ levels }`) reports each shortage on the line where it occurs, so\n * the same SKU can appear once per place it is used, and adds `level`,\n * `path`, `uom` and `buildable`.\n */\nexport interface MaterialShortage {\n /** Plain string reference to the missing component {@link Sku}. */\n componentSkuId: string;\n /** Total quantity required for the requested production run. */\n requested: number;\n /**\n * Available stock across all locations (`available` state). In a\n * multi-level check, the part of it not already allocated to lines planned\n * earlier in the walk.\n */\n available: number;\n /** Multi-level only: the level of the line that is short (1 = the bill's own lines). */\n level?: number;\n /** Multi-level only: the bills from the top down to the one the line is on. */\n path?: ExplosionPathEntry[];\n /** Multi-level only: the line's unit of measure. */\n uom?: string;\n /**\n * Multi-level only: `true` for a sub-assembly with an active bill that the\n * walk did not open because the `levels` limit was reached. It is short,\n * but could be built.\n */\n buildable?: boolean;\n}\n\n/**\n * Result returned by {@link BomService.canProduce}.\n *\n * `ok: true` means every material requirement is currently covered by\n * available stock; `ok: false` means at least one component is short.\n */\nexport type CanProduceResult =\n | { ok: true; shortages: [] }\n | { ok: false; shortages: MaterialShortage[] };\n\n/**\n * Thrown when a service operation needs to resolve a BOM by id but the row\n * does not exist. Carries the requested id so callers can surface a\n * meaningful message.\n */\nexport class BomNotFoundError extends Error {\n override name = 'BomNotFoundError';\n\n constructor(public readonly bomId: string) {\n super(`Bill of Materials not found: ${bomId}`);\n }\n}\n\n/**\n * Thrown when a production-order operation needs a BOM to plan against but\n * no active BOM is currently registered for the production order's\n * `productId`. The caller should either link a BOM by passing one in\n * explicitly or activate one for the given product.\n */\nexport class NoActiveBomForProductError extends Error {\n override name = 'NoActiveBomForProductError';\n\n constructor(public readonly productId: string) {\n super(\n `No active Bill of Materials found for product: ${productId}. ` +\n `Activate a BOM for this product or pass one explicitly.`,\n );\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Multi-level walks (sub-assemblies)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * How many bill levels a walk reads. `1` is the bill's own lines only (the\n * single-level behaviour every method keeps by default); `2` also opens each\n * sub-assembly's active bill; and so on. `'all'` walks down to materials,\n * bought items and assemblies without an active bill, up to\n * {@link MAX_EXPLOSION_DEPTH} levels.\n */\nexport type ExplosionLevels = number | 'all';\n\n/** Options for the multi-level forms of the {@link BomService} methods. */\nexport interface ExplosionOptions {\n /** How deep to walk. Default `1`. See {@link ExplosionLevels}. */\n levels?: ExplosionLevels;\n}\n\n/**\n * The deepest structure a walk opens. A numeric `levels` above it is refused;\n * `'all'` on a structure deeper than this fails with\n * {@link BomExplosionLimitError} rather than running unbounded.\n */\nexport const MAX_EXPLOSION_DEPTH = 32;\n\n/**\n * The most lines one walk returns. A structure that shares sub-assemblies\n * widely can multiply out; past this a walk fails with\n * {@link BomExplosionLimitError}.\n */\nexport const MAX_EXPLOSION_LINES = 10_000;\n\n/** One bill on the way down a multi-level walk. */\nexport interface ExplosionPathEntry {\n /** The bill. */\n bomId: string;\n /** The product the bill makes. */\n productId: string;\n /** The product's name, or its id when it has none or cannot be read. */\n name: string;\n}\n\n/**\n * One bill line in a multi-level walk, in depth-first order: an expanded\n * sub-assembly is followed by its own bill's lines.\n */\nexport interface ExplodedLine {\n /** The `BomLine` id. */\n lineId: string;\n /** The bill the line is on. */\n bomId: string;\n /** 1 for the top bill's own lines, 2 for a sub-assembly's lines, ... */\n level: number;\n /** The bills from the top down to the one this line is on (`level` entries). */\n path: ExplosionPathEntry[];\n /** The component SKU. */\n componentSkuId: string;\n /** What the component is (see `AssemblyService.resolveComponent`). */\n kind: ComponentKind;\n /** The component product's name; `''` when it cannot be resolved. */\n name: string;\n /** The component SKU's code; `''` when it cannot be resolved. */\n skuCode: string;\n /** Quantity per unit of the parent, as on the line (before waste). */\n qtyPerUnit: number;\n /** Waste percent on the line. */\n wastePercent: number;\n /** Quantity per unit of the parent including this line's waste. */\n effectiveQtyPerUnit: number;\n /** The line's own unit of measure; never converted. */\n uom: string;\n /**\n * Quantity needed for the run: the parent's quantity times\n * `effectiveQtyPerUnit`, so waste compounds down the levels.\n */\n totalQty: number;\n /** `true` for a sub-assembly with an active bill (it can be built here). */\n buildable: boolean;\n /** The sub-assembly's active bill id, or `null`. */\n subBomId: string | null;\n /** `true` when the sub-assembly's bill was opened: its lines follow this one. */\n expanded: boolean;\n}\n\n/** Result of {@link BomService.explode}: the gross multi-level requirements. */\nexport interface Explosion {\n /** The top bill. */\n bomId: string;\n /** The product the top bill makes. */\n productId: string;\n /** Units of the top product the run makes. */\n qty: number;\n /** The `levels` the walk used. */\n levels: ExplosionLevels;\n /** Every line walked, depth first. */\n lines: ExplodedLine[];\n /**\n * The rolled-up shopping list: every line that was not expanded (materials,\n * bought items, missing components, sub-assemblies without an active bill\n * or past the `levels` limit), summed per component SKU. As in the\n * single-level form, a SKU listed in two units keeps the first unit.\n */\n totals: MaterialRequirement[];\n}\n\n/**\n * One line of {@link RequirementsPlan}. `totalQty` is the *net* quantity: the\n * run's quantity for the top bill's lines, and only a sub-assembly's\n * shortfall for the lines of its bill.\n */\nexport interface PlannedLine extends ExplodedLine {\n /**\n * Available stock of the component (all locations) not already allocated\n * to lines planned earlier in the walk, so stock used once is not counted\n * twice.\n */\n available: number;\n /** `totalQty` minus what `available` covers; `0` when covered. */\n short: number;\n}\n\n/**\n * Result of {@link BomService.planRequirements}: facts for deciding what to\n * build, buy or pull. A sub-assembly that is short and has an active bill is\n * opened for its shortfall only; whether the application builds or buys it is\n * the application's decision.\n */\nexport interface RequirementsPlan {\n /** The top bill. */\n bomId: string;\n /** The product the top bill makes. */\n productId: string;\n /** Units of the top product the run makes. */\n qty: number;\n /** The `levels` the walk used. */\n levels: ExplosionLevels;\n /** Every line planned, depth first. */\n lines: PlannedLine[];\n /**\n * Every line that is short and was not opened (a material, a bought item,\n * a missing component, or a sub-assembly with no active bill or past the\n * `levels` limit), reported at its own level.\n */\n shortages: MaterialShortage[];\n /** `true` when `shortages` is empty. */\n ok: boolean;\n}\n\n/** One sub-assembly's labour in a multi-level {@link LabourEstimate}. */\nexport interface SubAssemblyLabour {\n /** The line naming the sub-assembly. */\n lineId: string;\n /** The sub-assembly's component SKU. */\n componentSkuId: string;\n /** The sub-assembly's name. */\n name: string;\n /** The level of the line naming it (1 = on the top bill). */\n level: number;\n /** The bills from the top down to the one the line is on. */\n path: ExplosionPathEntry[];\n /**\n * Units of the sub-assembly per unit of the top product, waste compounded\n * through every level above.\n */\n unitsPerUnit: number;\n /** The sub-assembly bill's own routing, per unit of the sub-assembly. */\n estimate: LabourEstimate;\n}\n\n/**\n * Thrown when a multi-level walk would exceed {@link MAX_EXPLOSION_DEPTH}\n * levels (with `levels: 'all'`) or {@link MAX_EXPLOSION_LINES} lines.\n */\nexport class BomExplosionLimitError extends Error {\n override name = 'BomExplosionLimitError';\n\n constructor(\n /** The bill the walk started from. */\n public readonly bomId: string,\n /** Which limit was reached. */\n public readonly limit: 'depth' | 'lines',\n ) {\n super(\n limit === 'depth'\n ? `Bill ${bomId} is nested deeper than ${MAX_EXPLOSION_DEPTH} levels.`\n : `Bill ${bomId} explodes to more than ${MAX_EXPLOSION_LINES} lines.`,\n );\n }\n}\n"],"mappings":";AAoJO,IAAM,mBAAN,cAA+B,MAAM;CAG1C,YAA4B,OAAe;EACzC,MAAM,gCAAgC,OAAO;EADnB,KAAA,QAAA;CAE5B;CAF4B;CAFnB,OAAO;AAKlB;AAQO,IAAM,6BAAN,cAAyC,MAAM;CAGpD,YAA4B,WAAmB;EAC7C,MACE,kDAAkD,UAAS,0DAE7D;EAJ0B,KAAA,YAAA;CAK5B;CAL4B;CAFnB,OAAO;AAQlB;AA0BO,IAAM,sBAAsB;AAO5B,IAAM,sBAAsB;AA+I5B,IAAM,yBAAN,cAAqC,MAAM;CAGhD,YAEkB,OAEA,OAChB;EACA,MACE,UAAU,UACN,QAAQ,MAAK,qCACb,QAAQ,MAAK,yBAA0B,oBAAmB,QAChE;EARgB,KAAA,QAAA;EAEA,KAAA,QAAA;CAOlB;CATkB;CAEA;CANT,OAAO;AAclB"}
package/dist/ui.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Manufacturing Module UI Slot Declarations
3
+ *
4
+ * UI extension points for the manufacturing module. Components live in the
5
+ * ./svelte subpath and are props-driven: hosts load records through the
6
+ * services and pass plain view objects.
7
+ */
8
+ import type { ModuleUISlot, SmrtModuleMeta } from '@happyvertical/smrt-types';
9
+ /**
10
+ * Manufacturing module UI slots
11
+ */
12
+ export declare const MANUFACTURING_UI_SLOTS: Record<string, ModuleUISlot>;
13
+ /**
14
+ * Manufacturing module metadata
15
+ */
16
+ export declare const MANUFACTURING_MODULE_META: SmrtModuleMeta;
17
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE9E;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAoE/D,CAAC;AACF;;GAEG;AACH,eAAO,MAAM,yBAAyB,EAAE,cAwBvC,CAAC"}