From f5b122d37ab18c557b66de1616df9a025984b38c Mon Sep 17 00:00:00 2001 From: Jonathan Fallon Date: Fri, 17 Jan 2025 11:04:53 +0100 Subject: [PATCH] fix(policy): Haute Correze 2025 (#2757) --- .../20240902_haute_correze_2025.html.ts | 34 ++++ .../policies/20240902_haute_correze_2025.ts | 113 +++++++++++++ .../20240902_haute_correze_2025.unit.spec.ts | 154 ++++++++++++++++++ .../services/policy/engine/policies/index.ts | 62 +++---- 4 files changed, 333 insertions(+), 30 deletions(-) create mode 100644 api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.html.ts create mode 100644 api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts create mode 100644 api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.unit.spec.ts diff --git a/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.html.ts b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.html.ts new file mode 100644 index 000000000..bf851f62b --- /dev/null +++ b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.html.ts @@ -0,0 +1,34 @@ +export const description = ` +
+ +

+ Campagne d'incitation au covoiturage du 02 septembre 2024 au 01 septembre 2025, + toute la semaine +

+ +

Cette campagne est limitée à 10 000,00 €.

+ +

+ Les conducteurs effectuant un trajet en covoiturage d'au moins 2 km + au départ ou à l'arrivée de la CC Haute-Corrèze Communauté + sont incités selon les règles suivantes : +

+ + + +

Les restrictions suivantes seront appliquées :

+ + + +

+ La campagne est limitée à l'opérateur Blablacar Daily proposant des preuves de classe B ou C. +

+ +
`; diff --git a/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts new file mode 100644 index 000000000..6bf7a9d68 --- /dev/null +++ b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts @@ -0,0 +1,113 @@ +import { getOperatorsAt, TimestampedOperators } from "@/pdc/services/policy/engine/helpers/getOperatorsAt.ts"; +import { isOperatorClassOrThrow } from "@/pdc/services/policy/engine/helpers/isOperatorClassOrThrow.ts"; +import { isOperatorOrThrow } from "@/pdc/services/policy/engine/helpers/isOperatorOrThrow.ts"; +import { + LimitTargetEnum, + watchForGlobalMaxAmount, + watchForPersonMaxAmountByMonth, + watchForPersonMaxTripByDay, +} from "@/pdc/services/policy/engine/helpers/limits.ts"; +import { onDistanceRange, onDistanceRangeOrThrow } from "@/pdc/services/policy/engine/helpers/onDistanceRange.ts"; +import { perKm, perSeat } from "@/pdc/services/policy/engine/helpers/per.ts"; +import { startsOrEndsAtOrThrow } from "@/pdc/services/policy/engine/helpers/startsOrEndsAtOrThrow.ts"; +import { description } from "@/pdc/services/policy/engine/policies/20240902_haute_correze_2025.html.ts"; +import { AbstractPolicyHandler } from "@/pdc/services/policy/engine/policies/AbstractPolicyHandler.ts"; +import { RunnableSlices } from "@/pdc/services/policy/interfaces/engine/PolicyInterface.ts"; +import { + OperatorsEnum, + PolicyHandlerInterface, + PolicyHandlerParamsInterface, + PolicyHandlerStaticInterface, + StatelessContextInterface, +} from "@/pdc/services/policy/interfaces/index.ts"; + +/* eslint-disable-next-line */ +export const HauteCorreze2025: PolicyHandlerStaticInterface = class extends AbstractPolicyHandler + implements PolicyHandlerInterface { + static readonly id = "haute_correze_2025"; + + protected operators: TimestampedOperators = [ + { + date: new Date("2024-09-02T00:00:00+0200"), + operators: [OperatorsEnum.BLABLACAR_DAILY], + }, + ]; + + // 7 cts per km per passenger + protected slices: RunnableSlices = [ + { + start: 2_000, + end: 15_000, + fn: (ctx: StatelessContextInterface) => perSeat(ctx, 1_50), + }, + { + start: 15_000, + end: 30_000, + fn: (ctx: StatelessContextInterface) => perSeat(ctx, perKm(ctx, { amount: 10, offset: 15_000, limit: 30_000 })), + }, + { + start: 30_000, + end: 80_001, + fn: (_ctx: StatelessContextInterface) => 0, + }, + ]; + + constructor(public max_amount: number) { + super(); + this.limits = [ + [ + "17a34876-97dc-409e-a45a-eb1c1a7f9924", + max_amount, + watchForGlobalMaxAmount, + ], + [ + "23ad0e0c-6805-41ae-915d-bcc566486bb6", + 6, + watchForPersonMaxTripByDay, + LimitTargetEnum.Driver, + ], + [ + "4437e7aa-efe6-4eb8-b844-3139819f8fcf", + 150_00, + watchForPersonMaxAmountByMonth, + LimitTargetEnum.Driver, + ], + ]; + } + + protected processExclusion(ctx: StatelessContextInterface) { + isOperatorOrThrow(ctx, getOperatorsAt(this.operators, ctx.carpool.datetime)); + onDistanceRangeOrThrow(ctx, { min: 2_000, max: 80_001 }); + isOperatorClassOrThrow(ctx, ["B", "C"]); + startsOrEndsAtOrThrow(ctx, { aom: ["200066744"] }); + } + + processStateless(ctx: StatelessContextInterface): void { + this.processExclusion(ctx); + super.processStateless(ctx); + + let amount = 0; + for (const { start, fn } of this.slices) { + if (onDistanceRange(ctx, { min: start })) { + amount += fn(ctx); + } + } + + ctx.incentive.set(amount); + } + + params(): PolicyHandlerParamsInterface { + return { + tz: "Europe/Paris", + slices: this.slices, + operators: getOperatorsAt(this.operators), + limits: { + glob: this.max_amount, + }, + }; + } + + describe(): string { + return description; + } +}; diff --git a/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.unit.spec.ts b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.unit.spec.ts new file mode 100644 index 000000000..712585d26 --- /dev/null +++ b/api/src/pdc/services/policy/engine/policies/20240902_haute_correze_2025.unit.spec.ts @@ -0,0 +1,154 @@ +import { it } from "@/dev_deps.ts"; +import { v4 as uuidV4 } from "@/lib/uuid/index.ts"; +import { HauteCorreze2025 as Handler } from "@/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts"; +import { makeProcessHelper } from "@/pdc/services/policy/engine/tests/macro.ts"; +import { OperatorsEnum } from "@/pdc/services/policy/interfaces/index.ts"; + +const defaultPosition = { + arr: "19139", + com: "19139", + aom: "200066744", + epci: "200066744", + dep: "19", + reg: "75", + country: "XXXXX", + reseau: "73", +}; +const defaultLat = 45.54858380899173; +const defaultLon = 2.3146017323921195; + +const defaultCarpool = { + _id: 1, + operator_trip_id: uuidV4(), + passenger_identity_key: uuidV4(), + driver_identity_key: uuidV4(), + operator_uuid: OperatorsEnum.BLABLACAR_DAILY, + operator_class: "C", + passenger_is_over_18: true, + passenger_has_travel_pass: true, + driver_has_travel_pass: true, + datetime: new Date("2024-11-01"), + seats: 1, + distance: 5_000, + operator_journey_id: uuidV4(), + operator_id: 1, + driver_revenue: 20, + passenger_contribution: 20, + start: { ...defaultPosition }, + end: { ...defaultPosition }, + start_lat: defaultLat, + start_lon: defaultLon, + end_lat: 45.53725299731382, + end_lon: 2.3059201226861297, +}; + +const process = makeProcessHelper(defaultCarpool); + +it("should work with exclusions", async () => + await process( + { + policy: { handler: Handler.id }, + carpool: [ + { operator_uuid: "not in list" }, + { operator_uuid: OperatorsEnum.KLAXIT }, + { distance: 100 }, + { distance: 90_000 }, + { operator_class: "A" }, + ], + meta: [], + }, + { incentive: [0, 0, 0, 0, 0], meta: [] }, + )); + +it("should work basic with start/end inside aom", async () => + await process( + { + policy: { handler: Handler.id }, + carpool: [ + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, seats: 2, driver_identity_key: "one" }, + { distance: 25_000, driver_identity_key: "two" }, + { distance: 25_000, seats: 2, driver_identity_key: "two" }, + { distance: 80_000, driver_identity_key: "marcel" }, + ], + meta: [], + }, + { + incentive: [150, 300, 250, 500, 300], + meta: [ + { + key: "max_amount_restriction.global.campaign.global", + value: 1500, + }, + { + key: "max_amount_restriction.0-one.month.10-2024", + value: 450, + }, + { + key: "max_amount_restriction.0-two.month.10-2024", + value: 750, + }, + { + key: "max_amount_restriction.0-marcel.month.10-2024", + value: 300, + }, + ], + }, + )); + +it("should work with global limits", async () => + await process( + { + policy: { handler: Handler.id, max_amount: 15_000_00 }, + carpool: [{ distance: 79_000, driver_identity_key: "one" }], + meta: [ + { + key: "max_amount_restriction.global.campaign.global", + value: 14_999_99, + }, + ], + }, + { + incentive: [1], // <-- should be 250. capped to 1 + meta: [ + { + key: "max_amount_restriction.global.campaign.global", + value: 15_000_00, + }, + { + key: "max_amount_restriction.0-one.month.10-2024", + value: 300, + }, + ], + }, + )); + +it("should work with 6 trips per day limit", async () => + await process( + { + policy: { handler: Handler.id }, + carpool: [ + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, + { distance: 5_000, driver_identity_key: "one" }, // too many + ], + meta: [], + }, + { + incentive: [150, 150, 150, 150, 150, 150, 0], + meta: [ + { + key: "max_amount_restriction.global.campaign.global", + value: 900, + }, + { + key: "max_amount_restriction.0-one.month.10-2024", + value: 900, + }, + ], + }, + )); diff --git a/api/src/pdc/services/policy/engine/policies/index.ts b/api/src/pdc/services/policy/engine/policies/index.ts index 79591a0e8..1829bf4ed 100644 --- a/api/src/pdc/services/policy/engine/policies/index.ts +++ b/api/src/pdc/services/policy/engine/policies/index.ts @@ -1,44 +1,45 @@ -import { PaysDeLaLoire2021 } from "@/pdc/services/policy/engine/policies/20210105_PaysDeLaLoire.ts"; +import { ATMB202305 } from "@/pdc/services/policy/engine/policies/20230502_ATMB.ts"; +import { Cannes2024 } from "@/pdc/services/policy/engine/policies/20240101_Cannes.ts"; +import { CCPOA202410 } from "@/pdc/services/policy/engine/policies/20241015_CCPOA_orthe_et_arrigans_2024.ts"; +import { CCVMM202405 } from "@/pdc/services/policy/engine/policies/20240805_CCVMM_2024_05.ts"; +import { Cotentin2023 } from "@/pdc/services/policy/engine/policies/20230101_Cotentin.ts"; +import { GrandChatellerault2024 } from "@/pdc/services/policy/engine/policies/20240201_GrandChatellerault.ts"; +import { GrandPoitiers } from "@/pdc/services/policy/engine/policies/20230927_GrandPoitiers.ts"; +import { GrandPoitiers2025 } from "@/pdc/services/policy/engine/policies/20250101_GrandPoitiers2025.ts"; +import { HauteCorreze2025 } from "@/pdc/services/policy/engine/policies/20240902_haute_correze_2025.ts"; import { IDFMPeriodeNormale2021 } from "@/pdc/services/policy/engine/policies/20210520_IDFM.ts"; -import { NantesMetropoleXPCovoitan2021 } from "@/pdc/services/policy/engine/policies/20211202_NantesMetropoleXP.ts"; +import { Lannion202305 } from "@/pdc/services/policy/engine/policies/20230501_Lannion.ts"; +import { LannionTregor2024 } from "@/pdc/services/policy/engine/policies/20240401_LannionTregor.ts"; +import { LaRochelle20232024 } from "@/pdc/services/policy/engine/policies/20230101_LaRochelle.ts"; +import { LaRochelle2024 } from "@/pdc/services/policy/engine/policies/20240101_LaRochelle.ts"; import { LavalAgglo2022 } from "@/pdc/services/policy/engine/policies/20220412_LavalAgglo.ts"; -import { SMT2022 } from "@/pdc/services/policy/engine/policies/20220414_SMT.ts"; import { MetropoleRouenNormandie2022 } from "@/pdc/services/policy/engine/policies/20220420_MetropoleRouenNormandie.ts"; -import { Occitanie20232024 } from "@/pdc/services/policy/engine/policies/20221024_Occitanie.ts"; -import { PMGF2022 } from "@/pdc/services/policy/engine/policies/20221102_PMGF.ts"; -import { Montpellier } from "@/pdc/services/policy/engine/policies/20221206_Montpellier.ts"; -import { Cotentin2023 } from "@/pdc/services/policy/engine/policies/20230101_Cotentin.ts"; -import { LaRochelle20232024 } from "@/pdc/services/policy/engine/policies/20230101_LaRochelle.ts"; -import { Vitre2023 } from "@/pdc/services/policy/engine/policies/20230101_Vitre.ts"; import { MetropoleSavoie } from "@/pdc/services/policy/engine/policies/20230124_MetropoleSavoie.ts"; -import { SMT2023 } from "@/pdc/services/policy/engine/policies/20230126_SMT.ts"; -import { PaysDeLaLoire2023 } from "@/pdc/services/policy/engine/policies/20230201_PaysDeLaLoire.ts"; -import { PaysBasque20232024 } from "@/pdc/services/policy/engine/policies/20230401_PaysBasqueAdour.ts"; -import { Lannion202305 } from "@/pdc/services/policy/engine/policies/20230501_Lannion.ts"; -import { ATMB202305 } from "@/pdc/services/policy/engine/policies/20230502_ATMB.ts"; -import { PMGF2023 } from "@/pdc/services/policy/engine/policies/20230502_PMGF.ts"; -import { GrandPoitiers } from "@/pdc/services/policy/engine/policies/20230927_GrandPoitiers.ts"; -import { PMGFOctobre2023 } from "@/pdc/services/policy/engine/policies/20231001_PMGF.ts"; -import { Cannes2024 } from "@/pdc/services/policy/engine/policies/20240101_Cannes.ts"; -import { LaRochelle2024 } from "@/pdc/services/policy/engine/policies/20240101_LaRochelle.ts"; +import { Montpellier } from "@/pdc/services/policy/engine/policies/20221206_Montpellier.ts"; import { NantesMetropole2024 } from "@/pdc/services/policy/engine/policies/20240101_NantesMetropole.ts"; +import { NantesMetropoleXPCovoitan2021 } from "@/pdc/services/policy/engine/policies/20211202_NantesMetropoleXP.ts"; +import { Occitanie20232024 } from "@/pdc/services/policy/engine/policies/20221024_Occitanie.ts"; +import { PaysBasque20232024 } from "@/pdc/services/policy/engine/policies/20230401_PaysBasqueAdour.ts"; +import { PaysDeLaLoire2021 } from "@/pdc/services/policy/engine/policies/20210105_PaysDeLaLoire.ts"; +import { PaysDeLaLoire2023 } from "@/pdc/services/policy/engine/policies/20230201_PaysDeLaLoire.ts"; import { PaysDeLaLoire2024 } from "@/pdc/services/policy/engine/policies/20240101_PaysDeLaLoire.ts"; -import { SMTC2024Passenger } from "@/pdc/services/policy/engine/policies/20240101_SMTC2024Passenger.ts"; -import { SMTC2024Driver } from "@/pdc/services/policy/engine/policies/20240101_SMTCDriver.ts"; +import { PetrLunevillois092024032025 } from "@/pdc/services/policy/engine/policies/20240902_PetrLunevillois.ts"; import { PetrLunevilloisS12023 } from "@/pdc/services/policy/engine/policies/20240108_PetrLunevillois.ts"; -import { GrandChatellerault2024 } from "@/pdc/services/policy/engine/policies/20240201_GrandChatellerault.ts"; -import { TerresTouloises2024 } from "@/pdc/services/policy/engine/policies/20240201_TerresTouloises.ts"; -import { LannionTregor2024 } from "@/pdc/services/policy/engine/policies/20240401_LannionTregor.ts"; +import { PMGF2022 } from "@/pdc/services/policy/engine/policies/20221102_PMGF.ts"; +import { PMGF2023 } from "@/pdc/services/policy/engine/policies/20230502_PMGF.ts"; +import { PMGFOctobre2023 } from "@/pdc/services/policy/engine/policies/20231001_PMGF.ts"; import { PMGFxATMB2024 } from "@/pdc/services/policy/engine/policies/20240401_PMGFxATMB.ts"; -import { CCVMM202405 } from "@/pdc/services/policy/engine/policies/20240805_CCVMM_2024_05.ts"; -import { SiouleLimagne } from "@/pdc/services/policy/engine/policies/20240901_SiouleLimagne_2024_09.ts"; -import { PetrLunevillois092024032025 } from "@/pdc/services/policy/engine/policies/20240902_PetrLunevillois.ts"; -import { CCPOA202410 } from "@/pdc/services/policy/engine/policies/20241015_CCPOA_orthe_et_arrigans_2024.ts"; -import { GrandPoitiers2025 } from "@/pdc/services/policy/engine/policies/20250101_GrandPoitiers2025.ts"; +import { PolicyHandlerStaticInterface } from "@/pdc/services/policy/interfaces/index.ts"; import { PolicyTemplateOne } from "@/pdc/services/policy/engine/policies/unbound/PolicyTemplateOne.ts"; import { PolicyTemplateThree } from "@/pdc/services/policy/engine/policies/unbound/PolicyTemplateThree.ts"; import { PolicyTemplateTwo } from "@/pdc/services/policy/engine/policies/unbound/PolicyTemplateTwo.ts"; -import { PolicyHandlerStaticInterface } from "@/pdc/services/policy/interfaces/index.ts"; +import { SiouleLimagne } from "@/pdc/services/policy/engine/policies/20240901_SiouleLimagne_2024_09.ts"; +import { SMT2022 } from "@/pdc/services/policy/engine/policies/20220414_SMT.ts"; +import { SMT2023 } from "@/pdc/services/policy/engine/policies/20230126_SMT.ts"; +import { SMTC2024Driver } from "@/pdc/services/policy/engine/policies/20240101_SMTCDriver.ts"; +import { SMTC2024Passenger } from "@/pdc/services/policy/engine/policies/20240101_SMTC2024Passenger.ts"; +import { TerresTouloises2024 } from "@/pdc/services/policy/engine/policies/20240201_TerresTouloises.ts"; +import { Vitre2023 } from "@/pdc/services/policy/engine/policies/20230101_Vitre.ts"; export const policies: Map = new Map( [ @@ -49,6 +50,7 @@ export const policies: Map = new Map( Cotentin2023, GrandChatellerault2024, GrandPoitiers, + HauteCorreze2025, GrandPoitiers2025, IDFMPeriodeNormale2021, Lannion202305,