@unifiedcommerce/plugin-production 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ export type { Db } from "./types";
2
+ export { ProductionService } from "./services/production-service";
3
+ export { ProductionOrderService } from "./services/production-order-service";
4
+ export declare function productionPlugin(): import("@unifiedcommerce/core").CommercePlugin;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,wBAAgB,gBAAgB,mDAqB/B"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { defineCommercePlugin } from "@unifiedcommerce/core";
2
+ import { productionBoms, productionBomItems, productionOrders, productionConsumption } from "./schema";
3
+ import { ProductionService } from "./services/production-service";
4
+ import { ProductionOrderService } from "./services/production-order-service";
5
+ import { buildProductionRoutes } from "./routes/production";
6
+ export { ProductionService } from "./services/production-service";
7
+ export { ProductionOrderService } from "./services/production-order-service";
8
+ export function productionPlugin() {
9
+ return defineCommercePlugin({
10
+ id: "production",
11
+ version: "1.0.0",
12
+ permissions: [
13
+ { scope: "production:admin", description: "Create/edit BOMs, cost rollup, cancel orders." },
14
+ { scope: "production:create", description: "Create and manage production orders." },
15
+ { scope: "production:read", description: "View BOMs, orders, and BOM explosion." },
16
+ ],
17
+ schema: () => ({ productionBoms, productionBomItems, productionOrders, productionConsumption }),
18
+ hooks: () => [],
19
+ routes: (ctx) => {
20
+ const db = ctx.database.db;
21
+ if (!db)
22
+ return [];
23
+ return buildProductionRoutes(new ProductionService(db), new ProductionOrderService(db), ctx);
24
+ },
25
+ });
26
+ }
@@ -0,0 +1,10 @@
1
+ import type { ProductionService } from "../services/production-service";
2
+ import type { ProductionOrderService } from "../services/production-order-service";
3
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
4
+ export declare function buildProductionRoutes(bomSvc: ProductionService, orderSvc: ProductionOrderService, ctx: {
5
+ services?: Record<string, unknown>;
6
+ database?: {
7
+ db: unknown;
8
+ };
9
+ }): PluginRouteRegistration[];
10
+ //# sourceMappingURL=production.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"production.d.ts","sourceRoot":"","sources":["../../src/routes/production.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,sBAAsB,EAChC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAuK3B"}
@@ -0,0 +1,156 @@
1
+ import { router } from "@unifiedcommerce/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildProductionRoutes(bomSvc, orderSvc, ctx) {
4
+ const r = router("Production", "/production", ctx);
5
+ // --- BOM Routes ---
6
+ r.post("/boms").summary("Create BOM").permission("production:admin")
7
+ .input(z.object({
8
+ entityId: z.string().uuid(),
9
+ name: z.string().min(1),
10
+ yieldQuantity: z.number().int().positive().optional(),
11
+ yieldUomId: z.string().uuid().optional(),
12
+ level: z.number().int().min(0).optional(),
13
+ items: z.array(z.object({
14
+ entityId: z.string().uuid(),
15
+ itemName: z.string().min(1),
16
+ quantity: z.number().int().positive(),
17
+ unitCost: z.number().int().min(0),
18
+ uomId: z.string().uuid().optional(),
19
+ isSubAssembly: z.boolean().optional(),
20
+ subBomId: z.string().uuid().optional(),
21
+ })).min(1),
22
+ }))
23
+ .handler(async ({ input, orgId }) => {
24
+ const body = input;
25
+ const result = await bomSvc.createBOM(orgId, body);
26
+ if (!result.ok)
27
+ throw new Error(result.error);
28
+ return result.value;
29
+ });
30
+ r.get("/boms").summary("List BOMs").permission("production:read")
31
+ .handler(async ({ orgId }) => {
32
+ const result = await bomSvc.listBOMs(orgId);
33
+ if (!result.ok)
34
+ throw new Error(result.error);
35
+ return result.value;
36
+ });
37
+ r.get("/boms/{id}").summary("Get BOM").permission("production:read")
38
+ .handler(async ({ params, orgId }) => {
39
+ const result = await bomSvc.getBOM(orgId, params.id);
40
+ if (!result.ok)
41
+ throw new Error(result.error);
42
+ return result.value;
43
+ });
44
+ r.post("/boms/{id}/items").summary("Add item to BOM").permission("production:admin")
45
+ .input(z.object({
46
+ entityId: z.string().uuid(),
47
+ itemName: z.string().min(1),
48
+ quantity: z.number().int().positive(),
49
+ unitCost: z.number().int().min(0),
50
+ uomId: z.string().uuid().optional(),
51
+ isSubAssembly: z.boolean().optional(),
52
+ subBomId: z.string().uuid().optional(),
53
+ }))
54
+ .handler(async ({ params, input, orgId }) => {
55
+ const body = input;
56
+ const result = await bomSvc.addBOMItem(orgId, params.id, body);
57
+ if (!result.ok)
58
+ throw new Error(result.error);
59
+ return result.value;
60
+ });
61
+ r.post("/boms/{id}/cost-rollup").summary("Cost rollup").permission("production:admin")
62
+ .handler(async ({ params, orgId }) => {
63
+ const result = await bomSvc.costRollup(orgId, params.id);
64
+ if (!result.ok)
65
+ throw new Error(result.error);
66
+ return result.value;
67
+ });
68
+ r.post("/boms/{id}/explode").summary("BOM explosion").permission("production:read")
69
+ .input(z.object({ quantity: z.number().int().positive() }))
70
+ .handler(async ({ params, input, orgId }) => {
71
+ const body = input;
72
+ const result = await bomSvc.explode(orgId, params.id, body.quantity);
73
+ if (!result.ok)
74
+ throw new Error(result.error);
75
+ return result.value;
76
+ });
77
+ // --- Production Order Routes ---
78
+ r.post("/orders").summary("Create production order").permission("production:create")
79
+ .input(z.object({
80
+ bomId: z.string().uuid(),
81
+ entityId: z.string().uuid(),
82
+ quantity: z.number().int().positive(),
83
+ warehouseId: z.string().uuid(),
84
+ plannedDate: z.string(),
85
+ notes: z.string().optional(),
86
+ }))
87
+ .handler(async ({ input, orgId }) => {
88
+ const body = input;
89
+ const result = await orderSvc.create(orgId, {
90
+ ...body,
91
+ plannedDate: new Date(body.plannedDate),
92
+ });
93
+ if (!result.ok)
94
+ throw new Error(result.error);
95
+ return result.value;
96
+ });
97
+ r.get("/orders").summary("List production orders").permission("production:read")
98
+ .query(z.object({ status: z.enum(["planned", "in_progress", "completed", "cancelled"]).optional() }))
99
+ .handler(async ({ query, orgId }) => {
100
+ const q = query;
101
+ const result = await orderSvc.list(orgId, q.status);
102
+ if (!result.ok)
103
+ throw new Error(result.error);
104
+ return result.value;
105
+ });
106
+ r.get("/orders/{id}").summary("Get production order").permission("production:read")
107
+ .handler(async ({ params, orgId }) => {
108
+ const result = await orderSvc.getById(orgId, params.id);
109
+ if (!result.ok)
110
+ throw new Error(result.error);
111
+ return result.value;
112
+ });
113
+ r.post("/orders/{id}/start").summary("Start production order").permission("production:create")
114
+ .input(z.object({ producedBy: z.string().min(1) }))
115
+ .handler(async ({ params, input, orgId }) => {
116
+ const body = input;
117
+ const result = await orderSvc.start(orgId, params.id, body.producedBy);
118
+ if (!result.ok)
119
+ throw new Error(result.error);
120
+ return result.value;
121
+ });
122
+ r.post("/orders/{id}/consume").summary("Record consumption").permission("production:create")
123
+ .input(z.object({
124
+ items: z.array(z.object({
125
+ entityId: z.string().uuid(),
126
+ variantId: z.string().uuid().optional(),
127
+ plannedQuantity: z.number().int().min(0),
128
+ actualQuantity: z.number().int().min(0),
129
+ uomId: z.string().uuid().optional(),
130
+ unitCost: z.number().int().min(0),
131
+ batchNumber: z.string().optional(),
132
+ })).min(1),
133
+ }))
134
+ .handler(async ({ params, input, orgId }) => {
135
+ const body = input;
136
+ const result = await orderSvc.recordConsumption(orgId, params.id, body.items);
137
+ if (!result.ok)
138
+ throw new Error(result.error);
139
+ return result.value;
140
+ });
141
+ r.post("/orders/{id}/complete").summary("Complete production order").permission("production:create")
142
+ .handler(async ({ params, orgId }) => {
143
+ const result = await orderSvc.complete(orgId, params.id);
144
+ if (!result.ok)
145
+ throw new Error(result.error);
146
+ return result.value;
147
+ });
148
+ r.post("/orders/{id}/cancel").summary("Cancel production order").permission("production:admin")
149
+ .handler(async ({ params, orgId }) => {
150
+ const result = await orderSvc.cancel(orgId, params.id);
151
+ if (!result.ok)
152
+ throw new Error(result.error);
153
+ return result.value;
154
+ });
155
+ return r.routes();
156
+ }