222 lines
8.6 KiB
TypeScript
222 lines
8.6 KiB
TypeScript
import {
|
|
ImportBatchStatus,
|
|
StagedRecordStatus,
|
|
DispoStagedRecordType,
|
|
} from "@capakraken/db";
|
|
import {
|
|
assessDispoImportReadiness,
|
|
stageDispoImportBatch,
|
|
} from "@capakraken/application";
|
|
import { z } from "zod";
|
|
import { adminProcedure, createTRPCRouter } from "../trpc.js";
|
|
import { commitImportBatch, cancelImportBatch, resolveStagedRecord } from "./dispo-management.js";
|
|
import {
|
|
getImportBatch,
|
|
listImportBatches,
|
|
listStagedAssignments,
|
|
listStagedProjects,
|
|
listStagedResources,
|
|
listStagedUnresolvedRecords,
|
|
listStagedVacations,
|
|
} from "./dispo-read.js";
|
|
|
|
// ─── Shared schemas ──────────────────────────────────────────────────────────
|
|
|
|
const paginationSchema = z.object({
|
|
cursor: z.string().optional(),
|
|
limit: z.number().int().min(1).max(200).default(50),
|
|
});
|
|
|
|
const importBatchStatusSchema = z.nativeEnum(ImportBatchStatus);
|
|
const stagedRecordStatusSchema = z.nativeEnum(StagedRecordStatus);
|
|
const stagedRecordTypeSchema = z.nativeEnum(DispoStagedRecordType);
|
|
const workbookPathSchema = z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Workbook path is required.")
|
|
.refine((value) => value.toLowerCase().endsWith(".xlsx"), {
|
|
message: "Only .xlsx workbook paths are supported.",
|
|
});
|
|
|
|
// ─── Router ──────────────────────────────────────────────────────────────────
|
|
|
|
export const dispoRouter = createTRPCRouter({
|
|
// ── 1. stageImportBatch ──────────────────────────────────────────────────
|
|
|
|
stageImportBatch: adminProcedure
|
|
.input(
|
|
z.object({
|
|
chargeabilityWorkbookPath: workbookPathSchema,
|
|
costWorkbookPath: workbookPathSchema.optional(),
|
|
notes: z.string().nullish(),
|
|
planningWorkbookPath: workbookPathSchema,
|
|
referenceWorkbookPath: workbookPathSchema,
|
|
rosterWorkbookPath: workbookPathSchema.optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
return stageDispoImportBatch(ctx.db, {
|
|
chargeabilityWorkbookPath: input.chargeabilityWorkbookPath,
|
|
planningWorkbookPath: input.planningWorkbookPath,
|
|
referenceWorkbookPath: input.referenceWorkbookPath,
|
|
...(input.costWorkbookPath !== undefined ? { costWorkbookPath: input.costWorkbookPath } : {}),
|
|
...(input.notes !== undefined ? { notes: input.notes } : {}),
|
|
...(input.rosterWorkbookPath !== undefined ? { rosterWorkbookPath: input.rosterWorkbookPath } : {}),
|
|
});
|
|
}),
|
|
|
|
// ── 2. validateImportBatch ───────────────────────────────────────────────
|
|
|
|
validateImportBatch: adminProcedure
|
|
.input(
|
|
z.object({
|
|
chargeabilityWorkbookPath: workbookPathSchema,
|
|
costWorkbookPath: workbookPathSchema.optional(),
|
|
importBatchId: z.string().optional(),
|
|
notes: z.string().nullish(),
|
|
planningWorkbookPath: workbookPathSchema,
|
|
referenceWorkbookPath: workbookPathSchema,
|
|
rosterWorkbookPath: workbookPathSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input }) => {
|
|
return assessDispoImportReadiness({
|
|
chargeabilityWorkbookPath: input.chargeabilityWorkbookPath,
|
|
planningWorkbookPath: input.planningWorkbookPath,
|
|
referenceWorkbookPath: input.referenceWorkbookPath,
|
|
...(input.costWorkbookPath !== undefined ? { costWorkbookPath: input.costWorkbookPath } : {}),
|
|
...(input.importBatchId !== undefined ? { importBatchId: input.importBatchId } : {}),
|
|
...(input.notes !== undefined ? { notes: input.notes } : {}),
|
|
...(input.rosterWorkbookPath !== undefined ? { rosterWorkbookPath: input.rosterWorkbookPath } : {}),
|
|
});
|
|
}),
|
|
|
|
// ── 3. listImportBatches ─────────────────────────────────────────────────
|
|
|
|
listImportBatches: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
status: importBatchStatusSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listImportBatches(ctx.db, input);
|
|
}),
|
|
|
|
// ── 4. getImportBatch ────────────────────────────────────────────────────
|
|
|
|
getImportBatch: adminProcedure
|
|
.input(z.object({ id: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
return getImportBatch(ctx.db, input.id);
|
|
}),
|
|
|
|
// ── 5. cancelImportBatch ─────────────────────────────────────────────────
|
|
|
|
cancelImportBatch: adminProcedure
|
|
.input(z.object({ id: z.string() }))
|
|
.mutation(async ({ ctx, input }) => {
|
|
return cancelImportBatch(ctx.db, { id: input.id, userId: ctx.dbUser?.id });
|
|
}),
|
|
|
|
// ── 6. listStagedResources ───────────────────────────────────────────────
|
|
|
|
listStagedResources: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
importBatchId: z.string(),
|
|
status: stagedRecordStatusSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listStagedResources(ctx.db, input);
|
|
}),
|
|
|
|
// ── 7. listStagedProjects ────────────────────────────────────────────────
|
|
|
|
listStagedProjects: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
importBatchId: z.string(),
|
|
isTbd: z.boolean().optional(),
|
|
status: stagedRecordStatusSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listStagedProjects(ctx.db, input);
|
|
}),
|
|
|
|
// ── 8. listStagedAssignments ─────────────────────────────────────────────
|
|
|
|
listStagedAssignments: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
importBatchId: z.string(),
|
|
resourceExternalId: z.string().optional(),
|
|
status: stagedRecordStatusSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listStagedAssignments(ctx.db, input);
|
|
}),
|
|
|
|
// ── 9. listStagedVacations ───────────────────────────────────────────────
|
|
|
|
listStagedVacations: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
importBatchId: z.string(),
|
|
resourceExternalId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listStagedVacations(ctx.db, input);
|
|
}),
|
|
|
|
// ── 10. listStagedUnresolvedRecords ──────────────────────────────────────
|
|
|
|
listStagedUnresolvedRecords: adminProcedure
|
|
.input(
|
|
paginationSchema.extend({
|
|
importBatchId: z.string(),
|
|
recordType: stagedRecordTypeSchema.optional(),
|
|
}),
|
|
)
|
|
.query(async ({ ctx, input }) => {
|
|
return listStagedUnresolvedRecords(ctx.db, input);
|
|
}),
|
|
|
|
// ── 11. resolveStagedRecord ──────────────────────────────────────────────
|
|
|
|
resolveStagedRecord: adminProcedure
|
|
.input(
|
|
z.object({
|
|
action: z.enum(["APPROVE", "REJECT", "SKIP"]),
|
|
id: z.string(),
|
|
recordType: stagedRecordTypeSchema,
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
return resolveStagedRecord(ctx.db, input);
|
|
}),
|
|
|
|
// ── 12. commitImportBatch ────────────────────────────────────────────────
|
|
|
|
commitImportBatch: adminProcedure
|
|
.input(
|
|
z.object({
|
|
allowTbdUnresolved: z.boolean().optional(),
|
|
importBatchId: z.string(),
|
|
importTbdProjects: z.boolean().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
return commitImportBatch(ctx.db, {
|
|
importBatchId: input.importBatchId,
|
|
allowTbdUnresolved: input.allowTbdUnresolved,
|
|
importTbdProjects: input.importTbdProjects,
|
|
userId: ctx.dbUser?.id,
|
|
});
|
|
}),
|
|
});
|