feat(backend): expose POST /api/emprunts with departure checklist

This commit is contained in:
SaidSoighiri94
2026-07-06 09:46:03 +02:00
parent d8f044924e
commit 3215a3c11f
9 changed files with 267 additions and 11 deletions
@@ -1,6 +1,7 @@
import { Prisma } from '@prisma/client';
import { prisma } from '../db/prisma';
import { StatutEmprunt } from '../models/enums';
import { AppError } from '../errors/app-error';
export type EmpruntAvecMateriel = Prisma.EmpruntGetPayload<{
include: { materiel: { include: { categorie: true } } };
@@ -18,3 +19,74 @@ export function findEnCoursParUtilisateur(utilisateurId: number): Promise<Emprun
orderBy: { dateRetourPrevue: 'asc' },
});
}
export interface CreerEmpruntData {
utilisateurId: number;
materielId: number;
campusId: number;
sallePretId: number;
posteEmpruntId: number;
dateRetourPrevue: Date;
modeIdentification: string;
commentaireDepart?: string;
elements: {
accessoireId?: number;
nomElement: string;
etat: string;
quantiteConstatee: number;
commentaire?: string;
}[];
}
/* Création atomique : réservation du matériel (DISPONIBLE -> EMPRUNTE), emprunt,
checklist de départ et ses éléments. Si une étape échoue, tout est annulé. */
export function creerEmpruntComplet(data: CreerEmpruntData): Promise<EmpruntAvecMateriel> {
return prisma.$transaction(async (tx) => {
// Réservation atomique : empêche un double emprunt du même matériel (RG07).
const reservation = await tx.materiel.updateMany({
where: { id: data.materielId, statut: 'DISPONIBLE' },
data: { statut: 'EMPRUNTE' },
});
if (reservation.count === 0) {
throw new AppError(409, 'Materiel non disponible');
}
const emprunt = await tx.emprunt.create({
data: {
utilisateurId: data.utilisateurId,
materielId: data.materielId,
campusId: data.campusId,
sallePretId: data.sallePretId,
posteEmpruntId: data.posteEmpruntId,
dateEmprunt: new Date(),
dateRetourPrevue: data.dateRetourPrevue,
statut: 'EN_COURS',
modeIdentificationEmprunt: data.modeIdentification,
commentaireDepart: data.commentaireDepart ?? null,
},
});
await tx.checklist.create({
data: {
empruntId: emprunt.id,
utilisateurId: data.utilisateurId,
type: 'DEPART',
dateVerification: new Date(),
elements: {
create: data.elements.map((element) => ({
accessoireId: element.accessoireId ?? null,
nomElement: element.nomElement,
etat: element.etat,
quantiteConstatee: element.quantiteConstatee,
commentaire: element.commentaire ?? null,
})),
},
},
});
return tx.emprunt.findUniqueOrThrow({
where: { id: emprunt.id },
include: { materiel: { include: { categorie: true } } },
});
});
}