mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
- migration r3_gestion (7 tables) : Partner, Part (SANS colonne de quantité), StockMovement (signé, tracé, PU figé), PurchaseOrder/Line, LaborTime (taux figé), Document (R3.2) ; User.hourlyRate administrable - API (66 opérations) : tiers ; pièces (stock = Σ mouvements, alerte sous seuil) ; entrée/ajustement (motif requis, stock jamais négatif, en transaction) ; BC Brouillon→Envoyé→Reçu (la réception crée les RECEIPT et met à jour lastUnitPrice) ; consommation sur OT (stock suffisant, PRIX FIGÉ) ; main-d'œuvre (TAUX FIGÉ, refus si taux non défini) ; WorkOrderDetail.costs ; coûts verrouillés après clôture (409) - seed : tiers/pièces/BC/taux de la maquette — OT-0341 = 505 MAD (testé) - durcissement : références OT/DEM/BC/P par SÉQUENCES Postgres (nextval) — fin des courses « max+1 » (500 sporadiques sous charge parallèle) ; 3 runs Jest complets consécutifs verts - 55 tests (92 % stmts / 74,9 % branches) dont la recette officielle : consommer sous seuil → BC → réception → réappro, prix/taux figés prouvés Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
213 lines
6.8 KiB
TypeScript
213 lines
6.8 KiB
TypeScript
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<typeof WorkOrderSummarySchema>;
|
|
|
|
export const WorkOrdersResponseSchema = z.object({
|
|
workOrders: z.array(WorkOrderSummarySchema),
|
|
});
|
|
export type WorkOrdersResponse = z.infer<typeof WorkOrdersResponseSchema>;
|
|
|
|
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<typeof ChecklistItemSchema>;
|
|
|
|
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<typeof InterventionReportSchema>;
|
|
|
|
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<typeof WorkOrderDetailSchema>;
|
|
|
|
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<typeof WorkOrderCreateSchema>;
|
|
|
|
export const TransitionRequestSchema = z.object({
|
|
to: z.enum(WORK_ORDER_STATUSES),
|
|
comment: z.string().max(500).optional(),
|
|
});
|
|
export type TransitionRequest = z.infer<typeof TransitionRequestSchema>;
|
|
|
|
export const CommentCreateSchema = z.object({
|
|
message: z.string().min(1).max(1000),
|
|
});
|
|
export type CommentCreate = z.infer<typeof CommentCreateSchema>;
|
|
|
|
export const AssigneesUpdateSchema = z.object({
|
|
assigneeIds: z.array(z.uuid()).max(10),
|
|
});
|
|
export type AssigneesUpdate = z.infer<typeof AssigneesUpdateSchema>;
|
|
|
|
/** 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<typeof ReportUpsertSchema>;
|
|
|
|
export const ChecklistPatchSchema = z.object({
|
|
state: z.enum(CHECKLIST_STATES),
|
|
});
|
|
export type ChecklistPatch = z.infer<typeof ChecklistPatchSchema>;
|
|
|
|
// ————— 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<typeof RequestSummarySchema>;
|
|
|
|
export const RequestsResponseSchema = z.object({
|
|
requests: z.array(RequestSummarySchema),
|
|
});
|
|
export type RequestsResponse = z.infer<typeof RequestsResponseSchema>;
|
|
|
|
export const RequestCreateSchema = z.object({
|
|
assetId: z.uuid(),
|
|
description: z.string().min(1).max(2000),
|
|
isPersonTrapped: z.boolean().optional(),
|
|
});
|
|
export type RequestCreate = z.infer<typeof RequestCreateSchema>;
|
|
|
|
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<typeof RequestApproveSchema>;
|
|
|
|
export const RequestRejectSchema = z.object({
|
|
reason: z.string().min(3, 'Le motif est requis').max(500),
|
|
});
|
|
export type RequestReject = z.infer<typeof RequestRejectSchema>;
|
|
|
|
// ————— 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<typeof ReferenceValueSchema>;
|
|
|
|
export const ReferenceValuesResponseSchema = z.object({
|
|
referenceValues: z.array(ReferenceValueSchema),
|
|
});
|
|
export type ReferenceValuesResponse = z.infer<typeof ReferenceValuesResponseSchema>;
|
|
|
|
export const ReferenceValueCreateSchema = z.object({
|
|
field: z.enum(BILAN_FIELDS),
|
|
label: z.string().min(1).max(120),
|
|
});
|
|
export type ReferenceValueCreate = z.infer<typeof ReferenceValueCreateSchema>;
|
|
|
|
export const ReferenceValueUpdateSchema = z.object({
|
|
label: z.string().min(1).max(120).optional(),
|
|
isActive: z.boolean().optional(),
|
|
});
|
|
export type ReferenceValueUpdate = z.infer<typeof ReferenceValueUpdateSchema>;
|