mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-09 21:21:54 +00:00
feat(r2.1): socle backend exploitation — machine à états, bilan codé, demandes 1-1
- migration r2_exploitation (10 tables) : WorkOrder (référence séquentielle, horodatages), WorkOrderEvent, Request (1-1, motif de rejet), ReferenceValue, InterventionReport (6 FK), TaskTemplate/ChecklistItem, Meter/MeterReading - contrat : 15 opérations (41 total) ; la table des transitions et les champs requis du bilan vivent dans @siop/shared ; la fiche OT expose allowedTransitions + closureBlockers (messages métier) - API : machine à états stricte ; garde de clôture (bilan 3 champs requis + checklist sans tâche en attente) ; approbation → OT lié 1-1 (409 si déjà traitée) ; rejet à motif obligatoire ; scoping « voir autre » sur listes et accès directs (404 sans fuite) ; validation des valeurs de bilan par champ ; « personne bloquée » triée en tête côté API - seed : 31 valeurs de référentiels, 8 gabarits (parachute réglementaire), OT/demandes/compteurs de la maquette — idempotent - 45 tests verts (95 % stmts / 79 % branches) dont la recette officielle rejouée de bout en bout ; smoke test sur build de prod Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
93
apps/api/src/reference-values/reference-values.service.ts
Normal file
93
apps/api/src/reference-values/reference-values.service.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
ConflictException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import type {
|
||||
ReferenceValueCreate,
|
||||
ReferenceValueDto,
|
||||
ReferenceValuesResponse,
|
||||
ReferenceValueUpdate,
|
||||
} from '@siop/shared';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
|
||||
const usageInclude = {
|
||||
_count: {
|
||||
select: {
|
||||
doorStates: true,
|
||||
cabinPositions: true,
|
||||
anomalies: true,
|
||||
externalCauses: true,
|
||||
actionsTaken: true,
|
||||
componentsConcerned: true,
|
||||
},
|
||||
},
|
||||
} satisfies Prisma.ReferenceValueInclude;
|
||||
|
||||
type Row = Prisma.ReferenceValueGetPayload<{ include: typeof usageInclude }>;
|
||||
|
||||
@Injectable()
|
||||
export class ReferenceValuesService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async list(): Promise<ReferenceValuesResponse> {
|
||||
const rows = await this.prisma.referenceValue.findMany({
|
||||
include: usageInclude,
|
||||
orderBy: [{ field: 'asc' }, { label: 'asc' }],
|
||||
});
|
||||
return { referenceValues: rows.map((r) => this.toDto(r)) };
|
||||
}
|
||||
|
||||
async create(dto: ReferenceValueCreate): Promise<ReferenceValueDto> {
|
||||
try {
|
||||
const created = await this.prisma.referenceValue.create({
|
||||
data: dto,
|
||||
include: usageInclude,
|
||||
});
|
||||
return this.toDto(created);
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
|
||||
throw new ConflictException('Ce libellé existe déjà pour ce champ');
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Renommage / (dés)activation — jamais de suppression (même règle que Category). */
|
||||
async update(id: string, dto: ReferenceValueUpdate): Promise<ReferenceValueDto> {
|
||||
try {
|
||||
const updated = await this.prisma.referenceValue.update({
|
||||
where: { id },
|
||||
data: dto,
|
||||
include: usageInclude,
|
||||
});
|
||||
return this.toDto(updated);
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2025') {
|
||||
throw new NotFoundException('Valeur inconnue');
|
||||
}
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
|
||||
throw new ConflictException('Ce libellé existe déjà pour ce champ');
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private toDto(row: Row): ReferenceValueDto {
|
||||
const c = row._count;
|
||||
return {
|
||||
id: row.id,
|
||||
field: row.field,
|
||||
label: row.label,
|
||||
isActive: row.isActive,
|
||||
usageCount:
|
||||
c.doorStates +
|
||||
c.cabinPositions +
|
||||
c.anomalies +
|
||||
c.externalCauses +
|
||||
c.actionsTaken +
|
||||
c.componentsConcerned,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user