@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.
- package/bin/naisys-erp +2 -0
- package/client-dist/android-chrome-192x192.png +0 -0
- package/client-dist/android-chrome-512x512.png +0 -0
- package/client-dist/apple-touch-icon.png +0 -0
- package/client-dist/assets/index-45dVo30p.css +1 -0
- package/client-dist/assets/index-Dffms7F_.js +168 -0
- package/client-dist/assets/naisys-logo-CzoPnn5I.webp +0 -0
- package/client-dist/favicon.ico +0 -0
- package/client-dist/index.html +42 -0
- package/client-dist/site.webmanifest +22 -0
- package/dist/api-reference.d.ts +10 -0
- package/dist/api-reference.js +101 -0
- package/dist/audit.d.ts +5 -0
- package/dist/audit.js +14 -0
- package/dist/auth-middleware.d.ts +18 -0
- package/dist/auth-middleware.js +203 -0
- package/dist/dbConfig.d.ts +5 -0
- package/dist/dbConfig.js +10 -0
- package/dist/erpDb.d.ts +10 -0
- package/dist/erpDb.js +34 -0
- package/dist/erpServer.d.ts +10 -0
- package/dist/erpServer.js +321 -0
- package/dist/error-handler.d.ts +7 -0
- package/dist/error-handler.js +17 -0
- package/dist/generated/prisma/client.d.ts +154 -0
- package/dist/generated/prisma/client.js +35 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +637 -0
- package/dist/generated/prisma/commonInputTypes.js +11 -0
- package/dist/generated/prisma/enums.d.ts +59 -0
- package/dist/generated/prisma/enums.js +60 -0
- package/dist/generated/prisma/internal/class.d.ts +406 -0
- package/dist/generated/prisma/internal/class.js +50 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +2722 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +366 -0
- package/dist/generated/prisma/models/Attachment.d.ts +1455 -0
- package/dist/generated/prisma/models/Attachment.js +2 -0
- package/dist/generated/prisma/models/AuditLog.d.ts +1359 -0
- package/dist/generated/prisma/models/AuditLog.js +2 -0
- package/dist/generated/prisma/models/Field.d.ts +1880 -0
- package/dist/generated/prisma/models/Field.js +2 -0
- package/dist/generated/prisma/models/FieldAttachment.d.ts +1245 -0
- package/dist/generated/prisma/models/FieldAttachment.js +2 -0
- package/dist/generated/prisma/models/FieldRecord.d.ts +1625 -0
- package/dist/generated/prisma/models/FieldRecord.js +2 -0
- package/dist/generated/prisma/models/FieldSet.d.ts +1577 -0
- package/dist/generated/prisma/models/FieldSet.js +2 -0
- package/dist/generated/prisma/models/FieldValue.d.ts +1908 -0
- package/dist/generated/prisma/models/FieldValue.js +2 -0
- package/dist/generated/prisma/models/Item.d.ts +1858 -0
- package/dist/generated/prisma/models/Item.js +2 -0
- package/dist/generated/prisma/models/ItemInstance.d.ts +1987 -0
- package/dist/generated/prisma/models/ItemInstance.js +2 -0
- package/dist/generated/prisma/models/LaborTicket.d.ts +1867 -0
- package/dist/generated/prisma/models/LaborTicket.js +2 -0
- package/dist/generated/prisma/models/Operation.d.ts +2578 -0
- package/dist/generated/prisma/models/Operation.js +2 -0
- package/dist/generated/prisma/models/OperationDependency.d.ts +1434 -0
- package/dist/generated/prisma/models/OperationDependency.js +2 -0
- package/dist/generated/prisma/models/OperationFieldRef.d.ts +1539 -0
- package/dist/generated/prisma/models/OperationFieldRef.js +2 -0
- package/dist/generated/prisma/models/OperationRun.d.ts +2563 -0
- package/dist/generated/prisma/models/OperationRun.js +2 -0
- package/dist/generated/prisma/models/OperationRunComment.d.ts +1366 -0
- package/dist/generated/prisma/models/OperationRunComment.js +2 -0
- package/dist/generated/prisma/models/Order.d.ts +1931 -0
- package/dist/generated/prisma/models/Order.js +2 -0
- package/dist/generated/prisma/models/OrderRevision.d.ts +1962 -0
- package/dist/generated/prisma/models/OrderRevision.js +2 -0
- package/dist/generated/prisma/models/OrderRun.d.ts +2310 -0
- package/dist/generated/prisma/models/OrderRun.js +2 -0
- package/dist/generated/prisma/models/SchemaVersion.d.ts +985 -0
- package/dist/generated/prisma/models/SchemaVersion.js +2 -0
- package/dist/generated/prisma/models/Session.d.ts +1213 -0
- package/dist/generated/prisma/models/Session.js +2 -0
- package/dist/generated/prisma/models/Step.d.ts +2180 -0
- package/dist/generated/prisma/models/Step.js +2 -0
- package/dist/generated/prisma/models/StepRun.d.ts +1963 -0
- package/dist/generated/prisma/models/StepRun.js +2 -0
- package/dist/generated/prisma/models/User.d.ts +11819 -0
- package/dist/generated/prisma/models/User.js +2 -0
- package/dist/generated/prisma/models/UserPermission.d.ts +1348 -0
- package/dist/generated/prisma/models/UserPermission.js +2 -0
- package/dist/generated/prisma/models/WorkCenter.d.ts +1657 -0
- package/dist/generated/prisma/models/WorkCenter.js +2 -0
- package/dist/generated/prisma/models/WorkCenterUser.d.ts +1390 -0
- package/dist/generated/prisma/models/WorkCenterUser.js +2 -0
- package/dist/generated/prisma/models.d.ts +28 -0
- package/dist/generated/prisma/models.js +2 -0
- package/dist/hateoas.d.ts +7 -0
- package/dist/hateoas.js +61 -0
- package/dist/route-helpers.d.ts +318 -0
- package/dist/route-helpers.js +220 -0
- package/dist/routes/admin.d.ts +3 -0
- package/dist/routes/admin.js +147 -0
- package/dist/routes/audit.d.ts +3 -0
- package/dist/routes/audit.js +36 -0
- package/dist/routes/auth.d.ts +3 -0
- package/dist/routes/auth.js +112 -0
- package/dist/routes/dispatch.d.ts +3 -0
- package/dist/routes/dispatch.js +174 -0
- package/dist/routes/inventory.d.ts +3 -0
- package/dist/routes/inventory.js +70 -0
- package/dist/routes/item-fields.d.ts +3 -0
- package/dist/routes/item-fields.js +220 -0
- package/dist/routes/item-instances.d.ts +3 -0
- package/dist/routes/item-instances.js +426 -0
- package/dist/routes/items.d.ts +3 -0
- package/dist/routes/items.js +252 -0
- package/dist/routes/labor-tickets.d.ts +3 -0
- package/dist/routes/labor-tickets.js +268 -0
- package/dist/routes/operation-dependencies.d.ts +3 -0
- package/dist/routes/operation-dependencies.js +170 -0
- package/dist/routes/operation-field-refs.d.ts +3 -0
- package/dist/routes/operation-field-refs.js +263 -0
- package/dist/routes/operation-run-comments.d.ts +3 -0
- package/dist/routes/operation-run-comments.js +108 -0
- package/dist/routes/operation-run-transitions.d.ts +3 -0
- package/dist/routes/operation-run-transitions.js +249 -0
- package/dist/routes/operation-runs.d.ts +112 -0
- package/dist/routes/operation-runs.js +299 -0
- package/dist/routes/operations.d.ts +3 -0
- package/dist/routes/operations.js +283 -0
- package/dist/routes/order-revision-transitions.d.ts +3 -0
- package/dist/routes/order-revision-transitions.js +86 -0
- package/dist/routes/order-revisions.d.ts +51 -0
- package/dist/routes/order-revisions.js +327 -0
- package/dist/routes/order-run-transitions.d.ts +3 -0
- package/dist/routes/order-run-transitions.js +215 -0
- package/dist/routes/order-runs.d.ts +58 -0
- package/dist/routes/order-runs.js +335 -0
- package/dist/routes/orders.d.ts +3 -0
- package/dist/routes/orders.js +262 -0
- package/dist/routes/root.d.ts +3 -0
- package/dist/routes/root.js +123 -0
- package/dist/routes/schemas.d.ts +3 -0
- package/dist/routes/schemas.js +31 -0
- package/dist/routes/step-field-attachments.d.ts +3 -0
- package/dist/routes/step-field-attachments.js +231 -0
- package/dist/routes/step-fields.d.ts +100 -0
- package/dist/routes/step-fields.js +315 -0
- package/dist/routes/step-run-fields.d.ts +3 -0
- package/dist/routes/step-run-fields.js +438 -0
- package/dist/routes/step-run-transitions.d.ts +3 -0
- package/dist/routes/step-run-transitions.js +113 -0
- package/dist/routes/step-runs.d.ts +332 -0
- package/dist/routes/step-runs.js +324 -0
- package/dist/routes/steps.d.ts +3 -0
- package/dist/routes/steps.js +283 -0
- package/dist/routes/user-permissions.d.ts +3 -0
- package/dist/routes/user-permissions.js +100 -0
- package/dist/routes/users.d.ts +57 -0
- package/dist/routes/users.js +381 -0
- package/dist/routes/work-centers.d.ts +3 -0
- package/dist/routes/work-centers.js +280 -0
- package/dist/schema-registry.d.ts +3 -0
- package/dist/schema-registry.js +45 -0
- package/dist/services/attachment-service.d.ts +33 -0
- package/dist/services/attachment-service.js +118 -0
- package/dist/services/field-ref-service.d.ts +96 -0
- package/dist/services/field-ref-service.js +74 -0
- package/dist/services/field-service.d.ts +49 -0
- package/dist/services/field-service.js +114 -0
- package/dist/services/field-value-service.d.ts +61 -0
- package/dist/services/field-value-service.js +256 -0
- package/dist/services/item-instance-service.d.ts +152 -0
- package/dist/services/item-instance-service.js +155 -0
- package/dist/services/item-service.d.ts +47 -0
- package/dist/services/item-service.js +56 -0
- package/dist/services/labor-ticket-service.d.ts +40 -0
- package/dist/services/labor-ticket-service.js +148 -0
- package/dist/services/log-file-service.d.ts +4 -0
- package/dist/services/log-file-service.js +11 -0
- package/dist/services/operation-dependency-service.d.ts +33 -0
- package/dist/services/operation-dependency-service.js +30 -0
- package/dist/services/operation-run-comment-service.d.ts +17 -0
- package/dist/services/operation-run-comment-service.js +26 -0
- package/dist/services/operation-run-service.d.ts +126 -0
- package/dist/services/operation-run-service.js +347 -0
- package/dist/services/operation-service.d.ts +47 -0
- package/dist/services/operation-service.js +132 -0
- package/dist/services/order-revision-service.d.ts +53 -0
- package/dist/services/order-revision-service.js +264 -0
- package/dist/services/order-run-service.d.ts +138 -0
- package/dist/services/order-run-service.js +356 -0
- package/dist/services/order-service.d.ts +15 -0
- package/dist/services/order-service.js +68 -0
- package/dist/services/revision-diff-service.d.ts +3 -0
- package/dist/services/revision-diff-service.js +194 -0
- package/dist/services/step-run-service.d.ts +172 -0
- package/dist/services/step-run-service.js +106 -0
- package/dist/services/step-service.d.ts +104 -0
- package/dist/services/step-service.js +89 -0
- package/dist/services/user-service.d.ts +185 -0
- package/dist/services/user-service.js +132 -0
- package/dist/services/work-center-service.d.ts +29 -0
- package/dist/services/work-center-service.js +106 -0
- package/dist/supervisorAuth.d.ts +3 -0
- package/dist/supervisorAuth.js +16 -0
- package/dist/userService.d.ts +20 -0
- package/dist/userService.js +118 -0
- package/package.json +69 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { getAgentApiKeyByUuid, rotateAgentApiKeyByUuid, } from "@naisys/hub-database";
|
|
2
|
+
import bcrypt from "bcryptjs";
|
|
3
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
4
|
+
import erpDb from "../erpDb.js";
|
|
5
|
+
import { isSupervisorAuth } from "../supervisorAuth.js";
|
|
6
|
+
// --- Prisma include & result type ---
|
|
7
|
+
export const includePermissions = {
|
|
8
|
+
permissions: true,
|
|
9
|
+
};
|
|
10
|
+
// --- Constants ---
|
|
11
|
+
const SALT_ROUNDS = 10;
|
|
12
|
+
// --- Lookups ---
|
|
13
|
+
export async function listUsers(options) {
|
|
14
|
+
const { page, pageSize, search } = options;
|
|
15
|
+
const where = search ? { username: { contains: search } } : {};
|
|
16
|
+
const [items, total] = await Promise.all([
|
|
17
|
+
erpDb.user.findMany({
|
|
18
|
+
where,
|
|
19
|
+
include: includePermissions,
|
|
20
|
+
orderBy: { createdAt: "desc" },
|
|
21
|
+
skip: (page - 1) * pageSize,
|
|
22
|
+
take: pageSize,
|
|
23
|
+
}),
|
|
24
|
+
erpDb.user.count({ where }),
|
|
25
|
+
]);
|
|
26
|
+
return { items, total, pageSize };
|
|
27
|
+
}
|
|
28
|
+
export async function getUserByUsername(username) {
|
|
29
|
+
return erpDb.user.findUnique({
|
|
30
|
+
where: { username },
|
|
31
|
+
include: includePermissions,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export async function getUserById(id) {
|
|
35
|
+
return erpDb.user.findUnique({
|
|
36
|
+
where: { id },
|
|
37
|
+
include: includePermissions,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export async function getUserApiKey(id) {
|
|
41
|
+
const user = await erpDb.user.findUnique({
|
|
42
|
+
where: { id },
|
|
43
|
+
select: { isAgent: true, uuid: true, apiKey: true },
|
|
44
|
+
});
|
|
45
|
+
if (!user)
|
|
46
|
+
return null;
|
|
47
|
+
if (user.isAgent && isSupervisorAuth()) {
|
|
48
|
+
return getAgentApiKeyByUuid(user.uuid);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return user.apiKey ?? null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// --- Mutations ---
|
|
55
|
+
export async function getUserByUuid(uuid) {
|
|
56
|
+
return erpDb.user.findFirst({
|
|
57
|
+
where: { uuid },
|
|
58
|
+
include: includePermissions,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export async function createUserForAgent(username, uuid) {
|
|
62
|
+
return erpDb.user.create({
|
|
63
|
+
data: {
|
|
64
|
+
username,
|
|
65
|
+
uuid,
|
|
66
|
+
passwordHash: "",
|
|
67
|
+
isAgent: true,
|
|
68
|
+
},
|
|
69
|
+
include: includePermissions,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export async function createUserWithPassword(data) {
|
|
73
|
+
const passwordHash = await bcrypt.hash(data.password, SALT_ROUNDS);
|
|
74
|
+
const uuid = randomUUID();
|
|
75
|
+
return erpDb.user.create({
|
|
76
|
+
data: {
|
|
77
|
+
username: data.username,
|
|
78
|
+
uuid,
|
|
79
|
+
passwordHash,
|
|
80
|
+
isAgent: false,
|
|
81
|
+
apiKey: randomBytes(32).toString("hex"),
|
|
82
|
+
},
|
|
83
|
+
include: includePermissions,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
export async function updateUser(id, data) {
|
|
87
|
+
const updateData = {};
|
|
88
|
+
if (data.username !== undefined) {
|
|
89
|
+
updateData.username = data.username;
|
|
90
|
+
}
|
|
91
|
+
if (data.password !== undefined) {
|
|
92
|
+
updateData.passwordHash = await bcrypt.hash(data.password, SALT_ROUNDS);
|
|
93
|
+
}
|
|
94
|
+
return erpDb.user.update({
|
|
95
|
+
where: { id },
|
|
96
|
+
data: updateData,
|
|
97
|
+
include: includePermissions,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
export async function deleteUser(id) {
|
|
101
|
+
return erpDb.user.delete({ where: { id } });
|
|
102
|
+
}
|
|
103
|
+
export async function grantPermission(userId, permission, grantedBy) {
|
|
104
|
+
return erpDb.userPermission.create({
|
|
105
|
+
data: { userId, permission, grantedBy },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export async function revokePermission(userId, permission) {
|
|
109
|
+
return erpDb.userPermission.deleteMany({
|
|
110
|
+
where: { userId, permission },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
export async function rotateUserApiKey(id) {
|
|
114
|
+
const newKey = randomBytes(32).toString("hex");
|
|
115
|
+
const user = await erpDb.user.findUnique({
|
|
116
|
+
where: { id },
|
|
117
|
+
select: { isAgent: true, uuid: true },
|
|
118
|
+
});
|
|
119
|
+
if (!user)
|
|
120
|
+
throw new Error("User not found");
|
|
121
|
+
if (user.isAgent && isSupervisorAuth()) {
|
|
122
|
+
await rotateAgentApiKeyByUuid(user.uuid, newKey);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
await erpDb.user.update({
|
|
126
|
+
where: { id },
|
|
127
|
+
data: { apiKey: newKey },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return newKey;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=user-service.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { WorkCenterModel } from "../generated/prisma/models/WorkCenter.js";
|
|
2
|
+
import { type WithAuditUsers } from "../route-helpers.js";
|
|
3
|
+
export type WorkCenterWithDetail = WorkCenterModel & WithAuditUsers & {
|
|
4
|
+
userAssignments: Array<{
|
|
5
|
+
user: {
|
|
6
|
+
id: number;
|
|
7
|
+
username: string;
|
|
8
|
+
};
|
|
9
|
+
createdBy: {
|
|
10
|
+
username: string;
|
|
11
|
+
};
|
|
12
|
+
createdAt: Date;
|
|
13
|
+
}>;
|
|
14
|
+
_count: {
|
|
15
|
+
userAssignments: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function listWorkCenters(where: Record<string, unknown>, page: number, pageSize: number): Promise<[WorkCenterWithDetail[], number]>;
|
|
19
|
+
export declare function findExisting(key: string): Promise<WorkCenterWithDetail | null>;
|
|
20
|
+
export declare function createWorkCenter(key: string, description: string | undefined, userId: number): Promise<WorkCenterWithDetail>;
|
|
21
|
+
export declare function updateWorkCenter(key: string, data: Record<string, unknown>, userId: number): Promise<WorkCenterWithDetail>;
|
|
22
|
+
export declare function deleteWorkCenter(key: string): Promise<void>;
|
|
23
|
+
export declare function assignUser(workCenterKey: string, username: string, createdById: number): Promise<WorkCenterWithDetail>;
|
|
24
|
+
export declare function removeUser(workCenterKey: string, username: string): Promise<void>;
|
|
25
|
+
export declare function getUserWorkCenterIds(userId: number): Promise<number[]>;
|
|
26
|
+
export declare function findWorkCenterByKey(key: string): Promise<{
|
|
27
|
+
id: number;
|
|
28
|
+
} | null>;
|
|
29
|
+
//# sourceMappingURL=work-center-service.d.ts.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import erpDb from "../erpDb.js";
|
|
2
|
+
import { includeUsers } from "../route-helpers.js";
|
|
3
|
+
// --- Prisma include & result type ---
|
|
4
|
+
const includeDetail = {
|
|
5
|
+
...includeUsers,
|
|
6
|
+
userAssignments: {
|
|
7
|
+
include: {
|
|
8
|
+
user: { select: { id: true, username: true } },
|
|
9
|
+
createdBy: { select: { username: true } },
|
|
10
|
+
},
|
|
11
|
+
orderBy: { user: { username: "asc" } },
|
|
12
|
+
},
|
|
13
|
+
_count: { select: { userAssignments: true } },
|
|
14
|
+
};
|
|
15
|
+
// --- Lookups ---
|
|
16
|
+
export async function listWorkCenters(where, page, pageSize) {
|
|
17
|
+
return Promise.all([
|
|
18
|
+
erpDb.workCenter.findMany({
|
|
19
|
+
where,
|
|
20
|
+
include: includeDetail,
|
|
21
|
+
skip: (page - 1) * pageSize,
|
|
22
|
+
take: pageSize,
|
|
23
|
+
orderBy: { createdAt: "desc" },
|
|
24
|
+
}),
|
|
25
|
+
erpDb.workCenter.count({ where }),
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
export async function findExisting(key) {
|
|
29
|
+
return erpDb.workCenter.findUnique({
|
|
30
|
+
where: { key },
|
|
31
|
+
include: includeDetail,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// --- Mutations ---
|
|
35
|
+
export async function createWorkCenter(key, description, userId) {
|
|
36
|
+
return erpDb.workCenter.create({
|
|
37
|
+
data: {
|
|
38
|
+
key,
|
|
39
|
+
description,
|
|
40
|
+
createdById: userId,
|
|
41
|
+
updatedById: userId,
|
|
42
|
+
},
|
|
43
|
+
include: includeDetail,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export async function updateWorkCenter(key, data, userId) {
|
|
47
|
+
return erpDb.workCenter.update({
|
|
48
|
+
where: { key },
|
|
49
|
+
data: { ...data, updatedById: userId },
|
|
50
|
+
include: includeDetail,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export async function deleteWorkCenter(key) {
|
|
54
|
+
await erpDb.workCenter.delete({ where: { key } });
|
|
55
|
+
}
|
|
56
|
+
// --- User assignments ---
|
|
57
|
+
export async function assignUser(workCenterKey, username, createdById) {
|
|
58
|
+
const workCenter = await erpDb.workCenter.findUniqueOrThrow({
|
|
59
|
+
where: { key: workCenterKey },
|
|
60
|
+
});
|
|
61
|
+
const user = await erpDb.user.findUniqueOrThrow({
|
|
62
|
+
where: { username },
|
|
63
|
+
});
|
|
64
|
+
await erpDb.workCenterUser.create({
|
|
65
|
+
data: {
|
|
66
|
+
workCenterId: workCenter.id,
|
|
67
|
+
userId: user.id,
|
|
68
|
+
createdById,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return erpDb.workCenter.findUniqueOrThrow({
|
|
72
|
+
where: { key: workCenterKey },
|
|
73
|
+
include: includeDetail,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export async function removeUser(workCenterKey, username) {
|
|
77
|
+
const workCenter = await erpDb.workCenter.findUniqueOrThrow({
|
|
78
|
+
where: { key: workCenterKey },
|
|
79
|
+
});
|
|
80
|
+
const user = await erpDb.user.findUniqueOrThrow({
|
|
81
|
+
where: { username },
|
|
82
|
+
});
|
|
83
|
+
await erpDb.workCenterUser.delete({
|
|
84
|
+
where: {
|
|
85
|
+
workCenterId_userId: {
|
|
86
|
+
workCenterId: workCenter.id,
|
|
87
|
+
userId: user.id,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// --- Work center ID lookups for dispatch ---
|
|
93
|
+
export async function getUserWorkCenterIds(userId) {
|
|
94
|
+
const assignments = await erpDb.workCenterUser.findMany({
|
|
95
|
+
where: { userId },
|
|
96
|
+
select: { workCenterId: true },
|
|
97
|
+
});
|
|
98
|
+
return assignments.map((a) => a.workCenterId);
|
|
99
|
+
}
|
|
100
|
+
export async function findWorkCenterByKey(key) {
|
|
101
|
+
return erpDb.workCenter.findUnique({
|
|
102
|
+
where: { key },
|
|
103
|
+
select: { id: true },
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=work-center-service.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level flag indicating whether ERP should use the supervisor/hub
|
|
3
|
+
* databases for SSO authentication and agent API key lookups.
|
|
4
|
+
*
|
|
5
|
+
* Enabled by:
|
|
6
|
+
* - SUPERVISOR_AUTH=true environment variable
|
|
7
|
+
* - Supervisor calling `enableSupervisorAuth()` before registering the ERP plugin
|
|
8
|
+
*/
|
|
9
|
+
let _enabled = false;
|
|
10
|
+
export function enableSupervisorAuth() {
|
|
11
|
+
_enabled = true;
|
|
12
|
+
}
|
|
13
|
+
export function isSupervisorAuth() {
|
|
14
|
+
return _enabled || process.env.SUPERVISOR_AUTH === "true";
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=supervisorAuth.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure a superadmin user exists in the local ERP database.
|
|
3
|
+
* For standalone mode (no supervisor auth).
|
|
4
|
+
*/
|
|
5
|
+
export declare function ensureLocalSuperAdmin(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Sync superadmin from supervisor into ERP DB and ensure permissions.
|
|
8
|
+
* For supervisor auth mode.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureSupervisorSuperAdmin(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Ensure a user has the erp_admin permission.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureErpAdminPermission(userId: number): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Interactive CLI to reset a local user's password.
|
|
17
|
+
* For standalone mode (no supervisor auth).
|
|
18
|
+
*/
|
|
19
|
+
export declare function resetLocalPassword(): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=userService.d.ts.map
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { SUPER_ADMIN_USERNAME } from "@naisys/common";
|
|
2
|
+
import { ensureSuperAdmin } from "@naisys/supervisor-database";
|
|
3
|
+
import bcrypt from "bcryptjs";
|
|
4
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
5
|
+
import readline from "readline/promises";
|
|
6
|
+
import erpDb from "./erpDb.js";
|
|
7
|
+
const SALT_ROUNDS = 10;
|
|
8
|
+
/**
|
|
9
|
+
* Ensure a superadmin user exists in the local ERP database.
|
|
10
|
+
* For standalone mode (no supervisor auth).
|
|
11
|
+
*/
|
|
12
|
+
export async function ensureLocalSuperAdmin() {
|
|
13
|
+
const existing = await erpDb.user.findUnique({
|
|
14
|
+
where: { username: SUPER_ADMIN_USERNAME },
|
|
15
|
+
});
|
|
16
|
+
if (existing) {
|
|
17
|
+
// Ensure superadmin has erp_admin permission
|
|
18
|
+
await ensureErpAdminPermission(existing.id);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const password = randomUUID().slice(0, 8);
|
|
22
|
+
const hash = await bcrypt.hash(password, SALT_ROUNDS);
|
|
23
|
+
const user = await erpDb.user.create({
|
|
24
|
+
data: {
|
|
25
|
+
uuid: randomUUID(),
|
|
26
|
+
username: SUPER_ADMIN_USERNAME,
|
|
27
|
+
passwordHash: hash,
|
|
28
|
+
apiKey: randomBytes(32).toString("hex"),
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
await ensureErpAdminPermission(user.id);
|
|
32
|
+
console.log(`\n ${SUPER_ADMIN_USERNAME} user created. Password: ${password}`);
|
|
33
|
+
console.log(` Change it via --reset-password\n`);
|
|
34
|
+
}
|
|
35
|
+
// Warn if agent users exist without supervisor auth
|
|
36
|
+
const agentCount = await erpDb.user.count({ where: { isAgent: true } });
|
|
37
|
+
if (agentCount > 0) {
|
|
38
|
+
console.warn(`[ERP] Warning: ${agentCount} agent user(s) found but supervisor auth is disabled. ` +
|
|
39
|
+
`Agent API key lookups and authentication will not work. ` +
|
|
40
|
+
`Start with --supervisor-auth to enable.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sync superadmin from supervisor into ERP DB and ensure permissions.
|
|
45
|
+
* For supervisor auth mode.
|
|
46
|
+
*/
|
|
47
|
+
export async function ensureSupervisorSuperAdmin() {
|
|
48
|
+
const result = await ensureSuperAdmin();
|
|
49
|
+
await erpDb.user.upsert({
|
|
50
|
+
where: { uuid: result.user.uuid },
|
|
51
|
+
create: {
|
|
52
|
+
uuid: result.user.uuid,
|
|
53
|
+
username: result.user.username,
|
|
54
|
+
passwordHash: result.user.passwordHash,
|
|
55
|
+
apiKey: result.user.apiKey,
|
|
56
|
+
},
|
|
57
|
+
update: {
|
|
58
|
+
username: result.user.username,
|
|
59
|
+
passwordHash: result.user.passwordHash,
|
|
60
|
+
apiKey: result.user.apiKey,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
const localSuperAdmin = await erpDb.user.findUnique({
|
|
64
|
+
where: { uuid: result.user.uuid },
|
|
65
|
+
});
|
|
66
|
+
if (localSuperAdmin) {
|
|
67
|
+
await ensureErpAdminPermission(localSuperAdmin.id);
|
|
68
|
+
}
|
|
69
|
+
if (result.created) {
|
|
70
|
+
console.log(`[ERP] ${SUPER_ADMIN_USERNAME} user created. Password: ${result.generatedPassword}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Ensure a user has the erp_admin permission.
|
|
75
|
+
*/
|
|
76
|
+
export async function ensureErpAdminPermission(userId) {
|
|
77
|
+
const existing = await erpDb.userPermission.findUnique({
|
|
78
|
+
where: { userId_permission: { userId, permission: "erp_admin" } },
|
|
79
|
+
});
|
|
80
|
+
if (!existing) {
|
|
81
|
+
await erpDb.userPermission.create({
|
|
82
|
+
data: { userId, permission: "erp_admin" },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Interactive CLI to reset a local user's password.
|
|
88
|
+
* For standalone mode (no supervisor auth).
|
|
89
|
+
*/
|
|
90
|
+
export async function resetLocalPassword() {
|
|
91
|
+
const rl = readline.createInterface({
|
|
92
|
+
input: process.stdin,
|
|
93
|
+
output: process.stdout,
|
|
94
|
+
});
|
|
95
|
+
try {
|
|
96
|
+
const username = await rl.question("Username: ");
|
|
97
|
+
const user = await erpDb.user.findUnique({ where: { username } });
|
|
98
|
+
if (!user) {
|
|
99
|
+
console.error(`User '${username}' not found.`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
const password = await rl.question("New password: ");
|
|
103
|
+
if (password.length < 6) {
|
|
104
|
+
console.error("Password must be at least 6 characters.");
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const hash = await bcrypt.hash(password, SALT_ROUNDS);
|
|
108
|
+
await erpDb.user.update({
|
|
109
|
+
where: { id: user.id },
|
|
110
|
+
data: { passwordHash: hash },
|
|
111
|
+
});
|
|
112
|
+
console.log(`Password reset for '${username}'.`);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
rl.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=userService.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naisys/erp",
|
|
3
|
+
"version": "3.0.0-beta.3",
|
|
4
|
+
"description": "NAISYS ERP - Web UI for AI-driven order and work management",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/erpServer.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"naisys-erp": "bin/naisys-erp"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/erpServer.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"clean": "rimraf dist client-dist .test-naisys",
|
|
15
|
+
"dev": "tsx watch src/erpServer.ts",
|
|
16
|
+
"build": "prisma generate && tsc",
|
|
17
|
+
"bundle": "npx shx rm -rf client-dist && npx shx cp -r ../client/dist client-dist",
|
|
18
|
+
"start": "node dist/erpServer.js",
|
|
19
|
+
"start:reset-password": "node dist/erpServer.js --reset-password",
|
|
20
|
+
"type-check": "tsc --noEmit",
|
|
21
|
+
"npm:publish:dryrun": "npm publish --dry-run",
|
|
22
|
+
"npm:publish": "npm publish --access public",
|
|
23
|
+
"db:generate": "prisma generate",
|
|
24
|
+
"db:migrate": "prisma migrate dev",
|
|
25
|
+
"db:push": "prisma db push",
|
|
26
|
+
"test": "vitest run && npx playwright test"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"client-dist",
|
|
31
|
+
"bin",
|
|
32
|
+
"!dist/**/*.map",
|
|
33
|
+
"!dist/**/tests",
|
|
34
|
+
"!dist/**/*.test.*"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@fastify/cookie": "^11.0.2",
|
|
38
|
+
"@fastify/cors": "^11.2.0",
|
|
39
|
+
"@fastify/rate-limit": "^10.3.0",
|
|
40
|
+
"@fastify/static": "^9.0.0",
|
|
41
|
+
"@fastify/swagger": "^9.7.0",
|
|
42
|
+
"@naisys/erp-shared": "3.0.0-beta.3",
|
|
43
|
+
"@naisys/common": "3.0.0-beta.3",
|
|
44
|
+
"@naisys/common-node": "3.0.0-beta.3",
|
|
45
|
+
"@naisys/hub-database": "3.0.0-beta.3",
|
|
46
|
+
"@naisys/supervisor-database": "3.0.0-beta.3",
|
|
47
|
+
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
48
|
+
"@prisma/client": "^7.5.0",
|
|
49
|
+
"@scalar/fastify-api-reference": "^1.48.7",
|
|
50
|
+
"bcryptjs": "^3.0.2",
|
|
51
|
+
"dotenv": "^17.3.1",
|
|
52
|
+
"fastify": "^5.8.2",
|
|
53
|
+
"fastify-plugin": "^5.1.0",
|
|
54
|
+
"fastify-type-provider-zod": "^6.1.0",
|
|
55
|
+
"zod": "^4.3.6"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@playwright/test": "^1.58.2",
|
|
59
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
60
|
+
"@types/node": "^25.5.0",
|
|
61
|
+
"prisma": "^7.5.0",
|
|
62
|
+
"tsx": "^4.21.0",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vitest": "^4.1.0"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=22.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|