diff --git a/packages/code-du-travail-modeles/src/modeles/common/supported-agreements.ts b/packages/code-du-travail-modeles/src/modeles/common/supported-agreements.ts index bc33b0b82a..3ce19ffcc7 100644 --- a/packages/code-du-travail-modeles/src/modeles/common/supported-agreements.ts +++ b/packages/code-du-travail-modeles/src/modeles/common/supported-agreements.ts @@ -56,7 +56,7 @@ export const INDEMNITE_LICENCIEMENT_PRODUCTION_READY_CC: number[] = [ 16, 29, 44, 413, 573, 650, 1090, 1351, 1486, 1501, 1518, 1527, 1596, 1597, 1979, 2216, 2264, 2941, 3043, 3127, 3239, 1517, 2098, 2511, 2609, 787, 843, 675, 1996, 1505, 1147, 1702, 1266, 1672, 275, 86, 2614, 2596, 1043, 1483, - 1516, 1606, 2148, 1404, 292, 2120, 3248, + 1516, 1606, 2148, 1404, 292, 2120, 3248, 176, ]; export const getSupportedAgreement = ( diff --git a/packages/code-du-travail-modeles/src/modeles/common/utils/__tests__/accumulate-absence-by-year.spec.ts b/packages/code-du-travail-modeles/src/modeles/common/utils/__tests__/accumulate-absence-by-year.spec.ts index 9f5fa23c20..ed5d6b81a6 100644 --- a/packages/code-du-travail-modeles/src/modeles/common/utils/__tests__/accumulate-absence-by-year.spec.ts +++ b/packages/code-du-travail-modeles/src/modeles/common/utils/__tests__/accumulate-absence-by-year.spec.ts @@ -15,7 +15,7 @@ describe("Accumulation d'absence par année", () => { ${[{ durationInMonth: 1, motif: { value: 1 }, startedAt: "02/06/2020" }]} | ${[{ begin: date2020, end: exitIn2020 }]} | ${[{ totalAbsenceInMonth: 1, year: 2020 }]} ${[{ durationInMonth: 1, motif: { value: 1 }, startedAt: "10/05/2020" }, { durationInMonth: 2, motif: { value: 1 }, startedAt: "10/07/2020" }]} | ${[{ begin: date2020, end: exitIn2020 }]} | ${[{ totalAbsenceInMonth: 3, year: 2020 }]} ${[{ durationInMonth: 3, motif: { value: 1 }, startedAt: "10/07/2020" }, { durationInMonth: 2, motif: { value: 1 }, startedAt: "10/04/2021" }]} | ${[{ begin: date2020, end: date2021LessOneDay }, { begin: date2021, end: exitIn2021 }]} | ${[{ totalAbsenceInMonth: 3, year: 2020 }, { totalAbsenceInMonth: 2, year: 2021 }]} - ${[{ durationInMonth: 1, motif: { value: 1 }, startedAt: "20/03/2021" }]} | ${[{ begin: date2020, end: date2021LessOneDay }, { begin: date2021, end: exitIn2021 }]} | ${[{ totalAbsenceInMonth: 0.5, year: 2020 }, { totalAbsenceInMonth: 0.4666666666666667, year: 2021 }]} + ${[{ durationInMonth: 1, motif: { value: 1 }, startedAt: "20/03/2021" }]} | ${[{ begin: date2020, end: date2021LessOneDay }, { begin: date2021, end: exitIn2021 }]} | ${[{ totalAbsenceInMonth: 0.47433264887063653, year: 2020 }, { totalAbsenceInMonth: 0.459958932238193, year: 2021 }]} `( "Avec $absences.length absence(s) et $years.length année(s) on attend $expectedOutput.length découpe(s) par année", ({ absences, years, expectedOutput }) => { diff --git a/packages/code-du-travail-modeles/src/modeles/common/utils/seniority.ts b/packages/code-du-travail-modeles/src/modeles/common/utils/seniority.ts index bd986b4b62..863d1d1b8e 100644 --- a/packages/code-du-travail-modeles/src/modeles/common/utils/seniority.ts +++ b/packages/code-du-travail-modeles/src/modeles/common/utils/seniority.ts @@ -1,15 +1,22 @@ +import type { Interval } from "date-fns"; import { add, + addMonths, areIntervalsOverlapping, - getOverlappingDaysInIntervals, + differenceInCalendarMonths, + differenceInDays, isAfter, isWithinInterval, + max, + min, parse, sub, } from "date-fns"; import type { Absence } from "../types/seniority"; +const DAYS_IN_MONTH = 30.4375; + export type YearDetail = { begin: Date; end: Date; @@ -124,14 +131,12 @@ const splitByTwelveMonthsRollingRec = ( return splitByTwelveMonthsRollingRec(absences, year, acc.concat(year)); }; -const DAYS_IN_ONE_MONTH = 30; - const absenceInYear = (absence: Absence, year: YearDetail): boolean => { if (!absence.startedAt) return false; if (!absence.durationInMonth) return false; const absenceStartAt = parse(absence.startedAt, "dd/MM/yyyy", new Date()); const absenceEndAt = add(absenceStartAt, { - days: DAYS_IN_ONE_MONTH * absence.durationInMonth, + days: DAYS_IN_MONTH * absence.durationInMonth, }); return areIntervalsOverlapping( { @@ -147,17 +152,25 @@ const absenceDurationRatio = (absence: Absence, year: YearDetail): number => { if (!absence.durationInMonth) return 0; const absenceStartAt = parse(absence.startedAt, "dd/MM/yyyy", new Date()); const absenceEndAt = add(absenceStartAt, { - days: DAYS_IN_ONE_MONTH * absence.durationInMonth, + days: DAYS_IN_MONTH * absence.durationInMonth, }); if (absenceStartAt >= year.begin && absenceEndAt <= year.end) { return absence.durationInMonth * absence.motif.value; } - return ( - (getOverlappingDaysInIntervals( - { end: absenceEndAt, start: absenceStartAt }, - { end: year.end, start: year.begin } - ) / - DAYS_IN_ONE_MONTH) * - absence.motif.value + const overlappingMonth = getOverlappingMonthsInterval( + { end: absenceEndAt, start: absenceStartAt }, + { end: year.end, start: year.begin } ); + return overlappingMonth * absence.motif.value; +}; + +const getOverlappingMonthsInterval = (r1: Interval, r2: Interval) => { + if (areIntervalsOverlapping(r1, r2)) { + const start = max([r1.start, r2.start]); + const end = min([r1.end, r2.end]); + const diffInMonths = differenceInCalendarMonths(end, start); + const startDateWithDifferenceInMonths = addMonths(start, diffInMonths); + const diffInDays = differenceInDays(end, startDateWithDifferenceInMonths); + return diffInMonths + diffInDays / DAYS_IN_MONTH; + } else return 0; }; diff --git a/packages/code-du-travail-modeles/src/modeles/conventions/1527_immobilier/__tests__/indemnite-licenciement/anciennete.spec.ts b/packages/code-du-travail-modeles/src/modeles/conventions/1527_immobilier/__tests__/indemnite-licenciement/anciennete.spec.ts index df058f0155..b688d9b9d1 100644 --- a/packages/code-du-travail-modeles/src/modeles/conventions/1527_immobilier/__tests__/indemnite-licenciement/anciennete.spec.ts +++ b/packages/code-du-travail-modeles/src/modeles/conventions/1527_immobilier/__tests__/indemnite-licenciement/anciennete.spec.ts @@ -13,7 +13,8 @@ describe("CC 1527", () => { ${[{ durationInMonth: 0, motif: { key: MotifKeys.maladieNonPro } }, { durationInMonth: 0, motif: { key: MotifKeys.accidentTrajet } }, { durationInMonth: 0, motif: { key: MotifKeys.congesSabbatique } }, { durationInMonth: 0, motif: { key: MotifKeys.congesCreationEntreprise } }, { durationInMonth: 0, motif: { key: MotifKeys.congesParentalEducation } }, { durationInMonth: 0, motif: { key: MotifKeys.congesSansSolde } }, { durationInMonth: 0, motif: { key: MotifKeys.greve } }, { durationInMonth: 0, motif: { key: MotifKeys.miseAPied } }]} | ${"20/02/2020"} | ${"20/02/2021"} | ${1} ${[{ durationInMonth: 1, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/03/2020" }]} | ${"20/02/2020"} | ${"20/02/2021"} | ${1 - 1 / 12} ${[{ durationInMonth: 0.99, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/03/2018" }, { durationInMonth: 0.5, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "06/03/2019" }, { durationInMonth: 0.8, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "08/05/2020" }]} | ${"20/02/2018"} | ${"20/02/2021"} | ${3} - ${[{ durationInMonth: 0.2, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/03/2018" }, { durationInMonth: 0.3, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/09/2018" }, { durationInMonth: 0.5, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/04/2019" }, { durationInMonth: 0.5, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "06/08/2019" }, { durationInMonth: 2, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "08/09/2020" }]} | ${"20/02/2018"} | ${"20/02/2021"} | ${3 - 3 / 12} | ${[{ durationInMonth: 1, motif: { key: MotifKeys.congesSabbatique } }]} | ${"20/01/2022"} | ${"20/02/2023"} | ${1} + ${[{ durationInMonth: 0.2, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/03/2018" }, { durationInMonth: 0.3, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/09/2018" }, { durationInMonth: 0.5, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "05/04/2019" }, { durationInMonth: 0.5, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "06/08/2019" }, { durationInMonth: 2, motif: { key: MotifKeys.congesSansSolde, value: 1 }, startedAt: "08/09/2020" }]} | ${"20/02/2018"} | ${"20/02/2021"} | ${3 - 3 / 12} + ${[{ durationInMonth: 1, motif: { key: MotifKeys.congesSabbatique } }]} | ${"20/01/2022"} | ${"20/02/2023"} | ${1} `( "$#) Calcul de l'ancienneté avec $entryDate et $exitDate en attendant $expectedAnciennete an", ({ absences, entryDate, exitDate, expectedAnciennete }) => { diff --git a/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/__tests__/indemnite-licenciement/anciennete.spec.ts b/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/__tests__/indemnite-licenciement/anciennete.spec.ts index 5e93cac058..d4d1aab5f1 100644 --- a/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/__tests__/indemnite-licenciement/anciennete.spec.ts +++ b/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/__tests__/indemnite-licenciement/anciennete.spec.ts @@ -10,8 +10,12 @@ describe("CC 176", () => { absences | entryDate | exitDate | expectedAnciennete ${[]} | ${"20/02/2020"} | ${"20/02/2021"} | ${1} ${[{ durationInMonth: 5, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "20/04/2020" }]} | ${"20/02/2020"} | ${"20/02/2021"} | ${1} - ${[{ durationInMonth: 7, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/04/2020" }]} | ${"20/02/2020"} | ${"20/02/2021"} | ${11 / 12} - ${[{ durationInMonth: 4, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/03/2020" }, { durationInMonth: 3, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/10/2020" }]} | ${"01/08/2020"} | ${"01/08/2021"} | ${11 / 12} + ${[{ durationInMonth: 7, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/03/2020" }]} | ${"20/02/2020"} | ${"20/02/2022"} | ${17 / 12} + ${[{ durationInMonth: 3, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/08/2020" }, { durationInMonth: 4, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/03/2020" }]} | ${"20/02/2020"} | ${"20/02/2022"} | ${17 / 12} + ${[{ durationInMonth: 7, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/11/2020" }]} | ${"20/02/2020"} | ${"20/02/2022"} | ${2} + ${[{ durationInMonth: 6, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/07/2021" }]} | ${"01/01/2020"} | ${"01/01/2023"} | ${3} + ${[{ durationInMonth: 7, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "01/07/2021" }]} | ${"01/01/2020"} | ${"01/01/2023"} | ${3} + ${[{ durationInMonth: 7, motif: { key: MotifKeys.maladieNonPro, value: 1 }, startedAt: "15/06/2021" }]} | ${"01/01/2020"} | ${"01/01/2023"} | ${2.4561943874058865} `( "Calcul de l'ancienneté avec $entryDate et $exitDate en attendant $expectedAnciennete an", ({ absences, entryDate, exitDate, expectedAnciennete }) => { diff --git a/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/seniority.ts b/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/seniority.ts index 05c137881b..c2bf964687 100644 --- a/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/seniority.ts +++ b/packages/code-du-travail-modeles/src/modeles/conventions/176_industrie_pharmaceutique/seniority.ts @@ -31,7 +31,10 @@ const getTotalAbsenceNonPro = ( const absencesBySeniorityYear = accumulateAbsenceByYear(absences, years); return absencesBySeniorityYear.reduce((total, item) => { - return total + Math.max(item.totalAbsenceInMonth - 6, 0); + if (item.totalAbsenceInMonth <= 6) { + return total; + } + return total + item.totalAbsenceInMonth; }, 0); };