feat(#205): renommer absences_garde → evenements_agenda

Migration live + BDD.sql from-scratch, module Nest / API
/evenements-agenda, FK cartes id_evenement. Front stub path aligné.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-01 17:07:54 +02:00
co-authored by Cursor
parent 0842f66df8
commit 2114748d44
25 changed files with 353 additions and 247 deletions
@@ -65,7 +65,7 @@ export class CardsController {
@Roles(RoleType.PARENT, RoleType.ASSISTANTE_MATERNELLE)
@HttpCode(HttpStatus.CREATED)
@ApiOperation({
summary: 'Créer une bulle (+ hook absences_garde) — #194',
summary: 'Créer une bulle (+ hook evenements_agenda) — #194',
})
@ApiBody({ type: CreerCarteDto })
@ApiResponse({ status: 201, type: CarteDto })
+2 -2
View File
@@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AbsencesGardeModule } from '../absences-garde';
import { EvenementsAgendaModule } from '../evenements-agenda';
import { CardType } from 'src/entities/card_types.entity';
import { CardInstance } from 'src/entities/card_instances.entity';
import { CardAudienceMember } from 'src/entities/card_audience_members.entity';
@@ -16,7 +16,7 @@ import { CardsRealtimeService } from './cards-realtime.service';
@Module({
imports: [
AbsencesGardeModule,
EvenementsAgendaModule,
TypeOrmModule.forFeature([
CardType,
CardInstance,
@@ -3,7 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { ForbiddenException } from '@nestjs/common';
import { CardsService } from './cards.service';
import { CardsRealtimeService } from './cards-realtime.service';
import { AbsencesGardeService } from '../absences-garde/absences-garde.service';
import { EvenementsAgendaService } from '../evenements-agenda/evenements-agenda.service';
import { CardType, CardResponseModeType } from 'src/entities/card_types.entity';
import {
CardInstance,
@@ -15,7 +15,7 @@ import { CardResponse } from 'src/entities/card_responses.entity';
import { AmChildren } from 'src/entities/am_children.entity';
import { ParentsChildren } from 'src/entities/parents_children.entity';
import { RoleType } from 'src/entities/users.entity';
import { StatutAbsenceGardeType, TypeAbsenceGardeType } from 'src/entities/absences_garde.entity';
import { StatutEvenementAgendaType, TypeEvenementAgendaType } from 'src/entities/evenements_agenda.entity';
describe('CardsService (#194)', () => {
let service: CardsService;
@@ -41,7 +41,7 @@ describe('CardsService (#194)', () => {
};
const amChildrenRepo = { findOne: jest.fn() };
const parentsChildrenRepo = { find: jest.fn(), findOne: jest.fn() };
const absencesService = {
const evenementsService = {
creer: jest.fn(),
maj: jest.fn(),
supprimer: jest.fn(),
@@ -58,7 +58,7 @@ describe('CardsService (#194)', () => {
{ provide: getRepositoryToken(CardResponse), useValue: responsesRepo },
{ provide: getRepositoryToken(AmChildren), useValue: amChildrenRepo },
{ provide: getRepositoryToken(ParentsChildren), useValue: parentsChildrenRepo },
{ provide: AbsencesGardeService, useValue: absencesService },
{ provide: EvenementsAgendaService, useValue: evenementsService },
{ provide: CardsRealtimeService, useValue: realtime },
],
}).compile();
@@ -88,10 +88,10 @@ describe('CardsService (#194)', () => {
enfantId: 'e-1',
date_fin: null,
});
absencesService.creer.mockResolvedValue({
evenementsService.creer.mockResolvedValue({
id: 'abs-1',
type: TypeAbsenceGardeType.CONGE_AM,
statut: StatutAbsenceGardeType.EN_ATTENTE,
type: TypeEvenementAgendaType.CONGE_AM,
statut: StatutEvenementAgendaType.EN_ATTENTE,
});
parentsChildrenRepo.find.mockResolvedValue([
{ parentId: 'p-1', enfantId: 'e-1' },
@@ -101,7 +101,7 @@ describe('CardsService (#194)', () => {
id: 'card-1',
type_code: 'conge_am',
id_placement: 'pl-1',
id_absence: 'abs-1',
id_evenement: 'abs-1',
cree_par: 'am-1',
operation: CardOperationType.CREATE,
statut: CardInstanceStatutType.OUVERTE,
@@ -130,7 +130,7 @@ describe('CardsService (#194)', () => {
date_fin: '2026-11-07',
});
expect(absencesService.creer).toHaveBeenCalled();
expect(evenementsService.creer).toHaveBeenCalled();
expect(audienceRepo.save).toHaveBeenCalled();
expect(realtime.emitToUsers).toHaveBeenCalledWith(
['am-1', 'p-1', 'p-2'],
+28 -28
View File
@@ -6,11 +6,11 @@ import {
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Repository } from 'typeorm';
import { AbsencesGardeService } from '../absences-garde/absences-garde.service';
import { EvenementsAgendaService } from '../evenements-agenda/evenements-agenda.service';
import {
StatutAbsenceGardeType,
TypeAbsenceGardeType,
} from 'src/entities/absences_garde.entity';
StatutEvenementAgendaType,
TypeEvenementAgendaType,
} from 'src/entities/evenements_agenda.entity';
import { AmChildren } from 'src/entities/am_children.entity';
import { ParentsChildren } from 'src/entities/parents_children.entity';
import { RoleType } from 'src/entities/users.entity';
@@ -49,7 +49,7 @@ export class CardsService {
private readonly amChildrenRepo: Repository<AmChildren>,
@InjectRepository(ParentsChildren)
private readonly parentsChildrenRepo: Repository<ParentsChildren>,
private readonly absencesService: AbsencesGardeService,
private readonly evenementsService: EvenementsAgendaService,
private readonly realtime: CardsRealtimeService,
) {}
@@ -110,11 +110,11 @@ export class CardsService {
);
const operation = dto.operation ?? CardOperationType.CREATE;
let absenceId = dto.id_absence;
let absenceId = dto.id_evenement;
const absenceType = this.mapAbsenceType(dto.type_code);
if (operation === CardOperationType.CREATE) {
const absence = await this.absencesService.creer(userId, role, {
const absence = await this.evenementsService.creer(userId, role, {
id_placement: dto.id_placement,
type: absenceType,
date_debut: dto.date_debut,
@@ -124,16 +124,16 @@ export class CardsService {
absenceId = absence.id;
} else {
if (!absenceId) {
throw new BadRequestException('id_absence requis pour operation=update');
throw new BadRequestException('id_evenement requis pour operation=update');
}
await this.absencesService.maj(userId, role, absenceId, {
await this.evenementsService.maj(userId, role, absenceId, {
date_debut: dto.date_debut,
date_fin: dto.date_fin,
motif: dto.motif,
// Congé accepté modifié → repasse en attente via cartes respond flow;
// pour absence enfant update immédiat déjà fait.
...(dto.type_code === 'conge_am'
? { statut: StatutAbsenceGardeType.EN_ATTENTE }
? { statut: StatutEvenementAgendaType.EN_ATTENTE }
: {}),
});
}
@@ -146,7 +146,7 @@ export class CardsService {
const card = this.cardsRepo.create({
type_code: type.code,
id_placement: dto.id_placement,
id_absence: absenceId,
id_evenement: absenceId,
cree_par: userId,
operation,
statut: statutInitial,
@@ -211,15 +211,15 @@ export class CardsService {
comment: dto.comment?.trim() || undefined,
});
if (card.id_absence) {
if (card.id_evenement) {
if (dto.action === CardResponseActionType.ACCEPT || dto.action === CardResponseActionType.ACK) {
await this.absencesService.maj(userId, role, card.id_absence, {
statut: StatutAbsenceGardeType.ACCEPTE,
await this.evenementsService.maj(userId, role, card.id_evenement, {
statut: StatutEvenementAgendaType.ACCEPTE,
});
card.statut = CardInstanceStatutType.TRAITEE;
} else if (dto.action === CardResponseActionType.REFUSE) {
await this.absencesService.maj(userId, role, card.id_absence, {
statut: StatutAbsenceGardeType.REFUSE,
await this.evenementsService.maj(userId, role, card.id_evenement, {
statut: StatutEvenementAgendaType.REFUSE,
motif: dto.comment!.trim(),
});
card.statut = CardInstanceStatutType.REFUSEE;
@@ -264,12 +264,12 @@ export class CardsService {
throw new BadRequestException('Dates invalides');
}
if (card.id_absence) {
await this.absencesService.maj(userId, role, card.id_absence, {
if (card.id_evenement) {
await this.evenementsService.maj(userId, role, card.id_evenement, {
date_debut: debut,
date_fin: fin,
motif: dto.motif,
statut: StatutAbsenceGardeType.EN_ATTENTE,
statut: StatutEvenementAgendaType.EN_ATTENTE,
});
}
@@ -298,17 +298,17 @@ export class CardsService {
throw new ForbiddenException('Seul le créateur peut supprimer cette carte');
}
const audienceIds = await this.audienceUserIds(card);
if (card.id_absence) {
if (card.id_evenement) {
const absStatut =
card.statut === CardInstanceStatutType.TRAITEE
? null
: card.id_absence;
: card.id_evenement;
// Supprime l’absence liée si pas encore acceptée définitivement
if (
card.statut === CardInstanceStatutType.OUVERTE ||
card.statut === CardInstanceStatutType.REFUSEE
) {
await this.absencesService.supprimer(userId, role, card.id_absence);
await this.evenementsService.supprimer(userId, role, card.id_evenement);
}
void absStatut;
}
@@ -336,13 +336,13 @@ export class CardsService {
return rows.map((r) => r.id_utilisateur);
}
private mapAbsenceType(typeCode: string): TypeAbsenceGardeType {
private mapAbsenceType(typeCode: string): TypeEvenementAgendaType {
if (typeCode === 'absence_enfant' || typeCode === 'absence_enfant_modif') {
return TypeAbsenceGardeType.ABSENCE_ENFANT;
return TypeEvenementAgendaType.ABSENCE_ENFANT;
}
if (typeCode === 'conge_am') return TypeAbsenceGardeType.CONGE_AM;
if (typeCode === 'conge_am') return TypeEvenementAgendaType.CONGE_AM;
if (typeCode === 'arret_maladie_am') {
return TypeAbsenceGardeType.ARRET_MALADIE_AM;
return TypeEvenementAgendaType.ARRET_MALADIE_AM;
}
throw new BadRequestException(`Type non mappé à une absence: ${typeCode}`);
}
@@ -350,7 +350,7 @@ export class CardsService {
private async linkAbsenceCard(absenceId: string, cardId: string): Promise<void> {
// Update direct pour éviter droits maj vides
await this.cardsRepo.manager.query(
`UPDATE absences_garde SET id_card_instance = $1, modifie_le = now() WHERE id = $2`,
`UPDATE evenements_agenda SET id_card_instance = $1, modifie_le = now() WHERE id = $2`,
[cardId, absenceId],
);
}
@@ -471,7 +471,7 @@ export class CardsService {
titre: card.type?.titre ?? card.type_code,
couleur: card.type?.couleur ?? null,
id_placement: card.id_placement,
id_absence: card.id_absence ?? null,
id_evenement: card.id_evenement ?? null,
operation: card.operation,
statut: card.statut,
payload: card.payload ?? {},
+3 -3
View File
@@ -38,11 +38,11 @@ export class CreerCarteDto {
motif?: string;
@ApiPropertyOptional({
description: 'Requis pour operation=update (même id absences_garde)',
description: 'Requis pour operation=update (même id evenements_agenda)',
})
@IsOptional()
@IsUUID()
id_absence?: string;
id_evenement?: string;
@ApiPropertyOptional({ enum: CardOperationType, default: CardOperationType.CREATE })
@IsOptional()
@@ -98,7 +98,7 @@ export class CarteDto {
id_placement: string;
@ApiPropertyOptional()
id_absence?: string | null;
id_evenement?: string | null;
@ApiProperty({ enum: CardOperationType })
operation: CardOperationType;