Skip to content

Commit

Permalink
feat: integration de deca (#3645)
Browse files Browse the repository at this point in the history
Co-authored-by: Paul Gaucher <[email protected]>
Co-authored-by: Nicolas KREMER <[email protected]>
  • Loading branch information
3 people authored May 7, 2024
1 parent 2d908a6 commit 549391c
Show file tree
Hide file tree
Showing 31 changed files with 1,634 additions and 255 deletions.
17 changes: 17 additions & 0 deletions server/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,14 @@ program
.option("-f, --full", "Récupère l'intégralité des données disponibles via l'API Deca", false)
.action(createJobAction("hydrate:contratsDeca"));

program
.command("hydrate:contrats-deca-raw")
.description("Remplissage des contrats Deca")
.option("-q, --queued", "Run job asynchronously", false)
.option("-d, --drop", "Supprime les contrats existants avant de les recréer", false)
.option("-f, --full", "Récupère l'intégralité des données disponibles via l'API Deca", false)
.action(createJobAction("hydrate:contrats-deca-raw"));

program
.command("dev:generate-open-api")
.description("Création/maj du fichier open-api.json")
Expand All @@ -477,6 +485,15 @@ program
.option("-q, --queued", "Run job asynchronously", false)
.action(createJobAction("hydrate:organismes-effectifs-count"));

/**
* Mise à jour des organismes avec le nombre d'effectifs hierarchisé
*/
program
.command("hydrate:organismes-effectifs-count-with-hierarchy")
.description("Mise à jour des organismes avec le nombre d'effectifs hierarchisé")
.option("-q, --queued", "Run job asynchronously", false)
.action(createJobAction("hydrate:organismes-effectifs-count-with-hierarchy"));

/**
* Job de mise à jour des organismes en allant appeler des API externes pour remplir
* - Les informations liés au SIRET (API Entreprise)
Expand Down
16 changes: 14 additions & 2 deletions server/src/common/actions/effectifs.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { IEffectif } from "shared/models/data/effectifs.model";
import { IOrganisme } from "shared/models/data/organismes.model";
import type { Paths } from "type-fest";

import { effectifsDb } from "@/common/model/collections";
import { effectifsDECADb, effectifsDb } from "@/common/model/collections";
import { defaultValuesEffectif } from "@/common/model/effectifs.model/effectifs.model";

import { stripEmptyFields } from "../utils/miscUtils";
Expand Down Expand Up @@ -155,7 +155,12 @@ export const addComputedFields = ({
};

export async function getEffectifForm(effectifId: ObjectId): Promise<any> {
const effectif = await effectifsDb().findOne({ _id: effectifId });
let effectif = await effectifsDb().findOne({ _id: effectifId });

if (!effectif) {
effectif = await effectifsDECADb().findOne({ _id: effectifId });
}

return buildEffectifResult(effectif);
}

Expand Down Expand Up @@ -260,6 +265,13 @@ export async function updateEffectifFromForm(effectifId: ObjectId, body: any): P
function buildEffectifResult(effectif) {
const { properties: effectifSchema } = legacySchema;

if (!effectif.is_lock) {
effectif.is_lock = {
apprenant: {},
formation: {},
};
}

function customizer(objValue, srcValue) {
if (objValue !== undefined) {
return {
Expand Down
11 changes: 11 additions & 0 deletions server/src/common/actions/helpers/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,14 @@ export function findOrganismeFormateursIds(organisme: IOrganisme, withResponsabi
.map((organisme) => organisme._id as ObjectId)
);
}

export async function findOrganismeResponsableIdsOfOrganisme(organismeId: ObjectId) {
const organisme = await getOrganismeById(organismeId);
return findOrganismeResponsablesIds(organisme);
}

export function findOrganismeResponsablesIds(organisme: IOrganisme): ObjectId[] {
return (organisme.organismesResponsables ?? [])
.filter((organisme) => !!organisme._id)
.map((organisme) => organisme._id as ObjectId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { tryCachedExecution } from "@/common/utils/cacheUtils";

import { DateFilters, TerritoireFilters } from "../helpers/filters";

import { getIndicateursEffectifsParDepartement, getIndicateursOrganismesParDepartement } from "./indicateurs.actions";
import { getIndicateursEffectifsParDepartement } from "./indicateurs-with-deca.actions";
import { getIndicateursOrganismesParDepartement } from "./indicateurs.actions";

const indicateursNationalCacheExpirationMs = 3600 * 1000; // 1 hour

Expand Down
127 changes: 127 additions & 0 deletions server/src/common/actions/indicateurs/indicateurs-with-deca.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { ObjectId } from "mongodb";
import { TypeEffectifNominatif } from "shared/constants/indicateurs";
import { Acl } from "shared/constants/permissions";

import { effectifsDECADb, effectifsDb } from "@/common/model/collections";
import { AuthContext } from "@/common/model/internal/AuthContext";

import { DateFilters, EffectifsFiltersTerritoire, FullEffectifsFilters, TerritoireFilters } from "../helpers/filters";

import {
getIndicateursEffectifsParDepartementGenerique,
getIndicateursEffectifsParOrganismeGenerique,
getEffectifsNominatifsGenerique,
getOrganismeIndicateursEffectifsParFormationGenerique,
getOrganismeIndicateursEffectifsGenerique,
} from "./indicateurs.actions";

export const buildDECAFilter = (decaMode) => (decaMode ? { is_deca_compatible: true } : {});

// Attention ca marche pas, il faut ensuite merger par departement et sommer les valeurs
export const getIndicateursEffectifsParDepartement = async (filters: DateFilters & TerritoireFilters, acl: Acl) => {
const indicateurs = [
...(await getIndicateursEffectifsParDepartementGenerique(filters, acl, effectifsDb(), false)),
...(await getIndicateursEffectifsParDepartementGenerique(filters, acl, effectifsDECADb(), true)),
];

const mapDepartement = indicateurs.reduce((acc, { departement, ...rest }) => {
return acc[departement]
? {
...acc,
[departement]: {
departement,
apprentis: acc[departement].apprentis + rest.apprentis,
abandons: acc[departement].abandons + rest.abandons,
inscrits: acc[departement].inscrits + rest.inscrits,
apprenants: acc[departement].apprenants + rest.apprenants,
rupturants: acc[departement].rupturants + rest.rupturants,
},
}
: {
...acc,
[departement]: {
departement,
...rest,
},
};
}, {});
return Object.values(mapDepartement);
};

export const getIndicateursEffectifsParOrganisme = async (
ctx: AuthContext,
filters: FullEffectifsFilters,
organismeId?: ObjectId
) => [
...(await getIndicateursEffectifsParOrganismeGenerique(ctx, filters, effectifsDb(), false, organismeId)),
...(await getIndicateursEffectifsParOrganismeGenerique(ctx, filters, effectifsDECADb(), true, organismeId)),
];

export const getEffectifsNominatifs = async (
ctx: AuthContext,
filters: FullEffectifsFilters,
type: TypeEffectifNominatif,
organismeId?: ObjectId
) => [
...(await getEffectifsNominatifsGenerique(ctx, filters, type, effectifsDb(), false, organismeId)),
...(await getEffectifsNominatifsGenerique(ctx, filters, type, effectifsDECADb(), true, organismeId)),
];

export const getOrganismeIndicateursEffectifs = async (
ctx: AuthContext,
organismeId: ObjectId,
filters: EffectifsFiltersTerritoire
) => {
const eff = await getOrganismeIndicateursEffectifsGenerique(ctx, organismeId, filters, effectifsDb(), false);
const effDECA = await getOrganismeIndicateursEffectifsGenerique(ctx, organismeId, filters, effectifsDECADb(), true);

return {
apprenants: eff.apprenants + effDECA.apprenants,
apprentis: eff.apprentis + effDECA.apprentis,
inscrits: eff.inscrits + effDECA.inscrits,
abandons: eff.abandons + effDECA.abandons,
rupturants: eff.rupturants + effDECA.rupturants,
};
};

export const getOrganismeIndicateursEffectifsParFormation = async (
ctx: AuthContext,
organismeId: ObjectId,
filters: FullEffectifsFilters
) => {
const indicateurs = [
...(await getOrganismeIndicateursEffectifsParFormationGenerique(ctx, organismeId, filters, effectifsDb())),
...(await getOrganismeIndicateursEffectifsParFormationGenerique(
ctx,
organismeId,
filters,
effectifsDECADb(),
true
)),
];

const mapRNCP = indicateurs.reduce((acc, { rncp_code, ...rest }) => {
const rncp = rncp_code ?? "null";
return acc[rncp]
? {
...acc,
[rncp]: {
rncp_code,
apprentis: acc[rncp].apprentis + rest.apprentis,
abandons: acc[rncp].abandons + rest.abandons,
inscrits: acc[rncp].inscrits + rest.inscrits,
apprenants: acc[rncp].apprenants + rest.apprenants,
rupturants: acc[rncp].rupturants + rest.rupturants,
},
}
: {
...acc,
[rncp]: {
rncp_code,
...rest,
},
};
}, {});

return Object.values(mapRNCP);
};
46 changes: 31 additions & 15 deletions server/src/common/actions/indicateurs/indicateurs.actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ObjectId } from "mongodb";
import { Collection, ObjectId } from "mongodb";
import {
Acl,
CODES_STATUT_APPRENANT,
Expand All @@ -20,10 +20,11 @@ import {
combineFilters,
} from "@/common/actions/helpers/filters";
import { findOrganismesFormateursIdsOfOrganisme } from "@/common/actions/helpers/permissions";
import { effectifsDb, organismesDb } from "@/common/model/collections";
import { organismesDb } from "@/common/model/collections";
import { AuthContext } from "@/common/model/internal/AuthContext";

import { buildEffectifMongoFilters } from "./effectifs/effectifs-filters";
import { buildDECAFilter } from "./indicateurs-with-deca.actions";
import { buildOrganismeMongoFilters } from "./organismes/organismes-filters";

function buildIndicateursEffectifsPipeline(groupBy: string | null, currentDate: Date) {
Expand Down Expand Up @@ -93,17 +94,20 @@ function buildIndicateursEffectifsPipeline(groupBy: string | null, currentDate:
];
}

export async function getIndicateursEffectifsParDepartement(
export async function getIndicateursEffectifsParDepartementGenerique(
filters: DateFilters & TerritoireFilters,
acl: Acl
acl: Acl,
db: Collection<any>,
decaMode: boolean = false
): Promise<IndicateursEffectifsAvecDepartement[]> {
const indicateurs = await effectifsDb()
const indicateurs = await db
.aggregate([
{
$match: combineFilters(
{
"_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables
},
buildDECAFilter(decaMode),
...buildEffectifMongoFilters(filters, acl.indicateursEffectifs)
),
},
Expand Down Expand Up @@ -419,16 +423,19 @@ export async function getIndicateursOrganismesParDepartement(
return indicateurs;
}

export async function getIndicateursEffectifsParOrganisme(
export async function getIndicateursEffectifsParOrganismeGenerique(
ctx: AuthContext,
filters: FullEffectifsFilters,
db: Collection<any>,
decaMode: boolean = false,
organismeId?: ObjectId
): Promise<IndicateursEffectifsAvecOrganisme[]> {
const indicateurs = (await effectifsDb()
const indicateurs = (await db
.aggregate([
{
$match: combineFilters(
await getOrganismeRestriction(organismeId),
buildDECAFilter(decaMode),
...buildEffectifMongoFilters(filters, ctx.acl.indicateursEffectifs),
{
"_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables
Expand Down Expand Up @@ -485,16 +492,19 @@ export async function getIndicateursEffectifsParOrganisme(
return indicateurs;
}

export async function getOrganismeIndicateursEffectifsParFormation(
export async function getOrganismeIndicateursEffectifsParFormationGenerique(
ctx: AuthContext,
organismeId: ObjectId,
filters: FullEffectifsFilters
filters: FullEffectifsFilters,
db: Collection<any>,
decaMode: boolean = false
): Promise<IndicateursEffectifsAvecFormation[]> {
const indicateurs = (await effectifsDb()
const indicateurs = (await db
.aggregate([
{
$match: combineFilters(
await getOrganismeRestriction(organismeId),
buildDECAFilter(decaMode),
...buildEffectifMongoFilters(filters, ctx.acl.indicateursEffectifs),
{
"_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables
Expand Down Expand Up @@ -540,17 +550,20 @@ export async function getOrganismeIndicateursEffectifsParFormation(
return indicateurs;
}

export async function getEffectifsNominatifs(
export async function getEffectifsNominatifsGenerique(
ctx: AuthContext,
filters: FullEffectifsFilters,
type: TypeEffectifNominatif,
db: Collection<any>,
decaMode: boolean = false,
organismeId?: ObjectId
): Promise<IndicateursEffectifsAvecOrganisme[]> {
const indicateurs = (await effectifsDb()
const indicateurs = (await db
.aggregate([
{
$match: combineFilters(
await getOrganismeRestriction(organismeId),
buildDECAFilter(decaMode),
...buildEffectifMongoFilters(filters, ctx.acl.effectifsNominatifs[type]),
{
"_computed.organisme.fiable": true, // TODO : a supprimer si on permet de choisir de voir les effectifs des non fiables
Expand Down Expand Up @@ -701,16 +714,19 @@ export async function getEffectifsNominatifs(
return indicateurs;
}

export async function getOrganismeIndicateursEffectifs(
export async function getOrganismeIndicateursEffectifsGenerique(
ctx: AuthContext,
organismeId: ObjectId,
filters: EffectifsFiltersTerritoire
filters: EffectifsFiltersTerritoire,
db: Collection<any>,
decaMode: boolean = false
): Promise<IndicateursEffectifs> {
const indicateurs = (await effectifsDb()
const indicateurs = (await db
.aggregate([
{
$match: combineFilters(
await getOrganismeRestriction(organismeId),
buildDECAFilter(decaMode),
...buildEffectifMongoFilters(filters, ctx.acl.indicateursEffectifs)
),
},
Expand Down
Loading

0 comments on commit 549391c

Please sign in to comment.