@naisys/erp 3.0.0-beta.50 → 3.0.0-beta.51
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/client-dist/assets/{index-CNe-LDbP.js → index-CO2ivEdE.js} +79 -8
- package/client-dist/assets/{vendor-Co7ZCNxO.js → vendor-CJ0ET9hP.js} +8488 -1
- package/client-dist/index.html +2 -2
- package/dist/database/dbConfig.js +1 -1
- package/dist/erpServer.js +2 -0
- package/dist/generated/prisma/internal/class.js +4 -4
- package/dist/generated/prisma/internal/prismaNamespace.js +2 -0
- package/dist/routes/operations/operation-run-transitions.js +15 -6
- package/dist/routes/operations/operation-runs.js +3 -0
- package/dist/routes/production/labor-tickets.js +1 -0
- package/dist/services/operations/operation-run-service.js +2 -1
- package/dist/services/orders/order-revision-service.js +2 -3
- package/dist/services/orders/order-run-service.js +4 -5
- package/dist/services/orders/revision-diff-service.js +10 -9
- package/dist/services/production/labor-ticket-backfill.js +67 -0
- package/dist/services/production/labor-ticket-service.js +20 -14
- package/npm-shrinkwrap.json +50 -28
- package/package.json +6 -6
- package/prisma/migrations/20260517000000_add_op_run_tokens/migration.sql +2 -0
- package/prisma/schema.prisma +2 -0
|
@@ -225,6 +225,7 @@ export const OperationRunScalarFieldEnum = {
|
|
|
225
225
|
status: 'status',
|
|
226
226
|
assignedToId: 'assignedToId',
|
|
227
227
|
cost: 'cost',
|
|
228
|
+
tokens: 'tokens',
|
|
228
229
|
statusNote: 'statusNote',
|
|
229
230
|
completedAt: 'completedAt',
|
|
230
231
|
createdAt: 'createdAt',
|
|
@@ -315,6 +316,7 @@ export const LaborTicketScalarFieldEnum = {
|
|
|
315
316
|
clockIn: 'clockIn',
|
|
316
317
|
clockOut: 'clockOut',
|
|
317
318
|
cost: 'cost',
|
|
319
|
+
tokens: 'tokens',
|
|
318
320
|
createdAt: 'createdAt',
|
|
319
321
|
createdById: 'createdById',
|
|
320
322
|
updatedAt: 'updatedAt',
|
|
@@ -4,7 +4,7 @@ import { requirePermission } from "../../middleware/auth-middleware.js";
|
|
|
4
4
|
import { checkOrderRunStarted, checkWorkCenterAccess, mutationResult, resolveOpRun, } from "../../route-helpers.js";
|
|
5
5
|
import { checkPredecessorsComplete, checkStepsComplete, reblockSuccessors, transitionStatus, unblockSuccessors, validateStatusFor, } from "../../services/operations/operation-run-service.js";
|
|
6
6
|
import { transitionStatus as transitionOrderRunStatus } from "../../services/orders/order-run-service.js";
|
|
7
|
-
import { clockIn, clockOutAllForOpRun, isUserClockedIn,
|
|
7
|
+
import { clockIn, clockOutAllForOpRun, isUserClockedIn, sumLaborTicketMetrics, } from "../../services/production/labor-ticket-service.js";
|
|
8
8
|
import { formatOpRunTransition, SeqNoParamsSchema } from "./operation-runs.js";
|
|
9
9
|
export default function operationRunTransitionRoutes(fastify) {
|
|
10
10
|
const app = fastify.withTypeProvider();
|
|
@@ -99,10 +99,11 @@ export default function operationRunTransitionRoutes(fastify) {
|
|
|
99
99
|
if (stepsErr)
|
|
100
100
|
return unprocessable(reply, stepsErr);
|
|
101
101
|
await clockOutAllForOpRun(resolved.opRun.id, userId);
|
|
102
|
-
const cost = await
|
|
102
|
+
const { cost, tokens } = await sumLaborTicketMetrics(resolved.opRun.id);
|
|
103
103
|
const opRun = await transitionStatus(resolved.opRun.id, "complete", OperationRunStatus.in_progress, OperationRunStatus.completed, userId, {
|
|
104
104
|
completedAt: new Date(),
|
|
105
105
|
cost,
|
|
106
|
+
tokens,
|
|
106
107
|
statusNote: note ?? null,
|
|
107
108
|
});
|
|
108
109
|
await unblockSuccessors(resolved.run.id, resolved.opRun.operationId, userId);
|
|
@@ -153,8 +154,12 @@ export default function operationRunTransitionRoutes(fastify) {
|
|
|
153
154
|
if (resolved.opRun.status === OperationRunStatus.in_progress) {
|
|
154
155
|
await clockOutAllForOpRun(resolved.opRun.id, userId);
|
|
155
156
|
}
|
|
156
|
-
const cost = await
|
|
157
|
-
const opRun = await transitionStatus(resolved.opRun.id, "skip", resolved.opRun.status, OperationRunStatus.skipped, userId, {
|
|
157
|
+
const { cost, tokens } = await sumLaborTicketMetrics(resolved.opRun.id);
|
|
158
|
+
const opRun = await transitionStatus(resolved.opRun.id, "skip", resolved.opRun.status, OperationRunStatus.skipped, userId, {
|
|
159
|
+
...(cost > 0 ? { cost } : undefined),
|
|
160
|
+
...(tokens > 0 ? { tokens } : undefined),
|
|
161
|
+
statusNote: note ?? null,
|
|
162
|
+
});
|
|
158
163
|
await unblockSuccessors(resolved.run.id, resolved.opRun.operationId, userId);
|
|
159
164
|
const full = await formatOpRunTransition(orderKey, runNo, request.erpUser, opRun);
|
|
160
165
|
return mutationResult(request, reply, full, {
|
|
@@ -196,8 +201,12 @@ export default function operationRunTransitionRoutes(fastify) {
|
|
|
196
201
|
if (statusErr)
|
|
197
202
|
return conflict(reply, statusErr);
|
|
198
203
|
await clockOutAllForOpRun(resolved.opRun.id, userId);
|
|
199
|
-
const cost = await
|
|
200
|
-
const opRun = await transitionStatus(resolved.opRun.id, "fail", OperationRunStatus.in_progress, OperationRunStatus.failed, userId, {
|
|
204
|
+
const { cost, tokens } = await sumLaborTicketMetrics(resolved.opRun.id);
|
|
205
|
+
const opRun = await transitionStatus(resolved.opRun.id, "fail", OperationRunStatus.in_progress, OperationRunStatus.failed, userId, {
|
|
206
|
+
...(cost > 0 ? { cost } : undefined),
|
|
207
|
+
...(tokens > 0 ? { tokens } : undefined),
|
|
208
|
+
statusNote: note ?? null,
|
|
209
|
+
});
|
|
201
210
|
const full = await formatOpRunTransition(orderKey, runNo, request.erpUser, opRun);
|
|
202
211
|
return mutationResult(request, reply, full, {
|
|
203
212
|
status: opRun.status,
|
|
@@ -136,6 +136,7 @@ export async function formatOpRun(orderKey, runNo, user, opRun) {
|
|
|
136
136
|
status: opRun.status,
|
|
137
137
|
assignedTo: opRun.assignedTo?.username ?? null,
|
|
138
138
|
cost: opRun.cost,
|
|
139
|
+
tokens: opRun.tokens,
|
|
139
140
|
note: opRun.statusNote ?? null,
|
|
140
141
|
completedAt: formatDate(opRun.completedAt),
|
|
141
142
|
stepSummary: stepSummaryRows.map((sr) => ({
|
|
@@ -182,6 +183,7 @@ export async function formatOpRunTransition(orderKey, runNo, user, opRun) {
|
|
|
182
183
|
status: opRun.status,
|
|
183
184
|
assignedTo: opRun.assignedTo?.username ?? null,
|
|
184
185
|
cost: opRun.cost,
|
|
186
|
+
tokens: opRun.tokens,
|
|
185
187
|
note: opRun.statusNote ?? null,
|
|
186
188
|
completedAt: formatDate(opRun.completedAt),
|
|
187
189
|
...formatAuditFields(opRun),
|
|
@@ -203,6 +205,7 @@ function formatListOpRun(opRun) {
|
|
|
203
205
|
status: opRun.status,
|
|
204
206
|
assignedTo: opRun.assignedTo?.username ?? null,
|
|
205
207
|
cost: opRun.cost,
|
|
208
|
+
tokens: opRun.tokens,
|
|
206
209
|
note: opRun.statusNote ?? null,
|
|
207
210
|
completedAt: formatDate(opRun.completedAt),
|
|
208
211
|
...formatAuditFields(opRun),
|
|
@@ -92,6 +92,7 @@ function formatLaborTicket(orderKey, runNo, seqNo, ticket) {
|
|
|
92
92
|
clockIn: ticket.clockIn.toISOString(),
|
|
93
93
|
clockOut: formatDate(ticket.clockOut),
|
|
94
94
|
cost: ticket.cost,
|
|
95
|
+
tokens: ticket.tokens,
|
|
95
96
|
...formatAuditFields(ticket),
|
|
96
97
|
_links: [
|
|
97
98
|
selfLink(`/${laborResource(orderKey, runNo, seqNo)}/${ticket.id}`),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keyBy } from "@naisys/common";
|
|
1
2
|
import { OperationRunStatus as OperationRunStatusValues, } from "@naisys/erp-shared";
|
|
2
3
|
import { fieldTypeString, getValueFormatHint, } from "@naisys/erp-shared";
|
|
3
4
|
import erpDb from "../../database/erpDb.js";
|
|
@@ -153,7 +154,7 @@ export async function getOpRunFieldRefSummary(operationId, orderRunId, orderKey,
|
|
|
153
154
|
},
|
|
154
155
|
},
|
|
155
156
|
});
|
|
156
|
-
const stepRunMap =
|
|
157
|
+
const stepRunMap = keyBy(stepRuns, (sr) => sr.stepId);
|
|
157
158
|
return fieldRefs.map((ref) => {
|
|
158
159
|
const sr = stepRunMap.get(ref.sourceStep.id);
|
|
159
160
|
const storedFieldValues = sr?.fieldRecord?.fieldValues ?? [];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapDefined } from "@naisys/common";
|
|
1
2
|
import { RevisionStatus as RevisionStatusValues, } from "@naisys/erp-shared";
|
|
2
3
|
import erpDb from "../../database/erpDb.js";
|
|
3
4
|
import { includeUsers } from "../../route-helpers.js";
|
|
@@ -230,9 +231,7 @@ export async function deleteRevision(id) {
|
|
|
230
231
|
where: { operationId: { in: opIds } },
|
|
231
232
|
select: { id: true, fieldSetId: true },
|
|
232
233
|
});
|
|
233
|
-
const fieldSetIds = steps
|
|
234
|
-
.map((s) => s.fieldSetId)
|
|
235
|
-
.filter((id) => id !== null);
|
|
234
|
+
const fieldSetIds = mapDefined(steps, (s) => s.fieldSetId);
|
|
236
235
|
// Steps reference field_sets via FK, so delete steps first
|
|
237
236
|
await erpTx.step.deleteMany({
|
|
238
237
|
where: { operationId: { in: opIds } },
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keyBy, mapDefined } from "@naisys/common";
|
|
1
2
|
import { OperationRunStatus as OperationRunStatusValues, OrderRunStatus as OrderRunStatusValues, } from "@naisys/erp-shared";
|
|
2
3
|
import erpDb from "../../database/erpDb.js";
|
|
3
4
|
import { writeAuditEntry } from "../audit.js";
|
|
@@ -188,9 +189,7 @@ export async function deleteOrderRun(id) {
|
|
|
188
189
|
where: { operationRunId: { in: opRunIds } },
|
|
189
190
|
select: { fieldRecordId: true },
|
|
190
191
|
});
|
|
191
|
-
const fieldRecordIds = stepRuns
|
|
192
|
-
.map((s) => s.fieldRecordId)
|
|
193
|
-
.filter((id) => id !== null);
|
|
192
|
+
const fieldRecordIds = mapDefined(stepRuns, (s) => s.fieldRecordId);
|
|
194
193
|
if (fieldRecordIds.length > 0) {
|
|
195
194
|
await tx.fieldValue.deleteMany({
|
|
196
195
|
where: { fieldRecordId: { in: fieldRecordIds } },
|
|
@@ -294,8 +293,8 @@ export async function completeOrderRun(orderRunId, orderId, data, userId) {
|
|
|
294
293
|
};
|
|
295
294
|
}
|
|
296
295
|
const itemFields = order.item.fieldSet?.fields ?? [];
|
|
297
|
-
const fieldsBySeqNo =
|
|
298
|
-
const fieldsById =
|
|
296
|
+
const fieldsBySeqNo = keyBy(itemFields, (f) => f.seqNo);
|
|
297
|
+
const fieldsById = keyBy(itemFields, (f) => f.id);
|
|
299
298
|
// Validate caller-supplied fieldSeqNos exist on the item.
|
|
300
299
|
const callerValues = data.fieldValues ?? [];
|
|
301
300
|
for (const fv of callerValues) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { keyBy, unique } from "@naisys/common";
|
|
1
2
|
import erpDb from "../../database/erpDb.js";
|
|
2
3
|
// --- Prisma deep include for full revision tree ---
|
|
3
4
|
const includeFullTree = {
|
|
@@ -41,9 +42,9 @@ function compareProps(pairs) {
|
|
|
41
42
|
return changes;
|
|
42
43
|
}
|
|
43
44
|
function diffFields(fromFields, toFields) {
|
|
44
|
-
const fromMap =
|
|
45
|
-
const toMap =
|
|
46
|
-
const allSeqNos =
|
|
45
|
+
const fromMap = keyBy(fromFields, (f) => f.seqNo);
|
|
46
|
+
const toMap = keyBy(toFields, (f) => f.seqNo);
|
|
47
|
+
const allSeqNos = unique([...fromMap.keys(), ...toMap.keys()]);
|
|
47
48
|
const result = [];
|
|
48
49
|
for (const seqNo of [...allSeqNos].sort((a, b) => a - b)) {
|
|
49
50
|
const from = fromMap.get(seqNo);
|
|
@@ -72,9 +73,9 @@ function diffFields(fromFields, toFields) {
|
|
|
72
73
|
return result;
|
|
73
74
|
}
|
|
74
75
|
function diffSteps(fromSteps, toSteps) {
|
|
75
|
-
const fromMap =
|
|
76
|
-
const toMap =
|
|
77
|
-
const allSeqNos =
|
|
76
|
+
const fromMap = keyBy(fromSteps, (s) => s.seqNo);
|
|
77
|
+
const toMap = keyBy(toSteps, (s) => s.seqNo);
|
|
78
|
+
const allSeqNos = unique([...fromMap.keys(), ...toMap.keys()]);
|
|
78
79
|
const result = [];
|
|
79
80
|
for (const seqNo of [...allSeqNos].sort((a, b) => a - b)) {
|
|
80
81
|
const from = fromMap.get(seqNo);
|
|
@@ -138,9 +139,9 @@ function diffDeps(fromDeps, toDeps) {
|
|
|
138
139
|
return result;
|
|
139
140
|
}
|
|
140
141
|
function diffOperations(fromOps, toOps) {
|
|
141
|
-
const fromMap =
|
|
142
|
-
const toMap =
|
|
143
|
-
const allSeqNos =
|
|
142
|
+
const fromMap = keyBy(fromOps, (op) => op.seqNo);
|
|
143
|
+
const toMap = keyBy(toOps, (op) => op.seqNo);
|
|
144
|
+
const allSeqNos = unique([...fromMap.keys(), ...toMap.keys()]);
|
|
144
145
|
const result = [];
|
|
145
146
|
for (const seqNo of [...allSeqNos].sort((a, b) => a - b)) {
|
|
146
147
|
const from = fromMap.get(seqNo);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { sumAgentMetricsByUuid } from "@naisys/hub-database";
|
|
2
|
+
import { OperationRunStatus } from "@naisys/erp-shared";
|
|
3
|
+
import erpDb from "../../database/erpDb.js";
|
|
4
|
+
/**
|
|
5
|
+
* Populate `tokens` on labor tickets and operation runs finalized before the
|
|
6
|
+
* column existed. Idempotent — only touches rows where `tokens IS NULL`, and
|
|
7
|
+
* only for agent users (others can't have tokens, so their rows stay NULL
|
|
8
|
+
* and the next startup ignores them too). Requires the hub DB client.
|
|
9
|
+
*/
|
|
10
|
+
export async function backfillOpRunTokens() {
|
|
11
|
+
const tickets = await erpDb.laborTicket.findMany({
|
|
12
|
+
where: {
|
|
13
|
+
tokens: null,
|
|
14
|
+
clockOut: { not: null },
|
|
15
|
+
operationRun: {
|
|
16
|
+
status: {
|
|
17
|
+
in: [
|
|
18
|
+
OperationRunStatus.completed,
|
|
19
|
+
OperationRunStatus.skipped,
|
|
20
|
+
OperationRunStatus.failed,
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
user: { isAgent: true },
|
|
25
|
+
},
|
|
26
|
+
select: {
|
|
27
|
+
id: true,
|
|
28
|
+
operationRunId: true,
|
|
29
|
+
clockIn: true,
|
|
30
|
+
clockOut: true,
|
|
31
|
+
user: { select: { uuid: true } },
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
if (tickets.length === 0)
|
|
35
|
+
return;
|
|
36
|
+
const dirtyOpRunIds = new Set();
|
|
37
|
+
for (const ticket of tickets) {
|
|
38
|
+
const { tokens } = await sumAgentMetricsByUuid(ticket.user.uuid, ticket.clockIn, ticket.clockOut);
|
|
39
|
+
await erpDb.laborTicket.update({
|
|
40
|
+
where: { id: ticket.id },
|
|
41
|
+
data: { tokens: Math.round(tokens) },
|
|
42
|
+
});
|
|
43
|
+
dirtyOpRunIds.add(ticket.operationRunId);
|
|
44
|
+
}
|
|
45
|
+
// Re-aggregate touched op_runs. Skip rows that already have a snapshot so
|
|
46
|
+
// we never clobber a value set by the normal transition path.
|
|
47
|
+
for (const opRunId of dirtyOpRunIds) {
|
|
48
|
+
const opRun = await erpDb.operationRun.findUnique({
|
|
49
|
+
where: { id: opRunId },
|
|
50
|
+
select: { tokens: true },
|
|
51
|
+
});
|
|
52
|
+
if (!opRun || opRun.tokens !== null)
|
|
53
|
+
continue;
|
|
54
|
+
const agg = await erpDb.laborTicket.aggregate({
|
|
55
|
+
where: { operationRunId: opRunId },
|
|
56
|
+
_sum: { tokens: true },
|
|
57
|
+
});
|
|
58
|
+
const total = agg._sum.tokens ?? 0;
|
|
59
|
+
if (total > 0) {
|
|
60
|
+
await erpDb.operationRun.update({
|
|
61
|
+
where: { id: opRunId },
|
|
62
|
+
data: { tokens: total },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=labor-ticket-backfill.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getLatestRunInfoByUuid,
|
|
1
|
+
import { getLatestRunInfoByUuid, sumAgentMetricsByUuid, } from "@naisys/hub-database";
|
|
2
2
|
import erpDb from "../../database/erpDb.js";
|
|
3
3
|
import { writeAuditEntry } from "../audit.js";
|
|
4
4
|
// --- Prisma include & result type ---
|
|
@@ -9,19 +9,22 @@ export const includeLaborTicket = {
|
|
|
9
9
|
};
|
|
10
10
|
// --- Helpers ---
|
|
11
11
|
/**
|
|
12
|
-
* Compute
|
|
12
|
+
* Compute cost + tokens for a labor ticket at clock-out time.
|
|
13
13
|
* Agents: sum of hub cost entries for the user within the clock-in/out window.
|
|
14
|
-
* Non-agents:
|
|
14
|
+
* Non-agents: zeros.
|
|
15
15
|
*/
|
|
16
|
-
async function
|
|
16
|
+
async function computeAgentMetrics(userId, clockIn, clockOut) {
|
|
17
17
|
const user = await erpDb.user.findUnique({
|
|
18
18
|
where: { id: userId },
|
|
19
19
|
select: { isAgent: true, uuid: true },
|
|
20
20
|
});
|
|
21
21
|
if (!user?.isAgent)
|
|
22
|
-
return 0;
|
|
23
|
-
const cost = await
|
|
24
|
-
return
|
|
22
|
+
return { cost: 0, tokens: 0 };
|
|
23
|
+
const { cost, tokens } = await sumAgentMetricsByUuid(user.uuid, clockIn, clockOut);
|
|
24
|
+
return {
|
|
25
|
+
cost: Math.round(cost * 100) / 100,
|
|
26
|
+
tokens: Math.round(tokens),
|
|
27
|
+
};
|
|
25
28
|
}
|
|
26
29
|
/**
|
|
27
30
|
* Get the current hub run info (run_id + session start) for an agent user.
|
|
@@ -67,10 +70,10 @@ export async function clockIn(operationRunId, userId, actorId) {
|
|
|
67
70
|
where: { userId, clockOut: null },
|
|
68
71
|
});
|
|
69
72
|
for (const ticket of openTickets) {
|
|
70
|
-
const cost = await
|
|
73
|
+
const { cost, tokens } = await computeAgentMetrics(userId, ticket.clockIn, now);
|
|
71
74
|
await tx.laborTicket.update({
|
|
72
75
|
where: { id: ticket.id },
|
|
73
|
-
data: { clockOut: now, cost, updatedById: actorId },
|
|
76
|
+
data: { clockOut: now, cost, tokens, updatedById: actorId },
|
|
74
77
|
});
|
|
75
78
|
}
|
|
76
79
|
// If no tickets were auto-closed and this is the first ticket for the
|
|
@@ -118,10 +121,10 @@ export async function clockOut(operationRunId, opts, actorId) {
|
|
|
118
121
|
const openTickets = await tx.laborTicket.findMany({ where });
|
|
119
122
|
const updated = [];
|
|
120
123
|
for (const ticket of openTickets) {
|
|
121
|
-
const cost = await
|
|
124
|
+
const { cost, tokens } = await computeAgentMetrics(ticket.userId, ticket.clockIn, now);
|
|
122
125
|
const result = await tx.laborTicket.update({
|
|
123
126
|
where: { id: ticket.id },
|
|
124
|
-
data: { clockOut: now, cost, updatedById: actorId },
|
|
127
|
+
data: { clockOut: now, cost, tokens, updatedById: actorId },
|
|
125
128
|
include: includeLaborTicket,
|
|
126
129
|
});
|
|
127
130
|
updated.push(result);
|
|
@@ -132,12 +135,15 @@ export async function clockOut(operationRunId, opts, actorId) {
|
|
|
132
135
|
export async function clockOutAllForOpRun(operationRunId, actorId) {
|
|
133
136
|
await clockOut(operationRunId, {}, actorId);
|
|
134
137
|
}
|
|
135
|
-
export async function
|
|
138
|
+
export async function sumLaborTicketMetrics(operationRunId) {
|
|
136
139
|
const result = await erpDb.laborTicket.aggregate({
|
|
137
140
|
where: { operationRunId },
|
|
138
|
-
_sum: { cost: true },
|
|
141
|
+
_sum: { cost: true, tokens: true },
|
|
139
142
|
});
|
|
140
|
-
return
|
|
143
|
+
return {
|
|
144
|
+
cost: Math.round((result._sum.cost ?? 0) * 100) / 100,
|
|
145
|
+
tokens: result._sum.tokens ?? 0,
|
|
146
|
+
};
|
|
141
147
|
}
|
|
142
148
|
export async function deleteLaborTicket(ticketId, actorId) {
|
|
143
149
|
await erpDb.$transaction(async (tx) => {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naisys/erp",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.51",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@naisys/erp",
|
|
9
|
-
"version": "3.0.0-beta.
|
|
9
|
+
"version": "3.0.0-beta.51",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@fastify/cookie": "^11.0.2",
|
|
12
12
|
"@fastify/cors": "^11.2.0",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"@fastify/rate-limit": "^10.3.0",
|
|
15
15
|
"@fastify/static": "^9.0.0",
|
|
16
16
|
"@fastify/swagger": "^9.7.0",
|
|
17
|
-
"@naisys/common": "3.0.0-beta.
|
|
18
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
19
|
-
"@naisys/erp-shared": "3.0.0-beta.
|
|
20
|
-
"@naisys/hub-database": "3.0.0-beta.
|
|
21
|
-
"@naisys/supervisor-database": "3.0.0-beta.
|
|
17
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
18
|
+
"@naisys/common-node": "3.0.0-beta.51",
|
|
19
|
+
"@naisys/erp-shared": "3.0.0-beta.51",
|
|
20
|
+
"@naisys/hub-database": "3.0.0-beta.51",
|
|
21
|
+
"@naisys/supervisor-database": "3.0.0-beta.51",
|
|
22
22
|
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
23
23
|
"@prisma/client": "^7.5.0",
|
|
24
24
|
"@scalar/fastify-api-reference": "^1.48.7",
|
|
@@ -394,41 +394,42 @@
|
|
|
394
394
|
}
|
|
395
395
|
},
|
|
396
396
|
"node_modules/@naisys/common": {
|
|
397
|
-
"version": "3.0.0-beta.
|
|
398
|
-
"resolved": "https://registry.npmjs.org/@naisys/common/-/common-3.0.0-beta.
|
|
399
|
-
"integrity": "sha512-
|
|
397
|
+
"version": "3.0.0-beta.51",
|
|
398
|
+
"resolved": "https://registry.npmjs.org/@naisys/common/-/common-3.0.0-beta.51.tgz",
|
|
399
|
+
"integrity": "sha512-CTv2SNKRMnR0N1rbHM5xeqVOVAQpc16dcnATCwerJS41Uha9kakMaBITlBhoQA8O2PhO/Cc6VbzBYRnSKBsWag==",
|
|
400
400
|
"dependencies": {
|
|
401
|
+
"cron-parser": "^5.5.0",
|
|
401
402
|
"semver": "^7.7.4",
|
|
402
403
|
"zod": "^4.3.6"
|
|
403
404
|
}
|
|
404
405
|
},
|
|
405
406
|
"node_modules/@naisys/common-node": {
|
|
406
|
-
"version": "3.0.0-beta.
|
|
407
|
-
"resolved": "https://registry.npmjs.org/@naisys/common-node/-/common-node-3.0.0-beta.
|
|
408
|
-
"integrity": "sha512-
|
|
407
|
+
"version": "3.0.0-beta.51",
|
|
408
|
+
"resolved": "https://registry.npmjs.org/@naisys/common-node/-/common-node-3.0.0-beta.51.tgz",
|
|
409
|
+
"integrity": "sha512-0G3uDNTKpCu6ZMO5NL/vQOn/0iK4B1HOQbW3U1d8eFIZbbS2YBlLhxL8ee2p4uDlnPiwA7V3nUTXrFRcHpwGJg==",
|
|
409
410
|
"dependencies": {
|
|
410
|
-
"@naisys/common": "3.0.0-beta.
|
|
411
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
411
412
|
"better-sqlite3": "^12.6.2",
|
|
412
413
|
"js-yaml": "^4.1.1",
|
|
413
414
|
"pino": "^10.3.1"
|
|
414
415
|
}
|
|
415
416
|
},
|
|
416
417
|
"node_modules/@naisys/erp-shared": {
|
|
417
|
-
"version": "3.0.0-beta.
|
|
418
|
-
"resolved": "https://registry.npmjs.org/@naisys/erp-shared/-/erp-shared-3.0.0-beta.
|
|
419
|
-
"integrity": "sha512-
|
|
418
|
+
"version": "3.0.0-beta.51",
|
|
419
|
+
"resolved": "https://registry.npmjs.org/@naisys/erp-shared/-/erp-shared-3.0.0-beta.51.tgz",
|
|
420
|
+
"integrity": "sha512-6I3ohn19tHpcYwJDFcoNpI70IUPT9Em+xpkRIG11j0G/gxOszGHIlOELsEeOtL/+qDK9MfFfsth6aoFewm11Uw==",
|
|
420
421
|
"dependencies": {
|
|
421
|
-
"@naisys/common": "3.0.0-beta.
|
|
422
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
422
423
|
"zod": "^4.3.6"
|
|
423
424
|
}
|
|
424
425
|
},
|
|
425
426
|
"node_modules/@naisys/hub-database": {
|
|
426
|
-
"version": "3.0.0-beta.
|
|
427
|
-
"resolved": "https://registry.npmjs.org/@naisys/hub-database/-/hub-database-3.0.0-beta.
|
|
428
|
-
"integrity": "sha512-
|
|
427
|
+
"version": "3.0.0-beta.51",
|
|
428
|
+
"resolved": "https://registry.npmjs.org/@naisys/hub-database/-/hub-database-3.0.0-beta.51.tgz",
|
|
429
|
+
"integrity": "sha512-TG2lOubOjl+guafQ4vKk9Vetw4Z7Vc43geRlYLYJjDBgN1twuwEBlFncRDbGdjD3Ohu81BUxhONOC5LSZiU/0A==",
|
|
429
430
|
"dependencies": {
|
|
430
|
-
"@naisys/common": "3.0.0-beta.
|
|
431
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
431
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
432
|
+
"@naisys/common-node": "3.0.0-beta.51",
|
|
432
433
|
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
433
434
|
"@prisma/client": "^7.5.0",
|
|
434
435
|
"better-sqlite3": "^12.6.2",
|
|
@@ -436,12 +437,12 @@
|
|
|
436
437
|
}
|
|
437
438
|
},
|
|
438
439
|
"node_modules/@naisys/supervisor-database": {
|
|
439
|
-
"version": "3.0.0-beta.
|
|
440
|
-
"resolved": "https://registry.npmjs.org/@naisys/supervisor-database/-/supervisor-database-3.0.0-beta.
|
|
441
|
-
"integrity": "sha512-
|
|
440
|
+
"version": "3.0.0-beta.51",
|
|
441
|
+
"resolved": "https://registry.npmjs.org/@naisys/supervisor-database/-/supervisor-database-3.0.0-beta.51.tgz",
|
|
442
|
+
"integrity": "sha512-cSIjScSiSloqgtU1AdkgvXeBIiDy5K4eXYTc4lAsokbx3EJWuRx7tibuu/kLnPrAZfzfC2uii/wPeTv5ryTR3g==",
|
|
442
443
|
"dependencies": {
|
|
443
|
-
"@naisys/common": "3.0.0-beta.
|
|
444
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
444
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
445
|
+
"@naisys/common-node": "3.0.0-beta.51",
|
|
445
446
|
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
446
447
|
"@prisma/client": "^7.5.0",
|
|
447
448
|
"bcryptjs": "^3.0.2",
|
|
@@ -1267,6 +1268,18 @@
|
|
|
1267
1268
|
"url": "https://opencollective.com/express"
|
|
1268
1269
|
}
|
|
1269
1270
|
},
|
|
1271
|
+
"node_modules/cron-parser": {
|
|
1272
|
+
"version": "5.5.0",
|
|
1273
|
+
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-5.5.0.tgz",
|
|
1274
|
+
"integrity": "sha512-oML4lKUXxizYswqmxuOCpgFS8BNUJpIu6k/2HVHyaL8Ynnf3wdf9tkns0yRdJLSIjkJ+b0DXHMZEHGpMwjnPww==",
|
|
1275
|
+
"license": "MIT",
|
|
1276
|
+
"dependencies": {
|
|
1277
|
+
"luxon": "^3.7.1"
|
|
1278
|
+
},
|
|
1279
|
+
"engines": {
|
|
1280
|
+
"node": ">=18"
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1270
1283
|
"node_modules/cross-spawn": {
|
|
1271
1284
|
"version": "7.0.6",
|
|
1272
1285
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
|
@@ -1991,6 +2004,15 @@
|
|
|
1991
2004
|
"url": "https://github.com/sponsors/wellwelwel"
|
|
1992
2005
|
}
|
|
1993
2006
|
},
|
|
2007
|
+
"node_modules/luxon": {
|
|
2008
|
+
"version": "3.7.2",
|
|
2009
|
+
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz",
|
|
2010
|
+
"integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==",
|
|
2011
|
+
"license": "MIT",
|
|
2012
|
+
"engines": {
|
|
2013
|
+
"node": ">=12"
|
|
2014
|
+
}
|
|
2015
|
+
},
|
|
1994
2016
|
"node_modules/mime": {
|
|
1995
2017
|
"version": "3.0.0",
|
|
1996
2018
|
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naisys/erp",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.51",
|
|
4
4
|
"description": "NAISYS ERP - Web UI for AI-driven order and work management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/erpServer.js",
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"@fastify/rate-limit": "^10.3.0",
|
|
47
47
|
"@fastify/static": "^9.0.0",
|
|
48
48
|
"@fastify/swagger": "^9.7.0",
|
|
49
|
-
"@naisys/common": "3.0.0-beta.
|
|
50
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
51
|
-
"@naisys/erp-shared": "3.0.0-beta.
|
|
52
|
-
"@naisys/hub-database": "3.0.0-beta.
|
|
53
|
-
"@naisys/supervisor-database": "3.0.0-beta.
|
|
49
|
+
"@naisys/common": "3.0.0-beta.51",
|
|
50
|
+
"@naisys/common-node": "3.0.0-beta.51",
|
|
51
|
+
"@naisys/erp-shared": "3.0.0-beta.51",
|
|
52
|
+
"@naisys/hub-database": "3.0.0-beta.51",
|
|
53
|
+
"@naisys/supervisor-database": "3.0.0-beta.51",
|
|
54
54
|
"@prisma/adapter-better-sqlite3": "^7.5.0",
|
|
55
55
|
"@prisma/client": "^7.5.0",
|
|
56
56
|
"@scalar/fastify-api-reference": "^1.48.7",
|
package/prisma/schema.prisma
CHANGED
|
@@ -307,6 +307,7 @@ model OperationRun {
|
|
|
307
307
|
status OperationRunStatus @default(pending)
|
|
308
308
|
assignedToId Int? @map("assigned_to_id")
|
|
309
309
|
cost Float?
|
|
310
|
+
tokens Int?
|
|
310
311
|
statusNote String? @map("status_note")
|
|
311
312
|
completedAt DateTime? @map("completed_at")
|
|
312
313
|
createdAt DateTime @default(now()) @map("created_at")
|
|
@@ -518,6 +519,7 @@ model LaborTicket {
|
|
|
518
519
|
clockIn DateTime @map("clock_in")
|
|
519
520
|
clockOut DateTime? @map("clock_out")
|
|
520
521
|
cost Float?
|
|
522
|
+
tokens Int?
|
|
521
523
|
createdAt DateTime @default(now()) @map("created_at")
|
|
522
524
|
createdById Int @map("created_by")
|
|
523
525
|
updatedAt DateTime @updatedAt @map("updated_at")
|