feat(#110): refus dossier propagé aux co-parents + mail aligné
- `refuseUser` charge tous les parents du même numéro de dossier, leur applique le même token_reprise (7 jours), trace une validation refus par compte et envoie un mail de refus à chacun. Le refus devient une action dossier : peu importe quel parent ouvre ensuite le lien. - Échec d'envoi mail loggé sans bloquer les autres destinataires. - Mail de refus aligné sur le look des autres templates (titre/bouton verts, bloc motif gestionnaire en encart, échappement HTML cohérent, appUrl normalisée). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -332,7 +332,7 @@ export class UserService {
|
||||
return savedUser;
|
||||
}
|
||||
|
||||
/** Refuser un compte (en_attente -> refuse) ; tracé validations, token reprise, email. Ticket #110 */
|
||||
/** Refuser un dossier (en_attente -> refuse) ; tracé validations, token reprise partagé, emails. Ticket #110 */
|
||||
async refuseUser(user_id: string, currentUser: Users, comment?: string): Promise<Users> {
|
||||
if (![RoleType.SUPER_ADMIN, RoleType.ADMINISTRATEUR, RoleType.GESTIONNAIRE].includes(currentUser.role)) {
|
||||
throw new ForbiddenException('Accès réservé aux super admins, administrateurs et gestionnaires');
|
||||
@@ -340,40 +340,71 @@ export class UserService {
|
||||
const user = await this.usersRepository.findOne({ where: { id: user_id } });
|
||||
if (!user) throw new NotFoundException('Utilisateur introuvable');
|
||||
if (user.statut !== StatutUtilisateurType.EN_ATTENTE) {
|
||||
throw new BadRequestException('Seul un compte en attente peut être refusé.');
|
||||
throw new BadRequestException('Seul un dossier en attente peut être refusé.');
|
||||
}
|
||||
|
||||
const tokenReprise = crypto.randomUUID();
|
||||
const expireLe = new Date();
|
||||
expireLe.setDate(expireLe.getDate() + 7);
|
||||
|
||||
user.statut = StatutUtilisateurType.REFUSE;
|
||||
user.token_reprise = tokenReprise;
|
||||
user.token_reprise_expire_le = expireLe;
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
const usersDossier = user.role === RoleType.PARENT && user.numero_dossier
|
||||
? await this.usersRepository.find({
|
||||
where: {
|
||||
role: RoleType.PARENT,
|
||||
numero_dossier: user.numero_dossier,
|
||||
},
|
||||
})
|
||||
: [user];
|
||||
|
||||
const validation = this.validationRepository.create({
|
||||
user: savedUser,
|
||||
type: 'refus_compte',
|
||||
status: StatutValidationType.REFUSE,
|
||||
validated_by: currentUser,
|
||||
comment,
|
||||
});
|
||||
await this.validationRepository.save(validation);
|
||||
|
||||
try {
|
||||
await this.mailService.sendRefusEmail(
|
||||
savedUser.email,
|
||||
savedUser.prenom ?? '',
|
||||
savedUser.nom ?? '',
|
||||
comment,
|
||||
tokenReprise,
|
||||
const usersARefuser = usersDossier.length ? usersDossier : [user];
|
||||
const utilisateurInvalide = usersARefuser.find(
|
||||
(u) => u.statut !== StatutUtilisateurType.EN_ATTENTE,
|
||||
);
|
||||
if (utilisateurInvalide) {
|
||||
throw new BadRequestException(
|
||||
'Tous les comptes du dossier doivent être en attente pour refuser le dossier.',
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.warn(`Envoi email refus échoué pour ${savedUser.email}`, err);
|
||||
}
|
||||
|
||||
return savedUser;
|
||||
const savedUsers = await this.usersRepository.manager.transaction(async (manager) => {
|
||||
const updatedUsers: Users[] = [];
|
||||
|
||||
for (const userARefuser of usersARefuser) {
|
||||
userARefuser.statut = StatutUtilisateurType.REFUSE;
|
||||
userARefuser.token_reprise = tokenReprise;
|
||||
userARefuser.token_reprise_expire_le = expireLe;
|
||||
|
||||
const savedUser = await manager.save(Users, userARefuser);
|
||||
updatedUsers.push(savedUser);
|
||||
|
||||
const validation = manager.create(Validation, {
|
||||
user: savedUser,
|
||||
type: 'refus_compte',
|
||||
status: StatutValidationType.REFUSE,
|
||||
validated_by: currentUser,
|
||||
comment,
|
||||
});
|
||||
await manager.save(Validation, validation);
|
||||
}
|
||||
|
||||
return updatedUsers;
|
||||
});
|
||||
|
||||
for (const savedUser of savedUsers) {
|
||||
try {
|
||||
await this.mailService.sendRefusEmail(
|
||||
savedUser.email,
|
||||
savedUser.prenom ?? '',
|
||||
savedUser.nom ?? '',
|
||||
comment,
|
||||
tokenReprise,
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.warn(`Envoi email refus échoué pour ${savedUser.email}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
return savedUsers.find((savedUser) => savedUser.id === user.id) ?? savedUsers[0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user