Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4007d7010e | ||
|
|
4261667198 | ||
|
|
15e2d8d850 | ||
|
|
da71803852 |
@@ -1,4 +1,4 @@
|
||||
import { Entity, PrimaryColumn, Column, OneToOne, OneToMany, JoinColumn } from 'typeorm';
|
||||
import { Entity, PrimaryColumn, Column, OneToOne, OneToMany, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Users } from './users.entity';
|
||||
import { AmChildren } from './am_children.entity';
|
||||
|
||||
@@ -37,22 +37,32 @@ export class AssistanteMaternelle {
|
||||
@Column({ name: 'ville_residence', length: 100, nullable: true })
|
||||
residence_city?: string;
|
||||
|
||||
@Column( { name: 'date_agrement', type: 'date', nullable: true })
|
||||
@Column({ name: 'date_agrement', type: 'date', nullable: true })
|
||||
agreement_date?: Date;
|
||||
|
||||
@Column( { name: 'annee_experience', type: 'smallint', nullable: true })
|
||||
@Column({ name: 'annee_experience', type: 'smallint', nullable: true })
|
||||
years_experience?: number;
|
||||
|
||||
@Column( { name: 'specialite', length: 100, nullable: true })
|
||||
|
||||
@Column({ name: 'specialite', length: 100, nullable: true })
|
||||
specialty?: string;
|
||||
|
||||
@Column( { name: 'place_disponible', type: 'integer', nullable: true })
|
||||
@Column({ name: 'place_disponible', type: 'integer', nullable: true })
|
||||
places_available?: number;
|
||||
|
||||
/** Numéro de dossier (format AAAA-NNNNNN), même valeur que sur utilisateurs (ticket #103) */
|
||||
@Column({ name: 'numero_dossier', length: 20, nullable: true })
|
||||
numero_dossier?: string;
|
||||
|
||||
/**
|
||||
* Placement AM↔enfant sélectionné sur le TdB AM (couple actif) — ticket #171.
|
||||
*/
|
||||
@Column({ name: 'id_placement_garde_courant', type: 'uuid', nullable: true })
|
||||
id_placement_garde_courant?: string;
|
||||
|
||||
@ManyToOne(() => AmChildren, { nullable: true, onDelete: 'SET NULL' })
|
||||
@JoinColumn({ name: 'id_placement_garde_courant', referencedColumnName: 'id' })
|
||||
placement_garde_courant?: AmChildren;
|
||||
|
||||
@OneToMany(() => AmChildren, (ac) => ac.am)
|
||||
amChildren: AmChildren[];
|
||||
}
|
||||
|
||||
+29
-1
@@ -10,7 +10,10 @@ describe('AssistantesMaternellesController', () => {
|
||||
const authServiceMock = {
|
||||
createAmDossierStaff: jest.fn(),
|
||||
};
|
||||
const amServiceMock = {};
|
||||
const amServiceMock = {
|
||||
listerCouplesGarde: jest.fn(),
|
||||
definirCoupleGardeCourant: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
@@ -66,4 +69,29 @@ describe('AssistantesMaternellesController', () => {
|
||||
);
|
||||
expect(res.numero_dossier).toBe('2026-000001');
|
||||
});
|
||||
|
||||
it('listerCouplesGarde délègue au service (#171)', async () => {
|
||||
amServiceMock.listerCouplesGarde.mockResolvedValue({
|
||||
couples: [],
|
||||
couple_courant_id: null,
|
||||
});
|
||||
const res = await controller.listerCouplesGarde('am-uuid');
|
||||
expect(amServiceMock.listerCouplesGarde).toHaveBeenCalledWith('am-uuid');
|
||||
expect(res.couple_courant_id).toBeNull();
|
||||
});
|
||||
|
||||
it('definirCoupleGardeCourant délègue au service (#171)', async () => {
|
||||
amServiceMock.definirCoupleGardeCourant.mockResolvedValue({
|
||||
couples: [{ id: 'pl-1', courant: true }],
|
||||
couple_courant_id: 'pl-1',
|
||||
});
|
||||
const res = await controller.definirCoupleGardeCourant('am-uuid', {
|
||||
couple_id: 'pl-1',
|
||||
});
|
||||
expect(amServiceMock.definirCoupleGardeCourant).toHaveBeenCalledWith(
|
||||
'am-uuid',
|
||||
'pl-1',
|
||||
);
|
||||
expect(res.couple_courant_id).toBe('pl-1');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
@@ -20,6 +21,8 @@ import { UpdateAssistanteDto } from '../user/dto/update_assistante.dto';
|
||||
import { UpdateAmFicheAdminDto } from './dto/update-am-fiche-admin.dto';
|
||||
import { StaffCreateAmDossierDto } from './dto/staff-create-am-dossier.dto';
|
||||
import { StaffCreateAmDossierResponseDto } from './dto/staff-create-am-dossier-response.dto';
|
||||
import { CouplesGardeAmResponseDto } from './dto/couples-garde-am.dto';
|
||||
import { DefinirCoupleGardeCourantAmDto } from './dto/definir-couple-garde-courant-am.dto';
|
||||
import { RolesGuard } from 'src/common/guards/roles.guard';
|
||||
import { AuthGuard } from 'src/common/guards/auth.guard';
|
||||
import { User } from 'src/common/decorators/user.decorator';
|
||||
@@ -83,6 +86,36 @@ export class AssistantesMaternellesController {
|
||||
return mapAmsForApi(ams);
|
||||
}
|
||||
|
||||
@Get('me/couples-garde')
|
||||
@Roles(RoleType.ASSISTANTE_MATERNELLE)
|
||||
@ApiOperation({
|
||||
summary: 'Couples de garde de l’AM connectée — ticket #171',
|
||||
description:
|
||||
'Placements actifs (enfant + parents) pour peupler le bandeau couple TdB AM, ' +
|
||||
'avec indication du couple courant.',
|
||||
})
|
||||
@ApiResponse({ status: 200, type: CouplesGardeAmResponseDto })
|
||||
listerCouplesGarde(
|
||||
@User('id') userId: string,
|
||||
): Promise<CouplesGardeAmResponseDto> {
|
||||
return this.assistantesMaternellesService.listerCouplesGarde(userId);
|
||||
}
|
||||
|
||||
@Put('me/couples-garde/courant')
|
||||
@Roles(RoleType.ASSISTANTE_MATERNELLE)
|
||||
@ApiOperation({ summary: 'Définir le couple de garde courant (AM) — ticket #171' })
|
||||
@ApiBody({ type: DefinirCoupleGardeCourantAmDto })
|
||||
@ApiResponse({ status: 200, type: CouplesGardeAmResponseDto })
|
||||
definirCoupleGardeCourant(
|
||||
@User('id') userId: string,
|
||||
@Body() dto: DefinirCoupleGardeCourantAmDto,
|
||||
): Promise<CouplesGardeAmResponseDto> {
|
||||
return this.assistantesMaternellesService.definirCoupleGardeCourant(
|
||||
userId,
|
||||
dto.couple_id,
|
||||
);
|
||||
}
|
||||
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.GESTIONNAIRE, RoleType.ADMINISTRATEUR)
|
||||
@Get(':id')
|
||||
@ApiParam({ name: 'id', description: "UUID de la nounou" })
|
||||
|
||||
@@ -4,13 +4,21 @@ import { AssistantesMaternellesController } from './assistantes_maternelles.cont
|
||||
import { AssistanteMaternelle } from 'src/entities/assistantes_maternelles.entity';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
import { Children } from 'src/entities/children.entity';
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Users } from 'src/entities/users.entity';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([AssistanteMaternelle, AmChildren, Children, Users]),
|
||||
AuthModule
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
AssistanteMaternelle,
|
||||
AmChildren,
|
||||
Children,
|
||||
Users,
|
||||
ParentsChildren,
|
||||
]),
|
||||
AuthModule,
|
||||
],
|
||||
controllers: [AssistantesMaternellesController],
|
||||
providers: [AssistantesMaternellesService],
|
||||
@@ -19,4 +27,4 @@ import { AuthModule } from '../auth/auth.module';
|
||||
TypeOrmModule,
|
||||
],
|
||||
})
|
||||
export class AssistantesMaternellesModule { }
|
||||
export class AssistantesMaternellesModule {}
|
||||
|
||||
+138
-6
@@ -1,18 +1,150 @@
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { AssistantesMaternellesService } from './assistantes_maternelles.service';
|
||||
import { AssistanteMaternelle } from 'src/entities/assistantes_maternelles.entity';
|
||||
import { Users } from 'src/entities/users.entity';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
import { Children } from 'src/entities/children.entity';
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
|
||||
describe('AssistantesMaternellesService', () => {
|
||||
describe('AssistantesMaternellesService — couples de garde (#171)', () => {
|
||||
let service: AssistantesMaternellesService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AssistantesMaternellesService],
|
||||
}).compile();
|
||||
const amRepo = { findOne: jest.fn(), update: jest.fn() };
|
||||
const usersRepo = {};
|
||||
const amChildrenRepo = { find: jest.fn(), findOne: jest.fn() };
|
||||
const childrenRepo = {};
|
||||
const parentsChildrenRepo = { find: jest.fn() };
|
||||
|
||||
service = module.get<AssistantesMaternellesService>(AssistantesMaternellesService);
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
AssistantesMaternellesService,
|
||||
{ provide: getRepositoryToken(AssistanteMaternelle), useValue: amRepo },
|
||||
{ provide: getRepositoryToken(Users), useValue: usersRepo },
|
||||
{ provide: getRepositoryToken(AmChildren), useValue: amChildrenRepo },
|
||||
{ provide: getRepositoryToken(Children), useValue: childrenRepo },
|
||||
{
|
||||
provide: getRepositoryToken(ParentsChildren),
|
||||
useValue: parentsChildrenRepo,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
service = module.get(AssistantesMaternellesService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
describe('listerCouplesGarde', () => {
|
||||
it('retourne vide si aucun placement', async () => {
|
||||
amRepo.findOne.mockResolvedValue({
|
||||
user_id: 'am-1',
|
||||
id_placement_garde_courant: null,
|
||||
});
|
||||
amChildrenRepo.find.mockResolvedValue([]);
|
||||
const res = await service.listerCouplesGarde('am-1');
|
||||
expect(res).toEqual({ couples: [], couple_courant_id: null });
|
||||
expect(parentsChildrenRepo.find).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('mappe placements + parents et marque le courant', async () => {
|
||||
amRepo.findOne.mockResolvedValue({
|
||||
user_id: 'am-1',
|
||||
id_placement_garde_courant: 'pl-2',
|
||||
});
|
||||
amChildrenRepo.find.mockResolvedValue([
|
||||
{
|
||||
id: 'pl-1',
|
||||
enfantId: 'e1',
|
||||
child: { id: 'e1', first_name: 'Léa', last_name: 'M', photo_url: null },
|
||||
},
|
||||
{
|
||||
id: 'pl-2',
|
||||
enfantId: 'e2',
|
||||
child: { id: 'e2', first_name: 'Emma', last_name: 'M', photo_url: null },
|
||||
},
|
||||
]);
|
||||
parentsChildrenRepo.find.mockResolvedValue([
|
||||
{
|
||||
parentId: 'p1',
|
||||
enfantId: 'e1',
|
||||
parent: { user: { prenom: 'Claire', nom: 'Martin', photo_url: null } },
|
||||
},
|
||||
{
|
||||
parentId: 'p2',
|
||||
enfantId: 'e1',
|
||||
parent: { user: { prenom: 'Thomas', nom: 'Martin', photo_url: null } },
|
||||
},
|
||||
{
|
||||
parentId: 'p1',
|
||||
enfantId: 'e2',
|
||||
parent: { user: { prenom: 'Claire', nom: 'Martin', photo_url: null } },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await service.listerCouplesGarde('am-1');
|
||||
expect(res.couples).toHaveLength(2);
|
||||
expect(res.couple_courant_id).toBe('pl-2');
|
||||
expect(res.couples[1].courant).toBe(true);
|
||||
expect(res.couples[0].parents).toHaveLength(2);
|
||||
expect(res.couples[0].parents[0].prenom).toBe('Claire');
|
||||
expect(res.couples[0].enfant.prenom).toBe('Léa');
|
||||
});
|
||||
|
||||
it('404 si AM inconnue', async () => {
|
||||
amRepo.findOne.mockResolvedValue(null);
|
||||
await expect(service.listerCouplesGarde('x')).rejects.toBeInstanceOf(
|
||||
NotFoundException,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('definirCoupleGardeCourant', () => {
|
||||
it('persiste si le placement appartient à l’AM', async () => {
|
||||
amRepo.findOne.mockResolvedValue({
|
||||
user_id: 'am-1',
|
||||
id_placement_garde_courant: null,
|
||||
});
|
||||
amChildrenRepo.findOne.mockResolvedValue({
|
||||
id: 'pl-1',
|
||||
amId: 'am-1',
|
||||
enfantId: 'e1',
|
||||
});
|
||||
amRepo.update.mockResolvedValue({ affected: 1 });
|
||||
amChildrenRepo.find.mockResolvedValue([
|
||||
{
|
||||
id: 'pl-1',
|
||||
enfantId: 'e1',
|
||||
child: { id: 'e1', first_name: 'Léa', last_name: null, photo_url: null },
|
||||
},
|
||||
]);
|
||||
parentsChildrenRepo.find.mockResolvedValue([
|
||||
{
|
||||
parentId: 'p1',
|
||||
enfantId: 'e1',
|
||||
parent: { user: { prenom: 'Claire', nom: 'M', photo_url: null } },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await service.definirCoupleGardeCourant('am-1', 'pl-1');
|
||||
expect(amRepo.update).toHaveBeenCalledWith(
|
||||
{ user_id: 'am-1' },
|
||||
{ id_placement_garde_courant: 'pl-1' },
|
||||
);
|
||||
expect(res.couple_courant_id).toBe('pl-1');
|
||||
expect(res.couples[0].courant).toBe(true);
|
||||
});
|
||||
|
||||
it('404 si placement d’une autre AM', async () => {
|
||||
amRepo.findOne.mockResolvedValue({ user_id: 'am-1' });
|
||||
amChildrenRepo.findOne.mockResolvedValue(null);
|
||||
await expect(
|
||||
service.definirCoupleGardeCourant('am-1', 'pl-x'),
|
||||
).rejects.toBeInstanceOf(NotFoundException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,14 +5,16 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
import { In, IsNull, Repository } from 'typeorm';
|
||||
import { RoleType, Users } from 'src/entities/users.entity';
|
||||
import { AssistanteMaternelle } from 'src/entities/assistantes_maternelles.entity';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
import { Children, StatutEnfantType } from 'src/entities/children.entity';
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
import { CreateAssistanteDto } from '../user/dto/create_assistante.dto';
|
||||
import { UpdateAssistanteDto } from '../user/dto/update_assistante.dto';
|
||||
import { UpdateAmFicheAdminDto } from './dto/update-am-fiche-admin.dto';
|
||||
import { CouplesGardeAmResponseDto } from './dto/couples-garde-am.dto';
|
||||
import { validateNir } from 'src/common/utils/nir.util';
|
||||
|
||||
const AM_CHILDREN_RELATIONS = ['user', 'amChildren', 'amChildren.child'] as const;
|
||||
@@ -28,6 +30,8 @@ export class AssistantesMaternellesService {
|
||||
private readonly amChildrenRepository: Repository<AmChildren>,
|
||||
@InjectRepository(Children)
|
||||
private readonly childrenRepository: Repository<Children>,
|
||||
@InjectRepository(ParentsChildren)
|
||||
private readonly parentsChildrenRepository: Repository<ParentsChildren>,
|
||||
) {}
|
||||
|
||||
async create(dto: CreateAssistanteDto): Promise<AssistanteMaternelle> {
|
||||
@@ -264,4 +268,107 @@ export class AssistantesMaternellesService {
|
||||
await this.assistantesMaternelleRepository.delete(id);
|
||||
return { message: 'Assistante maternelle supprimée' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste les couples de garde (enfant ↔ parents) de l’AM connectée — ticket #171.
|
||||
* Un couple = un placement actif dans enfants_assistantes_maternelles pour cette AM.
|
||||
*/
|
||||
async listerCouplesGarde(amUserId: string): Promise<CouplesGardeAmResponseDto> {
|
||||
const am = await this.assistantesMaternelleRepository.findOne({
|
||||
where: { user_id: amUserId },
|
||||
});
|
||||
if (!am) {
|
||||
throw new NotFoundException('Assistante maternelle introuvable');
|
||||
}
|
||||
|
||||
const placements = await this.amChildrenRepository.find({
|
||||
where: { amId: amUserId, date_fin: IsNull() },
|
||||
relations: ['child'],
|
||||
order: { date_debut: 'ASC' },
|
||||
});
|
||||
|
||||
if (placements.length === 0) {
|
||||
return { couples: [], couple_courant_id: null };
|
||||
}
|
||||
|
||||
const enfantIds = placements.map((p) => p.enfantId);
|
||||
const liens = await this.parentsChildrenRepository.find({
|
||||
where: { enfantId: In(enfantIds) },
|
||||
relations: ['parent', 'parent.user'],
|
||||
});
|
||||
const parentsByEnfant = new Map<
|
||||
string,
|
||||
{ id: string; prenom: string | null; nom: string | null; photo_url: string | null }[]
|
||||
>();
|
||||
for (const l of liens) {
|
||||
const list = parentsByEnfant.get(l.enfantId) ?? [];
|
||||
const u = l.parent?.user;
|
||||
list.push({
|
||||
id: l.parentId,
|
||||
prenom: u?.prenom ?? null,
|
||||
nom: u?.nom ?? null,
|
||||
photo_url: u?.photo_url ?? null,
|
||||
});
|
||||
parentsByEnfant.set(l.enfantId, list);
|
||||
}
|
||||
|
||||
let idCourant = am.id_placement_garde_courant ?? null;
|
||||
const idsValides = new Set(placements.map((p) => p.id));
|
||||
if (idCourant && !idsValides.has(idCourant)) {
|
||||
idCourant = null;
|
||||
await this.assistantesMaternelleRepository.update(
|
||||
{ user_id: amUserId },
|
||||
{ id_placement_garde_courant: () => 'NULL' },
|
||||
);
|
||||
}
|
||||
if (!idCourant && placements.length === 1) {
|
||||
idCourant = placements[0].id;
|
||||
}
|
||||
|
||||
const couples = placements.map((p) => ({
|
||||
id: p.id,
|
||||
enfant: {
|
||||
id: p.child.id,
|
||||
prenom: p.child.first_name ?? null,
|
||||
nom: p.child.last_name ?? null,
|
||||
photo_url: p.child.photo_url ?? null,
|
||||
},
|
||||
parents: parentsByEnfant.get(p.enfantId) ?? [],
|
||||
courant: idCourant != null && p.id === idCourant,
|
||||
}));
|
||||
|
||||
return {
|
||||
couples,
|
||||
couple_courant_id: idCourant,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Persiste le couple de garde actif pour l’AM — ticket #171.
|
||||
*/
|
||||
async definirCoupleGardeCourant(
|
||||
amUserId: string,
|
||||
coupleId: string,
|
||||
): Promise<CouplesGardeAmResponseDto> {
|
||||
const am = await this.assistantesMaternelleRepository.findOne({
|
||||
where: { user_id: amUserId },
|
||||
});
|
||||
if (!am) {
|
||||
throw new NotFoundException('Assistante maternelle introuvable');
|
||||
}
|
||||
|
||||
const placement = await this.amChildrenRepository.findOne({
|
||||
where: { id: coupleId, amId: amUserId, date_fin: IsNull() },
|
||||
});
|
||||
if (!placement) {
|
||||
throw new NotFoundException('Couple de garde introuvable ou inactif pour cette AM');
|
||||
}
|
||||
|
||||
await this.assistantesMaternelleRepository.update(
|
||||
{ user_id: amUserId },
|
||||
{ id_placement_garde_courant: coupleId },
|
||||
);
|
||||
|
||||
return this.listerCouplesGarde(amUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
/** Identité minimale enfant — ticket #171 (miroir #168) */
|
||||
export class CoupleGardeAmEnfantDto {
|
||||
@ApiProperty({ format: 'uuid' })
|
||||
id: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
prenom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
nom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
photo_url?: string | null;
|
||||
}
|
||||
|
||||
/** Identité minimale parent pour bandeau AM — ticket #171 */
|
||||
export class CoupleGardeAmParentDto {
|
||||
@ApiProperty({ format: 'uuid', description: 'UUID utilisateur du parent' })
|
||||
id: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
prenom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
nom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
photo_url?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Un couple côté AM = placement actif enfant ↔ foyer parents.
|
||||
* `id` = enfants_assistantes_maternelles.id (même clé que #168).
|
||||
*/
|
||||
export class CoupleGardeAmDto {
|
||||
@ApiProperty({
|
||||
format: 'uuid',
|
||||
description: 'Id du placement (enfants_assistantes_maternelles.id)',
|
||||
})
|
||||
id: string;
|
||||
|
||||
@ApiProperty({ type: CoupleGardeAmEnfantDto })
|
||||
enfant: CoupleGardeAmEnfantDto;
|
||||
|
||||
@ApiProperty({
|
||||
type: [CoupleGardeAmParentDto],
|
||||
description: 'Parents rattachés à l’enfant (0–2 typiquement)',
|
||||
})
|
||||
parents: CoupleGardeAmParentDto[];
|
||||
|
||||
@ApiProperty({ description: 'True si c’est le couple actuellement sélectionné' })
|
||||
courant: boolean;
|
||||
}
|
||||
|
||||
export class CouplesGardeAmResponseDto {
|
||||
@ApiProperty({ type: [CoupleGardeAmDto] })
|
||||
couples: CoupleGardeAmDto[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
format: 'uuid',
|
||||
nullable: true,
|
||||
description: 'Id du couple courant (null si aucun)',
|
||||
})
|
||||
couple_courant_id: string | null;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsUUID } from 'class-validator';
|
||||
|
||||
/** Corps PUT couple de garde courant AM — ticket #171 */
|
||||
export class DefinirCoupleGardeCourantAmDto {
|
||||
@ApiProperty({
|
||||
format: 'uuid',
|
||||
description: 'Id du placement (enfants_assistantes_maternelles.id) à sélectionner',
|
||||
})
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
couple_id: string;
|
||||
}
|
||||
+14
-1
@@ -143,7 +143,10 @@ CREATE TABLE assistantes_maternelles (
|
||||
annee_experience SMALLINT,
|
||||
specialite VARCHAR(100),
|
||||
place_disponible INT,
|
||||
numero_dossier VARCHAR(20)
|
||||
numero_dossier VARCHAR(20),
|
||||
-- Préférence couple de garde actif (TdB quotidien AM) — ticket #171
|
||||
-- FK ajoutée après création de enfants_assistantes_maternelles (voir ALTER plus bas)
|
||||
id_placement_garde_courant UUID
|
||||
);
|
||||
|
||||
CREATE INDEX idx_assistantes_maternelles_numero_dossier
|
||||
@@ -221,6 +224,16 @@ CREATE INDEX idx_parents_placement_garde_courant
|
||||
ON parents(id_placement_garde_courant)
|
||||
WHERE id_placement_garde_courant IS NOT NULL;
|
||||
|
||||
-- FK couple courant AM → placement (#171)
|
||||
ALTER TABLE assistantes_maternelles
|
||||
ADD CONSTRAINT fk_am_placement_garde_courant
|
||||
FOREIGN KEY (id_placement_garde_courant)
|
||||
REFERENCES enfants_assistantes_maternelles(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX idx_am_placement_garde_courant
|
||||
ON assistantes_maternelles(id_placement_garde_courant)
|
||||
WHERE id_placement_garde_courant IS NOT NULL;
|
||||
|
||||
-- ==========================================================
|
||||
-- Table : dossier_famille (inscription parent — ticket #119)
|
||||
-- ==========================================================
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
-- Ticket #171 — Couple de garde courant (préférence AM)
|
||||
-- Idempotent : safe à rejouer.
|
||||
|
||||
ALTER TABLE assistantes_maternelles
|
||||
ADD COLUMN IF NOT EXISTS id_placement_garde_courant UUID
|
||||
REFERENCES enfants_assistantes_maternelles(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_am_placement_garde_courant
|
||||
ON assistantes_maternelles(id_placement_garde_courant)
|
||||
WHERE id_placement_garde_courant IS NOT NULL;
|
||||
Reference in New Issue
Block a user