feat(#103): Numéro de dossier – backend
- Colonne numero_dossier (utilisateurs, assistantes_maternelles, parents) - Table numero_dossier_sequence, format AAAA-NNNNNN, séquence par année - Génération à la soumission AM et parent (famille) - Backfill existants (famille = co_parent ou enfants partagés) - API PATCH /users/:id/numero-dossier (gestionnaire/admin) - Garde-fous: max 2 parents/dossier, pas de mélange AM/parent Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { NumeroDossierService } from './numero-dossier.service';
|
||||
|
||||
@Module({
|
||||
providers: [NumeroDossierService],
|
||||
exports: [NumeroDossierService],
|
||||
})
|
||||
export class NumeroDossierModule {}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EntityManager } from 'typeorm';
|
||||
|
||||
const FORMAT_MAX_SEQUENCE = 990000;
|
||||
|
||||
/**
|
||||
* Service de génération du numéro de dossier (ticket #103).
|
||||
* Format AAAA-NNNNNN (année + 6 chiffres), séquence par année.
|
||||
* Si séquence >= 990000, overflowWarning est true (alerte gestionnaire).
|
||||
*/
|
||||
@Injectable()
|
||||
export class NumeroDossierService {
|
||||
/**
|
||||
* Génère le prochain numéro de dossier dans le cadre d'une transaction.
|
||||
* À appeler avec le manager de la transaction pour garantir l'unicité.
|
||||
*/
|
||||
async getNextNumeroDossier(manager: EntityManager): Promise<{
|
||||
numero: string;
|
||||
overflowWarning: boolean;
|
||||
}> {
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
// Garantir l'existence de la ligne pour l'année
|
||||
await manager.query(
|
||||
`INSERT INTO numero_dossier_sequence (annee, prochain)
|
||||
VALUES ($1, 1)
|
||||
ON CONFLICT (annee) DO NOTHING`,
|
||||
[year],
|
||||
);
|
||||
|
||||
// Prendre le prochain numéro et incrémenter (FOR UPDATE pour concurrence)
|
||||
const selectRows = await manager.query(
|
||||
`SELECT prochain FROM numero_dossier_sequence WHERE annee = $1 FOR UPDATE`,
|
||||
[year],
|
||||
);
|
||||
const currentVal = selectRows?.[0]?.prochain ?? 1;
|
||||
|
||||
await manager.query(
|
||||
`UPDATE numero_dossier_sequence SET prochain = prochain + 1 WHERE annee = $1`,
|
||||
[year],
|
||||
);
|
||||
|
||||
const nextVal = currentVal;
|
||||
const overflowWarning = nextVal >= FORMAT_MAX_SEQUENCE;
|
||||
if (overflowWarning) {
|
||||
// Log pour alerte gestionnaire (ticket #103)
|
||||
console.warn(
|
||||
`[NumeroDossierService] Séquence année ${year} >= ${FORMAT_MAX_SEQUENCE} (valeur ${nextVal}). Prévoir renouvellement ou format.`,
|
||||
);
|
||||
}
|
||||
|
||||
const numero = `${year}-${String(nextVal).padStart(6, '0')}`;
|
||||
return { numero, overflowWarning };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user