fix(cards): audience absence_enfant = AM + co-parents du foyer
Le resolver couple_am n’incluait que le créateur et l’AM ; le co-parent ne voyait pas la notification. Docs : V1 réponses + modifs via agenda. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -155,4 +155,75 @@ describe('CardsService (#194)', () => {
|
|||||||
}),
|
}),
|
||||||
).rejects.toBeInstanceOf(ForbiddenException);
|
).rejects.toBeInstanceOf(ForbiddenException);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('parent crée absence_enfant → audience AM + co-parent', async () => {
|
||||||
|
typesRepo.findOne.mockResolvedValue({
|
||||||
|
code: 'absence_enfant',
|
||||||
|
system: true,
|
||||||
|
titre: 'Absence enfant',
|
||||||
|
emitter_roles: [RoleType.PARENT],
|
||||||
|
recipient_roles: [RoleType.ASSISTANTE_MATERNELLE],
|
||||||
|
audience_resolver: 'couple_am',
|
||||||
|
response_mode: CardResponseModeType.NONE,
|
||||||
|
retention_days: 7,
|
||||||
|
});
|
||||||
|
amChildrenRepo.findOne.mockResolvedValue({
|
||||||
|
id: 'pl-1',
|
||||||
|
amId: 'am-1',
|
||||||
|
enfantId: 'e-1',
|
||||||
|
date_fin: null,
|
||||||
|
});
|
||||||
|
parentsChildrenRepo.findOne.mockResolvedValue({
|
||||||
|
parentId: 'p-1',
|
||||||
|
enfantId: 'e-1',
|
||||||
|
});
|
||||||
|
parentsChildrenRepo.find.mockResolvedValue([
|
||||||
|
{ parentId: 'p-1', enfantId: 'e-1' },
|
||||||
|
{ parentId: 'p-2', enfantId: 'e-1' },
|
||||||
|
]);
|
||||||
|
evenementsService.creer.mockResolvedValue({
|
||||||
|
id: 'abs-1',
|
||||||
|
type: TypeEvenementAgendaType.ABSENCE_ENFANT,
|
||||||
|
statut: StatutEvenementAgendaType.ACCEPTE,
|
||||||
|
});
|
||||||
|
cardsRepo.findOne.mockResolvedValue({
|
||||||
|
id: 'card-abs',
|
||||||
|
type_code: 'absence_enfant',
|
||||||
|
id_placement: 'pl-1',
|
||||||
|
id_evenement: 'abs-1',
|
||||||
|
cree_par: 'p-1',
|
||||||
|
operation: CardOperationType.CREATE,
|
||||||
|
statut: CardInstanceStatutType.OUVERTE,
|
||||||
|
payload: { date_debut: '2026-10-28', date_fin: '2026-10-29' },
|
||||||
|
purge_at: new Date(),
|
||||||
|
cree_le: new Date(),
|
||||||
|
modifie_le: new Date(),
|
||||||
|
type: {
|
||||||
|
titre: 'Absence enfant',
|
||||||
|
response_mode: CardResponseModeType.NONE,
|
||||||
|
retention_days: 7,
|
||||||
|
},
|
||||||
|
responses: [],
|
||||||
|
audience: [
|
||||||
|
{ id_utilisateur: 'p-1' },
|
||||||
|
{ id_utilisateur: 'am-1' },
|
||||||
|
{ id_utilisateur: 'p-2' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await service.creer('p-1', RoleType.PARENT, {
|
||||||
|
type_code: 'absence_enfant',
|
||||||
|
id_placement: 'pl-1',
|
||||||
|
date_debut: '2026-10-28',
|
||||||
|
date_fin: '2026-10-29',
|
||||||
|
});
|
||||||
|
|
||||||
|
const saved = audienceRepo.save.mock.calls[0][0] as Array<{
|
||||||
|
id_utilisateur: string;
|
||||||
|
is_creator: boolean;
|
||||||
|
}>;
|
||||||
|
const ids = saved.map((m) => m.id_utilisateur).sort();
|
||||||
|
expect(ids).toEqual(['am-1', 'p-1', 'p-2']);
|
||||||
|
expect(saved.find((m) => m.id_utilisateur === 'p-2')?.is_creator).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -395,12 +395,25 @@ export class CardsService {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (type.audience_resolver === 'couple_am') {
|
if (type.audience_resolver === 'couple_am') {
|
||||||
|
// Destinataire métier = AM + miroir foyer : tous les co-parents de l’enfant
|
||||||
members.push({
|
members.push({
|
||||||
id_card: card.id,
|
id_card: card.id,
|
||||||
id_utilisateur: placement.amId,
|
id_utilisateur: placement.amId,
|
||||||
role_snapshot: RoleType.ASSISTANTE_MATERNELLE,
|
role_snapshot: RoleType.ASSISTANTE_MATERNELLE,
|
||||||
is_creator: false,
|
is_creator: false,
|
||||||
});
|
});
|
||||||
|
const liensAm = await this.parentsChildrenRepo.find({
|
||||||
|
where: { enfantId: placement.enfantId },
|
||||||
|
});
|
||||||
|
for (const l of liensAm) {
|
||||||
|
if (l.parentId === creatorId) continue;
|
||||||
|
members.push({
|
||||||
|
id_card: card.id,
|
||||||
|
id_utilisateur: l.parentId,
|
||||||
|
role_snapshot: RoleType.PARENT,
|
||||||
|
is_creator: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (type.audience_resolver === 'couple_parents') {
|
} else if (type.audience_resolver === 'couple_parents') {
|
||||||
const liens = await this.parentsChildrenRepo.find({
|
const liens = await this.parentsChildrenRepo.find({
|
||||||
where: { enfantId: placement.enfantId },
|
where: { enfantId: placement.enfantId },
|
||||||
|
|||||||
@@ -587,6 +587,12 @@ POST /repos/jmartin/petitspas/pulls/{index}/merge
|
|||||||
|
|
||||||
**Flux V1** : BDD agenda → API liste/CRUD → module Cartes SYSTEM → front bulles (séparé).
|
**Flux V1** : BDD agenda → API liste/CRUD → module Cartes SYSTEM → front bulles (séparé).
|
||||||
|
|
||||||
|
**V1 cartes (réponses)** :
|
||||||
|
- `absence_enfant` → info (`none`) — pas d’ack AM ; audience **AM + tous les parents du foyer** (co-parent inclus)
|
||||||
|
- `arret_maladie_am` → ack parent (« Bien reçu »)
|
||||||
|
- `conge_am` → accept / refuse (+ motivation refus)
|
||||||
|
- **Modifs d’absence** → via **agenda / calendrier**, pas via bulle `absence_enfant_modif` (reporté au ticket calendrier)
|
||||||
|
|
||||||
**Réf. détail** : `docs/32_MINI-SPEC-BULLES-CARTES.md`
|
**Réf. détail** : `docs/32_MINI-SPEC-BULLES-CARTES.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ La teinte pastel est **100 % front** : table de mapping `type_code` → asset (`
|
|||||||
- Libellés UI :
|
- Libellés UI :
|
||||||
- `conge_am` → « Demande de congés »
|
- `conge_am` → « Demande de congés »
|
||||||
- `arret_maladie_am` → « Arrêt maladie »
|
- `arret_maladie_am` → « Arrêt maladie »
|
||||||
- `absence_enfant` (+ `_modif`) → « Notification d’absence »
|
- `absence_enfant` → « Notification d’absence »
|
||||||
|
|
||||||
### 3.2 Carte **congés** (`conge_am`)
|
### 3.2 Carte **congés** (`conge_am`)
|
||||||
|
|
||||||
@@ -93,10 +93,13 @@ Clé = **choix front**, pas une valeur API.
|
|||||||
|------------|---------|--------|
|
|------------|---------|--------|
|
||||||
| **`aqua`** | Congés AM | `conge_am` |
|
| **`aqua`** | Congés AM | `conge_am` |
|
||||||
| **`blue`** | Arrêt maladie AM | `arret_maladie_am` |
|
| **`blue`** | Arrêt maladie AM | `arret_maladie_am` |
|
||||||
| **`peach`** | Absence enfant / info pratique | `absence_enfant`, `absence_enfant_modif` |
|
| **`peach`** | Absence enfant / info pratique | `absence_enfant` |
|
||||||
| **`pink`** | Soins / bobo / problème **enfant** (AM → parents) | `soin_enfant` *(nouveau — voir §5)* |
|
| **`pink`** | Soins / bobo / problème **enfant** (AM → parents) | `soin_enfant` *(nouveau — voir §5)* |
|
||||||
| **`lavender`** | Admin / divers | futurs types admin |
|
| **`lavender`** | Admin / divers | futurs types admin |
|
||||||
|
|
||||||
|
**Hors scope V1 cartes** : `absence_enfant_modif` (ack AM sur modif).
|
||||||
|
Les **modifications d’absence** se font via l’**agenda / calendrier**, pas via une bulle dédiée. On rebranchera une notif éventuelle quand le calendrier sera implémenté.
|
||||||
|
|
||||||
**Principes**
|
**Principes**
|
||||||
|
|
||||||
- Couleur = famille visuelle (lisible sans tout lire).
|
- Couleur = famille visuelle (lisible sans tout lire).
|
||||||
@@ -138,6 +141,7 @@ Pourquoi **pas seulement la messagerie** ?
|
|||||||
| Famille | Couleur UI | Exemples | `response_mode` |
|
| Famille | Couleur UI | Exemples | `response_mode` |
|
||||||
|---------|------------|----------|-----------------|
|
|---------|------------|----------|-----------------|
|
||||||
| Soins (détail) | `pink` | `soin_temperature`, `soin_medicament`, `soin_bobo` — ou sous-types dans payload | `ack` |
|
| Soins (détail) | `pink` | `soin_temperature`, `soin_medicament`, `soin_bobo` — ou sous-types dans payload | `ack` |
|
||||||
|
| Modif absence | `peach` | `absence_enfant_modif` — **via calendrier** d’abord ; bulle ack AM éventuelle ensuite | `ack` |
|
||||||
| Sortie | `peach` / `lavender` | `sortie_a_valider` | `accept_refuse` |
|
| Sortie | `peach` / `lavender` | `sortie_a_valider` | `accept_refuse` |
|
||||||
| Admin | `lavender` | `info_admin`, `document_a_fournir` | `ack` / `none` |
|
| Admin | `lavender` | `info_admin`, `document_a_fournir` | `ack` / `none` |
|
||||||
|
|
||||||
@@ -150,7 +154,9 @@ Variante soins : un seul fond rose ; l’icône / sous-type change.
|
|||||||
- Créateur : pas de boutons réponse ; éventuel « En attente de réponse ».
|
- Créateur : pas de boutons réponse ; éventuel « En attente de réponse ».
|
||||||
- Refus : afficher `last_refuse_comment`.
|
- Refus : afficher `last_refuse_comment`.
|
||||||
- Congé : `accept_refuse` côté destinataire.
|
- Congé : `accept_refuse` côté destinataire.
|
||||||
- Absence enfant : info / ack — pas de veto AM en V1.
|
- Absence enfant : **info seule** (`response_mode: none`) — pas de veto ni ack AM en V1.
|
||||||
|
- Absence enfant : audience = **AM + tous les parents du foyer** (créateur + co-parent), pas seulement le déclarant.
|
||||||
|
- Modif / édition d’absence : **agenda**, pas les cartes (V1).
|
||||||
- File courte : `purge_at` ; l’**agenda** conserve l’historique métier.
|
- File courte : `purge_at` ; l’**agenda** conserve l’historique métier.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -167,11 +173,13 @@ Variante soins : un seul fond rose ; l’icône / sous-type change.
|
|||||||
## 9. Recettes
|
## 9. Recettes
|
||||||
|
|
||||||
- [ ] API cartes **sans** champ `couleur` (ni feed ni `/types`).
|
- [ ] API cartes **sans** champ `couleur` (ni feed ni `/types`).
|
||||||
- [ ] Front mappe `conge_am` → aqua, `arret_maladie_am` → blue, `absence_*` → peach.
|
- [ ] Front mappe `conge_am` → aqua, `arret_maladie_am` → blue, `absence_enfant` → peach.
|
||||||
- [ ] Accept / refuse congé OK.
|
- [ ] Accept / refuse congé OK.
|
||||||
- [ ] Arrêt traité + période en cours → reste visible.
|
- [ ] Arrêt : ack parent « Bien reçu » ; traité + période en cours → reste visible.
|
||||||
|
- [ ] Absence enfant : pas de bouton (info).
|
||||||
- [ ] Filtre couple / placement.
|
- [ ] Filtre couple / placement.
|
||||||
- [ ] (Plus tard) `soin_enfant` rose AM → parents + ligne agenda.
|
- [ ] (Plus tard) `soin_enfant` rose AM → parents + ligne agenda.
|
||||||
|
- [ ] (Plus tard / calendrier) modifs d’absence + éventuel `absence_enfant_modif`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user