@happyvertical/smrt-manufacturing 0.51.32 → 0.51.34
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/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/collections/BillOfMaterialsCollection.d.ts +30 -0
- package/dist/collections/BillOfMaterialsCollection.d.ts.map +1 -0
- package/dist/collections/BomLineCollection.d.ts +23 -0
- package/dist/collections/BomLineCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +14 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/index.d.ts +34 -846
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/models/BillOfMaterials.d.ts +78 -0
- package/dist/models/BillOfMaterials.d.ts.map +1 -0
- package/dist/models/BomLine.d.ts +88 -0
- package/dist/models/BomLine.d.ts.map +1 -0
- package/dist/models/index.d.ts +14 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/services/BomService.d.ts +157 -0
- package/dist/services/BomService.d.ts.map +1 -0
- package/dist/services/ProductionService.d.ts +322 -0
- package/dist/services/ProductionService.d.ts.map +1 -0
- package/dist/services/dispatch-handlers.d.ts +159 -0
- package/dist/services/dispatch-handlers.d.ts.map +1 -0
- package/dist/services/index.d.ts +9 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +4 -4
- package/dist/types.d.ts +129 -138
- package/dist/types.d.ts.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProductionService — the operational bridge from a production order to
|
|
3
|
+
* actual stock-mutating consume/produce events.
|
|
4
|
+
*
|
|
5
|
+
* Production orders themselves live in `@happyvertical/smrt-commerce` as a
|
|
6
|
+
* `Contract` STI subtype. This service does NOT modify those rows; it
|
|
7
|
+
* simply reads the order's `productId`, looks up the active BOM, and
|
|
8
|
+
* writes the right stock movements through {@link StockService}.
|
|
9
|
+
*
|
|
10
|
+
* Three methods:
|
|
11
|
+
*
|
|
12
|
+
* - {@link consumeMaterials} — for each BOM line, deduct
|
|
13
|
+
* `qtyPerUnit * (1 + wastePercent / 100) * runQty` from `available` at
|
|
14
|
+
* the production location. Stamps every movement with
|
|
15
|
+
* `sourceType: 'ProductionOrder'` + the production order id so audit
|
|
16
|
+
* queries can roll them up later. Atomic across BOM lines (one tx).
|
|
17
|
+
* - {@link produceFinishedGoods} — receive `runQty` of the finished
|
|
18
|
+
* product's SKU into `available` at the production location. The caller
|
|
19
|
+
* supplies the SKU id (the production order references a *product*, not
|
|
20
|
+
* a *SKU*; in practice the production-order-level "what we are making"
|
|
21
|
+
* gets resolved to a specific SKU per variant on the line items).
|
|
22
|
+
* - {@link runProduction} — consume materials AND receive finished
|
|
23
|
+
* goods in one transaction. Use this when consume + produce should be
|
|
24
|
+
* jointly atomic (e.g. a make-to-stock workflow where the factory step
|
|
25
|
+
* is invisible). Calling `consumeMaterials` then `produceFinishedGoods`
|
|
26
|
+
* separately is NOT jointly atomic — each opens its own transaction
|
|
27
|
+
* and a failure between them can leave materials deducted with no
|
|
28
|
+
* finished SKU receipt to balance it.
|
|
29
|
+
*
|
|
30
|
+
* ## Location convention (explicit-arg design)
|
|
31
|
+
*
|
|
32
|
+
* The original design considered carrying `originLocationId` on a per-
|
|
33
|
+
* package mixin of `ProductionOrder`, but that adds a meta field to a
|
|
34
|
+
* model owned by a sibling package. The cleaner design — and the one
|
|
35
|
+
* shipped here — keeps the location explicit on the call:
|
|
36
|
+
*
|
|
37
|
+
* ```typescript
|
|
38
|
+
* await production.consumeMaterials(order, { locationId, qty });
|
|
39
|
+
* await production.produceFinishedGoods(order, { locationId, qty, finishedSkuId });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* Callers that want a "default factory" convention can stash the
|
|
43
|
+
* `locationId` on their own production-order helper or wrap this service
|
|
44
|
+
* with a thin domain-level façade.
|
|
45
|
+
*
|
|
46
|
+
* @packageDocumentation
|
|
47
|
+
*/
|
|
48
|
+
import type { DatabaseConfig } from '@happyvertical/smrt-core';
|
|
49
|
+
import type { StockMovementReason, StockService } from '@happyvertical/smrt-inventory';
|
|
50
|
+
import { BillOfMaterialsCollection } from '../collections/BillOfMaterialsCollection.js';
|
|
51
|
+
import { BomLineCollection } from '../collections/BomLineCollection.js';
|
|
52
|
+
import type { BomLine } from '../models/BomLine.js';
|
|
53
|
+
/**
|
|
54
|
+
* Minimal shape of a production order this service needs. We deliberately
|
|
55
|
+
* accept this structural type rather than importing the `ProductionOrder`
|
|
56
|
+
* class from `@happyvertical/smrt-commerce` — that would either pull a
|
|
57
|
+
* dep on commerce into manufacturing or force commerce to extend a
|
|
58
|
+
* manufacturing interface. Plain duck typing keeps the dependency arrow
|
|
59
|
+
* pointing the way the architecture asks for (manufacturing builds on
|
|
60
|
+
* inventory; commerce stays orthogonal).
|
|
61
|
+
*/
|
|
62
|
+
export interface ProductionOrderRef {
|
|
63
|
+
/** Production order row id. Used for `sourceId` on every movement. */
|
|
64
|
+
id?: string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Plain string reference to the upstream product the order is asked to
|
|
67
|
+
* produce. Used to look up the active BOM for the consume step.
|
|
68
|
+
*/
|
|
69
|
+
productId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Optional explicit BOM id. When set, {@link consumeMaterials} uses this
|
|
72
|
+
* row even if the product has a different `active` BOM — useful when an
|
|
73
|
+
* order was kicked off against a specific revision.
|
|
74
|
+
*/
|
|
75
|
+
bomId?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Per-call options for {@link ProductionService.consumeMaterials}.
|
|
79
|
+
*/
|
|
80
|
+
export interface ConsumeMaterialsOptions {
|
|
81
|
+
/**
|
|
82
|
+
* Inventory location id (warehouse / factory) where the materials are
|
|
83
|
+
* pulled from. Required because the production order itself does not
|
|
84
|
+
* carry a stocking location — see "Location convention" in the module
|
|
85
|
+
* doc.
|
|
86
|
+
*/
|
|
87
|
+
locationId: string;
|
|
88
|
+
/**
|
|
89
|
+
* Run quantity — how many finished units the BOM is being multiplied
|
|
90
|
+
* by. Each BOM line's `effectiveQtyPerUnit()` is multiplied by this
|
|
91
|
+
* number before being deducted from `available` stock.
|
|
92
|
+
*/
|
|
93
|
+
qty: number;
|
|
94
|
+
/**
|
|
95
|
+
* Optional override of the reason code stamped on each
|
|
96
|
+
* {@link StockMovement}. Defaults to `'production_consume'`.
|
|
97
|
+
*/
|
|
98
|
+
reasonCode?: StockMovementReason;
|
|
99
|
+
/**
|
|
100
|
+
* Optional free-form note attached to every emitted movement.
|
|
101
|
+
*/
|
|
102
|
+
note?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Per-call options for {@link ProductionService.produceFinishedGoods}.
|
|
106
|
+
*/
|
|
107
|
+
export interface ProduceFinishedGoodsOptions {
|
|
108
|
+
/**
|
|
109
|
+
* Inventory location id (warehouse / factory) where the finished goods
|
|
110
|
+
* land. Required for the same reason as {@link ConsumeMaterialsOptions.locationId}.
|
|
111
|
+
*/
|
|
112
|
+
locationId: string;
|
|
113
|
+
/**
|
|
114
|
+
* Quantity of finished goods produced. Always positive.
|
|
115
|
+
*/
|
|
116
|
+
qty: number;
|
|
117
|
+
/**
|
|
118
|
+
* The SKU id of the finished product to receive into `available`. The
|
|
119
|
+
* production order references a `productId` (a `Product` from
|
|
120
|
+
* `@happyvertical/smrt-products`), but a product typically has multiple
|
|
121
|
+
* SKUs (one per variant). The caller decides which concrete SKU each
|
|
122
|
+
* line of the run produces.
|
|
123
|
+
*/
|
|
124
|
+
finishedSkuId: string;
|
|
125
|
+
/**
|
|
126
|
+
* Optional override of the reason code stamped on the
|
|
127
|
+
* {@link StockMovement}. Defaults to `'production_produce'`.
|
|
128
|
+
*/
|
|
129
|
+
reasonCode?: StockMovementReason;
|
|
130
|
+
/**
|
|
131
|
+
* Optional free-form note attached to the emitted movement.
|
|
132
|
+
*/
|
|
133
|
+
note?: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Options accepted by {@link ProductionService.create}.
|
|
137
|
+
*
|
|
138
|
+
* Either pass a `db` for the service to construct its own
|
|
139
|
+
* collections + {@link StockService}, or share a pre-built `stockService`
|
|
140
|
+
* across subsystems.
|
|
141
|
+
*/
|
|
142
|
+
export type ProductionServiceOptions = {
|
|
143
|
+
db: DatabaseConfig;
|
|
144
|
+
stockService?: StockService;
|
|
145
|
+
} | {
|
|
146
|
+
stockService: StockService;
|
|
147
|
+
db?: DatabaseConfig;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* A single emitted stock movement, returned by
|
|
151
|
+
* {@link ProductionService.consumeMaterials} so callers can audit / log
|
|
152
|
+
* the impact of a production run without re-querying.
|
|
153
|
+
*/
|
|
154
|
+
export interface ConsumeResult {
|
|
155
|
+
/** Component SKU id whose stock was deducted. */
|
|
156
|
+
componentSkuId: string;
|
|
157
|
+
/** Quantity deducted (already inflated for waste). */
|
|
158
|
+
qty: number;
|
|
159
|
+
/** Location the stock was deducted from. */
|
|
160
|
+
locationId: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Result of {@link ProductionService.produceFinishedGoods}.
|
|
164
|
+
*/
|
|
165
|
+
export interface ProduceResult {
|
|
166
|
+
/** Finished SKU id whose stock increased. */
|
|
167
|
+
finishedSkuId: string;
|
|
168
|
+
/** Quantity received. */
|
|
169
|
+
qty: number;
|
|
170
|
+
/** Location the stock was received into. */
|
|
171
|
+
locationId: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Result of {@link ProductionService.runProduction} — the consume + produce
|
|
175
|
+
* pair, run inside one transaction.
|
|
176
|
+
*/
|
|
177
|
+
export interface RunProductionResult {
|
|
178
|
+
consumed: ConsumeResult[];
|
|
179
|
+
produced: ProduceResult;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Operational bridge between a production order and the inventory ledger.
|
|
183
|
+
*/
|
|
184
|
+
export declare class ProductionService {
|
|
185
|
+
/**
|
|
186
|
+
* BOM collection bound to the OUTER (non-tx) database. Used for
|
|
187
|
+
* pre-flight reads in `prepareConsume()` — those run before the
|
|
188
|
+
* stock-service transaction opens, by design (read-then-tx keeps
|
|
189
|
+
* the transaction window narrow and rollback only covers actual
|
|
190
|
+
* mutations). DO NOT add BOM writes that depend on the stock-tx
|
|
191
|
+
* rolling them back together — this collection is not tx-scoped
|
|
192
|
+
* and writes here would commit independently. If joint BOM-plus-
|
|
193
|
+
* stock mutations are ever needed, build tx-scoped BOM collections
|
|
194
|
+
* inside the `stockService.withTransaction` callback (mirror the
|
|
195
|
+
* pattern in StockService.withTransaction itself).
|
|
196
|
+
*/
|
|
197
|
+
readonly boms: BillOfMaterialsCollection;
|
|
198
|
+
/**
|
|
199
|
+
* BomLine collection bound to the OUTER database. Same caveat as
|
|
200
|
+
* {@link boms} — pre-flight reads only.
|
|
201
|
+
*/
|
|
202
|
+
readonly lines: BomLineCollection;
|
|
203
|
+
readonly stockService: StockService;
|
|
204
|
+
private constructor();
|
|
205
|
+
/** Factory — prefer {@link createProductionService}. */
|
|
206
|
+
static create(options: ProductionServiceOptions): Promise<ProductionService>;
|
|
207
|
+
/**
|
|
208
|
+
* Walk every BOM line for the production order's BOM and deduct
|
|
209
|
+
* `effectiveQtyPerUnit() * qty` from `available` at `locationId`. Each
|
|
210
|
+
* deduction goes through {@link StockService.adjust} with `sourceType:
|
|
211
|
+
* 'ProductionOrder'` and `sourceId: order.id`. Returns the list of
|
|
212
|
+
* movements emitted so callers can log / surface them.
|
|
213
|
+
*
|
|
214
|
+
* **Atomic across lines**: all per-line deductions and their audit
|
|
215
|
+
* movements run inside a single `stockService.withTransaction(...)`
|
|
216
|
+
* scope. An `InsufficientStockError` on line N+1 rolls back lines 1..N
|
|
217
|
+
* so production-order posting never leaves materials half-consumed.
|
|
218
|
+
* Pre-flight with {@link BomService.canProduce} when you'd rather know
|
|
219
|
+
* upfront than discover the shortfall mid-run.
|
|
220
|
+
*
|
|
221
|
+
* Throws {@link NoActiveBomForProductError} if no BOM id is supplied
|
|
222
|
+
* on the order *and* no active BOM exists for the order's `productId`.
|
|
223
|
+
* Throws {@link BomNotFoundError} if `order.bomId` is supplied but
|
|
224
|
+
* doesn't resolve. Throws plain `Error` on missing `locationId`,
|
|
225
|
+
* non-positive `qty`, or when both `order.bomId` and `order.productId`
|
|
226
|
+
* are absent (a programmer error — neither input identifies a BOM).
|
|
227
|
+
* Re-throws `InsufficientStockError` from `StockService.adjust` if a
|
|
228
|
+
* line would drive `available` below zero.
|
|
229
|
+
*/
|
|
230
|
+
consumeMaterials(order: ProductionOrderRef, options: ConsumeMaterialsOptions): Promise<ConsumeResult[]>;
|
|
231
|
+
/**
|
|
232
|
+
* Receive `qty` of the finished SKU into `available` at `locationId`.
|
|
233
|
+
* Goes through {@link StockService.receive} with `sourceType:
|
|
234
|
+
* 'ProductionOrder'` and `sourceId: order.id`. Returns a single
|
|
235
|
+
* {@link ProduceResult} describing what landed.
|
|
236
|
+
*
|
|
237
|
+
* Throws plain `Error` on missing required arguments or non-positive
|
|
238
|
+
* `qty`.
|
|
239
|
+
*/
|
|
240
|
+
produceFinishedGoods(order: ProductionOrderRef, options: ProduceFinishedGoodsOptions): Promise<ProduceResult>;
|
|
241
|
+
/**
|
|
242
|
+
* Atomically consume materials AND receive finished goods for one
|
|
243
|
+
* production run.
|
|
244
|
+
*
|
|
245
|
+
* Both calls share a single `stockService.withTransaction(...)` scope:
|
|
246
|
+
*
|
|
247
|
+
* - Materials are deducted line-by-line via {@link StockService.adjust}.
|
|
248
|
+
* - Finished goods are received via {@link StockService.receive}.
|
|
249
|
+
* - If ANY step throws — a BOM-line shortage, the produce-leg adapter
|
|
250
|
+
* failing, a tenancy mismatch surfaced by an interceptor — every
|
|
251
|
+
* write in the transaction rolls back. The materials are restored
|
|
252
|
+
* and the finished SKU's `available` row is unchanged. Callers
|
|
253
|
+
* never observe "materials deducted but finished goods missing".
|
|
254
|
+
*
|
|
255
|
+
* Use this when consume + produce should be one indivisible event —
|
|
256
|
+
* e.g. a make-to-stock workflow posting `production_order:completed`
|
|
257
|
+
* where the shop floor step is invisible to the ledger.
|
|
258
|
+
*
|
|
259
|
+
* The two-call form (call {@link consumeMaterials} then {@link
|
|
260
|
+
* produceFinishedGoods} separately) is still appropriate when the
|
|
261
|
+
* factory step is a real wall-clock gap that other observers need to
|
|
262
|
+
* see — work-in-progress dashboards, partial-run reporting, etc.
|
|
263
|
+
*
|
|
264
|
+
* Throws the same errors as the individual methods: missing args
|
|
265
|
+
* (plain `Error`), unresolvable BOM ({@link BomNotFoundError} /
|
|
266
|
+
* {@link NoActiveBomForProductError}), or `InsufficientStockError`
|
|
267
|
+
* if a line would drive `available` below zero.
|
|
268
|
+
*/
|
|
269
|
+
runProduction(order: ProductionOrderRef, options: {
|
|
270
|
+
consume: ConsumeMaterialsOptions;
|
|
271
|
+
produce: ProduceFinishedGoodsOptions;
|
|
272
|
+
}): Promise<RunProductionResult>;
|
|
273
|
+
/**
|
|
274
|
+
* Validate consume args, resolve the BOM + lines, and pre-compute the
|
|
275
|
+
* mutation attribution. Anything that can throw without a tx open
|
|
276
|
+
* happens here so the transaction we open later doesn't have to roll
|
|
277
|
+
* back over a validation miss.
|
|
278
|
+
*/
|
|
279
|
+
private prepareConsume;
|
|
280
|
+
/**
|
|
281
|
+
* Execute the consume leg against a caller-supplied tx-bound
|
|
282
|
+
* {@link StockService}. Public entry points (`consumeMaterials`,
|
|
283
|
+
* `runProduction`) open the tx and call through here. Each per-line
|
|
284
|
+
* `tx.adjust(...)` shares the same transaction so a shortfall on
|
|
285
|
+
* line N+1 rolls back lines 1..N.
|
|
286
|
+
*/
|
|
287
|
+
private consumeMaterialsWith;
|
|
288
|
+
/**
|
|
289
|
+
* Execute the produce leg against a caller-supplied tx-bound
|
|
290
|
+
* {@link StockService}. Public entry points (`produceFinishedGoods`,
|
|
291
|
+
* `runProduction`) open the tx and call through here.
|
|
292
|
+
*/
|
|
293
|
+
private produceFinishedGoodsWith;
|
|
294
|
+
/**
|
|
295
|
+
* Resolve the BOM for a production order. Order of preference:
|
|
296
|
+
*
|
|
297
|
+
* 1. Explicit `order.bomId` if supplied — the caller pinned a specific
|
|
298
|
+
* revision; we honor that pin or fail. We deliberately do NOT fall
|
|
299
|
+
* back to the active BOM when `order.bomId` is stale or mistyped,
|
|
300
|
+
* because silently switching recipes would have the production run
|
|
301
|
+
* consume materials against a different BOM than the order locked.
|
|
302
|
+
* 2. The active BOM for `order.productId`.
|
|
303
|
+
*
|
|
304
|
+
* Throws {@link BomNotFoundError} when an explicit `order.bomId` is
|
|
305
|
+
* supplied but doesn't resolve to a row.
|
|
306
|
+
*
|
|
307
|
+
* Throws {@link NoActiveBomForProductError} when no `bomId` was supplied
|
|
308
|
+
* and the product has no active BOM.
|
|
309
|
+
*
|
|
310
|
+
* Throws plain `Error` when neither `order.bomId` nor `order.productId`
|
|
311
|
+
* is supplied — there's nothing to resolve against, so we surface that
|
|
312
|
+
* as a programmer error with a distinct message rather than overload
|
|
313
|
+
* `NoActiveBomForProductError` with an empty product id.
|
|
314
|
+
*/
|
|
315
|
+
private resolveBom;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Convenience factory. Returns a fully-initialized {@link ProductionService}.
|
|
319
|
+
*/
|
|
320
|
+
export declare function createProductionService(options: ProductionServiceOptions): Promise<ProductionService>;
|
|
321
|
+
export type { BomLine };
|
|
322
|
+
//# sourceMappingURL=ProductionService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductionService.d.ts","sourceRoot":"","sources":["../../src/services/ProductionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in DispatchBus subscribers that bridge upstream production-order
|
|
3
|
+
* signals to {@link ProductionService}.
|
|
4
|
+
*
|
|
5
|
+
* **Off by default.** The package never auto-subscribes — consumer apps
|
|
6
|
+
* call {@link installManufacturingDispatchHandlers} from their `smrt.ts`
|
|
7
|
+
* wiring once they have decided they want a `production_order:posted`
|
|
8
|
+
* emit to consume materials and produce finished goods automatically.
|
|
9
|
+
*
|
|
10
|
+
* Two paired toggles let consumers wire only the legs they want:
|
|
11
|
+
*
|
|
12
|
+
* - `installProductionPosted` (default `true`) — on `production_order:posted`,
|
|
13
|
+
* call {@link ProductionService.consumeMaterials} once.
|
|
14
|
+
* - `installProductionCompleted` (default `false`) — on `production_order:completed`,
|
|
15
|
+
* call {@link ProductionService.produceFinishedGoods} once. Off by default
|
|
16
|
+
* because not every shop emits a separate "completed" event; lots of
|
|
17
|
+
* workflows expect consume + produce to happen atomically when the
|
|
18
|
+
* order is posted. Set both flags to `true` to get the split lifecycle.
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
import type { DatabaseConfig, DispatchBus } from '@happyvertical/smrt-core';
|
|
23
|
+
import type { StockService } from '@happyvertical/smrt-inventory';
|
|
24
|
+
import { type ProductionService } from './ProductionService.js';
|
|
25
|
+
/**
|
|
26
|
+
* Shape of a `production_order:posted` payload this handler expects.
|
|
27
|
+
*
|
|
28
|
+
* The producer (typically the application's smrt.ts wiring once a
|
|
29
|
+
* `ProductionOrder` row transitions to the posted state) packs one
|
|
30
|
+
* payload per posted order. The handler consumes materials for every
|
|
31
|
+
* unit declared by `qty`, attributed to `('ProductionOrder', productionOrderId)`
|
|
32
|
+
* on each emitted {@link StockMovement}.
|
|
33
|
+
*/
|
|
34
|
+
export interface ProductionOrderPostedPayload {
|
|
35
|
+
/** Production order row id. Used for `sourceId` on every movement. */
|
|
36
|
+
productionOrderId: string;
|
|
37
|
+
/**
|
|
38
|
+
* Plain string reference to the upstream product the order is asked to
|
|
39
|
+
* produce. Used to resolve the active BOM at consume time.
|
|
40
|
+
*/
|
|
41
|
+
productId: string;
|
|
42
|
+
/**
|
|
43
|
+
* Inventory location id (factory / warehouse) where materials are
|
|
44
|
+
* pulled from.
|
|
45
|
+
*/
|
|
46
|
+
locationId: string;
|
|
47
|
+
/**
|
|
48
|
+
* Run quantity. Each BOM line's effective qty is multiplied by this
|
|
49
|
+
* before being deducted from `available`.
|
|
50
|
+
*/
|
|
51
|
+
qty: number;
|
|
52
|
+
/**
|
|
53
|
+
* Optional explicit BOM id, e.g. when the order locked itself to a
|
|
54
|
+
* specific BOM revision when it was created. Falls back to the active
|
|
55
|
+
* BOM for `productId` if omitted.
|
|
56
|
+
*/
|
|
57
|
+
bomId?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Optional finished SKU id. When provided AND the
|
|
60
|
+
* `installProductionPosted` handler is wired to also produce in one
|
|
61
|
+
* shot (which only happens when `installProductionCompleted` is false
|
|
62
|
+
* and `producedOnPosted` is true), this is the SKU to receive into
|
|
63
|
+
* `available`.
|
|
64
|
+
*/
|
|
65
|
+
finishedSkuId?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Shape of a `production_order:completed` payload this handler expects.
|
|
69
|
+
*
|
|
70
|
+
* Typically emitted when the factory signs off the run and finished
|
|
71
|
+
* goods are physically available to ship. Only used when callers opt in
|
|
72
|
+
* via `installProductionCompleted`.
|
|
73
|
+
*/
|
|
74
|
+
export interface ProductionOrderCompletedPayload {
|
|
75
|
+
/** Production order row id. Used for `sourceId` on the receipt movement. */
|
|
76
|
+
productionOrderId: string;
|
|
77
|
+
/**
|
|
78
|
+
* SKU id of the finished product to receive into `available`. Required.
|
|
79
|
+
*/
|
|
80
|
+
finishedSkuId: string;
|
|
81
|
+
/** Inventory location id where the finished goods land. */
|
|
82
|
+
locationId: string;
|
|
83
|
+
/** Quantity received. */
|
|
84
|
+
qty: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Options accepted by {@link installManufacturingDispatchHandlers}.
|
|
88
|
+
*
|
|
89
|
+
* Provide either a pre-built {@link ProductionService} (when sharing
|
|
90
|
+
* across subsystems) or a `db` / `stockService` for the helper to
|
|
91
|
+
* construct one on first use.
|
|
92
|
+
*/
|
|
93
|
+
export type InstallManufacturingDispatchHandlersOptions = {
|
|
94
|
+
/** Bus to subscribe on. Typically the app-wide DispatchBus. */
|
|
95
|
+
dispatchBus: DispatchBus;
|
|
96
|
+
/**
|
|
97
|
+
* When `true` (default), install the `production_order:posted` handler.
|
|
98
|
+
*/
|
|
99
|
+
installProductionPosted?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* When `true` (default `false`), install the
|
|
102
|
+
* `production_order:completed` handler. Off by default because many
|
|
103
|
+
* workflows want consume+produce to happen on `posted`; opt in to the
|
|
104
|
+
* split lifecycle when your shop emits a separate completion event.
|
|
105
|
+
*/
|
|
106
|
+
installProductionCompleted?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* When `true` (default `false`) AND `installProductionCompleted` is
|
|
109
|
+
* false, the `production_order:posted` handler also calls
|
|
110
|
+
* {@link ProductionService.produceFinishedGoods} after consume —
|
|
111
|
+
* handy for "make-to-stock instantly" workflows where the factory
|
|
112
|
+
* step is invisible.
|
|
113
|
+
*
|
|
114
|
+
* Ignored when `installProductionCompleted` is `true` (in that case
|
|
115
|
+
* production is the completed-handler's job).
|
|
116
|
+
*/
|
|
117
|
+
producedOnPosted?: boolean;
|
|
118
|
+
} & ({
|
|
119
|
+
productionService: ProductionService;
|
|
120
|
+
db?: DatabaseConfig;
|
|
121
|
+
stockService?: StockService;
|
|
122
|
+
} | {
|
|
123
|
+
stockService: StockService;
|
|
124
|
+
db?: DatabaseConfig;
|
|
125
|
+
productionService?: undefined;
|
|
126
|
+
} | {
|
|
127
|
+
db: DatabaseConfig;
|
|
128
|
+
stockService?: undefined;
|
|
129
|
+
productionService?: undefined;
|
|
130
|
+
});
|
|
131
|
+
/**
|
|
132
|
+
* Result handle returned by {@link installManufacturingDispatchHandlers}.
|
|
133
|
+
* Call `dispose()` to detach the subscribers (mainly useful in tests and
|
|
134
|
+
* on graceful shutdown).
|
|
135
|
+
*/
|
|
136
|
+
export interface InstalledManufacturingDispatchHandlers {
|
|
137
|
+
/** Resolved ProductionService — useful for follow-up writes in the same scope. */
|
|
138
|
+
productionService: ProductionService;
|
|
139
|
+
/** Detach every installed subscriber. Idempotent. */
|
|
140
|
+
dispose(): void;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Subscribe production-order handlers to the given DispatchBus.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* import { createDispatchBus } from '@happyvertical/smrt-core';
|
|
148
|
+
* import { installManufacturingDispatchHandlers } from '@happyvertical/smrt-manufacturing';
|
|
149
|
+
*
|
|
150
|
+
* const bus = await createDispatchBus({ db });
|
|
151
|
+
* const handlers = await installManufacturingDispatchHandlers({
|
|
152
|
+
* dispatchBus: bus,
|
|
153
|
+
* db,
|
|
154
|
+
* producedOnPosted: true, // consume + produce in one shot
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export declare function installManufacturingDispatchHandlers(options: InstallManufacturingDispatchHandlersOptions): Promise<InstalledManufacturingDispatchHandlers>;
|
|
159
|
+
//# sourceMappingURL=dispatch-handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-handlers.d.ts","sourceRoot":"","sources":["../../src/services/dispatch-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EAGZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAIhC;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA4B;IAC3C,sEAAsE;IACtE,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC9C,4EAA4E;IAC5E,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,MAAM,MAAM,2CAA2C,GAAG;IACxD,+DAA+D;IAC/D,WAAW,EAAE,WAAW,CAAC;IACzB;;OAEG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,CACA;IACE,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,GACD;IACE,YAAY,EAAE,YAAY,CAAC;IAC3B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,iBAAiB,CAAC,EAAE,SAAS,CAAC;CAC/B,GACD;IACE,EAAE,EAAE,cAAc,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,iBAAiB,CAAC,EAAE,SAAS,CAAC;CAC/B,CACJ,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,sCAAsC;IACrD,kFAAkF;IAClF,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,qDAAqD;IACrD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oCAAoC,CACxD,OAAO,EAAE,2CAA2C,GACnD,OAAO,CAAC,sCAAsC,CAAC,CAiDjD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service exports for `@happyvertical/smrt-manufacturing`.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { BomService, type BomServiceOptions, type ComponentCostResolver, createBomService, } from './BomService.js';
|
|
7
|
+
export { type InstalledManufacturingDispatchHandlers, type InstallManufacturingDispatchHandlersOptions, installManufacturingDispatchHandlers, type ProductionOrderCompletedPayload, type ProductionOrderPostedPayload, } from './dispatch-handlers.js';
|
|
8
|
+
export { type ConsumeMaterialsOptions, type ConsumeResult, createProductionService, type ProduceFinishedGoodsOptions, type ProduceResult, type ProductionOrderRef, ProductionService, type ProductionServiceOptions, } from './ProductionService.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,sCAAsC,EAC3C,KAAK,2CAA2C,EAChD,oCAAoC,EACpC,KAAK,+BAA+B,EACpC,KAAK,4BAA4B,GAClC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,uBAAuB,EACvB,KAAK,2BAA2B,EAChC,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,wBAAwB,CAAC"}
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-manufacturing",
|
|
6
|
-
"packageVersion": "0.51.
|
|
6
|
+
"packageVersion": "0.51.34",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
10
|
+
"manifest": "fdb5cf2122ae64bdea9eec900e45aca70122fd89a87e2590b89fd2562d54d1f7",
|
|
11
|
+
"packageJson": "51d5869d98fc7de6a54d1a327f63f5940e424ba0f9a4154f6c254f250b12e740",
|
|
12
12
|
"agents": "94d10408c859743730368f932f77e5602ebefb8fe9a8ac3178fa4b211e95ad29"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@happyvertical/sql": "catalog:",
|
|
25
25
|
"@happyvertical/smrt-vitest": "workspace:*",
|
|
26
26
|
"@types/node": "24.13.6",
|
|
27
|
-
"typescript": "
|
|
27
|
+
"typescript": "6.0.3",
|
|
28
28
|
"vite": "8.1.4",
|
|
29
29
|
"vitest": "4.1.10"
|
|
30
30
|
},
|