@tailor-platform/erp-kit 0.5.1 → 0.6.0

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 (251) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli.mjs +103 -23
  3. package/package.json +1 -1
  4. package/skills/erp-kit-app-5-impl-backend/SKILL.md +7 -4
  5. package/skills/erp-kit-app-7-impl-review/SKILL.md +1 -1
  6. package/skills/erp-kit-module-6-impl-review/SKILL.md +39 -17
  7. package/src/commands/generate-doc.ts +1 -1
  8. package/src/commands/lib/discovery.test.ts +13 -3
  9. package/src/commands/lib/discovery.ts +10 -2
  10. package/src/commands/lib/paths.ts +4 -2
  11. package/src/commands/lib/sync-check-tests.test.ts +84 -6
  12. package/src/commands/lib/sync-check-tests.ts +63 -3
  13. package/src/commands/sync-check.ts +7 -3
  14. package/src/generator/generate-app-code.ts +51 -16
  15. package/src/generator/generate-stubs.ts +4 -0
  16. package/src/generator/stub-templates.test.ts +11 -0
  17. package/src/generator/stub-templates.ts +22 -1
  18. package/src/modules/inventory/docs/features/inventory-adjustment.md +2 -1
  19. package/src/modules/inventory/docs/features/scrap-management.md +39 -1
  20. package/src/modules/manufacturing/README.md +63 -0
  21. package/src/modules/manufacturing/command/.gitkeep +0 -0
  22. package/src/modules/manufacturing/command/activateBillOfMaterial.generated.ts +6 -0
  23. package/src/modules/manufacturing/command/activateBillOfMaterial.test.ts +166 -0
  24. package/src/modules/manufacturing/command/activateBillOfMaterial.ts +173 -0
  25. package/src/modules/manufacturing/command/activateRouting.generated.ts +6 -0
  26. package/src/modules/manufacturing/command/activateRouting.test.ts +152 -0
  27. package/src/modules/manufacturing/command/activateRouting.ts +92 -0
  28. package/src/modules/manufacturing/command/activateWorkCenter.generated.ts +6 -0
  29. package/src/modules/manufacturing/command/activateWorkCenter.test.ts +135 -0
  30. package/src/modules/manufacturing/command/activateWorkCenter.ts +91 -0
  31. package/src/modules/manufacturing/command/cancelProductionOrder.generated.ts +6 -0
  32. package/src/modules/manufacturing/command/cancelProductionOrder.test.ts +151 -0
  33. package/src/modules/manufacturing/command/cancelProductionOrder.ts +114 -0
  34. package/src/modules/manufacturing/command/closeProductionOrder.generated.ts +6 -0
  35. package/src/modules/manufacturing/command/closeProductionOrder.test.ts +126 -0
  36. package/src/modules/manufacturing/command/closeProductionOrder.ts +87 -0
  37. package/src/modules/manufacturing/command/completeProductionOrder.generated.ts +6 -0
  38. package/src/modules/manufacturing/command/completeProductionOrder.test.ts +132 -0
  39. package/src/modules/manufacturing/command/completeProductionOrder.ts +97 -0
  40. package/src/modules/manufacturing/command/completeWorkOrder.generated.ts +6 -0
  41. package/src/modules/manufacturing/command/completeWorkOrder.test.ts +369 -0
  42. package/src/modules/manufacturing/command/completeWorkOrder.ts +212 -0
  43. package/src/modules/manufacturing/command/createBillOfMaterial.generated.ts +6 -0
  44. package/src/modules/manufacturing/command/createBillOfMaterial.test.ts +210 -0
  45. package/src/modules/manufacturing/command/createBillOfMaterial.ts +176 -0
  46. package/src/modules/manufacturing/command/createProductionOrder.generated.ts +6 -0
  47. package/src/modules/manufacturing/command/createProductionOrder.test.ts +160 -0
  48. package/src/modules/manufacturing/command/createProductionOrder.ts +129 -0
  49. package/src/modules/manufacturing/command/createRouting.generated.ts +6 -0
  50. package/src/modules/manufacturing/command/createRouting.test.ts +168 -0
  51. package/src/modules/manufacturing/command/createRouting.ts +128 -0
  52. package/src/modules/manufacturing/command/createWorkCenter.generated.ts +6 -0
  53. package/src/modules/manufacturing/command/createWorkCenter.test.ts +148 -0
  54. package/src/modules/manufacturing/command/createWorkCenter.ts +131 -0
  55. package/src/modules/manufacturing/command/deactivateBillOfMaterial.generated.ts +6 -0
  56. package/src/modules/manufacturing/command/deactivateBillOfMaterial.test.ts +103 -0
  57. package/src/modules/manufacturing/command/deactivateBillOfMaterial.ts +78 -0
  58. package/src/modules/manufacturing/command/deactivateRouting.generated.ts +6 -0
  59. package/src/modules/manufacturing/command/deactivateRouting.test.ts +112 -0
  60. package/src/modules/manufacturing/command/deactivateRouting.ts +76 -0
  61. package/src/modules/manufacturing/command/deactivateWorkCenter.generated.ts +6 -0
  62. package/src/modules/manufacturing/command/deactivateWorkCenter.test.ts +113 -0
  63. package/src/modules/manufacturing/command/deactivateWorkCenter.ts +85 -0
  64. package/src/modules/manufacturing/command/pauseWorkOrder.generated.ts +6 -0
  65. package/src/modules/manufacturing/command/pauseWorkOrder.test.ts +118 -0
  66. package/src/modules/manufacturing/command/pauseWorkOrder.ts +82 -0
  67. package/src/modules/manufacturing/command/recordInventoryIssueOutcome.generated.ts +6 -0
  68. package/src/modules/manufacturing/command/recordInventoryIssueOutcome.test.ts +183 -0
  69. package/src/modules/manufacturing/command/recordInventoryIssueOutcome.ts +139 -0
  70. package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.generated.ts +6 -0
  71. package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.test.ts +120 -0
  72. package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.ts +110 -0
  73. package/src/modules/manufacturing/command/releaseProductionOrder.generated.ts +6 -0
  74. package/src/modules/manufacturing/command/releaseProductionOrder.test.ts +220 -0
  75. package/src/modules/manufacturing/command/releaseProductionOrder.ts +450 -0
  76. package/src/modules/manufacturing/command/reopenProductionOrder.generated.ts +6 -0
  77. package/src/modules/manufacturing/command/reopenProductionOrder.test.ts +196 -0
  78. package/src/modules/manufacturing/command/reopenProductionOrder.ts +98 -0
  79. package/src/modules/manufacturing/command/reportWorkOrderProgress.generated.ts +6 -0
  80. package/src/modules/manufacturing/command/reportWorkOrderProgress.test.ts +204 -0
  81. package/src/modules/manufacturing/command/reportWorkOrderProgress.ts +129 -0
  82. package/src/modules/manufacturing/command/rescheduleProductionOrder.generated.ts +6 -0
  83. package/src/modules/manufacturing/command/rescheduleProductionOrder.test.ts +185 -0
  84. package/src/modules/manufacturing/command/rescheduleProductionOrder.ts +95 -0
  85. package/src/modules/manufacturing/command/resumeWorkOrder.generated.ts +6 -0
  86. package/src/modules/manufacturing/command/resumeWorkOrder.test.ts +122 -0
  87. package/src/modules/manufacturing/command/resumeWorkOrder.ts +94 -0
  88. package/src/modules/manufacturing/command/reviewManufacturingCostSummary.generated.ts +6 -0
  89. package/src/modules/manufacturing/command/reviewManufacturingCostSummary.test.ts +231 -0
  90. package/src/modules/manufacturing/command/reviewManufacturingCostSummary.ts +137 -0
  91. package/src/modules/manufacturing/command/startWorkOrder.generated.ts +6 -0
  92. package/src/modules/manufacturing/command/startWorkOrder.test.ts +118 -0
  93. package/src/modules/manufacturing/command/startWorkOrder.ts +126 -0
  94. package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.generated.ts +6 -0
  95. package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.test.ts +153 -0
  96. package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.ts +106 -0
  97. package/src/modules/manufacturing/command/unreleaseProductionOrder.generated.ts +6 -0
  98. package/src/modules/manufacturing/command/unreleaseProductionOrder.test.ts +140 -0
  99. package/src/modules/manufacturing/command/unreleaseProductionOrder.ts +131 -0
  100. package/src/modules/manufacturing/command/updateBillOfMaterial.generated.ts +6 -0
  101. package/src/modules/manufacturing/command/updateBillOfMaterial.test.ts +149 -0
  102. package/src/modules/manufacturing/command/updateBillOfMaterial.ts +174 -0
  103. package/src/modules/manufacturing/command/updateProductionOrder.generated.ts +6 -0
  104. package/src/modules/manufacturing/command/updateProductionOrder.test.ts +112 -0
  105. package/src/modules/manufacturing/command/updateProductionOrder.ts +145 -0
  106. package/src/modules/manufacturing/command/updateRouting.generated.ts +6 -0
  107. package/src/modules/manufacturing/command/updateRouting.test.ts +211 -0
  108. package/src/modules/manufacturing/command/updateRouting.ts +124 -0
  109. package/src/modules/manufacturing/command/updateWorkCenter.generated.ts +6 -0
  110. package/src/modules/manufacturing/command/updateWorkCenter.test.ts +152 -0
  111. package/src/modules/manufacturing/command/updateWorkCenter.ts +137 -0
  112. package/src/modules/manufacturing/db/.gitkeep +0 -0
  113. package/src/modules/manufacturing/db/billOfMaterial.ts +70 -0
  114. package/src/modules/manufacturing/db/billOfMaterialLine.ts +49 -0
  115. package/src/modules/manufacturing/db/costVarianceLine.ts +53 -0
  116. package/src/modules/manufacturing/db/manufacturingCostLine.ts +35 -0
  117. package/src/modules/manufacturing/db/manufacturingCostSettlementRecord.ts +39 -0
  118. package/src/modules/manufacturing/db/manufacturingCostSummary.ts +59 -0
  119. package/src/modules/manufacturing/db/productionOrder.ts +83 -0
  120. package/src/modules/manufacturing/db/productionOrderBomSnapshot.ts +44 -0
  121. package/src/modules/manufacturing/db/productionOrderCostBaseline.ts +44 -0
  122. package/src/modules/manufacturing/db/productionOrderMaterialRequirement.ts +57 -0
  123. package/src/modules/manufacturing/db/productionOrderRoutingSnapshot.ts +43 -0
  124. package/src/modules/manufacturing/db/routing.ts +63 -0
  125. package/src/modules/manufacturing/db/routingOperation.ts +57 -0
  126. package/src/modules/manufacturing/db/workCenter.ts +87 -0
  127. package/src/modules/manufacturing/db/workOrder.ts +65 -0
  128. package/src/modules/manufacturing/db/workOrderExecutionEvent.ts +54 -0
  129. package/src/modules/manufacturing/docs/commands/ActivateBillOfMaterial.md +50 -0
  130. package/src/modules/manufacturing/docs/commands/ActivateRouting.md +48 -0
  131. package/src/modules/manufacturing/docs/commands/ActivateWorkCenter.md +49 -0
  132. package/src/modules/manufacturing/docs/commands/CancelProductionOrder.md +48 -0
  133. package/src/modules/manufacturing/docs/commands/CloseProductionOrder.md +46 -0
  134. package/src/modules/manufacturing/docs/commands/CompleteProductionOrder.md +48 -0
  135. package/src/modules/manufacturing/docs/commands/CompleteWorkOrder.md +66 -0
  136. package/src/modules/manufacturing/docs/commands/CreateBillOfMaterial.md +54 -0
  137. package/src/modules/manufacturing/docs/commands/CreateProductionOrder.md +49 -0
  138. package/src/modules/manufacturing/docs/commands/CreateRouting.md +50 -0
  139. package/src/modules/manufacturing/docs/commands/CreateWorkCenter.md +51 -0
  140. package/src/modules/manufacturing/docs/commands/DeactivateBillOfMaterial.md +45 -0
  141. package/src/modules/manufacturing/docs/commands/DeactivateRouting.md +45 -0
  142. package/src/modules/manufacturing/docs/commands/DeactivateWorkCenter.md +45 -0
  143. package/src/modules/manufacturing/docs/commands/PauseWorkOrder.md +44 -0
  144. package/src/modules/manufacturing/docs/commands/RecordInventoryIssueOutcome.md +59 -0
  145. package/src/modules/manufacturing/docs/commands/RecordManufacturingCostSettlementAcknowledgment.md +49 -0
  146. package/src/modules/manufacturing/docs/commands/ReleaseProductionOrder.md +57 -0
  147. package/src/modules/manufacturing/docs/commands/ReopenProductionOrder.md +54 -0
  148. package/src/modules/manufacturing/docs/commands/ReportWorkOrderProgress.md +53 -0
  149. package/src/modules/manufacturing/docs/commands/RescheduleProductionOrder.md +45 -0
  150. package/src/modules/manufacturing/docs/commands/ResumeWorkOrder.md +44 -0
  151. package/src/modules/manufacturing/docs/commands/ReviewManufacturingCostSummary.md +52 -0
  152. package/src/modules/manufacturing/docs/commands/StartWorkOrder.md +46 -0
  153. package/src/modules/manufacturing/docs/commands/TechnicallyCompleteProductionOrder.md +51 -0
  154. package/src/modules/manufacturing/docs/commands/UnreleaseProductionOrder.md +46 -0
  155. package/src/modules/manufacturing/docs/commands/UpdateBillOfMaterial.md +48 -0
  156. package/src/modules/manufacturing/docs/commands/UpdateProductionOrder.md +48 -0
  157. package/src/modules/manufacturing/docs/commands/UpdateRouting.md +52 -0
  158. package/src/modules/manufacturing/docs/commands/UpdateWorkCenter.md +48 -0
  159. package/src/modules/manufacturing/docs/features/bill-of-material-management.md +83 -0
  160. package/src/modules/manufacturing/docs/features/manufacturing-cost-and-variance.md +191 -0
  161. package/src/modules/manufacturing/docs/features/production-order-lifecycle.md +103 -0
  162. package/src/modules/manufacturing/docs/features/routing-and-work-center-definition.md +63 -0
  163. package/src/modules/manufacturing/docs/features/work-order-execution.md +115 -0
  164. package/src/modules/manufacturing/docs/models/BillOfMaterial.md +60 -0
  165. package/src/modules/manufacturing/docs/models/ManufacturingCostSummary.md +66 -0
  166. package/src/modules/manufacturing/docs/models/ProductionOrder.md +76 -0
  167. package/src/modules/manufacturing/docs/models/Routing.md +58 -0
  168. package/src/modules/manufacturing/docs/models/WorkCenter.md +56 -0
  169. package/src/modules/manufacturing/docs/models/WorkOrder.md +63 -0
  170. package/src/modules/manufacturing/docs/queries/DetectBillOfMaterialCircularReference.md +39 -0
  171. package/src/modules/manufacturing/docs/queries/ExplodeBillOfMaterial.md +56 -0
  172. package/src/modules/manufacturing/docs/queries/GetBillOfMaterial.md +37 -0
  173. package/src/modules/manufacturing/docs/queries/GetManufacturingCostSummary.md +39 -0
  174. package/src/modules/manufacturing/docs/queries/GetProductionOrder.md +37 -0
  175. package/src/modules/manufacturing/docs/queries/GetRouting.md +39 -0
  176. package/src/modules/manufacturing/docs/queries/GetWorkCenter.md +35 -0
  177. package/src/modules/manufacturing/docs/queries/GetWorkOrder.md +38 -0
  178. package/src/modules/manufacturing/docs/queries/ListBillOfMaterialsByItem.md +42 -0
  179. package/src/modules/manufacturing/docs/queries/ListManufacturingCostSummariesByStatus.md +41 -0
  180. package/src/modules/manufacturing/docs/queries/ListProductionOrdersByStatus.md +41 -0
  181. package/src/modules/manufacturing/docs/queries/ListRoutingsByItem.md +42 -0
  182. package/src/modules/manufacturing/docs/queries/ListWorkCentersBySite.md +38 -0
  183. package/src/modules/manufacturing/docs/queries/ListWorkOrdersByProductionOrder.md +39 -0
  184. package/src/modules/manufacturing/docs/queries/ListWorkOrdersByWorkCenter.md +43 -0
  185. package/src/modules/manufacturing/executor/.gitkeep +0 -0
  186. package/src/modules/manufacturing/generated/enums.ts +113 -0
  187. package/src/modules/manufacturing/generated/kysely-tailordb.ts +247 -0
  188. package/src/modules/manufacturing/index.ts +2 -0
  189. package/src/modules/manufacturing/lib/_db_deps.ts +22 -0
  190. package/src/modules/manufacturing/lib/errors.generated.ts +592 -0
  191. package/src/modules/manufacturing/lib/permissions.generated.ts +35 -0
  192. package/src/modules/manufacturing/lib/types.ts +111 -0
  193. package/src/modules/manufacturing/module.ts +226 -0
  194. package/src/modules/manufacturing/permissions.ts +3 -0
  195. package/src/modules/manufacturing/query/.gitkeep +0 -0
  196. package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.generated.ts +5 -0
  197. package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.test.ts +115 -0
  198. package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.ts +79 -0
  199. package/src/modules/manufacturing/query/explodeBillOfMaterial.generated.ts +5 -0
  200. package/src/modules/manufacturing/query/explodeBillOfMaterial.test.ts +445 -0
  201. package/src/modules/manufacturing/query/explodeBillOfMaterial.ts +306 -0
  202. package/src/modules/manufacturing/query/getBillOfMaterial.generated.ts +5 -0
  203. package/src/modules/manufacturing/query/getBillOfMaterial.test.ts +64 -0
  204. package/src/modules/manufacturing/query/getBillOfMaterial.ts +27 -0
  205. package/src/modules/manufacturing/query/getManufacturingCostSummary.generated.ts +5 -0
  206. package/src/modules/manufacturing/query/getManufacturingCostSummary.test.ts +147 -0
  207. package/src/modules/manufacturing/query/getManufacturingCostSummary.ts +46 -0
  208. package/src/modules/manufacturing/query/getProductionOrder.generated.ts +5 -0
  209. package/src/modules/manufacturing/query/getProductionOrder.test.ts +139 -0
  210. package/src/modules/manufacturing/query/getProductionOrder.ts +84 -0
  211. package/src/modules/manufacturing/query/getRouting.generated.ts +5 -0
  212. package/src/modules/manufacturing/query/getRouting.test.ts +71 -0
  213. package/src/modules/manufacturing/query/getRouting.ts +34 -0
  214. package/src/modules/manufacturing/query/getWorkCenter.generated.ts +5 -0
  215. package/src/modules/manufacturing/query/getWorkCenter.test.ts +37 -0
  216. package/src/modules/manufacturing/query/getWorkCenter.ts +21 -0
  217. package/src/modules/manufacturing/query/getWorkOrder.generated.ts +5 -0
  218. package/src/modules/manufacturing/query/getWorkOrder.test.ts +73 -0
  219. package/src/modules/manufacturing/query/getWorkOrder.ts +28 -0
  220. package/src/modules/manufacturing/query/listBillOfMaterialsByItem.generated.ts +5 -0
  221. package/src/modules/manufacturing/query/listBillOfMaterialsByItem.test.ts +107 -0
  222. package/src/modules/manufacturing/query/listBillOfMaterialsByItem.ts +58 -0
  223. package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.generated.ts +5 -0
  224. package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.test.ts +96 -0
  225. package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.ts +77 -0
  226. package/src/modules/manufacturing/query/listProductionOrdersByStatus.generated.ts +5 -0
  227. package/src/modules/manufacturing/query/listProductionOrdersByStatus.test.ts +121 -0
  228. package/src/modules/manufacturing/query/listProductionOrdersByStatus.ts +83 -0
  229. package/src/modules/manufacturing/query/listRoutingsByItem.generated.ts +5 -0
  230. package/src/modules/manufacturing/query/listRoutingsByItem.test.ts +110 -0
  231. package/src/modules/manufacturing/query/listRoutingsByItem.ts +54 -0
  232. package/src/modules/manufacturing/query/listWorkCentersBySite.generated.ts +5 -0
  233. package/src/modules/manufacturing/query/listWorkCentersBySite.test.ts +81 -0
  234. package/src/modules/manufacturing/query/listWorkCentersBySite.ts +70 -0
  235. package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.generated.ts +5 -0
  236. package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.test.ts +102 -0
  237. package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.ts +53 -0
  238. package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.generated.ts +5 -0
  239. package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.test.ts +143 -0
  240. package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.ts +56 -0
  241. package/src/modules/manufacturing/seed/index.ts +19 -0
  242. package/src/modules/manufacturing/tailor.config.ts +13 -0
  243. package/src/modules/manufacturing/tailor.d.ts +13 -0
  244. package/src/modules/manufacturing/testing/commandTestUtils.ts +29 -0
  245. package/src/modules/manufacturing/testing/fixtures.ts +402 -0
  246. package/templates/scaffold/app/backend/package.json +9 -2
  247. package/templates/scaffold/app/backend/src/tests/utils/graphql-client.ts +66 -0
  248. package/templates/scaffold/app/backend/src/tests/utils/setup.ts +21 -0
  249. package/templates/scaffold/app/backend/tsconfig.json +9 -2
  250. package/templates/scaffold/app/backend/vitest.config.ts +35 -0
  251. package/templates/scaffold/app/frontend/package.json +2 -2
@@ -0,0 +1,210 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ ParentItemNotFoundError,
6
+ ParentItemNotManufacturedError,
7
+ InvalidBomTypeError,
8
+ ComponentLineRequiredError,
9
+ InvalidComponentQuantityError,
10
+ ComponentItemInactiveError,
11
+ BomVersionConflictError,
12
+ } from "../lib/errors.generated";
13
+ import { baseDraftBom, baseBomLine } from "../testing/fixtures";
14
+ import { run } from "./createBillOfMaterial";
15
+ import type { CommandContext } from "@tailor-platform/erp-kit/module";
16
+
17
+ describe("createBillOfMaterial", () => {
18
+ const ctx: CommandContext = {
19
+ actorId: "test-actor",
20
+ permissions: ["manufacturing:createBillOfMaterial"],
21
+ };
22
+
23
+ const validInput = {
24
+ parentItemId: "item-1",
25
+ companyId: "company-1",
26
+ siteId: null,
27
+ bomType: "MANUFACTURE",
28
+ effectivityStartDate: null,
29
+ effectivityEndDate: null,
30
+ defaultSelection: true,
31
+ revisionNumber: "V1",
32
+ lines: [
33
+ {
34
+ itemId: "item-2",
35
+ requiredQuantity: 2.0,
36
+ unitOfMeasure: "EA",
37
+ scrapAssumption: 5.0,
38
+ isSubassembly: false,
39
+ },
40
+ ],
41
+ };
42
+
43
+ it("creates a draft BOM for an active manufactured item", async () => {
44
+ const { db, spies } = createMockDb<Transaction>();
45
+ const createdBom = {
46
+ ...baseDraftBom,
47
+ id: "new-bom-id",
48
+ };
49
+
50
+ // parent item exists
51
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
52
+ // component item exists
53
+ spies.select.mockReturnValueOnce({ id: "item-2", status: "ACTIVE" });
54
+ // no existing BOM with same version identity
55
+ spies.select.mockReturnValueOnce(undefined);
56
+ // insert BOM
57
+ spies.insert.mockReturnValueOnce(createdBom);
58
+ // insert BOM line
59
+ spies.insert.mockReturnValueOnce({ ...baseBomLine, billOfMaterialId: "new-bom-id" });
60
+
61
+ const result = await run(db, validInput, ctx);
62
+
63
+ expect(result.ok).toBe(true);
64
+ if (result.ok) {
65
+ expect(result.value.billOfMaterial.status).toBe("DRAFT");
66
+ expect(result.value.billOfMaterial.id).toBe("new-bom-id");
67
+ }
68
+ expect(spies.insert).toHaveBeenCalled();
69
+ });
70
+
71
+ it("returns error when the parent item does not exist", async () => {
72
+ const { db, spies } = createMockDb<Transaction>();
73
+
74
+ // parent item not found
75
+ spies.select.mockReturnValueOnce(undefined);
76
+
77
+ const result = await run(db, validInput, ctx);
78
+
79
+ expect(result.ok).toBe(false);
80
+ if (!result.ok) {
81
+ expect(result.error).toBeInstanceOf(ParentItemNotFoundError);
82
+ }
83
+ });
84
+
85
+ it("returns error when the parent item is not manufacturable", async () => {
86
+ const { db, spies } = createMockDb<Transaction>();
87
+
88
+ // parent item exists but not manufacturable
89
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: false });
90
+
91
+ const result = await run(db, validInput, ctx);
92
+
93
+ expect(result.ok).toBe(false);
94
+ if (!result.ok) {
95
+ expect(result.error).toBeInstanceOf(ParentItemNotManufacturedError);
96
+ }
97
+ });
98
+
99
+ it("returns error when bomType is invalid", async () => {
100
+ const { db, spies } = createMockDb<Transaction>();
101
+
102
+ // parent item exists
103
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
104
+
105
+ const result = await run(db, { ...validInput, bomType: "UNSUPPORTED" }, ctx);
106
+
107
+ expect(result.ok).toBe(false);
108
+ if (!result.ok) {
109
+ expect(result.error).toBeInstanceOf(InvalidBomTypeError);
110
+ }
111
+ });
112
+
113
+ it("returns error when no component lines are provided", async () => {
114
+ const { db, spies } = createMockDb<Transaction>();
115
+
116
+ // parent item exists
117
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
118
+
119
+ const result = await run(db, { ...validInput, lines: [] }, ctx);
120
+
121
+ expect(result.ok).toBe(false);
122
+ if (!result.ok) {
123
+ expect(result.error).toBeInstanceOf(ComponentLineRequiredError);
124
+ }
125
+ });
126
+
127
+ it("returns error when a component quantity is not positive", async () => {
128
+ const { db, spies } = createMockDb<Transaction>();
129
+
130
+ // parent item exists
131
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
132
+
133
+ const result = await run(
134
+ db,
135
+ {
136
+ ...validInput,
137
+ lines: [{ itemId: "item-2", requiredQuantity: 0, unitOfMeasure: "EA" }],
138
+ },
139
+ ctx,
140
+ );
141
+
142
+ expect(result.ok).toBe(false);
143
+ if (!result.ok) {
144
+ expect(result.error).toBeInstanceOf(InvalidComponentQuantityError);
145
+ }
146
+ });
147
+
148
+ it("returns error when a component item is inactive", async () => {
149
+ const { db, spies } = createMockDb<Transaction>();
150
+
151
+ // parent item exists
152
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
153
+ // component item not found (treated as inactive)
154
+ spies.select.mockReturnValueOnce(undefined);
155
+
156
+ const result = await run(db, validInput, ctx);
157
+
158
+ expect(result.ok).toBe(false);
159
+ if (!result.ok) {
160
+ expect(result.error).toBeInstanceOf(ComponentItemInactiveError);
161
+ }
162
+ });
163
+
164
+ it("returns error when a component item exists but is inactive", async () => {
165
+ const { db, spies } = createMockDb<Transaction>();
166
+
167
+ // parent item exists
168
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
169
+ // component item exists but is inactive
170
+ spies.select.mockReturnValueOnce({ id: "item-2", isActive: false });
171
+
172
+ const result = await run(db, validInput, ctx);
173
+
174
+ expect(result.ok).toBe(false);
175
+ if (!result.ok) {
176
+ expect(result.error).toBeInstanceOf(ComponentItemInactiveError);
177
+ }
178
+ });
179
+
180
+ it("returns error when the version identity already exists in scope", async () => {
181
+ const { db, spies } = createMockDb<Transaction>();
182
+
183
+ // parent item exists
184
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "ACTIVE", isManufacturable: true });
185
+ // component item exists
186
+ spies.select.mockReturnValueOnce({ id: "item-2", status: "ACTIVE" });
187
+ // existing BOM with same version identity
188
+ spies.select.mockReturnValueOnce(baseDraftBom);
189
+
190
+ const result = await run(db, validInput, ctx);
191
+
192
+ expect(result.ok).toBe(false);
193
+ if (!result.ok) {
194
+ expect(result.error).toBeInstanceOf(BomVersionConflictError);
195
+ }
196
+ });
197
+
198
+ it("returns error when the parent item is inactive", async () => {
199
+ const { db, spies } = createMockDb<Transaction>();
200
+
201
+ spies.select.mockReturnValueOnce({ id: "item-1", status: "INACTIVE", isManufacturable: true });
202
+
203
+ const result = await run(db, validInput, ctx);
204
+
205
+ expect(result.ok).toBe(false);
206
+ if (!result.ok) {
207
+ expect(result.error).toBeInstanceOf(ParentItemNotManufacturedError);
208
+ }
209
+ });
210
+ });
@@ -0,0 +1,176 @@
1
+ import type { Transaction } from "../generated/kysely-tailordb";
2
+ import {
3
+ ParentItemNotFoundError,
4
+ ParentItemNotManufacturedError,
5
+ InvalidBomTypeError,
6
+ ComponentLineRequiredError,
7
+ InvalidComponentQuantityError,
8
+ ComponentItemInactiveError,
9
+ BomVersionConflictError,
10
+ } from "../lib/errors.generated";
11
+ import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
12
+
13
+ const VALID_BOM_TYPES = ["MANUFACTURE", "PHANTOM", "KIT"] as const;
14
+
15
+ export interface CreateBillOfMaterialLineInput {
16
+ itemId: string;
17
+ requiredQuantity: number;
18
+ unitOfMeasure?: string | null;
19
+ scrapAssumption?: number | null;
20
+ isSubassembly?: boolean | null;
21
+ }
22
+
23
+ export interface CreateBillOfMaterialInput {
24
+ parentItemId: string;
25
+ companyId: string;
26
+ siteId?: string | null;
27
+ bomType: string;
28
+ effectivityStartDate?: Date | null;
29
+ effectivityEndDate?: Date | null;
30
+ defaultSelection?: boolean | null;
31
+ revisionNumber?: string | null;
32
+ lines: CreateBillOfMaterialLineInput[];
33
+ }
34
+
35
+ /**
36
+ * Function: createBillOfMaterial
37
+ *
38
+ * Creates a draft BOM version for one manufactured parent item at company or
39
+ * site scope. Establishes the initial bomType, effectivity window,
40
+ * default-selection intent, and component-line payload.
41
+ */
42
+ export async function run<CF extends Record<string, unknown>>(
43
+ db: Transaction,
44
+ input: CreateBillOfMaterialInput & CF,
45
+ _ctx: CommandContext,
46
+ ) {
47
+ const {
48
+ parentItemId,
49
+ companyId,
50
+ siteId,
51
+ bomType,
52
+ effectivityStartDate,
53
+ effectivityEndDate,
54
+ defaultSelection,
55
+ revisionNumber,
56
+ lines,
57
+ ...customFields
58
+ } = input;
59
+
60
+ // 1. Validate parent item exists
61
+ const parentItem = await db
62
+ .selectFrom("Item")
63
+ .selectAll()
64
+ .where("id", "=", parentItemId)
65
+ .executeTakeFirst();
66
+
67
+ if (!parentItem) {
68
+ return err(new ParentItemNotFoundError(parentItemId));
69
+ }
70
+
71
+ // 2. Validate parent item is active and manufacturable.
72
+ const parentItemRecord = parentItem as Record<string, unknown>;
73
+ const isInactive =
74
+ ("status" in parentItemRecord && parentItemRecord.status !== "ACTIVE") ||
75
+ ("isActive" in parentItemRecord && parentItemRecord.isActive === false);
76
+ const isNotManufacturable =
77
+ "isManufacturable" in parentItemRecord && parentItemRecord.isManufacturable === false;
78
+
79
+ if (isInactive || isNotManufacturable) {
80
+ return err(new ParentItemNotManufacturedError(parentItemId));
81
+ }
82
+
83
+ // 3. Validate bomType
84
+ if (!VALID_BOM_TYPES.includes(bomType as (typeof VALID_BOM_TYPES)[number])) {
85
+ return err(new InvalidBomTypeError(parentItemId));
86
+ }
87
+
88
+ // 4. Validate at least one component line
89
+ if (!lines || lines.length === 0) {
90
+ return err(new ComponentLineRequiredError(parentItemId));
91
+ }
92
+
93
+ // 5. Validate each component line
94
+ for (const line of lines) {
95
+ if (line.requiredQuantity <= 0) {
96
+ return err(new InvalidComponentQuantityError(line.itemId));
97
+ }
98
+
99
+ // Check component item is not inactive (exists in Item table)
100
+ const componentItem = await db
101
+ .selectFrom("Item")
102
+ .selectAll()
103
+ .where("id", "=", line.itemId)
104
+ .executeTakeFirst();
105
+
106
+ if (!componentItem) {
107
+ return err(new ComponentItemInactiveError(line.itemId));
108
+ }
109
+
110
+ // Check component item is active
111
+ if ("isActive" in componentItem && componentItem.isActive === false) {
112
+ return err(new ComponentItemInactiveError(line.itemId));
113
+ }
114
+ if ("status" in componentItem && componentItem.status === "INACTIVE") {
115
+ return err(new ComponentItemInactiveError(line.itemId));
116
+ }
117
+ }
118
+
119
+ // 6. Check version identity uniqueness within same parent item and scope
120
+ const existingBomQuery = db
121
+ .selectFrom("BillOfMaterial")
122
+ .selectAll()
123
+ .where("parentItemId", "=", parentItemId)
124
+ .where("companyId", "=", companyId);
125
+
126
+ const existingBom = await (
127
+ siteId ? existingBomQuery.where("siteId", "=", siteId) : existingBomQuery
128
+ )
129
+ .where("revisionNumber", "=", revisionNumber ?? null)
130
+ .forUpdate()
131
+ .executeTakeFirst();
132
+
133
+ if (existingBom) {
134
+ return err(new BomVersionConflictError(parentItemId));
135
+ }
136
+
137
+ // 7. Create draft BOM
138
+ const billOfMaterial = await db
139
+ .insertInto("BillOfMaterial")
140
+ .values({
141
+ ...(customFields as Record<string, unknown>),
142
+ parentItemId,
143
+ companyId,
144
+ siteId: siteId ?? null,
145
+ bomType: bomType as "MANUFACTURE" | "PHANTOM" | "KIT",
146
+ effectivityStartDate: effectivityStartDate ?? null,
147
+ effectivityEndDate: effectivityEndDate ?? null,
148
+ defaultSelection: defaultSelection ?? null,
149
+ revisionNumber: revisionNumber ?? null,
150
+ status: "DRAFT",
151
+ createdAt: new Date(),
152
+ updatedAt: null,
153
+ })
154
+ .returningAll()
155
+ .executeTakeFirst();
156
+
157
+ // 8. Create component lines
158
+ for (const line of lines) {
159
+ await db
160
+ .insertInto("BillOfMaterialLine")
161
+ .values({
162
+ billOfMaterialId: billOfMaterial!.id,
163
+ itemId: line.itemId,
164
+ requiredQuantity: line.requiredQuantity,
165
+ unitOfMeasure: line.unitOfMeasure ?? null,
166
+ scrapAssumption: line.scrapAssumption ?? null,
167
+ isSubassembly: line.isSubassembly ?? null,
168
+ createdAt: new Date(),
169
+ updatedAt: null,
170
+ })
171
+ .returningAll()
172
+ .executeTakeFirst();
173
+ }
174
+
175
+ return ok({ billOfMaterial: billOfMaterial! });
176
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { permissions } from "../lib/permissions.generated";
3
+ import { run } from "./createProductionOrder";
4
+ import { defineCommand } from "@tailor-platform/erp-kit/module";
5
+
6
+ export const createProductionOrder = defineCommand(permissions.createProductionOrder, run);
@@ -0,0 +1,160 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ ProductionItemNotFoundError,
6
+ ProductionItemNotManufacturableError,
7
+ InvalidPlannedQuantityError,
8
+ InvalidSiteScopeError,
9
+ CrossScopeMasterReferenceError,
10
+ } from "../lib/errors.generated";
11
+ import { baseDraftProductionOrder, baseActiveBom, baseActiveRouting } from "../testing/fixtures";
12
+ import { run } from "./createProductionOrder";
13
+ import type { CommandContext } from "@tailor-platform/erp-kit/module";
14
+
15
+ describe("createProductionOrder", () => {
16
+ const ctx: CommandContext = {
17
+ actorId: "test-actor",
18
+ permissions: ["manufacturing:createProductionOrder"],
19
+ };
20
+
21
+ const validInput = {
22
+ orderedItemId: "item-1",
23
+ companyId: "company-1",
24
+ siteId: "site-1",
25
+ plannedQuantity: 100,
26
+ plannedStartDate: new Date("2024-03-01T00:00:00.000Z"),
27
+ plannedEndDate: new Date("2024-03-15T00:00:00.000Z"),
28
+ };
29
+
30
+ it("creates a draft production order for a manufacturable item", async () => {
31
+ const { db, spies } = createMockDb<Transaction>();
32
+ const createdOrder = {
33
+ ...baseDraftProductionOrder,
34
+ id: "new-order-id",
35
+ };
36
+
37
+ // item lookup
38
+ spies.select.mockReturnValueOnce({ id: "item-1" });
39
+ // site lookup
40
+ spies.select.mockReturnValueOnce({ id: "site-1" });
41
+ // insert
42
+ spies.insert.mockReturnValue(createdOrder);
43
+
44
+ const result = await run(db, validInput, ctx);
45
+
46
+ expect(result.ok).toBe(true);
47
+ if (result.ok) {
48
+ expect(result.value.productionOrder.status).toBe("DRAFT");
49
+ }
50
+ expect(spies.insert).toHaveBeenCalled();
51
+ });
52
+
53
+ it("returns error when the produced item does not exist", async () => {
54
+ const { db, spies } = createMockDb<Transaction>();
55
+
56
+ // item lookup returns undefined
57
+ spies.select.mockReturnValueOnce(undefined);
58
+
59
+ const result = await run(db, validInput, ctx);
60
+
61
+ expect(result.ok).toBe(false);
62
+ if (!result.ok) {
63
+ expect(result.error).toBeInstanceOf(ProductionItemNotFoundError);
64
+ }
65
+ });
66
+
67
+ it("returns error when the produced item is not manufacturable", async () => {
68
+ const { db, spies } = createMockDb<Transaction>();
69
+
70
+ // item exists but not manufacturable
71
+ spies.select.mockReturnValueOnce({ id: "item-1", isManufacturable: false });
72
+
73
+ const result = await run(db, validInput, ctx);
74
+
75
+ expect(result.ok).toBe(false);
76
+ if (!result.ok) {
77
+ expect(result.error).toBeInstanceOf(ProductionItemNotManufacturableError);
78
+ }
79
+ });
80
+
81
+ it("returns error when planned quantity is not positive", async () => {
82
+ const { db } = createMockDb<Transaction>();
83
+
84
+ const result = await run(db, { ...validInput, plannedQuantity: 0 }, ctx);
85
+
86
+ expect(result.ok).toBe(false);
87
+ if (!result.ok) {
88
+ expect(result.error).toBeInstanceOf(InvalidPlannedQuantityError);
89
+ }
90
+ });
91
+
92
+ it("returns error when site scope is inconsistent with company", async () => {
93
+ const { db } = createMockDb<Transaction>();
94
+
95
+ const result = await run(db, { ...validInput, siteId: "" }, ctx);
96
+
97
+ expect(result.ok).toBe(false);
98
+ if (!result.ok) {
99
+ expect(result.error).toBeInstanceOf(InvalidSiteScopeError);
100
+ }
101
+ });
102
+
103
+ it("returns error when site does not exist", async () => {
104
+ const { db, spies } = createMockDb<Transaction>();
105
+
106
+ // item lookup
107
+ spies.select.mockReturnValueOnce({ id: "item-1" });
108
+ // site lookup returns undefined
109
+ spies.select.mockReturnValueOnce(undefined);
110
+
111
+ const result = await run(db, validInput, ctx);
112
+
113
+ expect(result.ok).toBe(false);
114
+ if (!result.ok) {
115
+ expect(result.error).toBeInstanceOf(InvalidSiteScopeError);
116
+ }
117
+ });
118
+
119
+ it("returns error when an optional BOM reference is outside scope", async () => {
120
+ const { db, spies } = createMockDb<Transaction>();
121
+ const crossScopeBom = { ...baseActiveBom, companyId: "other-company" };
122
+
123
+ // item lookup
124
+ spies.select.mockReturnValueOnce({ id: "item-1" });
125
+ // site lookup
126
+ spies.select.mockReturnValueOnce({ id: "site-1" });
127
+ // bom lookup
128
+ spies.select.mockReturnValueOnce(crossScopeBom);
129
+
130
+ const result = await run(db, { ...validInput, selectedBomVersionId: crossScopeBom.id }, ctx);
131
+
132
+ expect(result.ok).toBe(false);
133
+ if (!result.ok) {
134
+ expect(result.error).toBeInstanceOf(CrossScopeMasterReferenceError);
135
+ }
136
+ });
137
+
138
+ it("returns error when an optional routing reference is outside scope", async () => {
139
+ const { db, spies } = createMockDb<Transaction>();
140
+ const crossScopeRouting = { ...baseActiveRouting, companyId: "other-company" };
141
+
142
+ // item lookup
143
+ spies.select.mockReturnValueOnce({ id: "item-1" });
144
+ // site lookup
145
+ spies.select.mockReturnValueOnce({ id: "site-1" });
146
+ // routing lookup
147
+ spies.select.mockReturnValueOnce(crossScopeRouting);
148
+
149
+ const result = await run(
150
+ db,
151
+ { ...validInput, selectedRoutingRevisionId: crossScopeRouting.id },
152
+ ctx,
153
+ );
154
+
155
+ expect(result.ok).toBe(false);
156
+ if (!result.ok) {
157
+ expect(result.error).toBeInstanceOf(CrossScopeMasterReferenceError);
158
+ }
159
+ });
160
+ });
@@ -0,0 +1,129 @@
1
+ import type { Transaction } from "../generated/kysely-tailordb";
2
+ import {
3
+ ProductionItemNotFoundError,
4
+ ProductionItemNotManufacturableError,
5
+ InvalidPlannedQuantityError,
6
+ InvalidSiteScopeError,
7
+ CrossScopeMasterReferenceError,
8
+ } from "../lib/errors.generated";
9
+ import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
10
+
11
+ export interface CreateProductionOrderInput {
12
+ orderedItemId: string;
13
+ companyId: string;
14
+ siteId: string;
15
+ plannedQuantity: number;
16
+ plannedStartDate: Date;
17
+ plannedEndDate: Date;
18
+ selectedBomVersionId?: string | null;
19
+ selectedRoutingRevisionId?: string | null;
20
+ }
21
+
22
+ /**
23
+ * Function: createProductionOrder
24
+ *
25
+ * Creates a draft manufacturing request with produced item, quantity, site,
26
+ * and planned dates. Records planner intent without freezing BOM, routing,
27
+ * work orders, or cost assumptions.
28
+ */
29
+ export async function run<CF extends Record<string, unknown>>(
30
+ db: Transaction,
31
+ input: CreateProductionOrderInput & CF,
32
+ _ctx: CommandContext,
33
+ ) {
34
+ const {
35
+ orderedItemId,
36
+ companyId,
37
+ siteId,
38
+ plannedQuantity,
39
+ plannedStartDate,
40
+ plannedEndDate,
41
+ selectedBomVersionId,
42
+ selectedRoutingRevisionId,
43
+ ...customFields
44
+ } = input;
45
+
46
+ // 1. Validate planned quantity > 0
47
+ if (plannedQuantity <= 0) {
48
+ return err(new InvalidPlannedQuantityError(orderedItemId));
49
+ }
50
+
51
+ // 2. Validate scope
52
+ if (!companyId || !siteId) {
53
+ return err(new InvalidSiteScopeError(orderedItemId));
54
+ }
55
+
56
+ // 3. Validate produced item exists
57
+ const item = await db
58
+ .selectFrom("Item")
59
+ .selectAll()
60
+ .where("id", "=", orderedItemId)
61
+ .executeTakeFirst();
62
+
63
+ if (!item) {
64
+ return err(new ProductionItemNotFoundError(orderedItemId));
65
+ }
66
+
67
+ // 4. Validate item is manufacturable
68
+ if (item && "isManufacturable" in item && item.isManufacturable === false) {
69
+ return err(new ProductionItemNotManufacturableError(orderedItemId));
70
+ }
71
+
72
+ // 5. Validate site belongs to company scope
73
+ const site = await db.selectFrom("Site").selectAll().where("id", "=", siteId).executeTakeFirst();
74
+
75
+ if (!site) {
76
+ return err(new InvalidSiteScopeError(orderedItemId));
77
+ }
78
+
79
+ // 5. Validate optional BOM reference scope
80
+ if (selectedBomVersionId) {
81
+ const bom = await db
82
+ .selectFrom("BillOfMaterial")
83
+ .selectAll()
84
+ .where("id", "=", selectedBomVersionId)
85
+ .executeTakeFirst();
86
+
87
+ if (bom && (bom.companyId !== companyId || (bom.siteId != null && bom.siteId !== siteId))) {
88
+ return err(new CrossScopeMasterReferenceError(orderedItemId));
89
+ }
90
+ }
91
+
92
+ // 6. Validate optional routing reference scope
93
+ if (selectedRoutingRevisionId) {
94
+ const routing = await db
95
+ .selectFrom("Routing")
96
+ .selectAll()
97
+ .where("id", "=", selectedRoutingRevisionId)
98
+ .executeTakeFirst();
99
+
100
+ if (
101
+ routing &&
102
+ (routing.companyId !== companyId || (routing.siteId != null && routing.siteId !== siteId))
103
+ ) {
104
+ return err(new CrossScopeMasterReferenceError(orderedItemId));
105
+ }
106
+ }
107
+
108
+ // 7. Create draft production order
109
+ const productionOrder = await db
110
+ .insertInto("ProductionOrder")
111
+ .values({
112
+ ...(customFields as Record<string, unknown>),
113
+ orderedItemId,
114
+ companyId,
115
+ siteId,
116
+ plannedQuantity,
117
+ plannedStartDate,
118
+ plannedEndDate,
119
+ selectedBomVersionId: selectedBomVersionId ?? null,
120
+ selectedRoutingRevisionId: selectedRoutingRevisionId ?? null,
121
+ status: "DRAFT",
122
+ createdAt: new Date(),
123
+ updatedAt: null,
124
+ })
125
+ .returningAll()
126
+ .executeTakeFirst();
127
+
128
+ return ok({ productionOrder: productionOrder! });
129
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { permissions } from "../lib/permissions.generated";
3
+ import { run } from "./createRouting";
4
+ import { defineCommand } from "@tailor-platform/erp-kit/module";
5
+
6
+ export const createRouting = defineCommand(permissions.createRouting, run);