@naisys/erp 3.0.0-beta.3

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.

Potentially problematic release.


This version of @naisys/erp might be problematic. Click here for more details.

Files changed (201) hide show
  1. package/bin/naisys-erp +2 -0
  2. package/client-dist/android-chrome-192x192.png +0 -0
  3. package/client-dist/android-chrome-512x512.png +0 -0
  4. package/client-dist/apple-touch-icon.png +0 -0
  5. package/client-dist/assets/index-45dVo30p.css +1 -0
  6. package/client-dist/assets/index-Dffms7F_.js +168 -0
  7. package/client-dist/assets/naisys-logo-CzoPnn5I.webp +0 -0
  8. package/client-dist/favicon.ico +0 -0
  9. package/client-dist/index.html +42 -0
  10. package/client-dist/site.webmanifest +22 -0
  11. package/dist/api-reference.d.ts +10 -0
  12. package/dist/api-reference.js +101 -0
  13. package/dist/audit.d.ts +5 -0
  14. package/dist/audit.js +14 -0
  15. package/dist/auth-middleware.d.ts +18 -0
  16. package/dist/auth-middleware.js +203 -0
  17. package/dist/dbConfig.d.ts +5 -0
  18. package/dist/dbConfig.js +10 -0
  19. package/dist/erpDb.d.ts +10 -0
  20. package/dist/erpDb.js +34 -0
  21. package/dist/erpServer.d.ts +10 -0
  22. package/dist/erpServer.js +321 -0
  23. package/dist/error-handler.d.ts +7 -0
  24. package/dist/error-handler.js +17 -0
  25. package/dist/generated/prisma/client.d.ts +154 -0
  26. package/dist/generated/prisma/client.js +35 -0
  27. package/dist/generated/prisma/commonInputTypes.d.ts +637 -0
  28. package/dist/generated/prisma/commonInputTypes.js +11 -0
  29. package/dist/generated/prisma/enums.d.ts +59 -0
  30. package/dist/generated/prisma/enums.js +60 -0
  31. package/dist/generated/prisma/internal/class.d.ts +406 -0
  32. package/dist/generated/prisma/internal/class.js +50 -0
  33. package/dist/generated/prisma/internal/prismaNamespace.d.ts +2722 -0
  34. package/dist/generated/prisma/internal/prismaNamespace.js +366 -0
  35. package/dist/generated/prisma/models/Attachment.d.ts +1455 -0
  36. package/dist/generated/prisma/models/Attachment.js +2 -0
  37. package/dist/generated/prisma/models/AuditLog.d.ts +1359 -0
  38. package/dist/generated/prisma/models/AuditLog.js +2 -0
  39. package/dist/generated/prisma/models/Field.d.ts +1880 -0
  40. package/dist/generated/prisma/models/Field.js +2 -0
  41. package/dist/generated/prisma/models/FieldAttachment.d.ts +1245 -0
  42. package/dist/generated/prisma/models/FieldAttachment.js +2 -0
  43. package/dist/generated/prisma/models/FieldRecord.d.ts +1625 -0
  44. package/dist/generated/prisma/models/FieldRecord.js +2 -0
  45. package/dist/generated/prisma/models/FieldSet.d.ts +1577 -0
  46. package/dist/generated/prisma/models/FieldSet.js +2 -0
  47. package/dist/generated/prisma/models/FieldValue.d.ts +1908 -0
  48. package/dist/generated/prisma/models/FieldValue.js +2 -0
  49. package/dist/generated/prisma/models/Item.d.ts +1858 -0
  50. package/dist/generated/prisma/models/Item.js +2 -0
  51. package/dist/generated/prisma/models/ItemInstance.d.ts +1987 -0
  52. package/dist/generated/prisma/models/ItemInstance.js +2 -0
  53. package/dist/generated/prisma/models/LaborTicket.d.ts +1867 -0
  54. package/dist/generated/prisma/models/LaborTicket.js +2 -0
  55. package/dist/generated/prisma/models/Operation.d.ts +2578 -0
  56. package/dist/generated/prisma/models/Operation.js +2 -0
  57. package/dist/generated/prisma/models/OperationDependency.d.ts +1434 -0
  58. package/dist/generated/prisma/models/OperationDependency.js +2 -0
  59. package/dist/generated/prisma/models/OperationFieldRef.d.ts +1539 -0
  60. package/dist/generated/prisma/models/OperationFieldRef.js +2 -0
  61. package/dist/generated/prisma/models/OperationRun.d.ts +2563 -0
  62. package/dist/generated/prisma/models/OperationRun.js +2 -0
  63. package/dist/generated/prisma/models/OperationRunComment.d.ts +1366 -0
  64. package/dist/generated/prisma/models/OperationRunComment.js +2 -0
  65. package/dist/generated/prisma/models/Order.d.ts +1931 -0
  66. package/dist/generated/prisma/models/Order.js +2 -0
  67. package/dist/generated/prisma/models/OrderRevision.d.ts +1962 -0
  68. package/dist/generated/prisma/models/OrderRevision.js +2 -0
  69. package/dist/generated/prisma/models/OrderRun.d.ts +2310 -0
  70. package/dist/generated/prisma/models/OrderRun.js +2 -0
  71. package/dist/generated/prisma/models/SchemaVersion.d.ts +985 -0
  72. package/dist/generated/prisma/models/SchemaVersion.js +2 -0
  73. package/dist/generated/prisma/models/Session.d.ts +1213 -0
  74. package/dist/generated/prisma/models/Session.js +2 -0
  75. package/dist/generated/prisma/models/Step.d.ts +2180 -0
  76. package/dist/generated/prisma/models/Step.js +2 -0
  77. package/dist/generated/prisma/models/StepRun.d.ts +1963 -0
  78. package/dist/generated/prisma/models/StepRun.js +2 -0
  79. package/dist/generated/prisma/models/User.d.ts +11819 -0
  80. package/dist/generated/prisma/models/User.js +2 -0
  81. package/dist/generated/prisma/models/UserPermission.d.ts +1348 -0
  82. package/dist/generated/prisma/models/UserPermission.js +2 -0
  83. package/dist/generated/prisma/models/WorkCenter.d.ts +1657 -0
  84. package/dist/generated/prisma/models/WorkCenter.js +2 -0
  85. package/dist/generated/prisma/models/WorkCenterUser.d.ts +1390 -0
  86. package/dist/generated/prisma/models/WorkCenterUser.js +2 -0
  87. package/dist/generated/prisma/models.d.ts +28 -0
  88. package/dist/generated/prisma/models.js +2 -0
  89. package/dist/hateoas.d.ts +7 -0
  90. package/dist/hateoas.js +61 -0
  91. package/dist/route-helpers.d.ts +318 -0
  92. package/dist/route-helpers.js +220 -0
  93. package/dist/routes/admin.d.ts +3 -0
  94. package/dist/routes/admin.js +147 -0
  95. package/dist/routes/audit.d.ts +3 -0
  96. package/dist/routes/audit.js +36 -0
  97. package/dist/routes/auth.d.ts +3 -0
  98. package/dist/routes/auth.js +112 -0
  99. package/dist/routes/dispatch.d.ts +3 -0
  100. package/dist/routes/dispatch.js +174 -0
  101. package/dist/routes/inventory.d.ts +3 -0
  102. package/dist/routes/inventory.js +70 -0
  103. package/dist/routes/item-fields.d.ts +3 -0
  104. package/dist/routes/item-fields.js +220 -0
  105. package/dist/routes/item-instances.d.ts +3 -0
  106. package/dist/routes/item-instances.js +426 -0
  107. package/dist/routes/items.d.ts +3 -0
  108. package/dist/routes/items.js +252 -0
  109. package/dist/routes/labor-tickets.d.ts +3 -0
  110. package/dist/routes/labor-tickets.js +268 -0
  111. package/dist/routes/operation-dependencies.d.ts +3 -0
  112. package/dist/routes/operation-dependencies.js +170 -0
  113. package/dist/routes/operation-field-refs.d.ts +3 -0
  114. package/dist/routes/operation-field-refs.js +263 -0
  115. package/dist/routes/operation-run-comments.d.ts +3 -0
  116. package/dist/routes/operation-run-comments.js +108 -0
  117. package/dist/routes/operation-run-transitions.d.ts +3 -0
  118. package/dist/routes/operation-run-transitions.js +249 -0
  119. package/dist/routes/operation-runs.d.ts +112 -0
  120. package/dist/routes/operation-runs.js +299 -0
  121. package/dist/routes/operations.d.ts +3 -0
  122. package/dist/routes/operations.js +283 -0
  123. package/dist/routes/order-revision-transitions.d.ts +3 -0
  124. package/dist/routes/order-revision-transitions.js +86 -0
  125. package/dist/routes/order-revisions.d.ts +51 -0
  126. package/dist/routes/order-revisions.js +327 -0
  127. package/dist/routes/order-run-transitions.d.ts +3 -0
  128. package/dist/routes/order-run-transitions.js +215 -0
  129. package/dist/routes/order-runs.d.ts +58 -0
  130. package/dist/routes/order-runs.js +335 -0
  131. package/dist/routes/orders.d.ts +3 -0
  132. package/dist/routes/orders.js +262 -0
  133. package/dist/routes/root.d.ts +3 -0
  134. package/dist/routes/root.js +123 -0
  135. package/dist/routes/schemas.d.ts +3 -0
  136. package/dist/routes/schemas.js +31 -0
  137. package/dist/routes/step-field-attachments.d.ts +3 -0
  138. package/dist/routes/step-field-attachments.js +231 -0
  139. package/dist/routes/step-fields.d.ts +100 -0
  140. package/dist/routes/step-fields.js +315 -0
  141. package/dist/routes/step-run-fields.d.ts +3 -0
  142. package/dist/routes/step-run-fields.js +438 -0
  143. package/dist/routes/step-run-transitions.d.ts +3 -0
  144. package/dist/routes/step-run-transitions.js +113 -0
  145. package/dist/routes/step-runs.d.ts +332 -0
  146. package/dist/routes/step-runs.js +324 -0
  147. package/dist/routes/steps.d.ts +3 -0
  148. package/dist/routes/steps.js +283 -0
  149. package/dist/routes/user-permissions.d.ts +3 -0
  150. package/dist/routes/user-permissions.js +100 -0
  151. package/dist/routes/users.d.ts +57 -0
  152. package/dist/routes/users.js +381 -0
  153. package/dist/routes/work-centers.d.ts +3 -0
  154. package/dist/routes/work-centers.js +280 -0
  155. package/dist/schema-registry.d.ts +3 -0
  156. package/dist/schema-registry.js +45 -0
  157. package/dist/services/attachment-service.d.ts +33 -0
  158. package/dist/services/attachment-service.js +118 -0
  159. package/dist/services/field-ref-service.d.ts +96 -0
  160. package/dist/services/field-ref-service.js +74 -0
  161. package/dist/services/field-service.d.ts +49 -0
  162. package/dist/services/field-service.js +114 -0
  163. package/dist/services/field-value-service.d.ts +61 -0
  164. package/dist/services/field-value-service.js +256 -0
  165. package/dist/services/item-instance-service.d.ts +152 -0
  166. package/dist/services/item-instance-service.js +155 -0
  167. package/dist/services/item-service.d.ts +47 -0
  168. package/dist/services/item-service.js +56 -0
  169. package/dist/services/labor-ticket-service.d.ts +40 -0
  170. package/dist/services/labor-ticket-service.js +148 -0
  171. package/dist/services/log-file-service.d.ts +4 -0
  172. package/dist/services/log-file-service.js +11 -0
  173. package/dist/services/operation-dependency-service.d.ts +33 -0
  174. package/dist/services/operation-dependency-service.js +30 -0
  175. package/dist/services/operation-run-comment-service.d.ts +17 -0
  176. package/dist/services/operation-run-comment-service.js +26 -0
  177. package/dist/services/operation-run-service.d.ts +126 -0
  178. package/dist/services/operation-run-service.js +347 -0
  179. package/dist/services/operation-service.d.ts +47 -0
  180. package/dist/services/operation-service.js +132 -0
  181. package/dist/services/order-revision-service.d.ts +53 -0
  182. package/dist/services/order-revision-service.js +264 -0
  183. package/dist/services/order-run-service.d.ts +138 -0
  184. package/dist/services/order-run-service.js +356 -0
  185. package/dist/services/order-service.d.ts +15 -0
  186. package/dist/services/order-service.js +68 -0
  187. package/dist/services/revision-diff-service.d.ts +3 -0
  188. package/dist/services/revision-diff-service.js +194 -0
  189. package/dist/services/step-run-service.d.ts +172 -0
  190. package/dist/services/step-run-service.js +106 -0
  191. package/dist/services/step-service.d.ts +104 -0
  192. package/dist/services/step-service.js +89 -0
  193. package/dist/services/user-service.d.ts +185 -0
  194. package/dist/services/user-service.js +132 -0
  195. package/dist/services/work-center-service.d.ts +29 -0
  196. package/dist/services/work-center-service.js +106 -0
  197. package/dist/supervisorAuth.d.ts +3 -0
  198. package/dist/supervisorAuth.js +16 -0
  199. package/dist/userService.d.ts +20 -0
  200. package/dist/userService.js +118 -0
  201. package/package.json +69 -0
@@ -0,0 +1,45 @@
1
+ import { AssignWorkCenterUserSchema, BatchCreateFieldSchema, BatchCreateStepSchema, BatchUpdateFieldValuesSchema, ChangePasswordSchema, ClockOutLaborTicketSchema, CompleteOrderRunSchema, CreateAgentUserSchema, CreateFieldRefSchema, CreateFieldSchema, CreateItemInstanceSchema, CreateItemSchema, CreateOperationDependencySchema, CreateOperationRunCommentSchema, CreateOperationSchema, CreateOrderRevisionSchema, CreateOrderRunSchema, CreateOrderSchema, CreateStepSchema, CreateUserSchema, CreateWorkCenterSchema, GrantPermissionSchema, LoginRequestSchema, TransitionNoteSchema, UpdateFieldSchema, UpdateFieldValueSchema, UpdateItemInstanceSchema, UpdateItemSchema, UpdateOperationRunSchema, UpdateOperationSchema, UpdateOrderRevisionSchema, UpdateOrderRunSchema, UpdateOrderSchema, UpdateStepSchema, UpdateUserSchema, UpdateWorkCenterSchema, } from "@naisys/erp-shared";
2
+ import { z } from "zod/v4";
3
+ export const schemaRegistry = {
4
+ CreateItem: CreateItemSchema,
5
+ UpdateItem: UpdateItemSchema,
6
+ CreateItemInstance: CreateItemInstanceSchema,
7
+ UpdateItemInstance: UpdateItemInstanceSchema,
8
+ CreateOrder: CreateOrderSchema,
9
+ UpdateOrder: UpdateOrderSchema,
10
+ CreateOrderRevision: CreateOrderRevisionSchema,
11
+ UpdateOrderRevision: UpdateOrderRevisionSchema,
12
+ CreateOrderRun: CreateOrderRunSchema,
13
+ UpdateOrderRun: UpdateOrderRunSchema,
14
+ CompleteOrderRun: CompleteOrderRunSchema,
15
+ CreateOperation: CreateOperationSchema,
16
+ CreateFieldRef: CreateFieldRefSchema,
17
+ CreateOperationDependency: CreateOperationDependencySchema,
18
+ UpdateOperation: UpdateOperationSchema,
19
+ TransitionNote: TransitionNoteSchema,
20
+ UpdateOperationRun: UpdateOperationRunSchema,
21
+ CreateOperationRunComment: CreateOperationRunCommentSchema,
22
+ CreateStep: CreateStepSchema,
23
+ BatchCreateStep: BatchCreateStepSchema,
24
+ UpdateStep: UpdateStepSchema,
25
+ CreateField: CreateFieldSchema,
26
+ BatchCreateField: BatchCreateFieldSchema,
27
+ UpdateField: UpdateFieldSchema,
28
+ UpdateFieldValue: UpdateFieldValueSchema,
29
+ BatchUpdateFieldValues: BatchUpdateFieldValuesSchema,
30
+ LoginRequest: LoginRequestSchema,
31
+ CreateUser: CreateUserSchema,
32
+ CreateAgentUser: CreateAgentUserSchema,
33
+ UpdateUser: UpdateUserSchema,
34
+ GrantPermission: GrantPermissionSchema,
35
+ ChangePassword: ChangePasswordSchema,
36
+ ClockOutLaborTicket: ClockOutLaborTicketSchema,
37
+ CreateWorkCenter: CreateWorkCenterSchema,
38
+ UpdateWorkCenter: UpdateWorkCenterSchema,
39
+ AssignWorkCenterUser: AssignWorkCenterUserSchema,
40
+ };
41
+ // Register schemas with Zod global registry for OpenAPI components/schemas population
42
+ for (const [name, schema] of Object.entries(schemaRegistry)) {
43
+ z.globalRegistry.add(schema, { id: name });
44
+ }
45
+ //# sourceMappingURL=schema-registry.js.map
@@ -0,0 +1,33 @@
1
+ export interface UploadResult {
2
+ attachmentId: string;
3
+ filename: string;
4
+ fileSize: number;
5
+ fileHash: string;
6
+ }
7
+ /**
8
+ * Store a file buffer as a content-addressable attachment under
9
+ * attachments/erp/<first2>/<next2>/<fullhash>
10
+ * and create the DB records (Attachment + FieldAttachment).
11
+ */
12
+ export declare function uploadAttachment(fileBuffer: Buffer, filename: string, uploadedById: number, fieldValueId: number): Promise<UploadResult>;
13
+ /**
14
+ * List attachments for a field value.
15
+ */
16
+ export declare function listAttachmentsForFieldValue(fieldValueId: number): Promise<{
17
+ id: string;
18
+ filename: string;
19
+ fileSize: number;
20
+ }[]>;
21
+ /**
22
+ * Get an attachment's file path for download.
23
+ */
24
+ export declare function getAttachmentFilePath(publicId: string): Promise<{
25
+ filepath: string;
26
+ filename: string;
27
+ } | null>;
28
+ /**
29
+ * Delete a field attachment link. Does NOT delete the file on disk
30
+ * (other records may reference the same content-addressable file).
31
+ */
32
+ export declare function deleteFieldAttachment(fieldValueId: number, publicId: string): Promise<void>;
33
+ //# sourceMappingURL=attachment-service.d.ts.map
@@ -0,0 +1,118 @@
1
+ import { MAX_ATTACHMENT_SIZE } from "@naisys/common";
2
+ import { createHash, randomBytes } from "crypto";
3
+ import { createWriteStream, existsSync, mkdirSync, renameSync, unlinkSync, } from "fs";
4
+ import { join } from "path";
5
+ import erpDb from "../erpDb.js";
6
+ function attachmentsDir() {
7
+ return join(process.env.NAISYS_FOLDER || "", "attachments");
8
+ }
9
+ /**
10
+ * Store a file buffer as a content-addressable attachment under
11
+ * attachments/erp/<first2>/<next2>/<fullhash>
12
+ * and create the DB records (Attachment + FieldAttachment).
13
+ */
14
+ export async function uploadAttachment(fileBuffer, filename, uploadedById, fieldValueId) {
15
+ if (fileBuffer.length === 0) {
16
+ throw new Error("Empty file");
17
+ }
18
+ if (fileBuffer.length > MAX_ATTACHMENT_SIZE) {
19
+ throw new Error(`File too large. Max size: ${MAX_ATTACHMENT_SIZE} bytes`);
20
+ }
21
+ const fileHash = createHash("sha256").update(fileBuffer).digest("hex");
22
+ // Write to temp, then move to content-addressable path
23
+ const tmpDir = join(attachmentsDir(), "tmp");
24
+ mkdirSync(tmpDir, { recursive: true });
25
+ const tmpPath = join(tmpDir, `${Date.now()}_${uploadedById}_${Math.random().toString(36).slice(2)}`);
26
+ const ws = createWriteStream(tmpPath);
27
+ await new Promise((resolve, reject) => {
28
+ ws.on("finish", resolve);
29
+ ws.on("error", reject);
30
+ ws.end(fileBuffer);
31
+ });
32
+ const storageDir = join(attachmentsDir(), "erp", fileHash.slice(0, 2), fileHash.slice(2, 4));
33
+ mkdirSync(storageDir, { recursive: true });
34
+ const storagePath = join(storageDir, fileHash);
35
+ if (existsSync(storagePath)) {
36
+ try {
37
+ unlinkSync(tmpPath);
38
+ }
39
+ catch {
40
+ /* ignore */
41
+ }
42
+ }
43
+ else {
44
+ renameSync(tmpPath, storagePath);
45
+ }
46
+ // Create Attachment + FieldAttachment in a transaction
47
+ const attachment = await erpDb.$transaction(async (tx) => {
48
+ const att = await tx.attachment.create({
49
+ data: {
50
+ publicId: randomBytes(8).toString("base64url").slice(0, 10),
51
+ filepath: storagePath,
52
+ filename,
53
+ fileSize: fileBuffer.length,
54
+ fileHash,
55
+ uploadedById,
56
+ },
57
+ });
58
+ await tx.fieldAttachment.create({
59
+ data: {
60
+ fieldValueId,
61
+ attachmentId: att.id,
62
+ },
63
+ });
64
+ return att;
65
+ });
66
+ return {
67
+ attachmentId: attachment.publicId,
68
+ filename: attachment.filename,
69
+ fileSize: attachment.fileSize,
70
+ fileHash: attachment.fileHash,
71
+ };
72
+ }
73
+ /**
74
+ * List attachments for a field value.
75
+ */
76
+ export async function listAttachmentsForFieldValue(fieldValueId) {
77
+ const links = await erpDb.fieldAttachment.findMany({
78
+ where: { fieldValueId },
79
+ include: {
80
+ attachment: {
81
+ select: { publicId: true, filename: true, fileSize: true },
82
+ },
83
+ },
84
+ });
85
+ return links.map((l) => ({
86
+ id: l.attachment.publicId,
87
+ filename: l.attachment.filename,
88
+ fileSize: l.attachment.fileSize,
89
+ }));
90
+ }
91
+ /**
92
+ * Get an attachment's file path for download.
93
+ */
94
+ export async function getAttachmentFilePath(publicId) {
95
+ const att = await erpDb.attachment.findUnique({
96
+ where: { publicId },
97
+ select: { filepath: true, filename: true },
98
+ });
99
+ return att;
100
+ }
101
+ /**
102
+ * Delete a field attachment link. Does NOT delete the file on disk
103
+ * (other records may reference the same content-addressable file).
104
+ */
105
+ export async function deleteFieldAttachment(fieldValueId, publicId) {
106
+ const att = await erpDb.attachment.findUnique({
107
+ where: { publicId },
108
+ select: { id: true },
109
+ });
110
+ if (!att)
111
+ throw new Error("Attachment not found");
112
+ await erpDb.fieldAttachment.delete({
113
+ where: {
114
+ fieldValueId_attachmentId: { fieldValueId, attachmentId: att.id },
115
+ },
116
+ });
117
+ }
118
+ //# sourceMappingURL=attachment-service.js.map
@@ -0,0 +1,96 @@
1
+ export type FieldRefWithDetails = Awaited<ReturnType<typeof listFieldRefs>>[number];
2
+ export declare function listFieldRefs(operationId: number): Promise<({
3
+ createdBy: {
4
+ username: string;
5
+ };
6
+ sourceStep: {
7
+ title: string;
8
+ operation: {
9
+ title: string;
10
+ seqNo: number;
11
+ };
12
+ fieldSet: {
13
+ fields: {
14
+ seqNo: number;
15
+ type: import("../generated/prisma/enums.js").FieldType;
16
+ label: string;
17
+ }[];
18
+ } | null;
19
+ seqNo: number;
20
+ };
21
+ } & {
22
+ title: string;
23
+ operationId: number;
24
+ createdAt: Date;
25
+ id: number;
26
+ seqNo: number;
27
+ createdById: number;
28
+ sourceStepId: number;
29
+ })[]>;
30
+ export declare function getFieldRef(operationId: number, seqNo: number): Promise<({
31
+ createdBy: {
32
+ username: string;
33
+ };
34
+ sourceStep: {
35
+ title: string;
36
+ operation: {
37
+ title: string;
38
+ seqNo: number;
39
+ };
40
+ fieldSet: {
41
+ fields: {
42
+ seqNo: number;
43
+ type: import("../generated/prisma/enums.js").FieldType;
44
+ label: string;
45
+ }[];
46
+ } | null;
47
+ seqNo: number;
48
+ };
49
+ } & {
50
+ title: string;
51
+ operationId: number;
52
+ createdAt: Date;
53
+ id: number;
54
+ seqNo: number;
55
+ createdById: number;
56
+ sourceStepId: number;
57
+ }) | null>;
58
+ export declare function createFieldRef(operationId: number, seqNo: number | undefined, title: string, sourceStepId: number, userId: number): Promise<{
59
+ createdBy: {
60
+ username: string;
61
+ };
62
+ sourceStep: {
63
+ title: string;
64
+ operation: {
65
+ title: string;
66
+ seqNo: number;
67
+ };
68
+ fieldSet: {
69
+ fields: {
70
+ seqNo: number;
71
+ type: import("../generated/prisma/enums.js").FieldType;
72
+ label: string;
73
+ }[];
74
+ } | null;
75
+ seqNo: number;
76
+ };
77
+ } & {
78
+ title: string;
79
+ operationId: number;
80
+ createdAt: Date;
81
+ id: number;
82
+ seqNo: number;
83
+ createdById: number;
84
+ sourceStepId: number;
85
+ }>;
86
+ export declare function deleteFieldRef(id: number): Promise<void>;
87
+ export declare function findExistingFieldRef(operationId: number, seqNo: number): Promise<{
88
+ id: number;
89
+ } | null>;
90
+ /**
91
+ * Check if a source step already has a field ref for this operation.
92
+ */
93
+ export declare function checkDuplicateSource(operationId: number, sourceStepId: number): Promise<{
94
+ id: number;
95
+ } | null>;
96
+ //# sourceMappingURL=field-ref-service.d.ts.map
@@ -0,0 +1,74 @@
1
+ import erpDb from "../erpDb.js";
2
+ const includeFieldRef = {
3
+ sourceStep: {
4
+ select: {
5
+ seqNo: true,
6
+ title: true,
7
+ operation: { select: { seqNo: true, title: true } },
8
+ fieldSet: {
9
+ select: {
10
+ fields: {
11
+ select: { seqNo: true, label: true, type: true },
12
+ orderBy: { seqNo: "asc" },
13
+ },
14
+ },
15
+ },
16
+ },
17
+ },
18
+ createdBy: { select: { username: true } },
19
+ };
20
+ export async function listFieldRefs(operationId) {
21
+ return erpDb.operationFieldRef.findMany({
22
+ where: { operationId },
23
+ include: includeFieldRef,
24
+ orderBy: { seqNo: "asc" },
25
+ });
26
+ }
27
+ export async function getFieldRef(operationId, seqNo) {
28
+ return erpDb.operationFieldRef.findFirst({
29
+ where: { operationId, seqNo },
30
+ include: includeFieldRef,
31
+ });
32
+ }
33
+ export async function createFieldRef(operationId, seqNo, title, sourceStepId, userId) {
34
+ // Auto-assign seqNo if not provided
35
+ let assignedSeqNo = seqNo;
36
+ if (!assignedSeqNo) {
37
+ const maxRow = await erpDb.operationFieldRef.findFirst({
38
+ where: { operationId },
39
+ orderBy: { seqNo: "desc" },
40
+ select: { seqNo: true },
41
+ });
42
+ const maxSeq = maxRow?.seqNo ?? 0;
43
+ assignedSeqNo = Math.ceil((maxSeq + 1) / 10) * 10;
44
+ }
45
+ return erpDb.operationFieldRef.create({
46
+ data: {
47
+ operationId,
48
+ seqNo: assignedSeqNo,
49
+ title,
50
+ sourceStepId,
51
+ createdById: userId,
52
+ },
53
+ include: includeFieldRef,
54
+ });
55
+ }
56
+ export async function deleteFieldRef(id) {
57
+ await erpDb.operationFieldRef.delete({ where: { id } });
58
+ }
59
+ export async function findExistingFieldRef(operationId, seqNo) {
60
+ return erpDb.operationFieldRef.findFirst({
61
+ where: { operationId, seqNo },
62
+ select: { id: true },
63
+ });
64
+ }
65
+ /**
66
+ * Check if a source step already has a field ref for this operation.
67
+ */
68
+ export async function checkDuplicateSource(operationId, sourceStepId) {
69
+ return erpDb.operationFieldRef.findFirst({
70
+ where: { operationId, sourceStepId },
71
+ select: { id: true },
72
+ });
73
+ }
74
+ //# sourceMappingURL=field-ref-service.js.map
@@ -0,0 +1,49 @@
1
+ import { FieldType } from "@naisys/erp-shared";
2
+ import type { FieldModel } from "../generated/prisma/models/Field.js";
3
+ import { type WithAuditUsers } from "../route-helpers.js";
4
+ export type FieldWithUsers = FieldModel & WithAuditUsers;
5
+ export declare function listFields(fieldSetId: number): Promise<FieldWithUsers[]>;
6
+ export declare function getField(fieldSetId: number, fieldSeqNo: number): Promise<FieldWithUsers | null>;
7
+ export declare function findExistingField(fieldSetId: number, fieldSeqNo: number): Promise<{
8
+ required: boolean;
9
+ createdAt: Date;
10
+ id: number;
11
+ updatedAt: Date;
12
+ seqNo: number;
13
+ type: import("../generated/prisma/enums.js").FieldType;
14
+ label: string;
15
+ isArray: boolean;
16
+ createdById: number;
17
+ updatedById: number;
18
+ fieldSetId: number;
19
+ } | null>;
20
+ export declare function ensureFieldSet(fieldSetId: number | null, userId: number): Promise<number>;
21
+ export declare function ensureFieldRecord(fieldRecordId: number | null, fieldSetId: number, userId: number): Promise<number>;
22
+ /**
23
+ * Get or create a FieldRecord for a StepRun, linking it back.
24
+ * Returns the fieldRecordId, or null if the step has no fieldSet.
25
+ */
26
+ export declare function ensureStepRunFieldRecord(stepRunId: number, userId: number): Promise<number | null>;
27
+ export declare function createFields(fieldSetId: number, items: Array<{
28
+ seqNo?: number | null;
29
+ label: string;
30
+ type?: FieldType | null;
31
+ isArray?: boolean | null;
32
+ required?: boolean | null;
33
+ }>, userId: number): Promise<FieldWithUsers[]>;
34
+ export declare function createField(fieldSetId: number, data: {
35
+ seqNo?: number | null;
36
+ label: string;
37
+ type?: FieldType | null;
38
+ isArray?: boolean | null;
39
+ required?: boolean | null;
40
+ }, userId: number): Promise<FieldWithUsers>;
41
+ export declare function updateField(id: number, data: {
42
+ label?: string;
43
+ type?: FieldType;
44
+ isArray?: boolean;
45
+ required?: boolean;
46
+ seqNo?: number;
47
+ }, userId: number): Promise<FieldWithUsers>;
48
+ export declare function deleteField(id: number): Promise<void>;
49
+ //# sourceMappingURL=field-service.d.ts.map
@@ -0,0 +1,114 @@
1
+ import { FieldType } from "@naisys/erp-shared";
2
+ import erpDb from "../erpDb.js";
3
+ import { calcNextSeqNo, includeUsers, } from "../route-helpers.js";
4
+ // --- Lookups ---
5
+ export async function listFields(fieldSetId) {
6
+ return erpDb.field.findMany({
7
+ where: { fieldSetId },
8
+ include: includeUsers,
9
+ orderBy: { seqNo: "asc" },
10
+ });
11
+ }
12
+ export async function getField(fieldSetId, fieldSeqNo) {
13
+ return erpDb.field.findFirst({
14
+ where: { fieldSetId, seqNo: fieldSeqNo },
15
+ include: includeUsers,
16
+ });
17
+ }
18
+ export async function findExistingField(fieldSetId, fieldSeqNo) {
19
+ return erpDb.field.findFirst({
20
+ where: { fieldSetId, seqNo: fieldSeqNo },
21
+ });
22
+ }
23
+ // --- FieldSet / FieldRecord helpers ---
24
+ export async function ensureFieldSet(fieldSetId, userId) {
25
+ if (fieldSetId)
26
+ return fieldSetId;
27
+ const fs = await erpDb.fieldSet.create({
28
+ data: { createdById: userId },
29
+ });
30
+ return fs.id;
31
+ }
32
+ export async function ensureFieldRecord(fieldRecordId, fieldSetId, userId) {
33
+ if (fieldRecordId)
34
+ return fieldRecordId;
35
+ const fr = await erpDb.fieldRecord.create({
36
+ data: { fieldSetId, createdById: userId },
37
+ });
38
+ return fr.id;
39
+ }
40
+ /**
41
+ * Get or create a FieldRecord for a StepRun, linking it back.
42
+ * Returns the fieldRecordId, or null if the step has no fieldSet.
43
+ */
44
+ export async function ensureStepRunFieldRecord(stepRunId, userId) {
45
+ const sr = await erpDb.stepRun.findUniqueOrThrow({
46
+ where: { id: stepRunId },
47
+ select: { fieldRecordId: true, step: { select: { fieldSetId: true } } },
48
+ });
49
+ if (sr.fieldRecordId)
50
+ return sr.fieldRecordId;
51
+ if (!sr.step.fieldSetId)
52
+ return null;
53
+ const fieldRecordId = await ensureFieldRecord(null, sr.step.fieldSetId, userId);
54
+ await erpDb.stepRun.update({
55
+ where: { id: stepRunId },
56
+ data: { fieldRecordId },
57
+ });
58
+ return fieldRecordId;
59
+ }
60
+ // --- Mutations ---
61
+ export async function createFields(fieldSetId, items, userId) {
62
+ return erpDb.$transaction(async (erpTx) => {
63
+ const maxSeq = await erpTx.field.findFirst({
64
+ where: { fieldSetId },
65
+ orderBy: { seqNo: "desc" },
66
+ select: { seqNo: true },
67
+ });
68
+ let nextSeqNo = calcNextSeqNo(maxSeq?.seqNo ?? 0);
69
+ const created = [];
70
+ for (const item of items) {
71
+ const seqNo = item.seqNo ?? nextSeqNo;
72
+ const field = await erpTx.field.create({
73
+ data: {
74
+ fieldSetId,
75
+ seqNo,
76
+ label: item.label,
77
+ type: item.type ?? FieldType.string,
78
+ isArray: item.isArray ?? false,
79
+ required: item.required ?? false,
80
+ createdById: userId,
81
+ updatedById: userId,
82
+ },
83
+ include: includeUsers,
84
+ });
85
+ created.push(field);
86
+ if (!item.seqNo) {
87
+ nextSeqNo = calcNextSeqNo(seqNo);
88
+ }
89
+ }
90
+ return created;
91
+ });
92
+ }
93
+ export async function createField(fieldSetId, data, userId) {
94
+ const [field] = await createFields(fieldSetId, [data], userId);
95
+ return field;
96
+ }
97
+ export async function updateField(id, data, userId) {
98
+ return erpDb.field.update({
99
+ where: { id },
100
+ data: {
101
+ ...(data.label !== undefined ? { label: data.label } : {}),
102
+ ...(data.type !== undefined ? { type: data.type } : {}),
103
+ ...(data.isArray !== undefined ? { isArray: data.isArray } : {}),
104
+ ...(data.required !== undefined ? { required: data.required } : {}),
105
+ ...(data.seqNo !== undefined ? { seqNo: data.seqNo } : {}),
106
+ updatedById: userId,
107
+ },
108
+ include: includeUsers,
109
+ });
110
+ }
111
+ export async function deleteField(id) {
112
+ await erpDb.field.delete({ where: { id } });
113
+ }
114
+ //# sourceMappingURL=field-service.js.map
@@ -0,0 +1,61 @@
1
+ import { type FieldValidation, type FieldValue } from "@naisys/erp-shared";
2
+ import type { StepRunWithStepAndFields } from "./step-run-service.js";
3
+ export declare function findStepRunWithField(id: number, opRunId: number, fieldSeqNo: number): Promise<({
4
+ step: {
5
+ fieldSet: {
6
+ fields: {
7
+ required: boolean;
8
+ id: number;
9
+ seqNo: number;
10
+ type: import("../generated/prisma/enums.js").FieldType;
11
+ label: string;
12
+ isArray: boolean;
13
+ fieldSetId: number;
14
+ }[];
15
+ } | null;
16
+ multiSet: boolean;
17
+ };
18
+ } & {
19
+ createdAt: Date;
20
+ id: number;
21
+ updatedAt: Date;
22
+ createdById: number;
23
+ updatedById: number;
24
+ statusNote: string | null;
25
+ completed: boolean;
26
+ operationRunId: number;
27
+ stepId: number;
28
+ fieldRecordId: number | null;
29
+ }) | null>;
30
+ /**
31
+ * Serialize a field value for DB storage.
32
+ * - Scalar (string): stored as-is
33
+ * - Array (string[]): stored as JSON array string
34
+ */
35
+ export declare function serializeFieldValue(value: FieldValue): string;
36
+ /**
37
+ * Deserialize a DB-stored value back to the API shape.
38
+ * - isArray fields: parse JSON array, falling back to comma-split for legacy data
39
+ * - Scalar fields: return as-is
40
+ */
41
+ export declare function deserializeFieldValue(dbValue: string, isArray: boolean): FieldValue;
42
+ /**
43
+ * Check that the value shape matches the field's isArray flag.
44
+ * Returns an error string if mismatched, or null if OK.
45
+ */
46
+ export declare function checkFieldValueShape(label: string, type: string, isArray: boolean, value: FieldValue): string | null;
47
+ export declare function validateFieldValue(type: string, isArray: boolean, required: boolean, value: FieldValue): FieldValidation;
48
+ export declare function validateCompletionFields(existing: StepRunWithStepAndFields): string | null;
49
+ export declare function formatAttachmentLabel(filename: string, fileSize: number): string;
50
+ /**
51
+ * Query current attachments for a field value and rebuild the stored value
52
+ * to reflect them. Returns the new API-shape value.
53
+ */
54
+ export declare function rebuildAttachmentFieldValue(fieldRecordId: number, fieldId: number, setIndex: number, isArray: boolean, userId: number): Promise<FieldValue>;
55
+ /**
56
+ * Clear an attachment field: delete all FieldAttachment links and set value to empty.
57
+ */
58
+ export declare function clearAttachmentFieldValue(fieldRecordId: number, fieldId: number, setIndex: number, userId: number): Promise<void>;
59
+ export declare function upsertFieldValue(fieldRecordId: number, fieldId: number, setIndex: number, value: FieldValue, userId: number): Promise<void>;
60
+ export declare function deleteFieldValueSet(fieldRecordId: number, setIndex: number): Promise<void>;
61
+ //# sourceMappingURL=field-value-service.d.ts.map