import { z } from 'zod'; import { BILAN_FIELDS, CHECKLIST_STATES, REQUEST_STATUSES, WORK_ORDER_PRIORITIES, WORK_ORDER_STATUSES, WORK_ORDER_TYPES, } from '../exploitation'; import { WorkOrderCostsSchema } from './gestion'; const PersonneSchema = z.object({ id: z.uuid(), displayName: z.string(), initials: z.string(), }); // ————— Ordres de travail ————— export const WorkOrderSummarySchema = z.object({ id: z.uuid(), reference: z.string(), title: z.string(), type: z.enum(WORK_ORDER_TYPES), status: z.enum(WORK_ORDER_STATUSES), priority: z.enum(WORK_ORDER_PRIORITIES), assetId: z.uuid(), assetReference: z.string(), siteName: z.string(), dueDate: z.iso.datetime().nullable(), assignees: z.array(PersonneSchema), createdAt: z.iso.datetime(), }); export type WorkOrderSummary = z.infer; export const WorkOrdersResponseSchema = z.object({ workOrders: z.array(WorkOrderSummarySchema), }); export type WorkOrdersResponse = z.infer; export const WorkOrderEventSchema = z.object({ id: z.uuid(), kind: z.string(), message: z.string().nullable(), by: PersonneSchema.nullable(), createdAt: z.iso.datetime(), }); export const ChecklistItemSchema = z.object({ id: z.uuid(), label: z.string(), state: z.enum(CHECKLIST_STATES), doneBy: PersonneSchema.nullable(), doneAt: z.iso.datetime().nullable(), }); export type ChecklistItemDto = z.infer; const BilanValueSchema = z.object({ id: z.uuid(), label: z.string() }).nullable(); export const InterventionReportSchema = z.object({ note: z.string().nullable(), doorState: BilanValueSchema, cabinPosition: BilanValueSchema, anomaly: BilanValueSchema, externalCause: BilanValueSchema, actionTaken: BilanValueSchema, componentConcerned: BilanValueSchema, }); export type InterventionReportDto = z.infer; export const WorkOrderDetailSchema = WorkOrderSummarySchema.extend({ description: z.string().nullable(), locationName: z.string(), startedAt: z.iso.datetime().nullable(), completedAt: z.iso.datetime().nullable(), cancelledAt: z.iso.datetime().nullable(), createdBy: PersonneSchema.nullable(), request: z .object({ id: z.uuid(), reference: z.string(), requesterLabel: z.string() }) .nullable(), events: z.array(WorkOrderEventSchema), checklist: z.array(ChecklistItemSchema), report: InterventionReportSchema.nullable(), /** Coûts figés (R3) : consommations + main-d'œuvre. */ costs: WorkOrderCostsSchema, /** Ce que la machine à états autorise depuis l'état courant. */ allowedTransitions: z.array(z.enum(WORK_ORDER_STATUSES)), /** Ce qui bloque la clôture (vide = clôturable) — messages métier. */ closureBlockers: z.array(z.string()), }); export type WorkOrderDetail = z.infer; export const WorkOrderCreateSchema = z.object({ title: z.string().min(1).max(200), description: z.string().max(2000).optional(), type: z.enum(WORK_ORDER_TYPES), priority: z.enum(WORK_ORDER_PRIORITIES).optional(), assetId: z.uuid(), dueDate: z.iso.datetime().optional(), assigneeIds: z.array(z.uuid()).optional(), }); export type WorkOrderCreate = z.infer; export const TransitionRequestSchema = z.object({ to: z.enum(WORK_ORDER_STATUSES), comment: z.string().max(500).optional(), }); export type TransitionRequest = z.infer; export const CommentCreateSchema = z.object({ message: z.string().min(1).max(1000), }); export type CommentCreate = z.infer; export const AssigneesUpdateSchema = z.object({ assigneeIds: z.array(z.uuid()).max(10), }); export type AssigneesUpdate = z.infer; /** Upsert du bilan — null efface un champ. */ export const ReportUpsertSchema = z.object({ note: z.string().max(2000).nullable().optional(), doorStateId: z.uuid().nullable().optional(), cabinPositionId: z.uuid().nullable().optional(), anomalyId: z.uuid().nullable().optional(), externalCauseId: z.uuid().nullable().optional(), actionTakenId: z.uuid().nullable().optional(), componentConcernedId: z.uuid().nullable().optional(), }); export type ReportUpsert = z.infer; export const ChecklistPatchSchema = z.object({ state: z.enum(CHECKLIST_STATES), }); export type ChecklistPatch = z.infer; // ————— Demandes ————— export const RequestSummarySchema = z.object({ id: z.uuid(), reference: z.string(), description: z.string(), isPersonTrapped: z.boolean(), status: z.enum(REQUEST_STATUSES), rejectionReason: z.string().nullable(), assetId: z.uuid(), assetReference: z.string(), siteName: z.string(), requesterLabel: z.string(), workOrder: z .object({ id: z.uuid(), reference: z.string(), status: z.enum(WORK_ORDER_STATUSES), }) .nullable(), createdAt: z.iso.datetime(), }); export type RequestSummary = z.infer; export const RequestsResponseSchema = z.object({ requests: z.array(RequestSummarySchema), }); export type RequestsResponse = z.infer; export const RequestCreateSchema = z.object({ assetId: z.uuid(), description: z.string().min(1).max(2000), isPersonTrapped: z.boolean().optional(), }); export type RequestCreate = z.infer; export const RequestApproveSchema = z.object({ title: z.string().min(1).max(200).optional(), // défaut : description tronquée priority: z.enum(WORK_ORDER_PRIORITIES).optional(), assigneeIds: z.array(z.uuid()).optional(), dueDate: z.iso.datetime().optional(), }); export type RequestApprove = z.infer; export const RequestRejectSchema = z.object({ reason: z.string().min(3, 'Le motif est requis').max(500), }); export type RequestReject = z.infer; // ————— Référentiels du bilan codé ————— export const ReferenceValueSchema = z.object({ id: z.uuid(), field: z.enum(BILAN_FIELDS), label: z.string(), isActive: z.boolean(), usageCount: z.number().int(), }); export type ReferenceValueDto = z.infer; export const ReferenceValuesResponseSchema = z.object({ referenceValues: z.array(ReferenceValueSchema), }); export type ReferenceValuesResponse = z.infer; export const ReferenceValueCreateSchema = z.object({ field: z.enum(BILAN_FIELDS), label: z.string().min(1).max(120), }); export type ReferenceValueCreate = z.infer; export const ReferenceValueUpdateSchema = z.object({ label: z.string().min(1).max(120).optional(), isActive: z.boolean().optional(), }); export type ReferenceValueUpdate = z.infer;