Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ajout du code dispositif pour les offres en apprentissage #513

Merged
merged 10 commits into from
Feb 24, 2025
2 changes: 1 addition & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fileignoreconfig:
- filename: server/static/files/lyceesACCE.csv
checksum: 10bcfb7324ef1968ff3c24f3047fc6ce8f148060e625b48ec1b6f7e7a4cde471
- filename: server/static/files/offres_apprentissage.csv
checksum: f8e173f11056708d2958e4f000428c2acb2281d9f19db55d9d72c5790bf0bf4b
checksum: d50238cbe4e0a97922ecd069d11ffb75607b0bdb059fe1c33d63b3261fb4b27c
- filename: server/tests/test_origin/controllers/campagnes.controller.test.js_old
checksum: 546c306130034fdce2c4165b1f31656dfa883bc8808f0e8b1fa5a5461da1cb08
- filename: server/tests/test_origin/controllers/users.controller.test.js_old
Expand Down
2 changes: 2 additions & 0 deletions server/src/modules/import/fileTypes/Offres_apprentissage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const OffresApprentissageSchema = z
"Formation: code CFD": z.string(),
"Formation: niveau BCN": z.string(),
"Offre: Tags": z.string(),
"Formation: codes MEF": z.string().optional(),
"Formation: durée collectée": z.string().optional(),
})
.superRefine((data, ctx) => {
if (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
import { sql } from "kysely";

import { getKbdClient } from "@/db/db";
import type { Offres_apprentissage } from "@/modules/import/fileTypes/Offres_apprentissage";

export const findOffresApprentissages = async ({ offset, limit }: { offset: number; limit: number }) => {
const items = await getKbdClient()
.selectFrom("rawData")
.selectAll("rawData")
.select(sql<string>`data->>'Formation: code CFD'`.as("cfd"))
.where("type", "=", "offres_apprentissage")
.where((eb) =>
eb.and([
eb.or([
eb(sql`"data"->>'Niveau de la formation'`, "like", "3%"),
eb(sql`"data"->>'Niveau de la formation'`, "like", "4%"),
eb(sql`"data"->>'Niveau de la formation'`, "like", "5%"),
eb(sql`"data"->>'Formation: code CFD'`, "like", "3%"),
eb(sql`"data"->>'Formation: code CFD'`, "like", "4%"),
eb(sql`"data"->>'Formation: code CFD'`, "like", "5%"),
]),
eb.or([eb(sql`"data"->>'Tags'`, "like", "%2023%"), eb(sql`"data"->>'Tags'`, "like", "%2024%")]),
eb.or([eb(sql`"data"->>'Offre: Tags'`, "like", "%2023%"), eb(sql`"data"->>'Offre: Tags'`, "like", "%2024%")]),
])
)
.distinctOn(
sql<string>`data->>'Code du diplome ou du titre suivant la nomenclature de l''Education nationale (CodeEN)'`
)
.offset(offset)
.$call((q) => {
if (!limit) return q;
return q.limit(limit);
})
.distinct()
.execute();

return items.map((item) => item.data as Offres_apprentissage);
return items.map((item) => item.cfd);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { inject } from "injecti";

import type { DiplomeProfessionnelLine } from "@/modules/import/fileTypes/DiplomesProfessionnels";
import type { Offres_apprentissage } from "@/modules/import/fileTypes/Offres_apprentissage";
import { streamIt } from "@/modules/import/utils/streamIt";

import { createDiplomeProfessionnel } from "./createDiplomeProfessionnel.dep";
Expand All @@ -17,14 +16,6 @@ const formatCFDDiplomeProfessionnel = (line: DiplomeProfessionnelLine) => {
return cfd;
};

const formatCFDOffreApprentissage = (line: Offres_apprentissage) => {
if (!line["Formation: code CFD"]) return;
const cfd = line["Formation: code CFD"];

if (isNaN(parseInt(cfd))) return;
return cfd;
};

export const [importDiplomesProfessionnels] = inject(
{
findDiplomesProfessionnels,
Expand Down Expand Up @@ -66,8 +57,7 @@ export const [importDiplomesProfessionnels] = inject(
errorCount = 0;
await streamIt(
async (count) => deps.findOffresApprentissages({ offset: count, limit: 60 }),
async (offreApprentissage, count) => {
const cfd = formatCFDOffreApprentissage(offreApprentissage);
async (cfd, count) => {
if (!cfd) return;
try {
await deps.createDiplomeProfessionnel({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

import { getKbdClient } from "@/db/db";

export const deleteFormationEtablissement = async ({ id }: {id: string }) => {
await getKbdClient().deleteFrom("indicateurSortie").where("formationEtablissementId", "=", id).execute();

return await getKbdClient()
.deleteFrom("formationEtablissement")
.where(eb => (
eb("id", "=", id)
))
.execute();
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Insertable } from "kysely";

import type { DB} from "@/db/db";
import { getKbdClient } from "@/db/db";

export const findFormationEtablissement = async (formationEtablissement: Insertable<DB["formationEtablissement"]>) => {
return getKbdClient()
.selectFrom("formationEtablissement")
.selectAll()
.where(eb => (
eb.and([
eb("cfd", "=", formationEtablissement.cfd),
eb("uai", "=", formationEtablissement.uai),
eb("voie", "=", formationEtablissement.voie),
eb("codeDispositif", "is", formationEtablissement.codeDispositif ?? null)
])
))
.executeTakeFirst();
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
import { inject } from "injecti";
import { MILLESIMES_IJ, RENTREES_SCOLAIRES } from "shared";

import { rawDataRepository } from "@/modules/import/repositories/rawData.repository";
import { getCfdDispositifs } from "@/modules/import/usecases/getCfdRentrees/getCfdDispositifs.dep";
import { getCfdRentrees } from "@/modules/import/usecases/getCfdRentrees/getCfdRentrees.usecase";
import { findDiplomesProfessionnels } from "@/modules/import/usecases/importIJData/findDiplomesProfessionnels.dep";
import { streamIt } from "@/modules/import/utils/streamIt";

import { deleteFormationEtablissement } from "./deleteFormationEtablissement";
import { findFamillesMetiers } from "./findFamillesMetiers.dep";
import { findFormationEtablissement } from "./findFormationEtablissement";
import { findUAIsApprentissage } from "./findUAIsApprentissage";
import { importEtablissement } from "./steps/importEtablissement/importEtablissement.step";
import { importFormation } from "./steps/importFormation/importFormation.step";
Expand All @@ -23,6 +26,7 @@ import {
importIndicateursRegionSortie,
importIndicateursRegionSortieApprentissage,
} from "./steps/importIndicateursSortieRegionaux/importIndicateursSortieRegionaux.step";
import { extractCfdFromMefAndDuree } from "./utils";

const processedUais = new Set<string>();

Expand Down Expand Up @@ -87,6 +91,10 @@ export const [importFormationEtablissements] = inject(
importIndicateurSortieApprentissage,
importIndicateursRegionSortieApprentissage,
findUAIsApprentissage,
findRawData: rawDataRepository.findRawData,
findRawDatas: rawDataRepository.findRawDatas,
findFormationEtablissement,
deleteFormationEtablissement
},
(deps) => {
return async ({ cfd, voie = "scolaire" }: { cfd: string; voie?: string }) => {
Expand All @@ -102,20 +110,92 @@ export const [importFormationEtablissements] = inject(
}
processedUais.add(uai);
}
const formationEtablissement = await deps.createFormationEtablissement({
uai,
cfd,
codeDispositif: null,
voie: "apprentissage",

// Récupération du codeDispositif pour les formations en apprentissage
// à partir du contenu du fichier offres_apprentissage
const offreApprentissage = await deps.findRawData({
type: "offres_apprentissage",
filter: { "Formation: code CFD": cfd },
});

for (const millesime of MILLESIMES_IJ) {
await deps.importIndicateurSortieApprentissage({
if (!offreApprentissage) continue;

const codesDispositifs: Array<string> = [];
const mefs = offreApprentissage["Formation: codes MEF"]?.split(",").map((mef) => mef.trim()) ?? [];
const dureeCollectee = offreApprentissage?.["Formation: durée collectée"]
? parseInt(offreApprentissage?.["Formation: durée collectée"])
: -1;

if (mefs.length > 0) {
/**
* Chercher ce MEF dans le fichier nMef le couple (FORMATION_DIPLOME, DISPOSITIF_FORMATION) qui correspond au (cfd, codeDispositif)
*/
for (const mef of mefs) {
const nMefs = await deps.findRawDatas({
type: "nMef",
filter: {
MEF: mef,
FORMATION_DIPLOME: cfd,
},
});

nMefs.forEach((nMef) => {
codesDispositifs.push(nMef.DISPOSITIF_FORMATION);
});
}
} else {
// déduire le code dispositif du cfd
const codeDispositif = extractCfdFromMefAndDuree(offreApprentissage?.["Formation: code CFD"], dureeCollectee);
if (codeDispositif > -1) {
codesDispositifs.push(codeDispositif.toString());
}
}

if (codesDispositifs.length > 0) {
// Il faut supprimer les anciens CodeDispositif à null puisqu'on les a maintenant déduits
const oldFormationEtablissement = await deps.findFormationEtablissement({
uai, cfd, voie: "apprentissage", codeDispositif: null
});

if (oldFormationEtablissement) {
console.log("Ancienne formationEtablissement trouvée avec un dispositif à null, suppression en cascade...", oldFormationEtablissement.id);
await deps.deleteFormationEtablissement({ id: oldFormationEtablissement.id });
console.log("Suppression ok", oldFormationEtablissement.id);
}

for (const codeDispositif of codesDispositifs) {
const formationEtablissement = await deps.createFormationEtablissement({
uai,
cfd,
codeDispositif,
voie: "apprentissage",
});

for (const millesime of MILLESIMES_IJ) {
await deps.importIndicateurSortieApprentissage({
uai,
formationEtablissementId: formationEtablissement.id,
millesime,
cfd,
});
}
}
} else {
const formationEtablissement = await deps.createFormationEtablissement({
uai,
formationEtablissementId: formationEtablissement.id,
millesime,
cfd,
codeDispositif: null,
voie: "apprentissage",
});

for (const millesime of MILLESIMES_IJ) {
await deps.importIndicateurSortieApprentissage({
uai,
formationEtablissementId: formationEtablissement.id,
millesime,
cfd,
});
}
}
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,32 @@ export const findEtablissementGeoloc = async ({
}

const search = [lyceeACCE?.adresse_uai, [lyceeACCE?.code_postal_uai, lyceeACCE?.commune_libe].join(" ")]
.filter((n) => n)
.filter((n) => !!n)
.join(", ");

if (search.trim().length === 0) {
console.log(
`Pas assez d'information pour trouver la géoloc de cet établissement: ${uai} / ${lyceeACCE?.appellation_officielle}, "${search}"`
);

return {
adresse: lyceeACCE?.adresse_uai,
codePostal: lyceeACCE?.code_postal_uai,
commune: lyceeACCE?.commune_libe,
latitude: undefined,
longitude: undefined,
source: "depp_acce",
};
}

const resultFromBAN = await findAddress({
search,
limit: 1,
});

const [longitude, latitude] = resultFromBAN?.features[0]?.geometry?.coordinates ?? [];


if (!latitude || !longitude) {
console.log(
`Aucune coordonnées de géoloc trouvée pour cet établissement: ${uai} / ${lyceeACCE?.appellation_officielle}, ${search} `
Expand Down
Loading
Loading