@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.
- package/CHANGELOG.md +15 -0
- package/dist/cli.mjs +103 -23
- package/package.json +1 -1
- package/skills/erp-kit-app-5-impl-backend/SKILL.md +7 -4
- package/skills/erp-kit-app-7-impl-review/SKILL.md +1 -1
- package/skills/erp-kit-module-6-impl-review/SKILL.md +39 -17
- package/src/commands/generate-doc.ts +1 -1
- package/src/commands/lib/discovery.test.ts +13 -3
- package/src/commands/lib/discovery.ts +10 -2
- package/src/commands/lib/paths.ts +4 -2
- package/src/commands/lib/sync-check-tests.test.ts +84 -6
- package/src/commands/lib/sync-check-tests.ts +63 -3
- package/src/commands/sync-check.ts +7 -3
- package/src/generator/generate-app-code.ts +51 -16
- package/src/generator/generate-stubs.ts +4 -0
- package/src/generator/stub-templates.test.ts +11 -0
- package/src/generator/stub-templates.ts +22 -1
- package/src/modules/inventory/docs/features/inventory-adjustment.md +2 -1
- package/src/modules/inventory/docs/features/scrap-management.md +39 -1
- package/src/modules/manufacturing/README.md +63 -0
- package/src/modules/manufacturing/command/.gitkeep +0 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.test.ts +166 -0
- package/src/modules/manufacturing/command/activateBillOfMaterial.ts +173 -0
- package/src/modules/manufacturing/command/activateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateRouting.test.ts +152 -0
- package/src/modules/manufacturing/command/activateRouting.ts +92 -0
- package/src/modules/manufacturing/command/activateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/activateWorkCenter.test.ts +135 -0
- package/src/modules/manufacturing/command/activateWorkCenter.ts +91 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.test.ts +151 -0
- package/src/modules/manufacturing/command/cancelProductionOrder.ts +114 -0
- package/src/modules/manufacturing/command/closeProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/closeProductionOrder.test.ts +126 -0
- package/src/modules/manufacturing/command/closeProductionOrder.ts +87 -0
- package/src/modules/manufacturing/command/completeProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/completeProductionOrder.test.ts +132 -0
- package/src/modules/manufacturing/command/completeProductionOrder.ts +97 -0
- package/src/modules/manufacturing/command/completeWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/completeWorkOrder.test.ts +369 -0
- package/src/modules/manufacturing/command/completeWorkOrder.ts +212 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.test.ts +210 -0
- package/src/modules/manufacturing/command/createBillOfMaterial.ts +176 -0
- package/src/modules/manufacturing/command/createProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/createProductionOrder.test.ts +160 -0
- package/src/modules/manufacturing/command/createProductionOrder.ts +129 -0
- package/src/modules/manufacturing/command/createRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/createRouting.test.ts +168 -0
- package/src/modules/manufacturing/command/createRouting.ts +128 -0
- package/src/modules/manufacturing/command/createWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/createWorkCenter.test.ts +148 -0
- package/src/modules/manufacturing/command/createWorkCenter.ts +131 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.test.ts +103 -0
- package/src/modules/manufacturing/command/deactivateBillOfMaterial.ts +78 -0
- package/src/modules/manufacturing/command/deactivateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateRouting.test.ts +112 -0
- package/src/modules/manufacturing/command/deactivateRouting.ts +76 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.test.ts +113 -0
- package/src/modules/manufacturing/command/deactivateWorkCenter.ts +85 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.test.ts +118 -0
- package/src/modules/manufacturing/command/pauseWorkOrder.ts +82 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.generated.ts +6 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.test.ts +183 -0
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.ts +139 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.generated.ts +6 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.test.ts +120 -0
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.ts +110 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.test.ts +220 -0
- package/src/modules/manufacturing/command/releaseProductionOrder.ts +450 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.test.ts +196 -0
- package/src/modules/manufacturing/command/reopenProductionOrder.ts +98 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.generated.ts +6 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.test.ts +204 -0
- package/src/modules/manufacturing/command/reportWorkOrderProgress.ts +129 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.test.ts +185 -0
- package/src/modules/manufacturing/command/rescheduleProductionOrder.ts +95 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.test.ts +122 -0
- package/src/modules/manufacturing/command/resumeWorkOrder.ts +94 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.generated.ts +6 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.test.ts +231 -0
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.ts +137 -0
- package/src/modules/manufacturing/command/startWorkOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/startWorkOrder.test.ts +118 -0
- package/src/modules/manufacturing/command/startWorkOrder.ts +126 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.test.ts +153 -0
- package/src/modules/manufacturing/command/technicallyCompleteProductionOrder.ts +106 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.test.ts +140 -0
- package/src/modules/manufacturing/command/unreleaseProductionOrder.ts +131 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.test.ts +149 -0
- package/src/modules/manufacturing/command/updateBillOfMaterial.ts +174 -0
- package/src/modules/manufacturing/command/updateProductionOrder.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateProductionOrder.test.ts +112 -0
- package/src/modules/manufacturing/command/updateProductionOrder.ts +145 -0
- package/src/modules/manufacturing/command/updateRouting.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateRouting.test.ts +211 -0
- package/src/modules/manufacturing/command/updateRouting.ts +124 -0
- package/src/modules/manufacturing/command/updateWorkCenter.generated.ts +6 -0
- package/src/modules/manufacturing/command/updateWorkCenter.test.ts +152 -0
- package/src/modules/manufacturing/command/updateWorkCenter.ts +137 -0
- package/src/modules/manufacturing/db/.gitkeep +0 -0
- package/src/modules/manufacturing/db/billOfMaterial.ts +70 -0
- package/src/modules/manufacturing/db/billOfMaterialLine.ts +49 -0
- package/src/modules/manufacturing/db/costVarianceLine.ts +53 -0
- package/src/modules/manufacturing/db/manufacturingCostLine.ts +35 -0
- package/src/modules/manufacturing/db/manufacturingCostSettlementRecord.ts +39 -0
- package/src/modules/manufacturing/db/manufacturingCostSummary.ts +59 -0
- package/src/modules/manufacturing/db/productionOrder.ts +83 -0
- package/src/modules/manufacturing/db/productionOrderBomSnapshot.ts +44 -0
- package/src/modules/manufacturing/db/productionOrderCostBaseline.ts +44 -0
- package/src/modules/manufacturing/db/productionOrderMaterialRequirement.ts +57 -0
- package/src/modules/manufacturing/db/productionOrderRoutingSnapshot.ts +43 -0
- package/src/modules/manufacturing/db/routing.ts +63 -0
- package/src/modules/manufacturing/db/routingOperation.ts +57 -0
- package/src/modules/manufacturing/db/workCenter.ts +87 -0
- package/src/modules/manufacturing/db/workOrder.ts +65 -0
- package/src/modules/manufacturing/db/workOrderExecutionEvent.ts +54 -0
- package/src/modules/manufacturing/docs/commands/ActivateBillOfMaterial.md +50 -0
- package/src/modules/manufacturing/docs/commands/ActivateRouting.md +48 -0
- package/src/modules/manufacturing/docs/commands/ActivateWorkCenter.md +49 -0
- package/src/modules/manufacturing/docs/commands/CancelProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/CloseProductionOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/CompleteProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/CompleteWorkOrder.md +66 -0
- package/src/modules/manufacturing/docs/commands/CreateBillOfMaterial.md +54 -0
- package/src/modules/manufacturing/docs/commands/CreateProductionOrder.md +49 -0
- package/src/modules/manufacturing/docs/commands/CreateRouting.md +50 -0
- package/src/modules/manufacturing/docs/commands/CreateWorkCenter.md +51 -0
- package/src/modules/manufacturing/docs/commands/DeactivateBillOfMaterial.md +45 -0
- package/src/modules/manufacturing/docs/commands/DeactivateRouting.md +45 -0
- package/src/modules/manufacturing/docs/commands/DeactivateWorkCenter.md +45 -0
- package/src/modules/manufacturing/docs/commands/PauseWorkOrder.md +44 -0
- package/src/modules/manufacturing/docs/commands/RecordInventoryIssueOutcome.md +59 -0
- package/src/modules/manufacturing/docs/commands/RecordManufacturingCostSettlementAcknowledgment.md +49 -0
- package/src/modules/manufacturing/docs/commands/ReleaseProductionOrder.md +57 -0
- package/src/modules/manufacturing/docs/commands/ReopenProductionOrder.md +54 -0
- package/src/modules/manufacturing/docs/commands/ReportWorkOrderProgress.md +53 -0
- package/src/modules/manufacturing/docs/commands/RescheduleProductionOrder.md +45 -0
- package/src/modules/manufacturing/docs/commands/ResumeWorkOrder.md +44 -0
- package/src/modules/manufacturing/docs/commands/ReviewManufacturingCostSummary.md +52 -0
- package/src/modules/manufacturing/docs/commands/StartWorkOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/TechnicallyCompleteProductionOrder.md +51 -0
- package/src/modules/manufacturing/docs/commands/UnreleaseProductionOrder.md +46 -0
- package/src/modules/manufacturing/docs/commands/UpdateBillOfMaterial.md +48 -0
- package/src/modules/manufacturing/docs/commands/UpdateProductionOrder.md +48 -0
- package/src/modules/manufacturing/docs/commands/UpdateRouting.md +52 -0
- package/src/modules/manufacturing/docs/commands/UpdateWorkCenter.md +48 -0
- package/src/modules/manufacturing/docs/features/bill-of-material-management.md +83 -0
- package/src/modules/manufacturing/docs/features/manufacturing-cost-and-variance.md +191 -0
- package/src/modules/manufacturing/docs/features/production-order-lifecycle.md +103 -0
- package/src/modules/manufacturing/docs/features/routing-and-work-center-definition.md +63 -0
- package/src/modules/manufacturing/docs/features/work-order-execution.md +115 -0
- package/src/modules/manufacturing/docs/models/BillOfMaterial.md +60 -0
- package/src/modules/manufacturing/docs/models/ManufacturingCostSummary.md +66 -0
- package/src/modules/manufacturing/docs/models/ProductionOrder.md +76 -0
- package/src/modules/manufacturing/docs/models/Routing.md +58 -0
- package/src/modules/manufacturing/docs/models/WorkCenter.md +56 -0
- package/src/modules/manufacturing/docs/models/WorkOrder.md +63 -0
- package/src/modules/manufacturing/docs/queries/DetectBillOfMaterialCircularReference.md +39 -0
- package/src/modules/manufacturing/docs/queries/ExplodeBillOfMaterial.md +56 -0
- package/src/modules/manufacturing/docs/queries/GetBillOfMaterial.md +37 -0
- package/src/modules/manufacturing/docs/queries/GetManufacturingCostSummary.md +39 -0
- package/src/modules/manufacturing/docs/queries/GetProductionOrder.md +37 -0
- package/src/modules/manufacturing/docs/queries/GetRouting.md +39 -0
- package/src/modules/manufacturing/docs/queries/GetWorkCenter.md +35 -0
- package/src/modules/manufacturing/docs/queries/GetWorkOrder.md +38 -0
- package/src/modules/manufacturing/docs/queries/ListBillOfMaterialsByItem.md +42 -0
- package/src/modules/manufacturing/docs/queries/ListManufacturingCostSummariesByStatus.md +41 -0
- package/src/modules/manufacturing/docs/queries/ListProductionOrdersByStatus.md +41 -0
- package/src/modules/manufacturing/docs/queries/ListRoutingsByItem.md +42 -0
- package/src/modules/manufacturing/docs/queries/ListWorkCentersBySite.md +38 -0
- package/src/modules/manufacturing/docs/queries/ListWorkOrdersByProductionOrder.md +39 -0
- package/src/modules/manufacturing/docs/queries/ListWorkOrdersByWorkCenter.md +43 -0
- package/src/modules/manufacturing/executor/.gitkeep +0 -0
- package/src/modules/manufacturing/generated/enums.ts +113 -0
- package/src/modules/manufacturing/generated/kysely-tailordb.ts +247 -0
- package/src/modules/manufacturing/index.ts +2 -0
- package/src/modules/manufacturing/lib/_db_deps.ts +22 -0
- package/src/modules/manufacturing/lib/errors.generated.ts +592 -0
- package/src/modules/manufacturing/lib/permissions.generated.ts +35 -0
- package/src/modules/manufacturing/lib/types.ts +111 -0
- package/src/modules/manufacturing/module.ts +226 -0
- package/src/modules/manufacturing/permissions.ts +3 -0
- package/src/modules/manufacturing/query/.gitkeep +0 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.generated.ts +5 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.test.ts +115 -0
- package/src/modules/manufacturing/query/detectBillOfMaterialCircularReference.ts +79 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.generated.ts +5 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.test.ts +445 -0
- package/src/modules/manufacturing/query/explodeBillOfMaterial.ts +306 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.generated.ts +5 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.test.ts +64 -0
- package/src/modules/manufacturing/query/getBillOfMaterial.ts +27 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.generated.ts +5 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.test.ts +147 -0
- package/src/modules/manufacturing/query/getManufacturingCostSummary.ts +46 -0
- package/src/modules/manufacturing/query/getProductionOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/getProductionOrder.test.ts +139 -0
- package/src/modules/manufacturing/query/getProductionOrder.ts +84 -0
- package/src/modules/manufacturing/query/getRouting.generated.ts +5 -0
- package/src/modules/manufacturing/query/getRouting.test.ts +71 -0
- package/src/modules/manufacturing/query/getRouting.ts +34 -0
- package/src/modules/manufacturing/query/getWorkCenter.generated.ts +5 -0
- package/src/modules/manufacturing/query/getWorkCenter.test.ts +37 -0
- package/src/modules/manufacturing/query/getWorkCenter.ts +21 -0
- package/src/modules/manufacturing/query/getWorkOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/getWorkOrder.test.ts +73 -0
- package/src/modules/manufacturing/query/getWorkOrder.ts +28 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.generated.ts +5 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.test.ts +107 -0
- package/src/modules/manufacturing/query/listBillOfMaterialsByItem.ts +58 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.generated.ts +5 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.test.ts +96 -0
- package/src/modules/manufacturing/query/listManufacturingCostSummariesByStatus.ts +77 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.generated.ts +5 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.test.ts +121 -0
- package/src/modules/manufacturing/query/listProductionOrdersByStatus.ts +83 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.generated.ts +5 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.test.ts +110 -0
- package/src/modules/manufacturing/query/listRoutingsByItem.ts +54 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.test.ts +81 -0
- package/src/modules/manufacturing/query/listWorkCentersBySite.ts +70 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.test.ts +102 -0
- package/src/modules/manufacturing/query/listWorkOrdersByProductionOrder.ts +53 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.generated.ts +5 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.test.ts +143 -0
- package/src/modules/manufacturing/query/listWorkOrdersByWorkCenter.ts +56 -0
- package/src/modules/manufacturing/seed/index.ts +19 -0
- package/src/modules/manufacturing/tailor.config.ts +13 -0
- package/src/modules/manufacturing/tailor.d.ts +13 -0
- package/src/modules/manufacturing/testing/commandTestUtils.ts +29 -0
- package/src/modules/manufacturing/testing/fixtures.ts +402 -0
- package/templates/scaffold/app/backend/package.json +9 -2
- package/templates/scaffold/app/backend/src/tests/utils/graphql-client.ts +66 -0
- package/templates/scaffold/app/backend/src/tests/utils/setup.ts +21 -0
- package/templates/scaffold/app/backend/tsconfig.json +9 -2
- package/templates/scaffold/app/backend/vitest.config.ts +35 -0
- package/templates/scaffold/app/frontend/package.json +2 -2
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
2
|
+
import {
|
|
3
|
+
RoutingNotFoundError,
|
|
4
|
+
RoutingNotMutableError,
|
|
5
|
+
DuplicateOperationSequenceError,
|
|
6
|
+
InvalidStandardTimeError,
|
|
7
|
+
WorkCenterNotFoundError,
|
|
8
|
+
CrossCompanyWorkCenterError,
|
|
9
|
+
} from "../lib/errors.generated";
|
|
10
|
+
import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
11
|
+
|
|
12
|
+
export interface UpdateRoutingOperationInput {
|
|
13
|
+
sequenceNumber: number;
|
|
14
|
+
operationDescription?: string | null;
|
|
15
|
+
workCenterId: string;
|
|
16
|
+
standardSetupTime: number;
|
|
17
|
+
standardRunTime: number;
|
|
18
|
+
operatorInstructions?: string | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface UpdateRoutingInput {
|
|
22
|
+
id: string;
|
|
23
|
+
revisionNumber?: string | null;
|
|
24
|
+
operations: UpdateRoutingOperationInput[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Function: updateRouting
|
|
29
|
+
*
|
|
30
|
+
* Updates a draft routing's operations. Only DRAFT routings are mutable.
|
|
31
|
+
* Replaces all existing operations with the revised set.
|
|
32
|
+
*/
|
|
33
|
+
export async function run<CF extends Record<string, unknown>>(
|
|
34
|
+
db: Transaction,
|
|
35
|
+
input: UpdateRoutingInput & CF,
|
|
36
|
+
_ctx: CommandContext,
|
|
37
|
+
) {
|
|
38
|
+
const { id, revisionNumber, operations, ...customFields } = input;
|
|
39
|
+
|
|
40
|
+
// 1. Fetch routing
|
|
41
|
+
const routing = await db
|
|
42
|
+
.selectFrom("Routing")
|
|
43
|
+
.selectAll()
|
|
44
|
+
.where("id", "=", id)
|
|
45
|
+
.forUpdate()
|
|
46
|
+
.executeTakeFirst();
|
|
47
|
+
|
|
48
|
+
if (!routing) {
|
|
49
|
+
return err(new RoutingNotFoundError(id));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 2. Verify DRAFT status
|
|
53
|
+
if (routing.status !== "DRAFT") {
|
|
54
|
+
return err(new RoutingNotMutableError(id));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 3. Validate unique sequence numbers
|
|
58
|
+
const seqNumbers = operations.map((op) => op.sequenceNumber);
|
|
59
|
+
const uniqueSeqs = new Set(seqNumbers);
|
|
60
|
+
if (uniqueSeqs.size !== seqNumbers.length) {
|
|
61
|
+
return err(new DuplicateOperationSequenceError(id));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 4. Validate standard times >= 0
|
|
65
|
+
for (const op of operations) {
|
|
66
|
+
if (op.standardSetupTime < 0 || op.standardRunTime < 0) {
|
|
67
|
+
return err(new InvalidStandardTimeError(id));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 5. Validate work centers exist and belong to same company
|
|
72
|
+
for (const op of operations) {
|
|
73
|
+
const workCenter = await db
|
|
74
|
+
.selectFrom("WorkCenter")
|
|
75
|
+
.selectAll()
|
|
76
|
+
.where("id", "=", op.workCenterId)
|
|
77
|
+
.executeTakeFirst();
|
|
78
|
+
|
|
79
|
+
if (!workCenter) {
|
|
80
|
+
return err(new WorkCenterNotFoundError(op.workCenterId));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (workCenter.companyId !== routing.companyId) {
|
|
84
|
+
return err(new CrossCompanyWorkCenterError(op.workCenterId));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 6. Update routing header
|
|
89
|
+
const updatedRouting = await db
|
|
90
|
+
.updateTable("Routing")
|
|
91
|
+
.set({
|
|
92
|
+
...(customFields as Record<string, unknown>),
|
|
93
|
+
...(revisionNumber !== undefined ? { revisionNumber } : {}),
|
|
94
|
+
updatedAt: new Date(),
|
|
95
|
+
})
|
|
96
|
+
.where("id", "=", id)
|
|
97
|
+
.returningAll()
|
|
98
|
+
.executeTakeFirst();
|
|
99
|
+
|
|
100
|
+
// 7. Delete existing operations and replace
|
|
101
|
+
await db.deleteFrom("RoutingOperation").where("routingId", "=", id).execute();
|
|
102
|
+
|
|
103
|
+
const createdOperations = [];
|
|
104
|
+
for (const op of operations) {
|
|
105
|
+
const operation = await db
|
|
106
|
+
.insertInto("RoutingOperation")
|
|
107
|
+
.values({
|
|
108
|
+
routingId: id,
|
|
109
|
+
sequenceNumber: op.sequenceNumber,
|
|
110
|
+
operationDescription: op.operationDescription ?? null,
|
|
111
|
+
workCenterId: op.workCenterId,
|
|
112
|
+
standardSetupTime: op.standardSetupTime,
|
|
113
|
+
standardRunTime: op.standardRunTime,
|
|
114
|
+
operatorInstructions: op.operatorInstructions ?? null,
|
|
115
|
+
createdAt: new Date(),
|
|
116
|
+
updatedAt: null,
|
|
117
|
+
})
|
|
118
|
+
.returningAll()
|
|
119
|
+
.executeTakeFirst();
|
|
120
|
+
createdOperations.push(operation!);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return ok({ routing: updatedRouting!, operations: createdOperations });
|
|
124
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @generated — do not edit
|
|
2
|
+
import { permissions } from "../lib/permissions.generated";
|
|
3
|
+
import { run } from "./updateWorkCenter";
|
|
4
|
+
import { defineCommand } from "@tailor-platform/erp-kit/module";
|
|
5
|
+
|
|
6
|
+
export const updateWorkCenter = defineCommand(permissions.updateWorkCenter, run);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMockDb } from "../../../testing/index";
|
|
3
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
|
+
import {
|
|
5
|
+
WorkCenterNotFoundError,
|
|
6
|
+
InvalidCapacityError,
|
|
7
|
+
InvalidRateError,
|
|
8
|
+
InvalidOverheadMethodError,
|
|
9
|
+
OverheadCurrencyRequiredError,
|
|
10
|
+
ImmutableScopeFieldError,
|
|
11
|
+
} from "../lib/errors.generated";
|
|
12
|
+
import { baseActiveWorkCenter } from "../testing/fixtures";
|
|
13
|
+
import { run } from "./updateWorkCenter";
|
|
14
|
+
import type { CommandContext } from "@tailor-platform/erp-kit/module";
|
|
15
|
+
|
|
16
|
+
describe("updateWorkCenter", () => {
|
|
17
|
+
const ctx: CommandContext = {
|
|
18
|
+
actorId: "test-actor",
|
|
19
|
+
permissions: ["manufacturing:updateWorkCenter"],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const validInput = {
|
|
23
|
+
id: baseActiveWorkCenter.id,
|
|
24
|
+
capacityAssumptions: 200,
|
|
25
|
+
laborRate: 30.0,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
it("updates an active work center without changing scope identity", async () => {
|
|
29
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
30
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
31
|
+
spies.update.mockReturnValue({
|
|
32
|
+
...baseActiveWorkCenter,
|
|
33
|
+
capacityAssumptions: 200,
|
|
34
|
+
laborRate: 30.0,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const result = await run(db, validInput, ctx);
|
|
38
|
+
|
|
39
|
+
expect(result.ok).toBe(true);
|
|
40
|
+
if (result.ok) {
|
|
41
|
+
expect(result.value.workCenter.capacityAssumptions).toBe(200);
|
|
42
|
+
expect(result.value.workCenter.laborRate).toBe(30.0);
|
|
43
|
+
}
|
|
44
|
+
expect(spies.update).toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("returns error when the work center does not exist", async () => {
|
|
48
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
49
|
+
spies.select.mockReturnValueOnce(undefined);
|
|
50
|
+
|
|
51
|
+
const result = await run(db, validInput, ctx);
|
|
52
|
+
|
|
53
|
+
expect(result.ok).toBe(false);
|
|
54
|
+
if (!result.ok) {
|
|
55
|
+
expect(result.error).toBeInstanceOf(WorkCenterNotFoundError);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("returns error when immutable scope fields are changed", async () => {
|
|
60
|
+
const { db } = createMockDb<Transaction>();
|
|
61
|
+
|
|
62
|
+
const result = await run(
|
|
63
|
+
db,
|
|
64
|
+
{ ...validInput, companyId: "other-company" } as Parameters<typeof run>[1],
|
|
65
|
+
ctx,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(result.ok).toBe(false);
|
|
69
|
+
if (!result.ok) {
|
|
70
|
+
expect(result.error).toBeInstanceOf(ImmutableScopeFieldError);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("returns error when capacity is not positive", async () => {
|
|
75
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
76
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
77
|
+
|
|
78
|
+
const result = await run(db, { ...validInput, capacityAssumptions: 0 }, ctx);
|
|
79
|
+
|
|
80
|
+
expect(result.ok).toBe(false);
|
|
81
|
+
if (!result.ok) {
|
|
82
|
+
expect(result.error).toBeInstanceOf(InvalidCapacityError);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("returns error when a rate is negative", async () => {
|
|
87
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
88
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
89
|
+
|
|
90
|
+
const result = await run(db, { ...validInput, laborRate: -1 }, ctx);
|
|
91
|
+
|
|
92
|
+
expect(result.ok).toBe(false);
|
|
93
|
+
if (!result.ok) {
|
|
94
|
+
expect(result.error).toBeInstanceOf(InvalidRateError);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("preserves released cost baselines after update", async () => {
|
|
99
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
100
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
101
|
+
spies.update.mockReturnValue({
|
|
102
|
+
...baseActiveWorkCenter,
|
|
103
|
+
machineRate: 75.0,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const result = await run(db, { id: baseActiveWorkCenter.id, machineRate: 75.0 }, ctx);
|
|
107
|
+
|
|
108
|
+
expect(result.ok).toBe(true);
|
|
109
|
+
expect(spies.update).toHaveBeenCalledTimes(1);
|
|
110
|
+
expect(spies.set).toHaveBeenCalledWith(expect.objectContaining({ machineRate: 75.0 }));
|
|
111
|
+
expect(spies.set).toHaveBeenCalledWith(
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
113
|
+
expect.not.objectContaining({ companyId: expect.anything() }),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("returns error when the overhead method is not supported", async () => {
|
|
118
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
119
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
120
|
+
|
|
121
|
+
const result = await run(
|
|
122
|
+
db,
|
|
123
|
+
{ id: baseActiveWorkCenter.id, overheadAbsorptionMethod: "PER_ORDER" },
|
|
124
|
+
ctx,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
expect(result.ok).toBe(false);
|
|
128
|
+
if (!result.ok) {
|
|
129
|
+
expect(result.error).toBeInstanceOf(InvalidOverheadMethodError);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("returns error when fixed-amount overhead omits currency", async () => {
|
|
134
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
135
|
+
spies.select.mockReturnValueOnce(baseActiveWorkCenter);
|
|
136
|
+
|
|
137
|
+
const result = await run(
|
|
138
|
+
db,
|
|
139
|
+
{
|
|
140
|
+
id: baseActiveWorkCenter.id,
|
|
141
|
+
overheadAbsorptionMethod: "FIXED_AMOUNT_PER_GOOD_UNIT",
|
|
142
|
+
overheadAbsorptionCurrency: null,
|
|
143
|
+
},
|
|
144
|
+
ctx,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
expect(result.ok).toBe(false);
|
|
148
|
+
if (!result.ok) {
|
|
149
|
+
expect(result.error).toBeInstanceOf(OverheadCurrencyRequiredError);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
2
|
+
import {
|
|
3
|
+
WorkCenterNotFoundError,
|
|
4
|
+
InvalidCapacityError,
|
|
5
|
+
InvalidRateError,
|
|
6
|
+
InvalidOverheadMethodError,
|
|
7
|
+
OverheadCurrencyRequiredError,
|
|
8
|
+
ImmutableScopeFieldError,
|
|
9
|
+
} from "../lib/errors.generated";
|
|
10
|
+
import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
11
|
+
|
|
12
|
+
const VALID_OVERHEAD_METHODS = [
|
|
13
|
+
"PERCENT_OF_LABOR_COST",
|
|
14
|
+
"PERCENT_OF_MACHINE_COST",
|
|
15
|
+
"FIXED_AMOUNT_PER_GOOD_UNIT",
|
|
16
|
+
] as const;
|
|
17
|
+
|
|
18
|
+
const IMMUTABLE_FIELDS = ["companyId", "siteId", "code"] as const;
|
|
19
|
+
|
|
20
|
+
export interface UpdateWorkCenterInput {
|
|
21
|
+
id: string;
|
|
22
|
+
capacityAssumptions?: number | null;
|
|
23
|
+
laborRate?: number | null;
|
|
24
|
+
machineRate?: number | null;
|
|
25
|
+
calendarReference?: string | null;
|
|
26
|
+
overheadAbsorptionMethod?: string | null;
|
|
27
|
+
overheadAbsorptionCurrency?: string | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Function: updateWorkCenter
|
|
32
|
+
*
|
|
33
|
+
* Revises mutable work-center master data such as capacity, calendar,
|
|
34
|
+
* rate assumptions, and overhead policy. Only DRAFT or ACTIVE work centers
|
|
35
|
+
* may be updated.
|
|
36
|
+
*/
|
|
37
|
+
export async function run<CF extends Record<string, unknown>>(
|
|
38
|
+
db: Transaction,
|
|
39
|
+
input: UpdateWorkCenterInput & CF,
|
|
40
|
+
_ctx: CommandContext,
|
|
41
|
+
) {
|
|
42
|
+
const {
|
|
43
|
+
id,
|
|
44
|
+
capacityAssumptions,
|
|
45
|
+
laborRate,
|
|
46
|
+
machineRate,
|
|
47
|
+
calendarReference,
|
|
48
|
+
overheadAbsorptionMethod,
|
|
49
|
+
overheadAbsorptionCurrency,
|
|
50
|
+
...customFields
|
|
51
|
+
} = input;
|
|
52
|
+
|
|
53
|
+
// 1. Reject immutable scope fields
|
|
54
|
+
for (const field of IMMUTABLE_FIELDS) {
|
|
55
|
+
if (field in customFields) {
|
|
56
|
+
return err(new ImmutableScopeFieldError(field));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 2. Check work center exists
|
|
61
|
+
const workCenter = await db
|
|
62
|
+
.selectFrom("WorkCenter")
|
|
63
|
+
.selectAll()
|
|
64
|
+
.where("id", "=", id)
|
|
65
|
+
.forUpdate()
|
|
66
|
+
.executeTakeFirst();
|
|
67
|
+
|
|
68
|
+
if (!workCenter) {
|
|
69
|
+
return err(new WorkCenterNotFoundError(id));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 3. Only DRAFT or ACTIVE allowed
|
|
73
|
+
if (workCenter.status !== "DRAFT" && workCenter.status !== "ACTIVE") {
|
|
74
|
+
return err(new WorkCenterNotFoundError(id));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 4. Validate capacity if provided
|
|
78
|
+
if (capacityAssumptions != null && capacityAssumptions <= 0) {
|
|
79
|
+
return err(new InvalidCapacityError(id));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 5. Validate rates if provided
|
|
83
|
+
if (laborRate != null && laborRate < 0) {
|
|
84
|
+
return err(new InvalidRateError(id));
|
|
85
|
+
}
|
|
86
|
+
if (machineRate != null && machineRate < 0) {
|
|
87
|
+
return err(new InvalidRateError(id));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Resolve the effective overhead method after update
|
|
91
|
+
const effectiveMethod =
|
|
92
|
+
overheadAbsorptionMethod !== undefined
|
|
93
|
+
? overheadAbsorptionMethod
|
|
94
|
+
: workCenter.overheadAbsorptionMethod;
|
|
95
|
+
const effectiveCurrency =
|
|
96
|
+
overheadAbsorptionCurrency !== undefined
|
|
97
|
+
? overheadAbsorptionCurrency
|
|
98
|
+
: workCenter.overheadAbsorptionCurrency;
|
|
99
|
+
|
|
100
|
+
// 6. Validate overhead method
|
|
101
|
+
if (
|
|
102
|
+
effectiveMethod != null &&
|
|
103
|
+
!VALID_OVERHEAD_METHODS.includes(effectiveMethod as (typeof VALID_OVERHEAD_METHODS)[number])
|
|
104
|
+
) {
|
|
105
|
+
return err(new InvalidOverheadMethodError(id));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 7. Overhead currency required for FIXED_AMOUNT_PER_GOOD_UNIT
|
|
109
|
+
if (effectiveMethod === "FIXED_AMOUNT_PER_GOOD_UNIT" && !effectiveCurrency) {
|
|
110
|
+
return err(new OverheadCurrencyRequiredError(id));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 8. Build update set
|
|
114
|
+
const updateSet: Record<string, unknown> = {
|
|
115
|
+
...(customFields as Record<string, unknown>),
|
|
116
|
+
updatedAt: new Date(),
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
if (capacityAssumptions !== undefined) updateSet.capacityAssumptions = capacityAssumptions;
|
|
120
|
+
if (laborRate !== undefined) updateSet.laborRate = laborRate;
|
|
121
|
+
if (machineRate !== undefined) updateSet.machineRate = machineRate;
|
|
122
|
+
if (calendarReference !== undefined) updateSet.calendarReference = calendarReference;
|
|
123
|
+
if (overheadAbsorptionMethod !== undefined)
|
|
124
|
+
updateSet.overheadAbsorptionMethod = overheadAbsorptionMethod;
|
|
125
|
+
if (overheadAbsorptionCurrency !== undefined)
|
|
126
|
+
updateSet.overheadAbsorptionCurrency = overheadAbsorptionCurrency;
|
|
127
|
+
|
|
128
|
+
// 9. Persist changes
|
|
129
|
+
const updated = await db
|
|
130
|
+
.updateTable("WorkCenter")
|
|
131
|
+
.set(updateSet)
|
|
132
|
+
.where("id", "=", id)
|
|
133
|
+
.returningAll()
|
|
134
|
+
.executeTakeFirstOrThrow();
|
|
135
|
+
|
|
136
|
+
return ok({ workCenter: updated });
|
|
137
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db,
|
|
3
|
+
type TailorAnyDBField,
|
|
4
|
+
type TailorAnyDBType,
|
|
5
|
+
unsafeAllowAllGqlPermission,
|
|
6
|
+
unsafeAllowAllTypePermission,
|
|
7
|
+
} from "@tailor-platform/sdk";
|
|
8
|
+
import { company as companyStub, site as siteStub, item as itemStub } from "../lib/_db_deps";
|
|
9
|
+
|
|
10
|
+
export const BOM_TYPES = ["MANUFACTURE", "PHANTOM", "KIT"] as const;
|
|
11
|
+
export const BASE_BOM_STATUSES = ["DRAFT", "ACTIVE", "INACTIVE"] as const;
|
|
12
|
+
|
|
13
|
+
export interface CreateBillOfMaterialTypeParams<F extends Record<string, TailorAnyDBField>> {
|
|
14
|
+
fields?: F;
|
|
15
|
+
companyType: TailorAnyDBType;
|
|
16
|
+
siteType: TailorAnyDBType;
|
|
17
|
+
itemType: TailorAnyDBType;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createBillOfMaterialType<const F extends Record<string, TailorAnyDBField>>(
|
|
21
|
+
params: CreateBillOfMaterialTypeParams<F>,
|
|
22
|
+
) {
|
|
23
|
+
return db
|
|
24
|
+
.type("BillOfMaterial", {
|
|
25
|
+
parentItemId: db
|
|
26
|
+
.uuid()
|
|
27
|
+
.relation({
|
|
28
|
+
type: "n-1",
|
|
29
|
+
toward: { type: params.itemType },
|
|
30
|
+
backward: "billOfMaterials",
|
|
31
|
+
})
|
|
32
|
+
.description("Foreign key to Item – the parent/finished item"),
|
|
33
|
+
companyId: db
|
|
34
|
+
.uuid()
|
|
35
|
+
.relation({
|
|
36
|
+
type: "n-1",
|
|
37
|
+
toward: { type: params.companyType },
|
|
38
|
+
backward: "billOfMaterials",
|
|
39
|
+
})
|
|
40
|
+
.description("Foreign key to Company"),
|
|
41
|
+
siteId: db
|
|
42
|
+
.uuid({ optional: true })
|
|
43
|
+
.relation({
|
|
44
|
+
type: "n-1",
|
|
45
|
+
toward: { type: params.siteType },
|
|
46
|
+
backward: "billOfMaterials",
|
|
47
|
+
})
|
|
48
|
+
.description("Optional foreign key to Site – site scope"),
|
|
49
|
+
bomType: db
|
|
50
|
+
.enum([...BOM_TYPES] as [string, ...string[]])
|
|
51
|
+
.description("BOM type: MANUFACTURE, PHANTOM, KIT"),
|
|
52
|
+
effectivityStartDate: db.datetime({ optional: true }).description("Effectivity start date"),
|
|
53
|
+
effectivityEndDate: db.datetime({ optional: true }).description("Effectivity end date"),
|
|
54
|
+
defaultSelection: db.bool({ optional: true }).description("Default selection flag"),
|
|
55
|
+
revisionNumber: db.string({ optional: true }).description("Revision number"),
|
|
56
|
+
status: db
|
|
57
|
+
.enum([...BASE_BOM_STATUSES] as [string, ...string[]])
|
|
58
|
+
.description("Lifecycle status: DRAFT, ACTIVE, INACTIVE"),
|
|
59
|
+
...((params.fields ?? {}) as F),
|
|
60
|
+
...db.fields.timestamps(),
|
|
61
|
+
})
|
|
62
|
+
.permission(unsafeAllowAllTypePermission)
|
|
63
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const billOfMaterial = createBillOfMaterialType({
|
|
67
|
+
companyType: companyStub,
|
|
68
|
+
siteType: siteStub,
|
|
69
|
+
itemType: itemStub,
|
|
70
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db,
|
|
3
|
+
type TailorAnyDBType,
|
|
4
|
+
unsafeAllowAllGqlPermission,
|
|
5
|
+
unsafeAllowAllTypePermission,
|
|
6
|
+
} from "@tailor-platform/sdk";
|
|
7
|
+
import { item as itemStub } from "../lib/_db_deps";
|
|
8
|
+
import { billOfMaterial } from "./billOfMaterial";
|
|
9
|
+
|
|
10
|
+
export interface CreateBillOfMaterialLineTypeParams {
|
|
11
|
+
billOfMaterialType: TailorAnyDBType;
|
|
12
|
+
itemType: TailorAnyDBType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createBillOfMaterialLineType(params: CreateBillOfMaterialLineTypeParams) {
|
|
16
|
+
return db
|
|
17
|
+
.type("BillOfMaterialLine", {
|
|
18
|
+
billOfMaterialId: db
|
|
19
|
+
.uuid()
|
|
20
|
+
.relation({
|
|
21
|
+
type: "n-1",
|
|
22
|
+
toward: { type: params.billOfMaterialType },
|
|
23
|
+
backward: "billOfMaterialLines",
|
|
24
|
+
})
|
|
25
|
+
.description("Foreign key to BillOfMaterial"),
|
|
26
|
+
itemId: db
|
|
27
|
+
.uuid()
|
|
28
|
+
.relation({
|
|
29
|
+
type: "n-1",
|
|
30
|
+
toward: { type: params.itemType },
|
|
31
|
+
backward: "bomLineReferences",
|
|
32
|
+
})
|
|
33
|
+
.description("Foreign key to Item – component item"),
|
|
34
|
+
requiredQuantity: db.float().description("Required quantity, must be greater than 0"),
|
|
35
|
+
unitOfMeasure: db.string({ optional: true }).description("Compatible unit of measure"),
|
|
36
|
+
scrapAssumption: db.float({ optional: true }).description("Scrap assumption percentage"),
|
|
37
|
+
isSubassembly: db
|
|
38
|
+
.bool({ optional: true })
|
|
39
|
+
.description("Whether this component is a subassembly"),
|
|
40
|
+
...db.fields.timestamps(),
|
|
41
|
+
})
|
|
42
|
+
.permission(unsafeAllowAllTypePermission)
|
|
43
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const billOfMaterialLine = createBillOfMaterialLineType({
|
|
47
|
+
billOfMaterialType: billOfMaterial,
|
|
48
|
+
itemType: itemStub,
|
|
49
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db,
|
|
3
|
+
type TailorAnyDBType,
|
|
4
|
+
unsafeAllowAllGqlPermission,
|
|
5
|
+
unsafeAllowAllTypePermission,
|
|
6
|
+
} from "@tailor-platform/sdk";
|
|
7
|
+
import { manufacturingCostSummary } from "./manufacturingCostSummary";
|
|
8
|
+
|
|
9
|
+
export const VARIANCE_TYPES = [
|
|
10
|
+
"MATERIAL_PRICE",
|
|
11
|
+
"MATERIAL_USAGE",
|
|
12
|
+
"LABOR_RATE",
|
|
13
|
+
"LABOR_EFFICIENCY",
|
|
14
|
+
"MACHINE_RATE",
|
|
15
|
+
"MACHINE_EFFICIENCY",
|
|
16
|
+
"SCRAP",
|
|
17
|
+
"YIELD",
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
export interface CreateCostVarianceLineTypeParams {
|
|
21
|
+
costSummaryType: TailorAnyDBType;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createCostVarianceLineType(params: CreateCostVarianceLineTypeParams) {
|
|
25
|
+
return db
|
|
26
|
+
.type("CostVarianceLine", {
|
|
27
|
+
costSummaryId: db
|
|
28
|
+
.uuid()
|
|
29
|
+
.relation({
|
|
30
|
+
type: "n-1",
|
|
31
|
+
toward: { type: params.costSummaryType },
|
|
32
|
+
backward: "varianceLines",
|
|
33
|
+
})
|
|
34
|
+
.description("Foreign key to ManufacturingCostSummary"),
|
|
35
|
+
varianceType: db
|
|
36
|
+
.enum([...VARIANCE_TYPES] as [string, ...string[]])
|
|
37
|
+
.description(
|
|
38
|
+
"Variance type: MATERIAL_PRICE, MATERIAL_USAGE, LABOR_RATE, LABOR_EFFICIENCY, MACHINE_RATE, MACHINE_EFFICIENCY, SCRAP, YIELD",
|
|
39
|
+
),
|
|
40
|
+
amount: db.float().description("Variance amount"),
|
|
41
|
+
accountReference: db
|
|
42
|
+
.string({ optional: true })
|
|
43
|
+
.description("Optional account reference for settlement"),
|
|
44
|
+
variancePercentage: db.float({ optional: true }).description("Variance as a percentage"),
|
|
45
|
+
...db.fields.timestamps(),
|
|
46
|
+
})
|
|
47
|
+
.permission(unsafeAllowAllTypePermission)
|
|
48
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const costVarianceLine = createCostVarianceLineType({
|
|
52
|
+
costSummaryType: manufacturingCostSummary,
|
|
53
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db,
|
|
3
|
+
type TailorAnyDBType,
|
|
4
|
+
unsafeAllowAllGqlPermission,
|
|
5
|
+
unsafeAllowAllTypePermission,
|
|
6
|
+
} from "@tailor-platform/sdk";
|
|
7
|
+
import { manufacturingCostSummary } from "./manufacturingCostSummary";
|
|
8
|
+
|
|
9
|
+
export interface CreateManufacturingCostLineTypeParams {
|
|
10
|
+
costSummaryType: TailorAnyDBType;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createManufacturingCostLineType(params: CreateManufacturingCostLineTypeParams) {
|
|
14
|
+
return db
|
|
15
|
+
.type("ManufacturingCostLine", {
|
|
16
|
+
costSummaryId: db
|
|
17
|
+
.uuid()
|
|
18
|
+
.relation({
|
|
19
|
+
type: "n-1",
|
|
20
|
+
toward: { type: params.costSummaryType },
|
|
21
|
+
backward: "costLines",
|
|
22
|
+
})
|
|
23
|
+
.description("Foreign key to ManufacturingCostSummary"),
|
|
24
|
+
costType: db.string().description("Cost type: e.g. MATERIAL, LABOR, MACHINE, OVERHEAD"),
|
|
25
|
+
plannedAmount: db.float().description("Planned cost amount"),
|
|
26
|
+
actualAmount: db.float().description("Actual cost amount"),
|
|
27
|
+
...db.fields.timestamps(),
|
|
28
|
+
})
|
|
29
|
+
.permission(unsafeAllowAllTypePermission)
|
|
30
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const manufacturingCostLine = createManufacturingCostLineType({
|
|
34
|
+
costSummaryType: manufacturingCostSummary,
|
|
35
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
db,
|
|
3
|
+
type TailorAnyDBType,
|
|
4
|
+
unsafeAllowAllGqlPermission,
|
|
5
|
+
unsafeAllowAllTypePermission,
|
|
6
|
+
} from "@tailor-platform/sdk";
|
|
7
|
+
import { manufacturingCostSummary } from "./manufacturingCostSummary";
|
|
8
|
+
|
|
9
|
+
export interface CreateManufacturingCostSettlementRecordTypeParams {
|
|
10
|
+
costSummaryType: TailorAnyDBType;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createManufacturingCostSettlementRecordType(
|
|
14
|
+
params: CreateManufacturingCostSettlementRecordTypeParams,
|
|
15
|
+
) {
|
|
16
|
+
return db
|
|
17
|
+
.type("ManufacturingCostSettlementRecord", {
|
|
18
|
+
costSummaryId: db
|
|
19
|
+
.uuid()
|
|
20
|
+
.relation({
|
|
21
|
+
type: "n-1",
|
|
22
|
+
toward: { type: params.costSummaryType },
|
|
23
|
+
backward: "settlementRecords",
|
|
24
|
+
})
|
|
25
|
+
.description("Foreign key to ManufacturingCostSummary"),
|
|
26
|
+
settlementDate: db.datetime().description("Date of settlement"),
|
|
27
|
+
settlementReference: db.string().description("Reference identifier for the settlement"),
|
|
28
|
+
acknowledgedDate: db
|
|
29
|
+
.datetime({ optional: true })
|
|
30
|
+
.description("Date when settlement was acknowledged"),
|
|
31
|
+
...db.fields.timestamps(),
|
|
32
|
+
})
|
|
33
|
+
.permission(unsafeAllowAllTypePermission)
|
|
34
|
+
.gqlPermission(unsafeAllowAllGqlPermission);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const manufacturingCostSettlementRecord = createManufacturingCostSettlementRecordType({
|
|
38
|
+
costSummaryType: manufacturingCostSummary,
|
|
39
|
+
});
|