mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-09 13:11:54 +00:00
- 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>
94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
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,
|
|
};
|
|
}
|
|
}
|