Files
EME_APP/eme-backend/src/dtos/emprunt.dto.ts
T
2026-07-24 13:41:40 +02:00

183 lines
5.9 KiB
TypeScript

import { EmpruntAvecMateriel } from '../repositories/emprunt.repository';
import { MaterielResponse, toMaterielResponse } from './materiel.dto';
import { AppError } from '../errors/app-error';
import { ETAT_CHECKLIST_ELEMENT, MODE_IDENTIFICATION } from '../models/enums';
export interface EmpruntResponse {
id: number;
dateEmprunt: Date;
dateRetourPrevue: Date;
dateRetourReelle: Date | null;
statut: string;
materiel: MaterielResponse;
checklistDepart: ChecklistElementResponse[];
}
export interface ChecklistElementResponse {
accessoireId: number | null;
nomElement: string;
etat: string;
quantiteConstatee: number;
}
export function toEmpruntResponse(emprunt: EmpruntAvecMateriel): EmpruntResponse {
const checklistDepart = emprunt.checklists.find((checklist) => checklist.type === 'DEPART');
return {
id: emprunt.id,
dateEmprunt: emprunt.dateEmprunt,
dateRetourPrevue: emprunt.dateRetourPrevue,
dateRetourReelle: emprunt.dateRetourReelle,
statut: emprunt.statut,
materiel: toMaterielResponse(emprunt.materiel),
checklistDepart:
checklistDepart?.elements.map((element) => ({
accessoireId: element.accessoireId,
nomElement: element.nomElement,
etat: element.etat,
quantiteConstatee: element.quantiteConstatee,
})) ?? [],
};
}
export interface ChecklistElementRequest {
accessoireId?: number;
nomElement: string;
etat: string;
quantiteConstatee: number;
commentaire?: string;
}
export interface CreerEmpruntRequest {
materielId: number;
posteEmpruntId: number;
modeIdentification: string;
commentaireDepart?: string;
elements: ChecklistElementRequest[];
}
function asObject(value: unknown, message: string): Record<string, unknown> {
if (typeof value !== 'object' || value === null) {
throw new AppError(400, message);
}
return value as Record<string, unknown>;
}
function asPositiveInt(value: unknown, champ: string): number {
if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
throw new AppError(400, `${champ} doit etre un entier positif`);
}
return value;
}
function asIntOrZero(value: unknown, champ: string): number {
if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
throw new AppError(400, `${champ} doit etre un entier positif ou nul`);
}
return value;
}
function asEnum<T extends string>(value: unknown, autorisees: readonly T[], champ: string): T {
if (typeof value !== 'string' || !(autorisees as readonly string[]).includes(value)) {
throw new AppError(400, `${champ} invalide`);
}
return value as T;
}
function parseElement(value: unknown, index: number): ChecklistElementRequest {
const obj = asObject(value, `elements[${index}] invalide`);
if (typeof obj.nomElement !== 'string' || obj.nomElement.trim() === '') {
throw new AppError(400, `elements[${index}].nomElement requis`);
}
const element: ChecklistElementRequest = {
nomElement: obj.nomElement,
etat: asEnum(obj.etat, ETAT_CHECKLIST_ELEMENT, `elements[${index}].etat`),
quantiteConstatee: asIntOrZero(obj.quantiteConstatee, `elements[${index}].quantiteConstatee`),
};
if (obj.accessoireId !== undefined) {
element.accessoireId = asPositiveInt(obj.accessoireId, `elements[${index}].accessoireId`);
}
if (obj.commentaire !== undefined) {
if (typeof obj.commentaire !== 'string') {
throw new AppError(400, `elements[${index}].commentaire invalide`);
}
element.commentaire = obj.commentaire;
}
return element;
}
export function parseCreerEmpruntRequest(body: unknown): CreerEmpruntRequest {
const obj = asObject(body, 'Corps de requete invalide');
if (!Array.isArray(obj.elements) || obj.elements.length === 0) {
throw new AppError(400, 'La checklist de depart est obligatoire (RG11)');
}
const request: CreerEmpruntRequest = {
materielId: asPositiveInt(obj.materielId, 'materielId'),
posteEmpruntId: asPositiveInt(obj.posteEmpruntId, 'posteEmpruntId'),
modeIdentification: asEnum(obj.modeIdentification, MODE_IDENTIFICATION, 'modeIdentification'),
elements: obj.elements.map((element, index) => parseElement(element, index)),
};
if (obj.commentaireDepart !== undefined) {
if (typeof obj.commentaireDepart !== 'string') {
throw new AppError(400, 'commentaireDepart invalide');
}
request.commentaireDepart = obj.commentaireDepart;
}
return request;
}
export interface RestituerEmpruntRequest {
modeIdentification: string;
commentaireRetour?: string;
elements: ChecklistElementRequest[];
}
export interface SignalerTentativeRetourRequest {
nomElement: string;
etatInitial: string;
etatDemande: string;
}
export function parseSignalerTentativeRetourRequest(body: unknown): SignalerTentativeRetourRequest {
const obj = asObject(body, 'Corps de requete invalide');
if (typeof obj.nomElement !== 'string' || obj.nomElement.trim() === '') {
throw new AppError(400, 'nomElement requis');
}
return {
nomElement: obj.nomElement.trim(),
etatInitial: asEnum(obj.etatInitial, ETAT_CHECKLIST_ELEMENT, 'etatInitial'),
etatDemande: asEnum(obj.etatDemande, ETAT_CHECKLIST_ELEMENT, 'etatDemande'),
};
}
export function parseRestituerEmpruntRequest(body: unknown): RestituerEmpruntRequest {
const obj = asObject(body, 'Corps de requete invalide');
if (!Array.isArray(obj.elements) || obj.elements.length === 0) {
throw new AppError(400, 'La checklist de retour est obligatoire (RG16)');
}
const request: RestituerEmpruntRequest = {
modeIdentification: asEnum(obj.modeIdentification, MODE_IDENTIFICATION, 'modeIdentification'),
elements: obj.elements.map((element, index) => parseElement(element, index)),
};
if (obj.commentaireRetour !== undefined) {
if (typeof obj.commentaireRetour !== 'string') {
throw new AppError(400, 'commentaireRetour invalide');
}
request.commentaireRetour = obj.commentaireRetour;
}
return request;
}