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: fiabilisation des formations via API Alternance #3920

Merged
merged 9 commits into from
Dec 10, 2024
2 changes: 2 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ fileignoreconfig:
checksum: 796635402459cd6f6edb18a01b54bb2ecbb75067335ec7b3a6fd291dfd25e806
- filename: server/src/common/actions/formations.actions.ts
checksum: c5e0d6f4a69dbae2c808fae2f8a2b9f9a54f4ff6ce2369b1d08f3b4034cffbcd
- filename: server/tests/integration/jobs/ingestion/process-ingestion.test.ts
checksum: eefd40dc5159f5246beaefa4896d7f4935c7a7a9f684cf83d64d343b39bd4ba5
- filename: shared/constants/aide.ts
checksum: 70dcdce75bb98d7c5b05a34074ccef0412a7bbfb1755b472d66a74a144d0e882
- filename: ui/common/utils/televersement.ts
Expand Down
35 changes: 27 additions & 8 deletions server/src/common/actions/effectifs.actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ICertification } from "api-alternance-sdk";
import Boom from "boom";
import { cloneDeep, isObject, merge, mergeWith, reduce, set, uniqBy } from "lodash-es";
import { ObjectId, WithoutId } from "mongodb";
import { ObjectId, type WithoutId } from "mongodb";
import { IOpcos, IRncp } from "shared/models";
import { IEffectif } from "shared/models/data/effectifs.model";
import { IEffectifDECA } from "shared/models/data/effectifsDECA.model";
Expand Down Expand Up @@ -126,21 +127,23 @@ export const lockEffectif = async (effectif: IEffectif) => {
return updated.value;
};

export const addComputedFields = async ({
export const addComputedFields = async <T extends IEffectif | WithoutId<IEffectifDECA>>({
organisme,
effectif,
certification,
}: {
organisme?: IOrganisme;
effectif?: IEffectif | WithoutId<IEffectif>;
}): Promise<Partial<IEffectif["_computed"]>> => {
const computedFields: Partial<IEffectif["_computed"]> = {};
effectif?: T;
certification: ICertification | null;
}): Promise<IEffectif["_computed"]> => {
const computedFields: IEffectif["_computed"] = {};

if (organisme) {
computedFields.organisme = generateOrganismeComputed(organisme);
}

if (effectif) {
const statut = createComputedStatutObject(effectif as IEffectif, new Date());
const statut = createComputedStatutObject(effectif, new Date());
computedFields.statut = statut;
}

Expand All @@ -149,7 +152,7 @@ export const addComputedFields = async ({

if (rncpList) {
computedFields.formation = {
// codes_rome: rncp.romes, TODO LATER
codes_rome: certification?.domaines.rome.rncp?.map(({ code }) => code) ?? null,
opcos: rncpList.map(({ _computed }) => _computed.opco.nom),
};
}
Expand All @@ -158,6 +161,22 @@ export const addComputedFields = async ({
return computedFields;
};

export const withComputedFields = async <T extends IEffectif | WithoutId<IEffectifDECA>>(
effectif: T,
{
organisme,
certification,
}: {
organisme?: IOrganisme;
certification: ICertification | null;
}
): Promise<T> => {
return {
...effectif,
_computed: await addComputedFields({ organisme, effectif, certification }),
};
};

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

Expand Down Expand Up @@ -268,7 +287,7 @@ export async function updateEffectifFromForm(effectifId: ObjectId, body: any): P

export async function softDeleteEffectif(
effectifId: ObjectId,
userId: ObjectId,
userId: ObjectId | null,
{
motif,
description,
Expand Down
14 changes: 9 additions & 5 deletions server/src/common/actions/effectifs.statut.actions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { captureException } from "@sentry/node";
import Boom from "boom";
import { cloneDeep } from "lodash-es";
import { MongoServerError, UpdateFilter } from "mongodb";
import { MongoServerError, UpdateFilter, type WithoutId } from "mongodb";
import { STATUT_APPRENANT, StatutApprenant } from "shared/constants";
import { IEffectif, IEffectifApprenant, IEffectifComputedStatut } from "shared/models/data/effectifs.model";
import type { IEffectifDECA } from "shared/models/data/effectifsDECA.model";
import { addDaysUTC } from "shared/utils";

import logger from "../logger";
Expand Down Expand Up @@ -43,7 +44,10 @@ function shouldUpdateStatut(effectif: IEffectif): boolean {
* @param {Date} evaluationDate La date à laquelle l'évaluation du statut est effectuée.
* @returns {IEffectifComputedStatut} L'objet de statut calculé pour l'effectif.
*/
export function createComputedStatutObject(effectif: IEffectif, evaluationDate: Date): IEffectifComputedStatut | null {
export function createComputedStatutObject(
effectif: IEffectif | WithoutId<IEffectifDECA>,
evaluationDate: Date
): IEffectifComputedStatut | null {
try {
const parcours = generateUnifiedParcours(effectif, evaluationDate);

Expand All @@ -59,7 +63,7 @@ export function createComputedStatutObject(effectif: IEffectif, evaluationDate:
{
context: "createComputedStatutObject",
evaluationDate,
effectifId: effectif._id,
effectifId: "_id" in effectif ? effectif._id : null,
errorStack: error instanceof Error ? error.stack : undefined,
}
);
Expand Down Expand Up @@ -97,7 +101,7 @@ function handleUpdateError(err: unknown, effectif: IEffectif) {
}

const generateUnifiedParcours = (
effectif: IEffectif,
effectif: IEffectif | WithoutId<IEffectifDECA>,
evaluationDate: Date
): { valeur: StatutApprenant; date: Date }[] => {
let parcours: { valeur: StatutApprenant; date: Date }[] = [];
Expand Down Expand Up @@ -139,7 +143,7 @@ function deduplicateAndSortParcours(parcours: { valeur: StatutApprenant; date: D
}

function determineStatutsByContrats(
effectif: IEffectif,
effectif: IEffectif | WithoutId<IEffectifDECA>,
evaluationDate?: Date
): { valeur: StatutApprenant; date: Date }[] {
if (!effectif.formation?.date_entree && !effectif.formation?.date_fin) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const getOrganismeIndicateursEffectifsParFormation = async (
];

const mapRNCP = indicateurs.reduce((acc, { rncp_code, ...rest }) => {
// TODO: get niveau from CFD if not found
const rncp = rncp_code ?? "null";
return acc[rncp]
? {
Expand Down
1 change: 1 addition & 0 deletions server/src/common/actions/v2/formation.v2.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const getFormationV2 = async (
organisme_responsable_id: ObjectId,
organisme_formateur_id: ObjectId
) => {
// CFD & RNCP --> tjr en uppercase
return formationV2Db().findOne({
cfd: cfd.replace(/\s/g, "").toLowerCase(),
rncp: rncp.replace(/\s/g, "").toLowerCase(),
Expand Down
Loading
Loading