Skip to content

Commit

Permalink
feat: mise à jour du tableau des effectifs et SIFA (#3948)
Browse files Browse the repository at this point in the history
  • Loading branch information
nkrmr authored Dec 23, 2024
1 parent e7c8303 commit 76078fa
Show file tree
Hide file tree
Showing 22 changed files with 2,124 additions and 1,021 deletions.
284 changes: 240 additions & 44 deletions server/src/http/routes/specific.routes/organisme.routes.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,260 @@
import { compact, get } from "lodash-es";
import { ObjectId } from "mongodb";
import { ObjectId } from "bson";
import {
STATUT_APPRENANT,
getAnneesScolaireListFromDate,
getSIFADate,
requiredApprenantAdresseFieldsSifa,
requiredFieldsSifa,
} from "shared";

import { isEligibleSIFA } from "@/common/actions/sifa.actions/sifa.actions";
import { effectifsDECADb, effectifsDb, organismesDb } from "@/common/model/collections";

export async function getOrganismeEffectifs(organismeId: ObjectId, sifa = false) {
export async function getOrganismeEffectifs(
organismeId: ObjectId,
sifa: boolean = false,
options: {
pageIndex: number;
pageSize: number;
search: string;
filters: any;
sortField: string | null;
sortOrder: string | null;
} = { pageIndex: 0, pageSize: 10, search: "", filters: {}, sortField: null, sortOrder: null }
) {
const organisme = await organismesDb().findOne({ _id: organismeId });
const { pageIndex, pageSize, search, filters, sortField, sortOrder } = options;
const isDeca = !organisme?.is_transmission_target;
const db = isDeca ? effectifsDECADb() : effectifsDb();

const effectifs = await db
.find({
organisme_id: organismeId,
...(sifa
? {
annee_scolaire: {
$in: getAnneesScolaireListFromDate(sifa ? getSIFADate(new Date()) : new Date()),
const parsedFilters = Object.entries(filters).reduce(
(acc, [key, value]) => {
if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
try {
const parsed = JSON.parse(value);
acc[key] = Array.isArray(parsed) ? parsed : [parsed];
} catch {
acc[key] = [value];
}
} else if (Array.isArray(value)) {
acc[key] = value;
}
return acc;
},
{} as Record<string, string[]>
);

const matchConditions = {
organisme_id: organismeId,
...(sifa && {
annee_scolaire: {
$in: getAnneesScolaireListFromDate(sifa ? getSIFADate(new Date()) : new Date()),
},
}),
...Object.keys(parsedFilters).reduce((acc, key) => {
if (parsedFilters[key]?.length > 0) {
const fieldKey =
key === "formation_libelle_long"
? "formation.libelle_long"
: key === "statut_courant"
? "_computed.statut.en_cours"
: key;
acc[fieldKey] = { $in: parsedFilters[key] };
}
return acc;
}, {}),
...(typeof search === "string" &&
search.trim() && {
$or: [
{ "apprenant.nom": { $regex: search.trim(), $options: "i" } },
{ "apprenant.prenom": { $regex: search.trim(), $options: "i" } },
],
}),
};

const fieldMap: Record<string, string> = {
nom: "apprenant.nom",
prenom: "apprenant.prenom",
formation: "formation.libelle_long",
statut_courant: "_computed.statut.en_cours",
annee_scolaire: "annee_scolaire",
};

const sortConditions =
sortField && sortOrder
? { [fieldMap[sortField] || sortField]: sortOrder === "desc" ? -1 : 1 }
: { "formation.annee_scolaire": -1 };

const pipeline = [
{
$facet: {
allFilters: [
{
$match: {
organisme_id: organismeId,
...(sifa && {
annee_scolaire: {
$in: getAnneesScolaireListFromDate(sifa ? getSIFADate(new Date()) : new Date()),
},
"_computed.statut.parcours": {
$elemMatch: {
valeur: STATUT_APPRENANT.APPRENTI,
date: {
$eq: {
$arrayElemAt: [
{
$filter: {
input: "$_computed.statut.parcours",
as: "parcours",
cond: { $eq: ["$$parcours.valeur", STATUT_APPRENANT.APPRENTI] },
},
},
-1,
],
},
},
},
},
}),
},
},
{
$group: {
_id: null,
annee_scolaire: { $addToSet: "$annee_scolaire" },
source: { $addToSet: "$source" },
statut_courant: { $addToSet: "$_computed.statut.en_cours" },
formation_libelle_long: { $addToSet: "$formation.libelle_long" },
},
}
: {}),
})
.toArray();
},
{
$project: {
_id: 0,
annee_scolaire: 1,
source: 1,
statut_courant: 1,
formation_libelle_long: 1,
},
},
],
results: [
{ $match: matchConditions },
{ $sort: sortConditions },
{ $skip: pageIndex * pageSize },
{ $limit: pageSize },
{
$project: {
id: { $toString: "$_id" },
id_erp_apprenant: 1,
organisme_id: 1,
annee_scolaire: 1,
source: 1,
validation_errors: 1,
formation: 1,
nom: "$apprenant.nom",
prenom: "$apprenant.prenom",
date_de_naissance: "$apprenant.date_de_naissance",
historique_statut: "$apprenant.historique_statut",
statut: "$_computed.statut",
...(sifa
? {
requiredSifa: {
$filter: {
input: {
$setUnion: [
requiredFieldsSifa,
{
$cond: [{ $not: "$apprenant.adresse.complete" }, requiredApprenantAdresseFieldsSifa, []],
},
],
},
as: "fieldName",
cond: { $or: [{ $not: { $ifNull: ["$$fieldName", false] } }] },
},
},
}
: {}),
},
},
],
totalCount: [
{ $match: matchConditions },
{
$count: "count",
},
],
},
},
{
$project: {
filters: {
annee_scolaire: { $arrayElemAt: ["$allFilters.annee_scolaire", 0] },
source: { $arrayElemAt: ["$allFilters.source", 0] },
statut_courant: { $arrayElemAt: ["$allFilters.statut_courant", 0] },
formation_libelle_long: { $arrayElemAt: ["$allFilters.formation_libelle_long", 0] },
},
results: "$results",
total: { $arrayElemAt: ["$totalCount.count", 0] },
},
},
];

const [data] = await db.aggregate(pipeline).toArray();

return {
fromDECA: isDeca,
organismesEffectifs: effectifs
.filter((effectif) => !sifa || isEligibleSIFA(effectif._computed?.statut))
.map((effectif) => ({
id: effectif._id.toString(),
id_erp_apprenant: effectif.id_erp_apprenant,
total: data?.total || 0,
filters: data?.filters || {},
organismesEffectifs: data?.results || [],
};
}

export async function getAllOrganismeEffectifsIds(organismeId: ObjectId, sifa = false) {
const organisme = await organismesDb().findOne({ _id: organismeId });
const isDeca = !organisme?.is_transmission_target;
const db = isDeca ? effectifsDECADb() : effectifsDb();

const pipeline = [
{
$match: {
organisme_id: organismeId,
annee_scolaire: effectif.annee_scolaire,
source: effectif.source,
validation_errors: effectif.validation_errors,
formation: effectif.formation,
nom: effectif.apprenant.nom,
prenom: effectif.apprenant.prenom,
date_de_naissance: effectif.apprenant.date_de_naissance,
historique_statut: effectif.apprenant.historique_statut,
statut: effectif._computed?.statut,
...(sifa
? {
requiredSifa: compact(
[
...(!effectif.apprenant.adresse?.complete
? [...requiredFieldsSifa, ...requiredApprenantAdresseFieldsSifa]
: requiredFieldsSifa),
].map((fieldName) =>
!get(effectif, fieldName) || get(effectif, fieldName) === "" ? fieldName : undefined
)
),
}
: {}),
})),
...(sifa && {
annee_scolaire: {
$in: getAnneesScolaireListFromDate(sifa ? getSIFADate(new Date()) : new Date()),
},
"_computed.statut.parcours": {
$elemMatch: {
valeur: STATUT_APPRENANT.APPRENTI,
date: {
$eq: {
$arrayElemAt: [
{
$filter: {
input: "$_computed.statut.parcours",
as: "parcours",
cond: { $eq: ["$$parcours.valeur", STATUT_APPRENANT.APPRENTI] },
},
},
-1,
],
},
},
},
},
}),
},
},
{
$project: {
id: { $toString: "$_id" },
},
},
];

const effectifs = await db.aggregate(pipeline).toArray();

return {
fromDECA: isDeca,
organismesEffectifs: effectifs,
};
}

Expand All @@ -70,7 +266,7 @@ export async function updateOrganismeEffectifs(
}
) {
if (!update["apprenant.type_cfa"]) return;
const { fromDECA, organismesEffectifs } = await getOrganismeEffectifs(organismeId, sifa);
const { fromDECA, organismesEffectifs } = await getAllOrganismeEffectifsIds(organismeId, sifa);

!fromDECA &&
(await effectifsDb().updateMany(
Expand Down
13 changes: 12 additions & 1 deletion server/src/http/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,18 @@ function setupRoutes(app: Application) {
"/effectifs",
requireOrganismePermission("manageEffectifs"),
returnResult(async (req, res) => {
return await getOrganismeEffectifs(res.locals.organismeId, req.query.sifa === "true");
const { pageIndex, pageSize, search, sortField, sortOrder, sifa, ...filters } = req.query;

const options = {
pageIndex: parseInt(pageIndex, 10) || 0,
pageSize: parseInt(pageSize, 10) || 10,
search: search || "",
sortField,
sortOrder,
filters,
};

return await getOrganismeEffectifs(res.locals.organismeId, sifa === "true", options);
})
)
.put(
Expand Down
5 changes: 5 additions & 0 deletions ui/common/utils/stringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ export const toPascalCase = (string) =>
.replace(new RegExp(/[^\w\s]/, "g"), "")
.replace(new RegExp(/\s+(.)(\w*)/, "g"), ($1, $2, $3) => `${$2.toUpperCase() + $3}`)
.replace(new RegExp(/\w/), (s) => s.toUpperCase());

export function capitalizeWords(str: string): string {
const formattedString = str.toLowerCase().replace(/_/g, " ");
return formattedString.charAt(0).toUpperCase() + formattedString.slice(1);
}
Loading

0 comments on commit 76078fa

Please sign in to comment.