diff --git a/server/src/common/actions/effectifs.actions.ts b/server/src/common/actions/effectifs.actions.ts index 40e29df11..2863f8bef 100644 --- a/server/src/common/actions/effectifs.actions.ts +++ b/server/src/common/actions/effectifs.actions.ts @@ -481,7 +481,7 @@ export const buildEffectifForMissionLocale = ( courriel: effectif.apprenant.courriel, rqth: effectif.apprenant.rqth, }, - parcours: effectif._computed?.statut, + statut: effectif._computed?.statut, formation: effectif.formation, organisme: effectif._computed?.organisme, user: { diff --git a/server/src/common/actions/effectifs/effectifs.actions.ts b/server/src/common/actions/effectifs/effectifs.actions.ts index 839f87c1f..f9088eb23 100644 --- a/server/src/common/actions/effectifs/effectifs.actions.ts +++ b/server/src/common/actions/effectifs/effectifs.actions.ts @@ -138,14 +138,14 @@ export const getDetailedEffectifById = async (_id: any) => { }; export const getPaginatedEffectifsByMissionLocaleId = async ( - missionLocaleId: string, + missionLocaleId: number, page: number = 1, limit: number = 20 ) => { const aggregation = [ { $match: { - "_computed.missionLocale.id": missionLocaleId, + "apprenant.adresse.mission_locale_id": missionLocaleId, annee_scolaire: { $in: getAnneesScolaireListFromDate(new Date()) }, }, }, @@ -184,12 +184,21 @@ export const getPaginatedEffectifsByMissionLocaleId = async ( data: [{ $skip: (page - 1) * limit }, { $limit: limit }], }, }, - { $unwind: { path: "$pagination" } }, + { $unwind: { path: "$pagination", preserveNullAndEmptyArrays: true } }, ]; - const { pagination, data } = (await effectifsDb().aggregate(aggregation).next()) as { + + const result = (await effectifsDb().aggregate(aggregation).next()) as { pagination: any; data: Array; }; - const effectifs = data.map((effectif) => buildEffectifForMissionLocale(effectif)); - return { pagination, data: effectifs }; + + if (!result) { + return { pagination: { total: 0, page, limit }, data: [] }; + } + + if (result.pagination) { + result.pagination.lastPage = Math.ceil(result.pagination.total / limit); + } + result.data = result.data.map((effectif) => buildEffectifForMissionLocale(effectif)); + return result; }; diff --git a/server/src/common/actions/engine/engine.actions.ts b/server/src/common/actions/engine/engine.actions.ts index def19868b..fc96dae38 100644 --- a/server/src/common/actions/engine/engine.actions.ts +++ b/server/src/common/actions/engine/engine.actions.ts @@ -86,6 +86,7 @@ export const completeEffectifAddress = async { +export const getEffectifIndicateursForMissionLocaleId = async (filters: DateFilters, missionLocaleId: number) => { const aggregation = [ { $match: { - "_computed.missionLocale.id": missionLocaleId, + "apprenant.adresse.mission_locale_id": missionLocaleId, }, }, ...buildIndicateursEffectifsPipeline(null, filters.date), diff --git a/server/src/http/routes/organisations.routes/mission-locale/mission-locale.routes.ts b/server/src/http/routes/organisations.routes/mission-locale/mission-locale.routes.ts index a8d3f7a26..1a96ea2c4 100644 --- a/server/src/http/routes/organisations.routes/mission-locale/mission-locale.routes.ts +++ b/server/src/http/routes/organisations.routes/mission-locale/mission-locale.routes.ts @@ -1,4 +1,5 @@ import express from "express"; +import { IOrganisationMissionLocale } from "shared/models"; import { getPaginatedEffectifsByMissionLocaleId } from "@/common/actions/effectifs/effectifs.actions"; import { dateFiltersSchema } from "@/common/actions/helpers/filters"; @@ -14,12 +15,12 @@ export default () => { }; const getIndicateursMissionLocale = async (req, { locals }) => { - const { missionLocale } = locals; + const missionLocale = locals.missionLocale as IOrganisationMissionLocale; const filters = await validateFullZodObjectSchema(req.query, dateFiltersSchema); - return await getEffectifIndicateursForMissionLocaleId(filters, missionLocale._id.toString()); + return await getEffectifIndicateursForMissionLocaleId(filters, missionLocale.ml_id); }; const getEffectifsMissionLocale = async (_req, { locals }) => { - const { missionLocale } = locals; - return await getPaginatedEffectifsByMissionLocaleId(missionLocale._id.toString()); + const missionLocale = locals.missionLocale as IOrganisationMissionLocale; + return await getPaginatedEffectifsByMissionLocaleId(missionLocale.ml_id); }; diff --git a/shared/models/data/effectifs.model.ts b/shared/models/data/effectifs.model.ts index 537ab918b..f406c3299 100644 --- a/shared/models/data/effectifs.model.ts +++ b/shared/models/data/effectifs.model.ts @@ -87,14 +87,13 @@ const indexes: [IndexSpecification, CreateIndexesOptions][] = [ [{ "_computed.organisme.fiable": 1, annee_scolaire: 1 }, {}], [{ "_computed.formation.codes_rome": 1 }, {}], [{ "_computed.formation.opcos": 1 }, {}], - [{ "_computed.missionLocale.id": 1 }, {}], ]; const StatutApprenantEnum = zodEnumFromArray( STATUT_APPRENANT_VALUES as (typeof STATUT_APPRENANT)[keyof typeof STATUT_APPRENANT][] ); -const zEffectifComputedStatut = z.object({ +export const zEffectifComputedStatut = z.object({ en_cours: StatutApprenantEnum, parcours: z.array( z.object({ @@ -104,10 +103,6 @@ const zEffectifComputedStatut = z.object({ ), }); -const zEffectifComputedMissionLocale = z.object({ - id: z.string(), -}); - export const zEffectif = z.object({ _id: zObjectId.describe("Identifiant MongoDB de l'effectif"), organisme_id: zObjectId.describe("Organisme id (lieu de formation de l'apprenant pour la v3)"), @@ -232,7 +227,6 @@ export const zEffectif = z.object({ .nullish(), // @TODO: nullish en attendant la migration et passage en nullable ensuite (migration: 20240305085918-effectifs-types.ts) statut: zEffectifComputedStatut.nullish(), - missionLocale: zEffectifComputedMissionLocale.nullish(), }, { description: "Propriétés calculées ou récupérées d'autres collections", diff --git a/shared/models/parts/adresseSchema.ts b/shared/models/parts/adresseSchema.ts index 449ac455a..df52ba107 100644 --- a/shared/models/parts/adresseSchema.ts +++ b/shared/models/parts/adresseSchema.ts @@ -73,4 +73,5 @@ export const zAdresse = zodOpenApi.object({ description: "Code Bassin d'emploi", }) .optional(), + mission_locale_id: zodOpenApi.number({ description: "Id de mission locale" }).optional(), }); diff --git a/shared/models/routes/mission-locale/MissionLocaleEffectif.ts b/shared/models/routes/mission-locale/MissionLocaleEffectif.ts new file mode 100644 index 000000000..5ed0b1346 --- /dev/null +++ b/shared/models/routes/mission-locale/MissionLocaleEffectif.ts @@ -0,0 +1,21 @@ +import { z } from "zod"; +import { zObjectId } from "zod-mongodb-schema"; + +import { zEffectif, zEffectifComputedStatut } from "../../data"; +import { zApprenant } from "../../data/effectifs/apprenant.part"; +import { zFormationEffectif } from "../../data/effectifs/formation.part"; + +const zEffectifMissionLocale = z.object({ + _id: zObjectId, + apprenant: zApprenant.pick({ + nom: true, + prenom: true, + date_de_naissance: true, + adresse: true, + telephone: true, + courriel: true, + rqth: true, + }), + statut: zEffectifComputedStatut, + formation: zFormationEffectif, +});