Files
Nexus/packages/api/src/router/estimate-version-workflow.ts
T
Hartmut b41c1d2501
CI / Architecture Guardrails (push) Successful in 2m38s
CI / Assistant Split Regression (push) Successful in 3m33s
CI / Typecheck (push) Successful in 3m51s
CI / Lint (push) Successful in 5m2s
CI / E2E Tests (push) Has been cancelled
CI / Fresh-Linux Docker Deploy (push) Has been cancelled
CI / Release Images (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)
rename(phase 1): CapaKraken → Nexus across code, UI, docs, CI (#61)

Co-authored-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
Co-committed-by: Hartmut Nörenberg <hn@hartmut-noerenberg.com>
2026-05-21 16:28:40 +02:00

172 lines
5.1 KiB
TypeScript

import {
approveEstimateVersion,
createEstimateRevision,
submitEstimateVersion,
} from "@nexus/application";
import type { Prisma } from "@nexus/db";
import {
ApproveEstimateVersionSchema,
CreateEstimateRevisionSchema,
PermissionKey,
SubmitEstimateVersionSchema,
} from "@nexus/shared";
import { managerProcedure, requirePermission } from "../trpc.js";
import { rethrowEstimateRouterError } from "./estimate-procedure-support.js";
export const estimateVersionWorkflowProcedures = {
submitVersion: managerProcedure
.input(SubmitEstimateVersionSchema)
.mutation(async ({ ctx, input }) => {
requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);
let estimate;
try {
estimate = await ctx.db.$transaction(async (tx) => {
const submitted = await submitEstimateVersion(
tx as unknown as Parameters<typeof submitEstimateVersion>[0],
input,
);
await tx.auditLog.create({
data: {
entityType: "Estimate",
entityId: submitted.id,
action: "UPDATE",
...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
changes: {
after: {
id: submitted.id,
status: submitted.status,
submittedVersionId: submitted.versions.find(
(version) => version.status === "SUBMITTED",
)?.id,
},
} as Prisma.InputJsonValue,
},
});
return submitted;
});
} catch (error) {
rethrowEstimateRouterError(error, [
{
code: "NOT_FOUND",
messages: ["Estimate not found", "Estimate version not found"],
},
{
code: "PRECONDITION_FAILED",
messages: ["Estimate has no working version", "Only working versions can be submitted"],
},
]);
}
return estimate;
}),
approveVersion: managerProcedure
.input(ApproveEstimateVersionSchema)
.mutation(async ({ ctx, input }) => {
requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);
let estimate;
try {
estimate = await ctx.db.$transaction(async (tx) => {
const approved = await approveEstimateVersion(
tx as unknown as Parameters<typeof approveEstimateVersion>[0],
input,
);
await tx.auditLog.create({
data: {
entityType: "Estimate",
entityId: approved.id,
action: "UPDATE",
...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
changes: {
after: {
id: approved.id,
status: approved.status,
approvedVersionId: approved.versions.find(
(version) => version.status === "APPROVED",
)?.id,
},
} as Prisma.InputJsonValue,
},
});
return approved;
});
} catch (error) {
rethrowEstimateRouterError(error, [
{
code: "NOT_FOUND",
messages: ["Estimate not found", "Estimate version not found"],
},
{
code: "PRECONDITION_FAILED",
messages: [
"Estimate has no submitted version",
"Only submitted versions can be approved",
],
},
]);
}
return estimate;
}),
createRevision: managerProcedure
.input(CreateEstimateRevisionSchema)
.mutation(async ({ ctx, input }) => {
requirePermission(ctx, PermissionKey.MANAGE_PROJECTS);
let estimate;
try {
estimate = await ctx.db.$transaction(async (tx) => {
const revision = await createEstimateRevision(
tx as unknown as Parameters<typeof createEstimateRevision>[0],
input,
);
await tx.auditLog.create({
data: {
entityType: "Estimate",
entityId: revision.id,
action: "UPDATE",
...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
changes: {
after: {
id: revision.id,
status: revision.status,
latestVersionNumber: revision.latestVersionNumber,
workingVersionId: revision.versions.find(
(version) => version.status === "WORKING",
)?.id,
},
} as Prisma.InputJsonValue,
},
});
return revision;
});
} catch (error) {
rethrowEstimateRouterError(error, [
{
code: "NOT_FOUND",
messages: ["Estimate not found", "Estimate version not found"],
},
{
code: "PRECONDITION_FAILED",
messages: [
"Estimate already has a working version",
"Estimate has no locked version to revise",
"Source version must be locked before creating a revision",
],
},
]);
}
return estimate;
}),
};