Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5a857ae6b |
@@ -5,6 +5,7 @@ import {
|
||||
import { Users } from './users.entity';
|
||||
import { ParentsChildren } from './parents_children.entity';
|
||||
import { Dossier } from './dossiers.entity';
|
||||
import { AmChildren } from './am_children.entity';
|
||||
|
||||
@Entity('parents', { schema: 'public' })
|
||||
export class Parents {
|
||||
@@ -25,6 +26,17 @@ export class Parents {
|
||||
@Column({ name: 'numero_dossier', length: 20, nullable: true })
|
||||
numero_dossier?: string;
|
||||
|
||||
/**
|
||||
* Placement AM↔enfant sélectionné sur le TdB parent (couple actif) — ticket #168.
|
||||
* Null = le front prend le premier couple actif retourné par l’API.
|
||||
*/
|
||||
@Column({ name: 'id_placement_garde_courant', type: 'uuid', nullable: true })
|
||||
id_placement_garde_courant?: string | null;
|
||||
|
||||
@ManyToOne(() => AmChildren, { nullable: true, onDelete: 'SET NULL' })
|
||||
@JoinColumn({ name: 'id_placement_garde_courant', referencedColumnName: 'id' })
|
||||
placement_garde_courant?: AmChildren | null;
|
||||
|
||||
// Lien vers enfants via la table enfants_parents
|
||||
@OneToMany(() => ParentsChildren, pc => pc.parent)
|
||||
parentChildren: ParentsChildren[];
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
/** Identité minimale enfant pour le bandeau couple — ticket #168 */
|
||||
export class CoupleGardeEnfantDto {
|
||||
@ApiProperty({ format: 'uuid' })
|
||||
id: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
prenom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
nom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
photo_url?: string | null;
|
||||
}
|
||||
|
||||
/** Identité minimale AM pour le bandeau couple — ticket #168 */
|
||||
export class CoupleGardeAmDto {
|
||||
@ApiProperty({ format: 'uuid', description: 'UUID utilisateur de l’AM' })
|
||||
id: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
prenom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
nom?: string | null;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
photo_url?: string | null;
|
||||
}
|
||||
|
||||
/** Un couple de garde = placement actif enfant ↔ AM */
|
||||
export class CoupleGardeDto {
|
||||
@ApiProperty({
|
||||
format: 'uuid',
|
||||
description: 'Id du placement (enfants_assistantes_maternelles.id)',
|
||||
})
|
||||
id: string;
|
||||
|
||||
@ApiProperty({ type: CoupleGardeEnfantDto })
|
||||
enfant: CoupleGardeEnfantDto;
|
||||
|
||||
@ApiProperty({ type: CoupleGardeAmDto })
|
||||
am: CoupleGardeAmDto;
|
||||
|
||||
@ApiProperty({ description: 'True si c’est le couple actuellement sélectionné' })
|
||||
courant: boolean;
|
||||
}
|
||||
|
||||
export class CouplesGardeResponseDto {
|
||||
@ApiProperty({ type: [CoupleGardeDto] })
|
||||
couples: CoupleGardeDto[];
|
||||
|
||||
@ApiPropertyOptional({
|
||||
format: 'uuid',
|
||||
nullable: true,
|
||||
description: 'Id du couple courant (null si aucun / premier couple implicite côté client)',
|
||||
})
|
||||
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 — ticket #168 */
|
||||
export class DefinirCoupleGardeCourantDto {
|
||||
@ApiProperty({
|
||||
format: 'uuid',
|
||||
description: 'Id du placement (enfants_assistantes_maternelles.id) à sélectionner',
|
||||
})
|
||||
@IsUUID()
|
||||
@IsNotEmpty()
|
||||
couple_id: string;
|
||||
}
|
||||
@@ -13,7 +13,10 @@ describe('ParentsController', () => {
|
||||
createParentDossierStaff: jest.fn(),
|
||||
addCoParentStaff: jest.fn(),
|
||||
};
|
||||
const parentsServiceMock = {};
|
||||
const parentsServiceMock = {
|
||||
listerCouplesGarde: jest.fn(),
|
||||
definirCoupleGardeCourant: jest.fn(),
|
||||
};
|
||||
const userServiceMock = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -39,6 +42,31 @@ describe('ParentsController', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
|
||||
it('listerCouplesGarde délègue au service (#168)', async () => {
|
||||
parentsServiceMock.listerCouplesGarde.mockResolvedValue({
|
||||
couples: [],
|
||||
couple_courant_id: null,
|
||||
});
|
||||
const res = await controller.listerCouplesGarde('parent-uuid');
|
||||
expect(parentsServiceMock.listerCouplesGarde).toHaveBeenCalledWith('parent-uuid');
|
||||
expect(res.couples).toEqual([]);
|
||||
});
|
||||
|
||||
it('definirCoupleGardeCourant délègue au service (#168)', async () => {
|
||||
parentsServiceMock.definirCoupleGardeCourant.mockResolvedValue({
|
||||
couples: [{ id: 'pl-1', courant: true }],
|
||||
couple_courant_id: 'pl-1',
|
||||
});
|
||||
const res = await controller.definirCoupleGardeCourant('parent-uuid', {
|
||||
couple_id: 'pl-1',
|
||||
});
|
||||
expect(parentsServiceMock.definirCoupleGardeCourant).toHaveBeenCalledWith(
|
||||
'parent-uuid',
|
||||
'pl-1',
|
||||
);
|
||||
expect(res.couple_courant_id).toBe('pl-1');
|
||||
});
|
||||
|
||||
it('createDossier delegates to authService.createParentDossierStaff with CGU accepted', async () => {
|
||||
authServiceMock.createParentDossierStaff.mockResolvedValue({
|
||||
message: 'Dossier famille créé et validé. Un e-mail de création de mot de passe a été envoyé.',
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Put,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { ParentsService } from './parents.service';
|
||||
@@ -39,6 +40,8 @@ import { User } from 'src/common/decorators/user.decorator';
|
||||
import { PendingFamilyDto } from './dto/pending-family.dto';
|
||||
import { DossierFamilleCompletDto } from './dto/dossier-famille-complet.dto';
|
||||
import { mapParentForApi, mapParentsForApi } from './parents.mapper';
|
||||
import { CouplesGardeResponseDto } from './dto/couples-garde.dto';
|
||||
import { DefinirCoupleGardeCourantDto } from './dto/definir-couple-garde-courant.dto';
|
||||
|
||||
@ApiTags('Parents')
|
||||
@ApiBearerAuth('access-token')
|
||||
@@ -51,6 +54,39 @@ export class ParentsController {
|
||||
private readonly authService: AuthService,
|
||||
) {}
|
||||
|
||||
@Get('me/couples-garde')
|
||||
@Roles(RoleType.PARENT)
|
||||
@ApiOperation({
|
||||
summary: 'Lister les couples de garde du parent connecté — ticket #168',
|
||||
description:
|
||||
'Retourne les placements actifs enfant↔AM rattachés au parent, ' +
|
||||
'avec indication du couple courant (bandeau TdB quotidien).',
|
||||
})
|
||||
@ApiResponse({ status: 200, type: CouplesGardeResponseDto })
|
||||
@ApiResponse({ status: 403, description: 'Réservé au rôle parent' })
|
||||
@ApiResponse({ status: 404, description: 'Parent introuvable' })
|
||||
listerCouplesGarde(@User('id') userId: string): Promise<CouplesGardeResponseDto> {
|
||||
return this.parentsService.listerCouplesGarde(userId);
|
||||
}
|
||||
|
||||
@Put('me/couples-garde/courant')
|
||||
@Roles(RoleType.PARENT)
|
||||
@ApiOperation({
|
||||
summary: 'Définir le couple de garde courant — ticket #168',
|
||||
description:
|
||||
'Persiste la préférence de couple actif (enfant|nounou) pour contextualiser le TdB.',
|
||||
})
|
||||
@ApiBody({ type: DefinirCoupleGardeCourantDto })
|
||||
@ApiResponse({ status: 200, type: CouplesGardeResponseDto })
|
||||
@ApiResponse({ status: 400, description: 'Couple hors périmètre du parent' })
|
||||
@ApiResponse({ status: 404, description: 'Parent ou couple introuvable' })
|
||||
definirCoupleGardeCourant(
|
||||
@User('id') userId: string,
|
||||
@Body() dto: DefinirCoupleGardeCourantDto,
|
||||
): Promise<CouplesGardeResponseDto> {
|
||||
return this.parentsService.definirCoupleGardeCourant(userId, dto.couple_id);
|
||||
}
|
||||
|
||||
@Roles(RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR, RoleType.GESTIONNAIRE)
|
||||
@Post('dossier')
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
|
||||
@@ -5,6 +5,7 @@ import { JwtModule } from '@nestjs/jwt';
|
||||
import { Parents } from 'src/entities/parents.entity';
|
||||
import { DossierFamille, DossierFamilleEnfant } from 'src/entities/dossier_famille.entity';
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
import { ParentsController } from './parents.controller';
|
||||
import { ParentsService } from './parents.service';
|
||||
import { Users } from 'src/entities/users.entity';
|
||||
@@ -13,7 +14,14 @@ import { AuthModule } from '../auth/auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Parents, Users, DossierFamille, DossierFamilleEnfant, ParentsChildren]),
|
||||
TypeOrmModule.forFeature([
|
||||
Parents,
|
||||
Users,
|
||||
DossierFamille,
|
||||
DossierFamilleEnfant,
|
||||
ParentsChildren,
|
||||
AmChildren,
|
||||
]),
|
||||
forwardRef(() => UserModule),
|
||||
forwardRef(() => AuthModule),
|
||||
JwtModule.registerAsync({
|
||||
|
||||
@@ -1,12 +1,43 @@
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { ParentsService } from './parents.service';
|
||||
import { Parents } from 'src/entities/parents.entity';
|
||||
import { Users } from 'src/entities/users.entity';
|
||||
import { DossierFamille } from 'src/entities/dossier_famille.entity';
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
|
||||
describe('ParentsService', () => {
|
||||
describe('ParentsService — couples de garde (#168)', () => {
|
||||
let service: ParentsService;
|
||||
|
||||
const parentsRepository = {
|
||||
findOne: jest.fn(),
|
||||
update: jest.fn(),
|
||||
};
|
||||
const parentsChildrenRepository = {
|
||||
find: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
};
|
||||
const amChildrenRepository = {
|
||||
find: jest.fn(),
|
||||
findOne: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ParentsService],
|
||||
providers: [
|
||||
ParentsService,
|
||||
{ provide: getRepositoryToken(Parents), useValue: parentsRepository },
|
||||
{ provide: getRepositoryToken(Users), useValue: {} },
|
||||
{ provide: getRepositoryToken(DossierFamille), useValue: {} },
|
||||
{
|
||||
provide: getRepositoryToken(ParentsChildren),
|
||||
useValue: parentsChildrenRepository,
|
||||
},
|
||||
{ provide: getRepositoryToken(AmChildren), useValue: amChildrenRepository },
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ParentsService>(ParentsService);
|
||||
@@ -15,4 +46,107 @@ describe('ParentsService', () => {
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
describe('listerCouplesGarde', () => {
|
||||
it('retourne une liste vide si le parent n’a pas d’enfant', async () => {
|
||||
parentsRepository.findOne.mockResolvedValue({
|
||||
user_id: 'p1',
|
||||
id_placement_garde_courant: null,
|
||||
});
|
||||
parentsChildrenRepository.find.mockResolvedValue([]);
|
||||
|
||||
const res = await service.listerCouplesGarde('p1');
|
||||
expect(res).toEqual({ couples: [], couple_courant_id: null });
|
||||
expect(amChildrenRepository.find).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('mappe les placements actifs en couples et marque le courant', async () => {
|
||||
parentsRepository.findOne.mockResolvedValue({
|
||||
user_id: 'p1',
|
||||
id_placement_garde_courant: 'pl-2',
|
||||
});
|
||||
parentsChildrenRepository.find.mockResolvedValue([
|
||||
{ enfantId: 'e1' },
|
||||
{ enfantId: 'e2' },
|
||||
]);
|
||||
amChildrenRepository.find.mockResolvedValue([
|
||||
{
|
||||
id: 'pl-1',
|
||||
amId: 'am-1',
|
||||
child: { id: 'e1', first_name: 'Léo', last_name: 'M', photo_url: null },
|
||||
am: { user: { prenom: 'Marie', nom: 'N', photo_url: '/a.jpg' } },
|
||||
},
|
||||
{
|
||||
id: 'pl-2',
|
||||
amId: 'am-2',
|
||||
child: { id: 'e2', first_name: 'Léa', last_name: 'M', photo_url: null },
|
||||
am: { user: { prenom: 'Sophie', nom: 'P', photo_url: null } },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await service.listerCouplesGarde('p1');
|
||||
expect(res.couples).toHaveLength(2);
|
||||
expect(res.couple_courant_id).toBe('pl-2');
|
||||
expect(res.couples[1].courant).toBe(true);
|
||||
expect(res.couples[0].am.prenom).toBe('Marie');
|
||||
expect(res.couples[0].enfant.prenom).toBe('Léo');
|
||||
});
|
||||
|
||||
it('404 si parent inconnu', async () => {
|
||||
parentsRepository.findOne.mockResolvedValue(null);
|
||||
await expect(service.listerCouplesGarde('x')).rejects.toBeInstanceOf(
|
||||
NotFoundException,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('definirCoupleGardeCourant', () => {
|
||||
it('persiste le couple si l’enfant est rattaché au parent', async () => {
|
||||
parentsRepository.findOne.mockResolvedValue({
|
||||
user_id: 'p1',
|
||||
id_placement_garde_courant: null,
|
||||
});
|
||||
amChildrenRepository.findOne.mockResolvedValue({
|
||||
id: 'pl-1',
|
||||
enfantId: 'e1',
|
||||
date_fin: null,
|
||||
});
|
||||
parentsChildrenRepository.findOne.mockResolvedValue({
|
||||
parentId: 'p1',
|
||||
enfantId: 'e1',
|
||||
});
|
||||
parentsRepository.update.mockResolvedValue({ affected: 1 });
|
||||
// second call via listerCouplesGarde
|
||||
parentsChildrenRepository.find.mockResolvedValue([{ enfantId: 'e1' }]);
|
||||
amChildrenRepository.find.mockResolvedValue([
|
||||
{
|
||||
id: 'pl-1',
|
||||
amId: 'am-1',
|
||||
child: { id: 'e1', first_name: 'Léo', last_name: null, photo_url: null },
|
||||
am: { user: { prenom: 'Marie', nom: null, photo_url: null } },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await service.definirCoupleGardeCourant('p1', 'pl-1');
|
||||
expect(parentsRepository.update).toHaveBeenCalledWith(
|
||||
{ user_id: 'p1' },
|
||||
{ id_placement_garde_courant: 'pl-1' },
|
||||
);
|
||||
expect(res.couple_courant_id).toBe('pl-1');
|
||||
expect(res.couples[0].courant).toBe(true);
|
||||
});
|
||||
|
||||
it('400 si le couple n’appartient pas au parent', async () => {
|
||||
parentsRepository.findOne.mockResolvedValue({ user_id: 'p1' });
|
||||
amChildrenRepository.findOne.mockResolvedValue({
|
||||
id: 'pl-1',
|
||||
enfantId: 'e99',
|
||||
});
|
||||
parentsChildrenRepository.findOne.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
service.definirCoupleGardeCourant('p1', 'pl-1'),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { In, IsNull, Repository } from 'typeorm';
|
||||
import { Parents } from 'src/entities/parents.entity';
|
||||
import { DossierFamille } from 'src/entities/dossier_famille.entity';
|
||||
import { RoleType, Users } from 'src/entities/users.entity';
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
import { ParentsChildren } from 'src/entities/parents_children.entity';
|
||||
import { Children } from 'src/entities/children.entity';
|
||||
import { UpdateParentFicheAdminDto } from './dto/update-parent-fiche-admin.dto';
|
||||
import { AmChildren } from 'src/entities/am_children.entity';
|
||||
import { CouplesGardeResponseDto } from './dto/couples-garde.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ParentsService {
|
||||
@@ -32,6 +34,8 @@ export class ParentsService {
|
||||
private readonly dossierFamilleRepository: Repository<DossierFamille>,
|
||||
@InjectRepository(ParentsChildren)
|
||||
private readonly parentsChildrenRepository: Repository<ParentsChildren>,
|
||||
@InjectRepository(AmChildren)
|
||||
private readonly amChildrenRepository: Repository<AmChildren>,
|
||||
) {}
|
||||
|
||||
// Création d’un parent
|
||||
@@ -505,4 +509,108 @@ export class ParentsService {
|
||||
}
|
||||
return raw.map((r: { id: string }) => r.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste les couples de garde (enfant ↔ AM) du parent connecté — ticket #168.
|
||||
* Un couple = un placement actif dans enfants_assistantes_maternelles pour un enfant du parent.
|
||||
*/
|
||||
async listerCouplesGarde(parentUserId: string): Promise<CouplesGardeResponseDto> {
|
||||
const parent = await this.parentsRepository.findOne({
|
||||
where: { user_id: parentUserId },
|
||||
});
|
||||
if (!parent) {
|
||||
throw new NotFoundException('Parent introuvable');
|
||||
}
|
||||
|
||||
const liensEnfants = await this.parentsChildrenRepository.find({
|
||||
where: { parentId: parentUserId },
|
||||
select: ['enfantId'],
|
||||
});
|
||||
const enfantIds = liensEnfants.map((l) => l.enfantId);
|
||||
if (enfantIds.length === 0) {
|
||||
return { couples: [], couple_courant_id: null };
|
||||
}
|
||||
|
||||
const placements = await this.amChildrenRepository.find({
|
||||
where: { enfantId: In(enfantIds), date_fin: IsNull() },
|
||||
relations: ['child', 'am', 'am.user'],
|
||||
order: { date_debut: 'ASC' },
|
||||
});
|
||||
|
||||
let idCourant = parent.id_placement_garde_courant ?? null;
|
||||
const idsValides = new Set(placements.map((p) => p.id));
|
||||
if (idCourant && !idsValides.has(idCourant)) {
|
||||
idCourant = null;
|
||||
await this.parentsRepository.update(
|
||||
{ user_id: parentUserId },
|
||||
{ id_placement_garde_courant: null },
|
||||
);
|
||||
}
|
||||
if (!idCourant && placements.length === 1) {
|
||||
idCourant = placements[0].id;
|
||||
}
|
||||
|
||||
const couples = placements.map((p) => {
|
||||
const amUser = p.am?.user;
|
||||
return {
|
||||
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,
|
||||
},
|
||||
am: {
|
||||
id: p.amId,
|
||||
prenom: amUser?.prenom ?? null,
|
||||
nom: amUser?.nom ?? null,
|
||||
photo_url: amUser?.photo_url ?? null,
|
||||
},
|
||||
courant: idCourant != null && p.id === idCourant,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
couples,
|
||||
couple_courant_id: idCourant,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Persiste le couple de garde actif pour le parent — ticket #168.
|
||||
*/
|
||||
async definirCoupleGardeCourant(
|
||||
parentUserId: string,
|
||||
coupleId: string,
|
||||
): Promise<CouplesGardeResponseDto> {
|
||||
const parent = await this.parentsRepository.findOne({
|
||||
where: { user_id: parentUserId },
|
||||
});
|
||||
if (!parent) {
|
||||
throw new NotFoundException('Parent introuvable');
|
||||
}
|
||||
|
||||
const placement = await this.amChildrenRepository.findOne({
|
||||
where: { id: coupleId, date_fin: IsNull() },
|
||||
});
|
||||
if (!placement) {
|
||||
throw new NotFoundException('Couple de garde introuvable ou inactif');
|
||||
}
|
||||
|
||||
const lien = await this.parentsChildrenRepository.findOne({
|
||||
where: { parentId: parentUserId, enfantId: placement.enfantId },
|
||||
});
|
||||
if (!lien) {
|
||||
throw new BadRequestException(
|
||||
'Ce couple ne concerne pas un enfant rattaché à ce parent',
|
||||
);
|
||||
}
|
||||
|
||||
await this.parentsRepository.update(
|
||||
{ user_id: parentUserId },
|
||||
{ id_placement_garde_courant: coupleId },
|
||||
);
|
||||
|
||||
return this.listerCouplesGarde(parentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -154,7 +154,10 @@ CREATE INDEX idx_assistantes_maternelles_numero_dossier
|
||||
CREATE TABLE parents (
|
||||
id_utilisateur UUID PRIMARY KEY REFERENCES utilisateurs(id) ON DELETE CASCADE,
|
||||
id_co_parent UUID REFERENCES utilisateurs(id),
|
||||
numero_dossier VARCHAR(20)
|
||||
numero_dossier VARCHAR(20),
|
||||
-- Préférence couple de garde actif (TdB quotidien) — ticket #168
|
||||
-- FK ajoutée après création de enfants_assistantes_maternelles (voir ALTER plus bas)
|
||||
id_placement_garde_courant UUID
|
||||
);
|
||||
|
||||
CREATE INDEX idx_parents_numero_dossier
|
||||
@@ -206,6 +209,16 @@ CREATE UNIQUE INDEX uq_enfant_garde_active
|
||||
ON enfants_assistantes_maternelles (id_enfant)
|
||||
WHERE date_fin IS NULL;
|
||||
|
||||
-- FK couple courant parent → placement (#168) — après table enfants_assistantes_maternelles
|
||||
ALTER TABLE parents
|
||||
ADD CONSTRAINT fk_parents_placement_garde_courant
|
||||
FOREIGN KEY (id_placement_garde_courant)
|
||||
REFERENCES enfants_assistantes_maternelles(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX idx_parents_placement_garde_courant
|
||||
ON parents(id_placement_garde_courant)
|
||||
WHERE id_placement_garde_courant IS NOT NULL;
|
||||
|
||||
-- ==========================================================
|
||||
-- Table : dossier_famille (inscription parent — ticket #119)
|
||||
-- ==========================================================
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
-- Ticket #168 — Couple de garde courant (préférence parent)
|
||||
-- Idempotent : safe à rejouer.
|
||||
|
||||
ALTER TABLE parents
|
||||
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_parents_placement_garde_courant
|
||||
ON parents(id_placement_garde_courant)
|
||||
WHERE id_placement_garde_courant IS NOT NULL;
|
||||
Reference in New Issue
Block a user