diff --git a/packages/applications/document-builder/src/candidature/attestation/attestation.saga.ts b/packages/applications/document-builder/src/candidature/attestation/attestation.saga.ts index c8ca3784b1..dde5a8a222 100644 --- a/packages/applications/document-builder/src/candidature/attestation/attestation.saga.ts +++ b/packages/applications/document-builder/src/candidature/attestation/attestation.saga.ts @@ -24,6 +24,7 @@ export const register = () => { notifiéePar, }, } = event; + switch (event.type) { case 'CandidatureNotifiée-V1': const candidature = await mediator.send({ diff --git a/packages/applications/projectors/src/subscribers/candidature/candidature.projector.ts b/packages/applications/projectors/src/subscribers/candidature/candidature.projector.ts index 738c30cffd..ec428d292a 100644 --- a/packages/applications/projectors/src/subscribers/candidature/candidature.projector.ts +++ b/packages/applications/projectors/src/subscribers/candidature/candidature.projector.ts @@ -73,6 +73,10 @@ export const register = () => { estNotifiée: true, notifiéeLe: payload.notifiéeLe, notifiéePar: payload.notifiéePar, + validateur: { + fonction: payload.validateur.fonction, + nomComplet: payload.validateur.nomComplet, + }, }, }, ); diff --git "a/packages/applications/scheduled-tasks/src/candidature/create-events-candidature-notifi\303\251e.ts" "b/packages/applications/scheduled-tasks/src/candidature/create-events-candidature-notifi\303\251e.ts" index 7696b5deb0..c7e3c932ec 100644 --- "a/packages/applications/scheduled-tasks/src/candidature/create-events-candidature-notifi\303\251e.ts" +++ "b/packages/applications/scheduled-tasks/src/candidature/create-events-candidature-notifi\303\251e.ts" @@ -5,11 +5,14 @@ import { Candidature } from '@potentiel-domain/candidature'; import { listProjection } from '@potentiel-infrastructure/pg-projections'; import { Lauréat } from '@potentiel-domain/laureat'; import { loadAggregate } from '@potentiel-infrastructure/pg-event-sourcing'; +import { ConsulterUtilisateurQuery } from '@potentiel-domain/utilisateur'; +import { Option } from '@potentiel-libraries/monads'; Candidature.registerCandidaturesUseCases({ loadAggregate }); (async () => { console.log('✨ Migration Candidature Notifiée'); + const lauréats = await listProjection('lauréat'); const éliminés = await listProjection<Éliminé.ÉliminéEntity>('éliminé'); const all = [...lauréats.items, ...éliminés.items]; @@ -17,6 +20,21 @@ Candidature.registerCandidaturesUseCases({ loadAggregate }); console.log(`ℹ️ ${all.length} éléments trouvés`); for (const { identifiantProjet, attestation, notifiéLe, notifiéPar } of all) { + console.log(`Get détails on notifiéPar for ${identifiantProjet}`); + const utilisateur = await mediator.send({ + type: 'Utilisateur.Query.ConsulterUtilisateur', + data: { + identifiantUtilisateur: notifiéPar, + }, + }); + + if (Option.isNone(utilisateur)) { + console.warn(`Utilisateur non trouvé`, { + identifiantProjet, + identifiantUtilisateur: notifiéPar, + }); + } + console.log(`Publish NotifierCandidature pour ${identifiantProjet}`); await mediator.publish({ type: 'Candidature.UseCase.NotifierCandidature', @@ -25,6 +43,10 @@ Candidature.registerCandidaturesUseCases({ loadAggregate }); attestationValue: { format: attestation.format }, notifiéeLeValue: notifiéLe, notifiéeParValue: notifiéPar, + validateurValue: { + fonction: Option.isNone(utilisateur) ? 'fonction inconnue' : utilisateur.fonction, + nomComplet: Option.isNone(utilisateur) ? 'validateur inconnu' : utilisateur.nomComplet, + }, }, }); } diff --git "a/packages/applications/ssr/src/components/pages/p\303\251riode/notifier/notifierP\303\251riode.action.ts" "b/packages/applications/ssr/src/components/pages/p\303\251riode/notifier/notifierP\303\251riode.action.ts" index b9963e5da8..e152d351ed 100644 --- "a/packages/applications/ssr/src/components/pages/p\303\251riode/notifier/notifierP\303\251riode.action.ts" +++ "b/packages/applications/ssr/src/components/pages/p\303\251riode/notifier/notifierP\303\251riode.action.ts" @@ -2,12 +2,15 @@ import * as zod from 'zod'; import { mediator } from 'mediateur'; +import { notFound } from 'next/navigation'; import { DateTime } from '@potentiel-domain/common'; import { Candidature } from '@potentiel-domain/candidature'; import { Période } from '@potentiel-domain/periode'; import { IdentifiantPériode } from '@potentiel-domain/periode/dist/période'; import { Routes } from '@potentiel-applications/routes'; +import { ConsulterUtilisateurQuery } from '@potentiel-domain/utilisateur'; +import { Option } from '@potentiel-libraries/monads'; import { FormAction, formAction, FormState } from '@/utils/formAction'; import { withUtilisateur } from '@/utils/withUtilisateur'; @@ -30,12 +33,27 @@ const action: FormAction = async (_, { appelOffre, per }, }); + const utilisateurDetails = await mediator.send({ + type: 'Utilisateur.Query.ConsulterUtilisateur', + data: { + identifiantUtilisateur: utilisateur.identifiantUtilisateur.formatter(), + }, + }); + + if (Option.isNone(utilisateurDetails)) { + return notFound(); + } + await mediator.send({ type: 'Période.UseCase.NotifierPériode', data: { identifiantPériodeValue, notifiéeLeValue: DateTime.now().formatter(), notifiéeParValue: utilisateur.identifiantUtilisateur.formatter(), + validateurValue: { + fonction: utilisateurDetails.fonction, + nomComplet: utilisateurDetails.nomComplet, + }, identifiantCandidatureValues: candidatures.items.map((candidatures) => candidatures.identifiantProjet.formatter(), ), diff --git a/packages/domain/candidature/src/candidature.entity.ts b/packages/domain/candidature/src/candidature.entity.ts index 916aa0bc31..cb1171ff15 100644 --- a/packages/domain/candidature/src/candidature.entity.ts +++ b/packages/domain/candidature/src/candidature.entity.ts @@ -42,6 +42,10 @@ export type CandidatureEntity = Entity< estNotifiée: true; notifiéeLe: DateTime.RawType; notifiéePar: Email.RawType; + validateur: { + fonction: string; + nomComplet: string; + }; }; } >; diff --git a/packages/domain/candidature/src/consulter/consulterCandidature.query.ts b/packages/domain/candidature/src/consulter/consulterCandidature.query.ts index 8cb09c11bf..2810ca5230 100644 --- a/packages/domain/candidature/src/consulter/consulterCandidature.query.ts +++ b/packages/domain/candidature/src/consulter/consulterCandidature.query.ts @@ -45,6 +45,10 @@ export type ConsulterCandidatureReadModel = { notification?: { notifiéeLe: DateTime.ValueType; notifiéePar: Email.ValueType; + validateur: { + fonction: string; + nomComplet: string; + }; }; }; @@ -130,5 +134,9 @@ export const mapToReadModel = ({ notification: notification && { notifiéeLe: DateTime.convertirEnValueType(notification.notifiéeLe), notifiéePar: Email.convertirEnValueType(notification.notifiéePar), + validateur: { + fonction: notification.validateur.fonction, + nomComplet: notification.validateur.nomComplet, + }, }, }); diff --git a/packages/domain/candidature/src/notifier/notifierCandidature.behavior.ts b/packages/domain/candidature/src/notifier/notifierCandidature.behavior.ts index e0bb01d761..892d78f35e 100644 --- a/packages/domain/candidature/src/notifier/notifierCandidature.behavior.ts +++ b/packages/domain/candidature/src/notifier/notifierCandidature.behavior.ts @@ -7,6 +7,10 @@ export type NotifierOptions = { identifiantProjet: IdentifiantProjet.ValueType; notifiéeLe: DateTime.ValueType; notifiéePar: Email.ValueType; + validateur: { + fonction: string; + nomComplet: string; + }; attestation: { format: string; }; @@ -18,7 +22,10 @@ export type CandidatureNotifiéeEvent = DomainEvent< identifiantProjet: IdentifiantProjet.RawType; notifiéeLe: DateTime.RawType; notifiéePar: Email.RawType; - + validateur: { + fonction: string; + nomComplet: string; + }; attestation: { format: string; }; @@ -27,17 +34,25 @@ export type CandidatureNotifiéeEvent = DomainEvent< export async function notifier( this: CandidatureAggregate, - { identifiantProjet, notifiéeLe, notifiéePar, attestation: { format } }: NotifierOptions, + { + identifiantProjet, + notifiéeLe, + notifiéePar, + validateur, + attestation: { format }, + }: NotifierOptions, ) { if (this.estNotifiée) { throw new CandidatureDéjàNotifiéeError(identifiantProjet); } + const event: CandidatureNotifiéeEvent = { type: 'CandidatureNotifiée-V1', payload: { identifiantProjet: identifiantProjet.formatter(), notifiéeLe: notifiéeLe.formatter(), notifiéePar: notifiéePar.formatter(), + validateur, attestation: { format, }, diff --git a/packages/domain/candidature/src/notifier/notifierCandidature.command.ts b/packages/domain/candidature/src/notifier/notifierCandidature.command.ts index 5750056b9b..50e3466cf8 100644 --- a/packages/domain/candidature/src/notifier/notifierCandidature.command.ts +++ b/packages/domain/candidature/src/notifier/notifierCandidature.command.ts @@ -11,6 +11,10 @@ export type NotifierCandidatureCommand = Message< identifiantProjet: IdentifiantProjet.ValueType; notifiéeLe: DateTime.ValueType; notifiéePar: Email.ValueType; + validateur: { + fonction: string; + nomComplet: string; + }; attestation: { format: string }; } >; diff --git a/packages/domain/candidature/src/notifier/notifierCandidature.usecase.ts b/packages/domain/candidature/src/notifier/notifierCandidature.usecase.ts index 2d563e6276..db7dce6bfc 100644 --- a/packages/domain/candidature/src/notifier/notifierCandidature.usecase.ts +++ b/packages/domain/candidature/src/notifier/notifierCandidature.usecase.ts @@ -10,6 +10,10 @@ export type NotifierCandidatureUseCase = Message< identifiantProjetValue: string; notifiéeLeValue: string; notifiéeParValue: string; + validateurValue: { + fonction: string; + nomComplet: string; + }; attestationValue: { format: string; }; @@ -21,6 +25,7 @@ export const registerNotifierCandidatureUseCase = () => { identifiantProjetValue, notifiéeParValue, notifiéeLeValue, + validateurValue, attestationValue: { format }, }) => { await mediator.send({ @@ -29,6 +34,7 @@ export const registerNotifierCandidatureUseCase = () => { identifiantProjet: IdentifiantProjet.convertirEnValueType(identifiantProjetValue), notifiéeLe: DateTime.convertirEnValueType(notifiéeLeValue), notifiéePar: Email.convertirEnValueType(notifiéeParValue), + validateur: validateurValue, attestation: { format }, }, }); diff --git "a/packages/domain/laur\303\251at/src/notifier/notifierLaur\303\251at.usecase.ts" "b/packages/domain/laur\303\251at/src/notifier/notifierLaur\303\251at.usecase.ts" index bfd637caa9..43d02c944a 100644 --- "a/packages/domain/laur\303\251at/src/notifier/notifierLaur\303\251at.usecase.ts" +++ "b/packages/domain/laur\303\251at/src/notifier/notifierLaur\303\251at.usecase.ts" @@ -11,6 +11,10 @@ export type NotifierLauréatUseCase = Message< identifiantProjetValue: string; notifiéLeValue: string; notifiéParValue: string; + validateurValue: { + fonction: string; + nomComplet: string; + }; attestationValue: { format: string; }; @@ -22,6 +26,7 @@ export const registerNotifierLauréatUseCase = () => { identifiantProjetValue, notifiéParValue, notifiéLeValue, + validateurValue, attestationValue: { format }, }) => { await mediator.send({ @@ -30,6 +35,7 @@ export const registerNotifierLauréatUseCase = () => { identifiantProjetValue, notifiéeLeValue: notifiéLeValue, notifiéeParValue: notifiéParValue, + validateurValue, attestationValue: { format: 'application/pdf', }, diff --git "a/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.command.ts" "b/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.command.ts" index a070afff87..7e31ccda33 100644 --- "a/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.command.ts" +++ "b/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.command.ts" @@ -16,6 +16,10 @@ export type NotifierPériodeCommand = Message< identifiantPériode: IdentifiantPériode.ValueType; notifiéeLe: DateTime.ValueType; notifiéePar: Email.ValueType; + validateur: { + fonction: string; + nomComplet: string; + }; identifiantCandidatures: ReadonlyArray; } >; @@ -28,6 +32,7 @@ export const registerNotifierPériodeCommand = (loadAggregate: LoadAggregate) => identifiantPériode, notifiéeLe, notifiéePar, + validateur, identifiantCandidatures, }) => { const identifiantLauréats: Array = []; @@ -38,12 +43,14 @@ export const registerNotifierPériodeCommand = (loadAggregate: LoadAggregate) => try { if (candidature.statut?.estClassé()) { + // TODO: devrait être appelé dans le usecase NotifierPériode await mediator.send({ type: 'Lauréat.UseCase.NotifierLauréat', data: { identifiantProjetValue: identifiantCandidature.formatter(), notifiéLeValue: notifiéeLe.formatter(), notifiéParValue: notifiéePar.formatter(), + validateurValue: validateur, attestationValue: { format: 'application/pdf', }, @@ -54,12 +61,14 @@ export const registerNotifierPériodeCommand = (loadAggregate: LoadAggregate) => } if (candidature.statut?.estÉliminé()) { + // TODO: devrait être appelé dans le usecase NotifierPériode await mediator.send<Éliminé.NotifierÉliminéUseCase>({ type: 'Éliminé.UseCase.NotifierÉliminé', data: { identifiantProjetValue: identifiantCandidature.formatter(), notifiéLeValue: notifiéeLe.formatter(), notifiéParValue: notifiéePar.formatter(), + validateurValue: validateur, attestationValue: { format: 'application/pdf', }, diff --git "a/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.usecase.ts" "b/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.usecase.ts" index a3693e4b63..ab3f86eaad 100644 --- "a/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.usecase.ts" +++ "b/packages/domain/p\303\251riode/src/notifier/notifierP\303\251riode.usecase.ts" @@ -12,6 +12,10 @@ export type NotifierPériodeUseCase = Message< identifiantPériodeValue: IdentifiantPériode.RawType; notifiéeLeValue: DateTime.RawType; notifiéeParValue: Email.RawType; + validateurValue: { + fonction: string; + nomComplet: string; + }; identifiantCandidatureValues: ReadonlyArray; } >; @@ -21,6 +25,7 @@ export const registerNotifierPériodeUseCase = () => { identifiantPériodeValue, notifiéeLeValue, notifiéeParValue, + validateurValue, identifiantCandidatureValues, }) => { const identifiantPériode = IdentifiantPériode.convertirEnValueType(identifiantPériodeValue); @@ -31,6 +36,7 @@ export const registerNotifierPériodeUseCase = () => { identifiantPériode, notifiéeLe: DateTime.convertirEnValueType(notifiéeLeValue), notifiéePar: Email.convertirEnValueType(notifiéeParValue), + validateur: validateurValue, identifiantCandidatures: identifiantCandidatureValues.map((identifiantCandidatureValue) => IdentifiantProjet.convertirEnValueType(identifiantCandidatureValue), ), diff --git "a/packages/domain/\303\251limin\303\251/src/notifier/notifier\303\211limin\303\251.usecase.ts" "b/packages/domain/\303\251limin\303\251/src/notifier/notifier\303\211limin\303\251.usecase.ts" index 6bcc1e8d17..2f233af364 100644 --- "a/packages/domain/\303\251limin\303\251/src/notifier/notifier\303\211limin\303\251.usecase.ts" +++ "b/packages/domain/\303\251limin\303\251/src/notifier/notifier\303\211limin\303\251.usecase.ts" @@ -11,6 +11,10 @@ export type NotifierÉliminéUseCase = Message< identifiantProjetValue: string; notifiéLeValue: string; notifiéParValue: string; + validateurValue: { + fonction: string; + nomComplet: string; + }; attestationValue: { format: string; }; @@ -22,6 +26,7 @@ export const registerNotifierÉliminéUseCase = () => { identifiantProjetValue, notifiéLeValue, notifiéParValue, + validateurValue, attestationValue: { format }, }) => { await mediator.send({ @@ -30,6 +35,7 @@ export const registerNotifierÉliminéUseCase = () => { identifiantProjetValue, notifiéeLeValue: notifiéLeValue, notifiéeParValue: notifiéParValue, + validateurValue, attestationValue: { format: 'application/pdf', }, diff --git "a/packages/specifications/src/projet/laur\303\251at/stepDefinitions/laur\303\251at.when.ts" "b/packages/specifications/src/projet/laur\303\251at/stepDefinitions/laur\303\251at.when.ts" deleted file mode 100644 index 01546af44a..0000000000 --- "a/packages/specifications/src/projet/laur\303\251at/stepDefinitions/laur\303\251at.when.ts" +++ /dev/null @@ -1,31 +0,0 @@ -import { mediator } from 'mediateur'; -import { When as Quand } from '@cucumber/cucumber'; - -import { Lauréat } from '@potentiel-domain/laureat'; -import { DateTime } from '@potentiel-domain/common'; - -import { PotentielWorld } from '../../../potentiel.world'; - -Quand( - 'le DGEC validateur notifie la candidature comme lauréate', - async function (this: PotentielWorld) { - const identifiantProjet = this.candidatureWorld.importerCandidature.identifiantProjet; - this.lauréatWorld.notifierLauréatFixture.créer({ - identifiantProjet, - }); - this.utilisateurWorld.porteurFixture.créer({ - email: this.candidatureWorld.importerCandidature.values.emailContactValue, - }); - await mediator.send({ - type: 'Lauréat.UseCase.NotifierLauréat', - data: { - identifiantProjetValue: identifiantProjet, - notifiéLeValue: DateTime.now().formatter(), - notifiéParValue: this.utilisateurWorld.validateurFixture.email, - attestationValue: { - format: `text/plain`, - }, - }, - }); - }, -); diff --git "a/packages/specifications/src/projet/\303\251limin\303\251/stepDefinitions/\303\251limin\303\251.when.ts" "b/packages/specifications/src/projet/\303\251limin\303\251/stepDefinitions/\303\251limin\303\251.when.ts" deleted file mode 100644 index 4b601bf4f9..0000000000 --- "a/packages/specifications/src/projet/\303\251limin\303\251/stepDefinitions/\303\251limin\303\251.when.ts" +++ /dev/null @@ -1,33 +0,0 @@ -import { mediator } from 'mediateur'; -import { When as Quand } from '@cucumber/cucumber'; - -import { Éliminé } from '@potentiel-domain/elimine'; -import { DateTime } from '@potentiel-domain/common'; - -import { PotentielWorld } from '../../../potentiel.world'; - -Quand( - 'le DGEC validateur notifie la candidature comme éliminée', - async function (this: PotentielWorld) { - const identifiantProjet = this.candidatureWorld.importerCandidature.identifiantProjet; - - this.eliminéWorld.notifierEliminéFixture.créer({ - identifiantProjet, - }); - this.utilisateurWorld.porteurFixture.créer({ - email: this.candidatureWorld.importerCandidature.values.emailContactValue, - }); - - await mediator.send<Éliminé.NotifierÉliminéUseCase>({ - type: 'Éliminé.UseCase.NotifierÉliminé', - data: { - identifiantProjetValue: identifiantProjet, - notifiéLeValue: DateTime.now().formatter(), - notifiéParValue: this.utilisateurWorld.validateurFixture.email, - attestationValue: { - format: `application/pdf`, - }, - }, - }); - }, -); diff --git "a/packages/specifications/src/p\303\251riode/stepDefinitions/p\303\251riode.when.ts" "b/packages/specifications/src/p\303\251riode/stepDefinitions/p\303\251riode.when.ts" index 982031ea40..0595afdae5 100644 --- "a/packages/specifications/src/p\303\251riode/stepDefinitions/p\303\251riode.when.ts" +++ "b/packages/specifications/src/p\303\251riode/stepDefinitions/p\303\251riode.when.ts" @@ -31,6 +31,10 @@ export async function notifierPériode(this: PotentielWorld) { this.périodeWorld.notifierPériodeFixture.notifiéeLe, ).formatter(), notifiéeParValue: this.périodeWorld.notifierPériodeFixture.notifiéePar, + validateurValue: { + fonction: this.utilisateurWorld.validateurFixture.fonction, + nomComplet: this.utilisateurWorld.validateurFixture.nom, + }, identifiantCandidatureValues: [...lauréats, ...éliminés], }, }); diff --git a/packages/specifications/src/utilisateur/fixtures/validateur.fixture.ts b/packages/specifications/src/utilisateur/fixtures/validateur.fixture.ts index d98b551406..d4ca1eb445 100644 --- a/packages/specifications/src/utilisateur/fixtures/validateur.fixture.ts +++ b/packages/specifications/src/utilisateur/fixtures/validateur.fixture.ts @@ -2,8 +2,12 @@ import { Fixture } from '../../fixture'; import { Utilisateur, AbstractUtilisateur } from './utilisateur'; +const validateurRole = 'dgec-validateur'; +const validateurFonction = 'fonction du DGEC validateur'; + interface Validateur extends Utilisateur { - readonly role: 'dgec-validateur'; + readonly role: typeof validateurRole; + readonly fonction: typeof validateurFonction; } export class ValidateurFixture @@ -16,15 +20,20 @@ export class ValidateurFixture return this.#aÉtéCréé; } - get role(): 'dgec-validateur' { - return 'dgec-validateur'; + get role(): typeof validateurRole { + return validateurRole; + } + + get fonction(): typeof validateurFonction { + return validateurFonction; } créer(partialFixture?: Partial'>>>): Readonly { const utilisateur = super.créer(partialFixture); const porteur: Validateur = { - role: 'dgec-validateur', + role: validateurRole, + fonction: validateurFonction, ...utilisateur, };