diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..b450dbcf34d580a2d7ce598133e33273ce6eca55 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/vitest.config.ts diff --git a/package.json b/package.json index 7eac8e71eec99b87f6bcfef8b4daff2d8b1a6352..6856bcb52d6f87afb1c62a92de44548cb8b8a8e3 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "prettier --write" ], "packages/api/**/*.{graphql,md}": "prettier --write", - "packages/common/**/*.ts": [ + "packages/common/src/**/*.ts": [ "eslint --cache --fix --max-warnings=0", "prettier --write" ], diff --git a/packages/api/src/api/rest/etapes.test.integration.ts b/packages/api/src/api/rest/etapes.test.integration.ts index 1e7f8b976e88fe305211c959a76026471d39e4ea..826ab75acd9d1fbf087553e6abfa1d19a20e17f1 100644 --- a/packages/api/src/api/rest/etapes.test.integration.ts +++ b/packages/api/src/api/rest/etapes.test.integration.ts @@ -3,7 +3,7 @@ import { titreCreate } from '../../database/queries/titres' import { titreDemarcheCreate } from '../../database/queries/titres-demarches' import { userSuper } from '../../database/user-super' import { restCall, restDeleteCall } from '../../../tests/_utils/index' -import { caminoDateValidator, getCurrent, toCaminoDate } from 'camino-common/src/date' +import { caminoDateValidator, toCaminoDate } from 'camino-common/src/date' import { afterAll, beforeAll, test, expect, describe, vi } from 'vitest' import type { Pool } from 'pg' import { HTTP_STATUS } from 'camino-common/src/http' @@ -51,7 +51,7 @@ describe('getEtapesTypesEtapesStatusWithMainStep', () => { typeId: 'oct', }) - const tested = await restCall(dbPool, '/rest/etapesTypes/:demarcheId/:date', { demarcheId: titreDemarche.id, date: getCurrent() }, userSuper) + const tested = await restCall(dbPool, '/rest/etapesTypes/:demarcheId/:date', { demarcheId: titreDemarche.id, date: toCaminoDate('2024-09-01') }, userSuper) expect(tested.statusCode).toBe(HTTP_STATUS.OK) // TODO 2024-06-19 changer ce format ? @@ -141,7 +141,7 @@ describe('getEtapesTypesEtapesStatusWithMainStep', () => { titre.id ) - const tested = await restCall(dbPool, '/rest/etapesTypes/:demarcheId/:date', { demarcheId: titreDemarche.id, date: getCurrent() }, userSuper) + const tested = await restCall(dbPool, '/rest/etapesTypes/:demarcheId/:date', { demarcheId: titreDemarche.id, date: toCaminoDate('2024-09-01') }, userSuper) expect(tested.statusCode).toBe(HTTP_STATUS.OK) expect(tested.body).toMatchInlineSnapshot(` diff --git a/packages/api/src/api/rest/etapes.ts b/packages/api/src/api/rest/etapes.ts index 110a49d5766048d7e14603421e2283a1803f8138..ddfb7c830ee760cb09e5081d3e5a7ec02596bab8 100644 --- a/packages/api/src/api/rest/etapes.ts +++ b/packages/api/src/api/rest/etapes.ts @@ -28,7 +28,7 @@ import { CaminoDate, caminoDateValidator, getCurrent } from 'camino-common/src/d import { titreDemarcheGet } from '../../database/queries/titres-demarches' import { userSuper } from '../../database/user-super' import { titreEtapeGet, titreEtapeUpdate, titreEtapeUpsert } from '../../database/queries/titres-etapes' -import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions' +import { machineFind } from '../../business/rules-demarches/definitions' import { User, isBureauDEtudes, isEntreprise } from 'camino-common/src/roles' import { canCreateEtape, canDeposeEtape, canDeleteEtape, canEditEtape, canEditDates, canEditDuree } from 'camino-common/src/permissions/titres-etapes' import { TitresStatutIds } from 'camino-common/src/static/titresStatuts' @@ -1057,7 +1057,7 @@ const demarcheEtapesTypesGet = async (titreDemarcheId: DemarcheId, date: CaminoD if (titreEtapeId && !titreEtape) throw new Error("l'étape n'existe pas") - const demarcheDefinition = demarcheDefinitionFind(titre.typeId, titreDemarche.typeId, titreDemarche.etapes, titreDemarche.id) + const demarcheDefinition = machineFind(titre.typeId, titreDemarche.typeId, titreDemarche.etapes, titreDemarche.id, date) const etapesTypes: EtapeTypeEtapeStatutWithMainStep[] = getPossiblesEtapesTypes( demarcheDefinition, diff --git a/packages/api/src/api/rest/titres.ts b/packages/api/src/api/rest/titres.ts index 2a60d166e7abe85401f15abe8a137879b1f16ad6..c9d99ba77ff946fbcb65d6dce0b94677de41a0ba 100644 --- a/packages/api/src/api/rest/titres.ts +++ b/packages/api/src/api/rest/titres.ts @@ -2,7 +2,7 @@ import { titreArchive, titresGet, titreGet, titreUpsert } from '../../database/q import { HTTP_STATUS } from 'camino-common/src/http' import { ITitre } from '../../types' import { CommonTitreAdministration, editableTitreValidator, TitreLink, TitreLinks, TitreGet, titreLinksValidator, utilisateurTitreAbonneValidator } from 'camino-common/src/titres' -import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions' +import { machineFind } from '../../business/rules-demarches/definitions' import { CaminoRequest, CustomResponse } from './express-type' import { userSuper } from '../../database/user-super' import { NotNullableKeys, isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, isNullOrUndefined, onlyUnique } from 'camino-common/src/typescript-tools' @@ -138,11 +138,11 @@ export const titresAdministrations = const etapes = demarcheLaPlusRecente.etapes.map(etape => titreEtapeForMachineValidator.parse(etape)) const etapesDerniereDemarche = toMachineEtapes(etapes) derniereEtape = etapesDerniereDemarche[etapesDerniereDemarche.length - 1] - const dd = demarcheDefinitionFind(titre.typeId, demarcheLaPlusRecente.typeId, demarcheLaPlusRecente.etapes, demarcheLaPlusRecente.id) - if (dd) { + const machine = machineFind(titre.typeId, demarcheLaPlusRecente.typeId, demarcheLaPlusRecente.etapes, demarcheLaPlusRecente.id) + if (machine) { try { - enAttenteDeAdministration = dd.machine.whoIsBlocking(etapesDerniereDemarche).includes(user.administrationId) - const nextEtapes = dd.machine.possibleNextEtapes(etapesDerniereDemarche, getCurrent()) + enAttenteDeAdministration = machine.whoIsBlocking(etapesDerniereDemarche).includes(user.administrationId) + const nextEtapes = machine.possibleNextEtapes(etapesDerniereDemarche, getCurrent()) prochainesEtapes.push( ...nextEtapes .map(etape => etape.etapeTypeId) diff --git a/packages/api/src/business/processes/titres-demarches-depot-create.ts b/packages/api/src/business/processes/titres-demarches-depot-create.ts index d75c84c8eb0c9dcb4b34bb199e4bcc1359027e84..b91fe885ea5c14a9c31103c331ecb41c495f770a 100644 --- a/packages/api/src/business/processes/titres-demarches-depot-create.ts +++ b/packages/api/src/business/processes/titres-demarches-depot-create.ts @@ -5,7 +5,7 @@ import { titreDemarcheGet } from '../../database/queries/titres-demarches' import { userSuper } from '../../database/user-super' import { titreEtapeUpdateTask } from '../titre-etape-update' import { titreEtapeAdministrationsEmailsSend } from '../../api/graphql/resolvers/_titre-etape-email' -import { demarcheDefinitionFind } from '../rules-demarches/definitions' +import { machineFind } from '../rules-demarches/definitions' import { titreUrlGet } from '../utils/urls-get' import { emailsWithTemplateSend } from '../../tools/api-mailjet/emails' import { EmailTemplateId, EmailAdministration } from '../../tools/api-mailjet/types' @@ -50,7 +50,7 @@ const titreEtapeDepotConfirmationEmailsSend = async (titreDemarche: ITitreDemarc // visibleForTesting export const titreDemarcheDepotCheck = (titreDemarche: ITitreDemarche): boolean => { - const demarcheDefinition = demarcheDefinitionFind(titreDemarche.titre!.typeId, titreDemarche.typeId, titreDemarche.etapes, titreDemarche.id) + const demarcheDefinition = machineFind(titreDemarche.titre!.typeId, titreDemarche.typeId, titreDemarche.etapes, titreDemarche.id) // On peut déposer automatiquement seulement les démarches qui possèdent une machine if (!demarcheDefinition) return false if (titreDemarche.titre!.typeId === 'arm' && titreDemarche.typeId === 'oct') { diff --git a/packages/api/src/business/rules-demarches/arm/__snapshots__/oct.machine.test.ts.snap b/packages/api/src/business/rules-demarches/arm/__snapshots__/oct.machine.test.ts.snap index 464d592b8d5bd6878ff8051f0a05d444e6ae401d..f7f3caa395535ad83ac9add96e8d5adfcc0be7c2 100644 --- a/packages/api/src/business/rules-demarches/arm/__snapshots__/oct.machine.test.ts.snap +++ b/packages/api/src/business/rules-demarches/arm/__snapshots__/oct.machine.test.ts.snap @@ -1,21 +1,21 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer 2 "mfr" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2020-01-03"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer 2 "mfr" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2020-01-03"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null,"date":"2020-01-03","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer deux "des" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"des","etapeStatutId":"fai","date":"2020-01-04"}' after '["mfr_fai","mdp_fai","des_fai"]'. The event {"type":"DESISTER_PAR_LE_DEMANDEUR"} should be one of 'VALIDER_FRAIS_DE_DOSSIER']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer deux "des" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"des","etapeStatutId":"fai","date":"2020-01-04"}' after '["mfr_fai","mdp_fai","des_fai"]'. The event {"type":"DESISTER_PAR_LE_DEMANDEUR","date":"2020-01-04","status":"fai"} should be one of 'VALIDER_FRAIS_DE_DOSSIER']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une "css" après une "des" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"css","etapeStatutId":"fai","date":"2020-01-05"}' after '["mfr_fai","mdp_fai","des_fai"]'. The event {"type":"CLASSER_SANS_SUITE"} should be one of 'VALIDER_FRAIS_DE_DOSSIER']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une "css" après une "des" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"css","etapeStatutId":"fai","date":"2020-01-05"}' after '["mfr_fai","mdp_fai","des_fai"]'. The event {"type":"CLASSER_SANS_SUITE","date":"2020-01-05","status":"fai"} should be one of 'VALIDER_FRAIS_DE_DOSSIER']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une "mno" après la "aca" si le titre n’est pas mécanisé 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mnb","etapeStatutId":"fai","date":"2020-01-04"}' after '["mfr_fai","mdp_fai","pfd_fai","mcp_com","vfd_fai","mcr_fav","asc_fai","sca_fai","aca_fav"]'. The event {"type":"NOTIFIER_DEMANDEUR_AVIS_FAVORABLE_CARM"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,SIGNER_AUTORISATION_DE_RECHERCHE_MINIERE']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une "mno" après la "aca" si le titre n’est pas mécanisé 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mnb","etapeStatutId":"fai","date":"2020-01-04"}' after '["mfr_fai","mdp_fai","pfd_fai","mcp_com","vfd_fai","mcr_fav","asc_fai","sca_fai","aca_fav"]'. The event {"type":"NOTIFIER_DEMANDEUR_AVIS_FAVORABLE_CARM","date":"2020-01-04","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,SIGNER_AUTORISATION_DE_RECHERCHE_MINIERE']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "{ etapeTypeId: 'mcb', etapeStatutId: 'fai' }" si il n’existe pas d’autres étapes 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcb","etapeStatutId":"fai","date":"2020-01-01"}' after '[]'. The event {"type":"DEMANDER_COMPLEMENTS_RDE"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "{ etapeTypeId: 'mcb', etapeStatutId: 'fai' }" si il n’existe pas d’autres étapes 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcb","etapeStatutId":"fai","date":"2020-01-01"}' after '[]'. The event {"type":"DEMANDER_COMPLEMENTS_RDE","date":"2020-01-01","status":"fai"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "{ etapeTypeId: 'mcd', etapeStatutId: 'fai' }" si il n’existe pas d’autres étapes 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcd","etapeStatutId":"fai","date":"2020-01-01"}' after '[]'. The event {"type":"DEMANDER_COMPLEMENTS_DAE"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "{ etapeTypeId: 'mcd', etapeStatutId: 'fai' }" si il n’existe pas d’autres étapes 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcd","etapeStatutId":"fai","date":"2020-01-01"}' after '[]'. The event {"type":"DEMANDER_COMPLEMENTS_DAE","date":"2020-01-01","status":"fai"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "mcp" sans "mdp" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcp","etapeStatutId":"com","date":"2022-04-16"}' after '["mfr_fai"]'. The event {"type":"ACCEPTER_COMPLETUDE"} should be one of 'DEPOSER_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas créer une étape "mcp" sans "mdp" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mcp","etapeStatutId":"com","date":"2022-04-16"}' after '["mfr_fai"]'. The event {"type":"ACCEPTER_COMPLETUDE","date":"2022-04-16","status":"com"} should be one of 'DEPOSER_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas déplacer une étape "mdp" sans "mfr" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2020-02-02"}' after '[]'. The event {"type":"DEPOSER_DEMANDE"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas déplacer une étape "mdp" sans "mfr" 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2020-02-02"}' after '[]'. The event {"type":"DEPOSER_DEMANDE","date":"2020-02-02","status":"fai"} should be one of 'ACCEPTER_RDE,DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas faire de mfr non mécanisée après une dae 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2021-02-25","contenu":{"arm":{"mecanise":false}}}' after '["dae_exe"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null} should be one of 'ACCEPTER_RDE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas faire de mfr non mécanisée après une dae 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2021-02-25","contenu":{"arm":{"mecanise":false}}}' after '["dae_exe"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null,"date":"2021-02-25","status":"fai"} should be one of 'ACCEPTER_RDE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER,REFUSER_RDE']`; -exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas faire de mfr non mécanisée après une rde 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2021-02-25","contenu":{"arm":{"mecanise":false}}}' after '["rde_fav"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null} should be one of 'DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; +exports[`vérifie l’arbre d’octroi d’ARM > ne peut pas faire de mfr non mécanisée après une rde 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2021-02-25","contenu":{"arm":{"mecanise":false}}}' after '["rde_fav"]'. The event {"type":"FAIRE_DEMANDE","mecanise":false,"franchissements":null,"date":"2021-02-25","status":"fai"} should be one of 'DEMANDER_MODIFICATION_DE_LA_DEMANDE,EXEMPTER_DAE,FAIRE_DEMANDE,PAYER_FRAIS_DE_DOSSIER']`; diff --git a/packages/api/src/business/rules-demarches/arm/oct.machine.test.ts b/packages/api/src/business/rules-demarches/arm/oct.machine.test.ts index 45902dad16b40bf6d162a5092e5006fbba76ffb4..bb9fe1266236725430cab5afaab63c583acb85ef 100644 --- a/packages/api/src/business/rules-demarches/arm/oct.machine.test.ts +++ b/packages/api/src/business/rules-demarches/arm/oct.machine.test.ts @@ -95,7 +95,7 @@ describe('vérifie l’arbre d’octroi d’ARM', () => { ETES.saisineDeLaCommissionDesAutorisationsDeRecherchesMinieres_CARM_.FAIT, ]) ).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"sca","etapeStatutId":"fai","date":"2023-10-03"}' after '["pfd_fai","mfr_fai","mdp_fai","mcp_com","vfd_fai","mcr_fav"]'. The event {"type":"FAIRE_SAISINE_CARM"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_EXPERTISE_SERVICE_EAU,RECEVOIR_EXPERTISE_SERVICE_MINES,RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"sca","etapeStatutId":"fai","date":"2023-10-03"}' after '["pfd_fai","mfr_fai","mdp_fai","mcp_com","vfd_fai","mcr_fav"]'. The event {"type":"FAIRE_SAISINE_CARM","date":"2023-10-03","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_EXPERTISE_SERVICE_EAU,RECEVOIR_EXPERTISE_SERVICE_MINES,RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES']` ) }) test('la demande ne peut pas être effectuée après une modification de la demande', () => { diff --git a/packages/api/src/business/rules-demarches/arm/oct.machine.ts b/packages/api/src/business/rules-demarches/arm/oct.machine.ts index d7d69033cf011be421453cf5b077f1b97b531e05..af45e71cf3ca4ecc52aff2d6cab3a15bf82444f5 100644 --- a/packages/api/src/business/rules-demarches/arm/oct.machine.ts +++ b/packages/api/src/business/rules-demarches/arm/oct.machine.ts @@ -178,15 +178,12 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { NOTIFIER_AVENANT_ARM: { db: EtapesTypesEtapesStatuts.notificationAuDemandeur_SignatureDeLavenantALautorisationDeRechercheMiniere_, mainStep: false }, } as const -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - export class ArmOctMachine extends CaminoMachine<OctARMContext, XStateEvent> { constructor() { super(armOctMachine, trad) } - caminoXStateEventToEtapes(event: XStateEvent): (Omit<Etape, 'date'> & { mainStep: boolean })[] { + override caminoXStateEventToEtapes(event: XStateEvent): (Omit<Etape, 'date' | 'titreTypeId' | 'demarcheTypeId'> & { mainStep: boolean })[] { const dbEtat: DBEtat = trad[event.type].db let contenu: IContenu | undefined switch (event.type) { @@ -214,49 +211,36 @@ export class ArmOctMachine extends CaminoMachine<OctARMContext, XStateEvent> { })) } - eventFrom(etape: Etape): XStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - switch (eventFromEntry) { - case 'FAIRE_DEMANDE': { - let mecanise = false - let franchissements = null - if (typeof etape.contenu?.arm?.mecanise === 'boolean') { - mecanise = etape.contenu?.arm.mecanise - } - if (typeof etape.contenu?.arm?.franchissements === 'number') { - franchissements = etape.contenu?.arm?.franchissements - } - - return { type: eventFromEntry, mecanise, franchissements } + override eventFromEntry(eventFromEntry: XStateEvent['type'], etape: Etape): XStateEvent { + switch (eventFromEntry) { + case 'FAIRE_DEMANDE': { + let mecanise = false + let franchissements = null + if (typeof etape.contenu?.arm?.mecanise === 'boolean') { + mecanise = etape.contenu?.arm.mecanise + } + if (typeof etape.contenu?.arm?.franchissements === 'number') { + franchissements = etape.contenu?.arm?.franchissements } - case 'ACCEPTER_RDE': - case 'REFUSER_RDE': - case 'RECEVOIR_COMPLEMENTS_RDE': { - let franchissements = null - if (typeof etape.contenu?.arm?.franchissements === 'number') { - franchissements = etape.contenu?.arm?.franchissements - } - - return { type: eventFromEntry, franchissements } + + return { type: eventFromEntry, mecanise, franchissements } + } + case 'ACCEPTER_RDE': + case 'REFUSER_RDE': + case 'RECEVOIR_COMPLEMENTS_RDE': { + let franchissements = null + if (typeof etape.contenu?.arm?.franchissements === 'number') { + franchissements = etape.contenu?.arm?.franchissements } - default: - // related to https://github.com/microsoft/TypeScript/issues/46497 https://github.com/microsoft/TypeScript/issues/40803 :( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { type: eventFromEntry } + + return { type: eventFromEntry, franchissements } } + default: + return super.eventFromEntry(eventFromEntry, etape) } - throw new Error(`no event from ${JSON.stringify(etape)}`) } - toPotentialCaminoXStateEvent(event: XStateEvent['type'], _date: CaminoDate): XStateEvent[] { + override toPotentialCaminoXStateEvent(event: XStateEvent['type'], _date: CaminoDate): XStateEvent[] { switch (event) { case 'FAIRE_DEMANDE': { return [ diff --git a/packages/api/src/business/rules-demarches/arm/ren-pro.machine.test.ts b/packages/api/src/business/rules-demarches/arm/ren-pro.machine.test.ts index 09731f27de9cdc9c882cc3cdcc487837b2ec2c51..0c3a6b314cf2c3ba545c35197576d72c17ebc121 100644 --- a/packages/api/src/business/rules-demarches/arm/ren-pro.machine.test.ts +++ b/packages/api/src/business/rules-demarches/arm/ren-pro.machine.test.ts @@ -17,7 +17,7 @@ describe('vérifie l’arbre de renonciation et de prolongation d’ARM', () => expect(() => setDateAndOrderAndInterpretMachine(armRenProMachine, '2020-05-26', [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.recevabiliteDeLaDemande.FAVORABLE, ETES.modificationDeLaDemande.FAIT]) ).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"mod","etapeStatutId":"fai","date":"2020-05-30"}' after '["mfr_fai","mdp_fai","mcr_fav"]'. The event {"type":"RECEVOIR_MODIFICATION_DE_LA_DEMANDE"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"mod","etapeStatutId":"fai","date":"2020-05-30"}' after '["mfr_fai","mdp_fai","mcr_fav"]'. The event {"type":"RECEVOIR_MODIFICATION_DE_LA_DEMANDE","date":"2020-05-30","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DESISTER_PAR_LE_DEMANDEUR,RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES']` ) }) @@ -31,7 +31,7 @@ describe('vérifie l’arbre de renonciation et de prolongation d’ARM', () => // {...ETES.recevabiliteDeLaDemande.DEFAVORABLE, date: toCaminoDate('2020-05-30') }, ]) ).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"mca","etapeStatutId":"fai","date":"2020-05-31"}' after '["mfr_fai","mdp_fai","mca_fai"]'. The event {"type":"DEMANDER_COMPLEMENTS_POUR_RECEVABILITE"} should be one of 'DESISTER_PAR_LE_DEMANDEUR,FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE,FAIRE_RECEVABILITE_DEMANDE_FAVORABLE,RECEVOIR_COMPLEMENTS_POUR_RECEVABILITE']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"mca","etapeStatutId":"fai","date":"2020-05-31"}' after '["mfr_fai","mdp_fai","mca_fai"]'. The event {"type":"DEMANDER_COMPLEMENTS_POUR_RECEVABILITE","date":"2020-05-31","status":"fai"} should be one of 'DESISTER_PAR_LE_DEMANDEUR,FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE,FAIRE_RECEVABILITE_DEMANDE_FAVORABLE,RECEVOIR_COMPLEMENTS_POUR_RECEVABILITE']` ) }) diff --git a/packages/api/src/business/rules-demarches/arm/ren-pro.machine.ts b/packages/api/src/business/rules-demarches/arm/ren-pro.machine.ts index f2009fb4f6102ca627dbeaa73bf85d540dd9478e..da8edff1ff9e8b192626244d180d118742eb3b77 100644 --- a/packages/api/src/business/rules-demarches/arm/ren-pro.machine.ts +++ b/packages/api/src/business/rules-demarches/arm/ren-pro.machine.ts @@ -1,7 +1,7 @@ import { assign, createMachine } from 'xstate' import { EtapesTypesEtapesStatuts } from 'camino-common/src/static/etapesTypesEtapesStatuts' import { CaminoMachine } from '../machine-helper' -import { CaminoCommonContext, DBEtat, Etape } from '../machine-common' +import { CaminoCommonContext, DBEtat } from '../machine-common' import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' type XStateEvent = @@ -48,31 +48,10 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { NOTIFIER_DEMANDEUR_APRES_CLASSEMENT_SANS_SUITE: { db: EtapesTypesEtapesStatuts.notificationAuDemandeur_ClassementSansSuite_, mainStep: true }, } as const -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - export class ArmRenProMachine extends CaminoMachine<CaminoCommonContext, XStateEvent> { constructor() { super(armRenProMachine, trad) } - - eventFrom(etape: Etape): XStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - - // related to https://github.com/microsoft/TypeScript/issues/46497 https://github.com/microsoft/TypeScript/issues/40803 :( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { type: eventFromEntry } - } - throw new Error(`no event from ${JSON.stringify(etape)}`) - } } const armRenProMachine = createMachine({ diff --git a/packages/api/src/business/rules-demarches/axm/__snapshots__/oct.machine.test.ts.snap b/packages/api/src/business/rules-demarches/axm/__snapshots__/oct.machine.test.ts.snap index f41eebd830c843abf862c1f7d9b3fb21e5b949ca..12c23804ac77d81a871c6a3069b1cdee6c2ddd1d 100644 --- a/packages/api/src/business/rules-demarches/axm/__snapshots__/oct.machine.test.ts.snap +++ b/packages/api/src/business/rules-demarches/axm/__snapshots__/oct.machine.test.ts.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`vérifie l’arbre d’octroi d’AXM > ne peut pas faire deux fois la même étape à la même date 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2022-04-01"}' after '["mfr_fai"]'. The event {"type":"FAIRE_DEMANDE"} should be one of 'FAIRE_DESISTEMENT_DEMANDEUR,RENDRE_DAE_EXEMPTEE,RENDRE_DAE_REQUISE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_DEFAVORABLE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_FAVORABLE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_FAVORABLE_AVEC_RESERVE']`; +exports[`vérifie l’arbre d’octroi d’AXM > ne peut pas faire deux fois la même étape à la même date 1`] = `[Error: Error: cannot execute step: '{"etapeTypeId":"mfr","etapeStatutId":"fai","date":"2022-04-01"}' after '["mfr_fai"]'. The event {"type":"FAIRE_DEMANDE","date":"2022-04-01","status":"fai"} should be one of 'FAIRE_DESISTEMENT_DEMANDEUR,RENDRE_DAE_EXEMPTEE,RENDRE_DAE_REQUISE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_DEFAVORABLE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_FAVORABLE,RENDRE_DECISION_DU_PROPRIETAIRE_DU_SOL_FAVORABLE_AVEC_RESERVE']`; diff --git a/packages/api/src/business/rules-demarches/axm/oct.machine.ts b/packages/api/src/business/rules-demarches/axm/oct.machine.ts index 7f8d9e52eb49c84e08c7d977b21f6f61389a1d30..64b420407927f8da2149b5da72d54dbb00e373a3 100644 --- a/packages/api/src/business/rules-demarches/axm/oct.machine.ts +++ b/packages/api/src/business/rules-demarches/axm/oct.machine.ts @@ -1,6 +1,6 @@ import { assign, createMachine } from 'xstate' import { CaminoMachine } from '../machine-helper' -import { CaminoCommonContext, DBEtat, Etape, tags } from '../machine-common' +import { CaminoCommonContext, DBEtat, tags } from '../machine-common' import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts' import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' import { ADMINISTRATION_IDS } from 'camino-common/src/static/administrations' @@ -150,16 +150,13 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { FAIRE_CLASSEMENT_SANS_SUITE: { db: ETES.classementSansSuite, mainStep: false }, } -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - // basé sur https://cacoo.com/diagrams/iUPEVBYNBjsiirfE/249D0 export class AxmOctMachine extends CaminoMachine<AxmContext, AXMOctXStateEvent> { constructor() { super(axmOctMachine, trad) } - toPotentialCaminoXStateEvent(event: AXMOctXStateEvent['type'], date: CaminoDate): AXMOctXStateEvent[] { + override toPotentialCaminoXStateEvent(event: AXMOctXStateEvent['type'], date: CaminoDate): AXMOctXStateEvent[] { switch (event) { case 'RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES': case 'RENDRE_AVIS_DREAL': @@ -171,30 +168,6 @@ export class AxmOctMachine extends CaminoMachine<AxmContext, AXMOctXStateEvent> return [{ type: event }] } } - - eventFrom(etape: Etape): AXMOctXStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - switch (eventFromEntry) { - case 'RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES': - case 'RENDRE_AVIS_DREAL': { - return { type: eventFromEntry, date: etape.date } - } - default: - // related to https://github.com/microsoft/TypeScript/issues/46497 https://github.com/microsoft/TypeScript/issues/40803 :( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { type: eventFromEntry } - } - } - throw new Error(`no event from ${JSON.stringify(etape)}`) - } } type RendreAvisDesServicesEtCommissonsConsultatives = { faite: false } | { faite: true; date: CaminoDate } diff --git a/packages/api/src/business/rules-demarches/axm/pro.machine.ts b/packages/api/src/business/rules-demarches/axm/pro.machine.ts index 50d99c9c71c914d1cfe7f122bf3fc4ee8173beba..e8bea2ce3aede69aec74d9b136604249c17f8b7c 100644 --- a/packages/api/src/business/rules-demarches/axm/pro.machine.ts +++ b/packages/api/src/business/rules-demarches/axm/pro.machine.ts @@ -1,6 +1,6 @@ import { assign, createMachine } from 'xstate' import { CaminoMachine } from '../machine-helper' -import { CaminoCommonContext, DBEtat, Etape, tags } from '../machine-common' +import { CaminoCommonContext, DBEtat, tags } from '../machine-common' import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts' import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' import { ADMINISTRATION_IDS } from 'camino-common/src/static/administrations' @@ -119,9 +119,6 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { }, } -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - // basé sur TODO 2023-04-17 mettre le lien vers le bon cacoo // TODO 2023-04-17 mettre à jour le cacoo quand on a de nouveau accès avec : // - modification de la demande comme pour l'octroi d'AXM @@ -130,7 +127,7 @@ export class AxmProMachine extends CaminoMachine<AxmProContext, AXMProXStateEven super(axmProMachine, trad) } - toPotentialCaminoXStateEvent(event: AXMProXStateEvent['type'], date: CaminoDate): AXMProXStateEvent[] { + override toPotentialCaminoXStateEvent(event: AXMProXStateEvent['type'], date: CaminoDate): AXMProXStateEvent[] { switch (event) { case 'RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES': case 'RENDRE_AVIS_DREAL': @@ -142,30 +139,6 @@ export class AxmProMachine extends CaminoMachine<AxmProContext, AXMProXStateEven return [{ type: event }] } } - - eventFrom(etape: Etape): AXMProXStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - switch (eventFromEntry) { - case 'RENDRE_AVIS_DES_SERVICES_ET_COMMISSIONS_CONSULTATIVES': - case 'RENDRE_AVIS_DREAL': { - return { type: eventFromEntry, date: etape.date } - } - default: - // related to https://github.com/microsoft/TypeScript/issues/46497 https://github.com/microsoft/TypeScript/issues/40803 :( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { type: eventFromEntry } - } - } - throw new Error(`no event from ${JSON.stringify(etape)}`) - } } type AvisDesServicesEtCommissionsConsultatives = { faite: false } | { faite: true; date: CaminoDate } diff --git a/packages/api/src/business/rules-demarches/definitions.test.ts b/packages/api/src/business/rules-demarches/definitions.test.ts index 7f82b93bc778b71eadb7c9bd1e0593923da7680f..dabf58e84d4712f110333a25f8e80c44a259d4c7 100644 --- a/packages/api/src/business/rules-demarches/definitions.test.ts +++ b/packages/api/src/business/rules-demarches/definitions.test.ts @@ -1,24 +1,24 @@ import { test, expect } from 'vitest' -import { demarcheDefinitionFind } from './definitions' +import { machineFind } from './definitions' import { toCaminoDate } from 'camino-common/src/date' import { newDemarcheId } from '../../database/models/_format/id-create' test('demarcheDefinitionFind retourne une machine', () => { - expect(demarcheDefinitionFind('prm', 'oct', [{ date: toCaminoDate('2023-06-07'), typeId: 'mdp' }], newDemarcheId('demarcheId'))).not.toBe(undefined) + expect(machineFind('prm', 'oct', [{ date: toCaminoDate('2023-06-07'), typeId: 'mdp' }], newDemarcheId('demarcheId'))).not.toBe(undefined) }) test("demarcheDefinitionFind retourne une machine quand il n'y a pas d'étape", () => { - expect(demarcheDefinitionFind('prm', 'oct', [], newDemarcheId('demarcheId'))).not.toBe(undefined) + expect(machineFind('prm', 'oct', [], newDemarcheId('demarcheId'))).not.toBe(undefined) }) test('demarcheDefinitionFind ne retourne pas une machine quand la démarche fait partie des exceptions', () => { - expect(demarcheDefinitionFind('prm', 'oct', [{ date: toCaminoDate('2023-06-07'), typeId: 'mdp' }], newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'))).toBe(undefined) + expect(machineFind('prm', 'oct', [{ date: toCaminoDate('2023-06-07'), typeId: 'mdp' }], newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'))).toBe(undefined) }) test('demarcheDefinitionFind ne retourne pas une machine quand les étapes sont trop anciennes', () => { - expect(demarcheDefinitionFind('prm', 'oct', [{ date: toCaminoDate('2010-06-07'), typeId: 'mdp' }], newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'))).toBe(undefined) + expect(machineFind('prm', 'oct', [{ date: toCaminoDate('2010-06-07'), typeId: 'mdp' }], newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'))).toBe(undefined) }) test('demarcheDefinitionFind', () => { - expect(demarcheDefinitionFind('arm', 'pro', [{ date: toCaminoDate('2018-10-22'), typeId: 'def' }], newDemarcheId('Anything'))).toBe(undefined) + expect(machineFind('arm', 'pro', [{ date: toCaminoDate('2018-10-22'), typeId: 'def' }], newDemarcheId('Anything'))).toBe(undefined) }) diff --git a/packages/api/src/business/rules-demarches/definitions.ts b/packages/api/src/business/rules-demarches/definitions.ts index 3a06b933853fccb30a5fcf6132995c3282e39ae3..99e9ec70c6db1425bb9f7aa8b8cd5cf88b851502 100644 --- a/packages/api/src/business/rules-demarches/definitions.ts +++ b/packages/api/src/business/rules-demarches/definitions.ts @@ -13,15 +13,14 @@ import { ArmRenProMachine } from './arm/ren-pro.machine' import { PrmOctMachine } from './prm/oct.machine' import { DeepReadonly, NonEmptyArray, isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, isNullOrUndefinedOrEmpty } from 'camino-common/src/typescript-tools' import { ProcedureSimplifieeMachine } from './procedure-simplifiee/ps.machine' +import { ProcedureSpecifiqueMachine } from './procedure-specifique/procedure-specifique.machine' -interface DemarcheDefinitionCommon { +interface DemarcheDefinition { titreTypeIds: NonEmptyArray<TitreTypeId> demarcheTypeIds: DemarcheTypeId[] dateDebut: CaminoDate demarcheIdExceptions: DemarcheId[] -} -export interface DemarcheDefinition extends DemarcheDefinitionCommon { - machine: CaminoMachines + machine: (titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId) => CaminoMachines } const allDemarcheNotTravaux = Object.values(DEMARCHES_TYPES_IDS).filter(demarcheTypeId => !DemarchesTypes[demarcheTypeId].travaux) const demarcheTypeIdsCxPr_G: DemarcheTypeId[] = [ @@ -43,21 +42,21 @@ export const demarchesDefinitions = [ { titreTypeIds: ['arm'], demarcheTypeIds: ['oct'], - machine: new ArmOctMachine(), + machine: () => new ArmOctMachine(), dateDebut: toCaminoDate('2019-10-31'), demarcheIdExceptions: [], }, { titreTypeIds: ['arm'], demarcheTypeIds: ['ren', 'pro'], - machine: new ArmRenProMachine(), + machine: () => new ArmRenProMachine(), dateDebut: toCaminoDate('2019-10-31'), demarcheIdExceptions: [], }, { titreTypeIds: ['prm'], demarcheTypeIds: ['oct'], - machine: new PrmOctMachine(), + machine: () => new PrmOctMachine(), dateDebut: toCaminoDate('2019-10-31'), demarcheIdExceptions: [ newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'), @@ -71,7 +70,7 @@ export const demarchesDefinitions = [ { titreTypeIds: ['axm'], demarcheTypeIds: ['oct'], - machine: new AxmOctMachine(), + machine: () => new AxmOctMachine(), // https://camino.beta.gouv.fr/titres/m-ax-crique-tumuc-humac-2020 dateDebut: toCaminoDate('2020-09-30'), demarcheIdExceptions: [ @@ -84,7 +83,7 @@ export const demarchesDefinitions = [ { titreTypeIds: ['axm'], demarcheTypeIds: ['pro'], - machine: new AxmProMachine(), + machine: () => new AxmProMachine(), dateDebut: toCaminoDate('2000-01-01'), demarcheIdExceptions: [ // Complète mais ne respectant pas le cacoo @@ -110,26 +109,43 @@ export const demarchesDefinitions = [ { titreTypeIds: ['pxg', 'arg', 'cxr', 'inr', 'prr', 'pxr', 'cxf', 'prf', 'pxf', 'arc', 'apc', 'pcc'], demarcheTypeIds: allDemarcheNotTravaux, - machine: new ProcedureSimplifieeMachine(), + machine: () => new ProcedureSimplifieeMachine(), dateDebut: plusVieilleDateEnBase, demarcheIdExceptions: [], }, { titreTypeIds: ['cxg', 'prg', 'cxs', 'prs', 'aph', 'cxh', 'prh', 'pxh'], demarcheTypeIds: demarcheTypeIdsCxPr_G, - machine: new ProcedureSimplifieeMachine(), + machine: () => new ProcedureSimplifieeMachine(), dateDebut: plusVieilleDateEnBase, demarcheIdExceptions: [], }, + { + titreTypeIds: ['arm', 'arc', 'axm', 'cxg', 'cxw', 'cxh', 'cxm', 'cxs', 'pcc', 'prg', 'prw', 'prh', 'prm', 'prs'], + demarcheTypeIds: [ + DEMARCHES_TYPES_IDS.Octroi, + DEMARCHES_TYPES_IDS.Prolongation, + DEMARCHES_TYPES_IDS.Prolongation1, + DEMARCHES_TYPES_IDS.Prolongation2, + DEMARCHES_TYPES_IDS.ProlongationExceptionnelle, + DEMARCHES_TYPES_IDS.ExtensionDePerimetre, + DEMARCHES_TYPES_IDS.ExtensionDeSubstance, + DEMARCHES_TYPES_IDS.Prorogation, + ], + machine: (titreTypeId, demarcheTypeId) => new ProcedureSpecifiqueMachine(titreTypeId, demarcheTypeId), + dateDebut: toCaminoDate('4000-01-01'), + demarcheIdExceptions: [], + }, ] as const satisfies readonly DemarcheDefinition[] -export const demarcheDefinitionFind = ( +export const machineFind = ( titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId, titreEtapes: DeepReadonly<Pick<ITitreEtape, 'date' | 'typeId'>[]> | undefined, - demarcheId: DemarcheId -): DemarcheDefinition | undefined => { - const date = titreDemarcheDepotDemandeDateFind(titreEtapes) + demarcheId: DemarcheId, + overrideDate: CaminoDate | null = null +): CaminoMachines | undefined => { + const date = titreDemarcheDepotDemandeDateFind(titreEtapes) ?? overrideDate const definition = demarchesDefinitions .toSorted((a, b) => b.dateDebut.localeCompare(a.dateDebut)) @@ -138,5 +154,5 @@ export const demarcheDefinitionFind = ( return undefined } - return definition + return definition?.machine(titreTypeId, demarcheTypeId) } diff --git a/packages/api/src/business/rules-demarches/machine-helper.ts b/packages/api/src/business/rules-demarches/machine-helper.ts index fb3163c899a4e5965fc1c8d5768e28519ac54c42..ff20e1b0c376a6ce3203b440409b1e432aa305d6 100644 --- a/packages/api/src/business/rules-demarches/machine-helper.ts +++ b/packages/api/src/business/rules-demarches/machine-helper.ts @@ -21,9 +21,29 @@ export abstract class CaminoMachine<CaminoContext extends CaminoCommonContext, C this.events = Object.keys(trad) as Array<CaminoEvent['type']> } - abstract eventFrom(etape: Etape): CaminoEvent + public eventFrom(etape: Etape): CaminoEvent { + const entries = Object.entries(this.trad).filter((entry): entry is [CaminoEvent['type'], { db: DBEtat; mainStep: boolean }] => this.events.includes(entry[0])) - protected caminoXStateEventToEtapes(event: CaminoEvent): (OmitDistributive<Etape, 'date'> & { mainStep: boolean })[] { + const entry = entries.find(([_key, { db: dbEtat }]) => { + return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) + }) + + if (entry) { + const eventFromEntr = entry[0] + + return { ...this.eventFromEntry(eventFromEntr, etape), date: etape.date, status: etape.etapeStatutId } + } + throw new Error(`no event from ${JSON.stringify(etape)}`) + } + + protected eventFromEntry(entryType: CaminoEvent['type'], _etape: Etape): CaminoEvent { + // @ts-ignore FIXMACHINE à voir si on repasse dessus ou si on laisse le ts-ignore + const result: CaminoEvent = { type: entryType } + + return result + } + + protected caminoXStateEventToEtapes(event: CaminoEvent): (OmitDistributive<Etape, 'date' | 'titreTypeId' | 'demarcheTypeId'> & { mainStep: boolean })[] { const dbEtat: { db: DBEtat; mainStep: boolean } = this.trad[event.type as CaminoEvent['type']] return Object.values(dbEtat.db).map(({ etapeTypeId, etapeStatutId }) => ({ @@ -194,7 +214,7 @@ export abstract class CaminoMachine<CaminoContext extends CaminoCommonContext, C return intervenants.filter(r => responsables.includes(tags.responsable[r])) } - public possibleNextEtapes(etapes: readonly Etape[], date: CaminoDate): (OmitDistributive<Etape, 'date'> & { mainStep: boolean })[] { + public possibleNextEtapes(etapes: readonly Etape[], date: CaminoDate): (OmitDistributive<Etape, 'date' | 'titreTypeId' | 'demarcheTypeId'> & { mainStep: boolean })[] { const state = this.assertGoTo(etapes) if (state !== undefined) { diff --git a/packages/api/src/business/rules-demarches/machine-test-helper.ts b/packages/api/src/business/rules-demarches/machine-test-helper.ts index b779c76ccd16406675f92758efe68b9f5b1d0b96..b58c10e0ae7d18fc0632eb2b0d1eaf65b0e6391b 100644 --- a/packages/api/src/business/rules-demarches/machine-test-helper.ts +++ b/packages/api/src/business/rules-demarches/machine-test-helper.ts @@ -81,7 +81,7 @@ export const interpretMachine = <T extends EventObject, C extends CaminoCommonCo export const setDateAndOrderAndInterpretMachine = <T extends EventObject, C extends CaminoCommonContext>( machine: CaminoMachine<C, T>, initDate: `${number}-${number}-${number}`, - etapes: readonly (EtapeTypeEtapeStatutValidPair & Omit<Etape, 'date' | 'etapeTypeId' | 'etapeStatutId'> & { addDays?: number })[] + etapes: readonly (EtapeTypeEtapeStatutValidPair & Omit<Etape, 'date' | 'etapeTypeId' | 'etapeStatutId' | 'titreTypeId' | 'demarcheTypeId'> & { addDays?: number })[] ): { service: Actor<(typeof machine)['machine']>; dateFin: CaminoDate; etapes: Etape[] } => { const firstDate = toCaminoDate(initDate) let index = 0 @@ -98,6 +98,9 @@ export const setDateAndOrderAndInterpretMachine = <T extends EventObject, C exte return { service, dateFin: dateAddDays(firstDate, etapes.length), etapes: fullEtapes } } -export const orderAndInterpretMachine = <T extends EventObject, C extends CaminoCommonContext>(machine: CaminoMachine<C, T>, etapes: readonly Etape[]): Actor<(typeof machine)['machine']> => { +export const orderAndInterpretMachine = <T extends EventObject, C extends CaminoCommonContext>( + machine: CaminoMachine<C, T>, + etapes: readonly Omit<Etape, 'titreTypeId' | 'demarcheTypeId'>[] +): Actor<(typeof machine)['machine']> => { return interpretMachine(machine, machine.orderMachine(etapes)) } diff --git a/packages/api/src/business/rules-demarches/machines.ts b/packages/api/src/business/rules-demarches/machines.ts index 5302799e07fced62ec13d5128ae96ea26dfb0984..23072ef3f50bd937349ab3bbeaa7918b3df2fcc1 100644 --- a/packages/api/src/business/rules-demarches/machines.ts +++ b/packages/api/src/business/rules-demarches/machines.ts @@ -4,5 +4,6 @@ import type { AxmOctMachine } from './axm/oct.machine' import type { AxmProMachine } from './axm/pro.machine' import type { PrmOctMachine } from './prm/oct.machine' import type { ProcedureSimplifieeMachine } from './procedure-simplifiee/ps.machine' +import type { ProcedureSpecifiqueMachine } from './procedure-specifique/procedure-specifique.machine' -export type CaminoMachines = ArmOctMachine | AxmOctMachine | AxmProMachine | ArmRenProMachine | PrmOctMachine | ProcedureSimplifieeMachine +export type CaminoMachines = ArmOctMachine | AxmOctMachine | AxmProMachine | ArmRenProMachine | PrmOctMachine | ProcedureSimplifieeMachine | ProcedureSpecifiqueMachine diff --git a/packages/api/src/business/rules-demarches/prm/oct.machine.test.ts b/packages/api/src/business/rules-demarches/prm/oct.machine.test.ts index 0545647cab0e3f5d12fe51c748f8921adbd4a9ec..c8c377ab3443219d050fbd3fd788760d8feb58b0 100644 --- a/packages/api/src/business/rules-demarches/prm/oct.machine.test.ts +++ b/packages/api/src/business/rules-demarches/prm/oct.machine.test.ts @@ -101,7 +101,7 @@ describe('vérifie l’arbre d’octroi de PRM', () => { ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, ] expect(() => setDateAndOrderAndInterpretMachine(prmOctMachine, '2022-04-13', etapes)).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"apd","etapeStatutId":"fav","date":"2022-04-20"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai"]'. The event {"type":"RENDRE_RAPPORT_DREAL","date":"2022-04-20"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATIONS,DEPOSER_DEMANDE_CONCURRENTE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_INFORMATIONS']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"apd","etapeStatutId":"fav","date":"2022-04-20"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai"]'. The event {"type":"RENDRE_RAPPORT_DREAL","date":"2022-04-20","status":"fav"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATIONS,DEPOSER_DEMANDE_CONCURRENTE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_INFORMATIONS']` ) }) @@ -116,7 +116,7 @@ describe('vérifie l’arbre d’octroi de PRM', () => { ETES.avisDesServicesEtCommissionsConsultatives.FAIT, ] expect(() => setDateAndOrderAndInterpretMachine(prmOctMachine, '2022-04-12', etapes)).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"asc","etapeStatutId":"fai","date":"2022-04-19"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai"]'. The event {"type":"RENDRE_AVIS_SERVICES_ET_COMMISSIONS_CONSULTATIVES","date":"2022-04-19"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATIONS,DEPOSER_DEMANDE_CONCURRENTE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_INFORMATIONS']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"asc","etapeStatutId":"fai","date":"2022-04-19"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai"]'. The event {"type":"RENDRE_AVIS_SERVICES_ET_COMMISSIONS_CONSULTATIVES","date":"2022-04-19","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATIONS,DEPOSER_DEMANDE_CONCURRENTE,DESISTER_PAR_LE_DEMANDEUR,MODIFIER_DEMANDE,RECEVOIR_INFORMATIONS']` ) }) @@ -156,7 +156,7 @@ describe('vérifie l’arbre d’octroi de PRM', () => { ] expect(() => setDateAndOrderAndInterpretMachine(prmOctMachine, '2022-04-13', etapes)).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"rpu","etapeStatutId":"fai","date":"2022-05-30"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai","ppu_ter","apd_fav","app_fav","scg_fai","rcg_fav","acg_fav","sas_fai","dex_rej","npp_fai","mno_fai"]'. The event {"type":"PUBLIER_DECISIONS_RECUEIL_ACTES_ADMINISTRATIFS"} should be one of 'RENDRE_DECISION_ABROGATION,RENDRE_DECISION_ANNULATION_PAR_JUGE_ADMINISTRATIF']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"rpu","etapeStatutId":"fai","date":"2022-05-30"}' after '["mfr_fai","mdp_fai","spp_fai","mcr_fav","anf_fai","asc_fai","ppu_ter","apd_fav","app_fav","scg_fai","rcg_fav","acg_fav","sas_fai","dex_rej","npp_fai","mno_fai"]'. The event {"type":"PUBLIER_DECISIONS_RECUEIL_ACTES_ADMINISTRATIFS","date":"2022-05-30","status":"fai"} should be one of 'RENDRE_DECISION_ABROGATION,RENDRE_DECISION_ANNULATION_PAR_JUGE_ADMINISTRATIF']` ) }) diff --git a/packages/api/src/business/rules-demarches/prm/oct.machine.ts b/packages/api/src/business/rules-demarches/prm/oct.machine.ts index 92b02e3463298cd92fec825c132f1b71a75beda3..17475eb5a24fd5453ab1e1d931109821963879e0 100644 --- a/packages/api/src/business/rules-demarches/prm/oct.machine.ts +++ b/packages/api/src/business/rules-demarches/prm/oct.machine.ts @@ -129,9 +129,6 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { RECEVOIR_INFORMATIONS: { db: EtapesTypesEtapesStatuts.receptionDinformation, mainStep: false }, } as const -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - const SUPERFICIE_MAX_POUR_EXONERATION_AVIS_MISE_EN_CONCURRENCE_AU_JORF = 50 export class PrmOctMachine extends CaminoMachine<PrmOctContext, XStateEvent> { @@ -139,7 +136,7 @@ export class PrmOctMachine extends CaminoMachine<PrmOctContext, XStateEvent> { super(prmOctMachine, trad) } - toPotentialCaminoXStateEvent(event: XStateEvent['type'], date: CaminoDate): XStateEvent[] { + override toPotentialCaminoXStateEvent(event: XStateEvent['type'], date: CaminoDate): XStateEvent[] { switch (event) { case 'RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF': case 'RENDRE_AVIS_SERVICES_ET_COMMISSIONS_CONSULTATIVES': @@ -167,43 +164,23 @@ export class PrmOctMachine extends CaminoMachine<PrmOctContext, XStateEvent> { } } - eventFrom(etape: Etape): XStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - switch (eventFromEntry) { - case 'RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF': - case 'RENDRE_AVIS_SERVICES_ET_COMMISSIONS_CONSULTATIVES': - case 'RENDRE_AVIS_CDM': - case 'RENDRE_RAPPORT_DREAL': - return { type: eventFromEntry, date: etape.date } - case 'OUVRIR_PARTICIPATION_DU_PUBLIC': - return { type: eventFromEntry, date: etape.date, status: etape.etapeStatutId } - case 'FAIRE_DEMANDE': - if (!etape.paysId) { - console.info(`paysId is mandatory in etape ${JSON.stringify(etape)}, defaulting to FR.`) + override eventFromEntry(eventType: XStateEvent['type'], etape: Etape): XStateEvent { + switch (eventType) { + case 'FAIRE_DEMANDE': + if (!etape.paysId) { + console.info(`paysId is mandatory in etape ${JSON.stringify(etape)}, defaulting to FR.`) - return { type: eventFromEntry, paysId: 'FR', surface: etape.surface ?? 0 } - } + return { type: eventType, paysId: 'FR', surface: etape.surface ?? 0 } + } - if (etape.paysId === 'GF' && etape.surface === null && etape.surface === undefined) { - throw new Error(`la surface pour la demande est obligatoire quand la demande est en Guyane ${JSON.stringify(etape)}`) - } + if (etape.paysId === 'GF' && etape.surface === null && etape.surface === undefined) { + throw new Error(`la surface pour la demande est obligatoire quand la demande est en Guyane ${JSON.stringify(etape)}`) + } - return { type: eventFromEntry, paysId: etape.paysId, surface: etape.surface ?? 0 } - default: - // related to https://github.com/microsoft/TypeScript/issues/46497 https://github.com/microsoft/TypeScript/issues/40803 :( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { type: eventFromEntry } - } + return { type: eventType, paysId: etape.paysId, surface: etape.surface ?? 0 } + default: + return super.eventFromEntry(eventType, etape) } - throw new Error(`no event from ${JSON.stringify(etape)}`) } } diff --git a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts index c37c3cfa797f8586f38372d7aea8b761bbba2e11..0c89324d1f83bbb113c6d072554d3736d939cc31 100644 --- a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts +++ b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts @@ -87,7 +87,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () => test('ne peut pas faire deux dépôts de la demande', () => { const etapes = [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.depotDeLaDemande.FAIT] expect(() => setDateAndOrderAndInterpretMachine(psMachine, '2022-04-12', etapes)).toThrowErrorMatchingInlineSnapshot( - `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2022-04-15"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"DEPOSER_DEMANDE"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_PARTICIPATION_DU_PUBLIC,RECEVOIR_INFORMATION,RENDRE_DECISION_ADMINISTRATION_ACCEPTEE,RENDRE_DECISION_ADMINISTRATION_REJETEE,RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE']` + `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2022-04-15"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"DEPOSER_DEMANDE","date":"2022-04-15","status":"fai"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_PARTICIPATION_DU_PUBLIC,RECEVOIR_INFORMATION,RENDRE_DECISION_ADMINISTRATION_ACCEPTEE,RENDRE_DECISION_ADMINISTRATION_REJETEE,RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE']` ) }) diff --git a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts index 9e95e63e4e54e53f9e1418b059367621d4e481dd..407583419af9ed06afc36a3fe51c426bd5e6b959 100644 --- a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts +++ b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts @@ -1,6 +1,6 @@ import { assign, createMachine } from 'xstate' import { CaminoMachine } from '../machine-helper' -import { CaminoCommonContext, DBEtat, Etape } from '../machine-common' +import { CaminoCommonContext, DBEtat } from '../machine-common' import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts' import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' import { CaminoDate, isBefore, toCaminoDate } from 'camino-common/src/date' @@ -71,16 +71,13 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE: { db: ETES.informationsHistoriquesIncompletes, mainStep: false }, } -// Related to https://github.com/Microsoft/TypeScript/issues/12870 -const EVENTS = Object.keys(trad) as Array<Extract<keyof typeof trad, string>> - // basé sur https://drive.google.com/file/d/16lXyw3pcuiP-rHkBBM0U2Al9sWHKCBP9/view export class ProcedureSimplifieeMachine extends CaminoMachine<ProcedureSimplifieeContext, ProcedureSimplifieeXStateEvent> { constructor() { super(procedureSimplifieeMachine, trad) } - toPotentialCaminoXStateEvent(event: ProcedureSimplifieeXStateEvent['type'], date: CaminoDate): ProcedureSimplifieeXStateEvent[] { + override toPotentialCaminoXStateEvent(event: ProcedureSimplifieeXStateEvent['type'], date: CaminoDate): ProcedureSimplifieeXStateEvent[] { switch (event) { case 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE': case 'RENDRE_DECISION_ADMINISTRATION_REJETEE': @@ -99,35 +96,6 @@ export class ProcedureSimplifieeMachine extends CaminoMachine<ProcedureSimplifie return [{ type: event }] } } - - eventFrom(etape: Etape): ProcedureSimplifieeXStateEvent { - const entries = Object.entries(trad).filter((entry): entry is [Event, { db: DBEtat; mainStep: boolean }] => EVENTS.includes(entry[0])) - - const entry = entries.find(([_key, { db: dbEtat }]) => { - return Object.values(dbEtat).some(dbEtatSingle => dbEtatSingle.etapeTypeId === etape.etapeTypeId && dbEtatSingle.etapeStatutId === etape.etapeStatutId) - }) - - if (entry) { - const eventFromEntry = entry[0] - switch (eventFromEntry) { - case 'PUBLIER_DECISION_ACCEPTEE_AU_JORF': - case 'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS': - case 'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE': - case 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE': - case 'RENDRE_DECISION_ADMINISTRATION_REJETEE': - case 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE': { - return { type: eventFromEntry, date: etape.date } - } - case 'OUVRIR_PARTICIPATION_DU_PUBLIC': { - return { type: eventFromEntry, status: etape.etapeStatutId } - } - - default: - return { type: eventFromEntry } - } - } - throw new Error(`no event from ${JSON.stringify(etape)}`) - } } interface ProcedureSimplifieeContext extends CaminoCommonContext { diff --git a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c5b9bf287f54357e8e06ba96d604d204eb18c57 --- /dev/null +++ b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts @@ -0,0 +1,92 @@ +import { orderAndInterpretMachine, setDateAndOrderAndInterpretMachine } from '../machine-test-helper' +import { toCaminoDate } from 'camino-common/src/date' +import { describe, expect, test } from 'vitest' +import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' +import { ProcedureSpecifiqueMachine } from './procedure-specifique.machine' +import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts' + +const psPccOctMachine = new ProcedureSpecifiqueMachine('pcc', 'oct') +const psCxmOctMachine = new ProcedureSpecifiqueMachine('cxm', 'oct') +const psPrmProMachine = new ProcedureSpecifiqueMachine('prm', 'pro') +const psArmProMachine = new ProcedureSpecifiqueMachine('arm', 'pro') + +describe('vérifie l’arbre des procédures spécifique', () => { + test('statut de la démarche simplifiee sans étape', () => { + const service = orderAndInterpretMachine(psPccOctMachine, []) + expect(service).canOnlyTransitionTo({ machine: psPccOctMachine, date: toCaminoDate('2024-10-10') }, ['FAIRE_DEMANDE']) + expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.EnConstruction) + }) + test('demande irrecevable', () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psPccOctMachine, '1999-04-14', [ + ETES.demande.FAIT, + ETES.depotDeLaDemande.FAIT, + ETES.recevabiliteDeLaDemande.DEFAVORABLE, + ETES.demandeDeComplements.FAIT, + ETES.receptionDeComplements.FAIT, + ETES.declarationDIrrecevabilite.FAIT, + ]) + expect(service).canOnlyTransitionTo({ machine: psPccOctMachine, date: dateFin }, []) + expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.Rejete) + expect(service.getSnapshot().context.visibilite).toBe('confidentielle') + }) + test('on peut notifier le demandeur apres une recevabilité favorable pour un PER ou une concession', () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psCxmOctMachine, '1999-04-14', [ + ETES.demande.FAIT, + ETES.depotDeLaDemande.FAIT, + ETES.recevabiliteDeLaDemande.FAVORABLE, + ETES.notificationAuDemandeur.FAIT, + ]) + expect(service).canOnlyTransitionTo({ machine: psCxmOctMachine, date: dateFin }, ['NOTIFIER_DEMANDEUR']) + }) + test('on ne peut pas notifier le demandeur apres une recevabilité favorable pour pcc', () => { + expect(() => + setDateAndOrderAndInterpretMachine(psPccOctMachine, '1999-04-14', [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.recevabiliteDeLaDemande.FAVORABLE, ETES.notificationAuDemandeur.FAIT]) + ).toThrowErrorMatchingInlineSnapshot( + `[Error: Error: cannot execute step: '{"etapeTypeId":"mno","etapeStatutId":"fai","date":"1999-04-18"}' after '["mfr_fai","mdp_fai","mcr_fav"]'. The event {"type":"NOTIFIER_DEMANDEUR","date":"1999-04-18","status":"fai"} should be one of '']` + ) + }) + test("après la recevabilité favorable la démarche devient publique si il n'y a pas de mise en concurrence", () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psPrmProMachine, '1999-04-14', [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.recevabiliteDeLaDemande.FAVORABLE]) + + expect(service).canOnlyTransitionTo({ machine: psPrmProMachine, date: dateFin }, ['RENDRE_AVIS_CGE_IGEDD', 'NOTIFIER_DEMANDEUR']) + expect(service.getSnapshot().context.visibilite).toBe('publique') + }) + test('après la recevabilité favorable la démarche reste confidentielle si il y a une mise en concurrence', () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psCxmOctMachine, '1999-04-14', [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.recevabiliteDeLaDemande.FAVORABLE]) + + expect(service).canOnlyTransitionTo({ machine: psCxmOctMachine, date: dateFin }, ['NOTIFIER_DEMANDEUR']) + expect(service.getSnapshot().context.visibilite).toBe('confidentielle') + }) + test("ne peut pas rendre la décision de l'administration si la participation du public n'est pas terminée", () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psArmProMachine, '1999-04-14', [ + ETES.demande.FAIT, + ETES.depotDeLaDemande.FAIT, + ETES.recevabiliteDeLaDemande.FAVORABLE, + ETES.avisDesCollectivites.FAIT, + ETES.avisDesServicesEtCommissionsConsultatives.FAIT, + ETES.avisDuPrefet.FAVORABLE, + ETES.participationDuPublic.EN_COURS, + ]) + + expect(service).canOnlyTransitionTo({ machine: psArmProMachine, date: dateFin }, []) + expect(service.getSnapshot().context.visibilite).toBe('publique') + }) + test("réalise une demande de prolongation d'ARM complète", () => { + const { service, dateFin } = setDateAndOrderAndInterpretMachine(psArmProMachine, '1999-04-14', [ + ETES.demande.FAIT, + ETES.depotDeLaDemande.FAIT, + ETES.recevabiliteDeLaDemande.FAVORABLE, + ETES.avisDesCollectivites.FAIT, + ETES.avisDesServicesEtCommissionsConsultatives.FAIT, + ETES.avisDuPrefet.FAVORABLE, + ETES.participationDuPublic.TERMINE, + ETES.decisionDeLadministration.ACCEPTE, + ]) + + expect(service).canOnlyTransitionTo({ machine: psArmProMachine, date: dateFin }, []) + expect(service.getSnapshot().context.visibilite).toBe('publique') + }) + + // FIXMACHINE tester que la participation du public peut-être optionnelle + // FIXMACHINE migrer l'enquête publique sur master +}) diff --git a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts new file mode 100644 index 0000000000000000000000000000000000000000..df51a4fd00fd56985c01e3b27f7e857d303daada --- /dev/null +++ b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts @@ -0,0 +1,367 @@ +import { and, assign, not, or, setup } from 'xstate' +import { CaminoMachine } from '../machine-helper' +import { CaminoCommonContext, DBEtat } from '../machine-common' +import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts' +import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' +import { TITRES_TYPES_IDS, TitreTypeId, getTitreTypeType } from 'camino-common/src/static/titresTypes' +import { DEMARCHES_TYPES_IDS, DemarcheTypeId, isDemarcheTypeProlongations } from 'camino-common/src/static/demarchesTypes' +import { TITRES_TYPES_TYPES_IDS } from 'camino-common/src/static/titresTypesTypes' +import { ETAPES_STATUTS, EtapeStatutId } from 'camino-common/src/static/etapesStatuts' +import { KM2, km2Validator } from 'camino-common/src/number' +import { CaminoDate } from 'camino-common/src/date' +// type SaisirInformationHistoriqueIncomplete = { +// date: CaminoDate +// type: 'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE' +// } +// type RendreDecisionAdministrationAcceptee = { +// date: CaminoDate +// type: 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE' +// } +// type RendreDecisionAdministrationRejetee = { +// date: CaminoDate +// type: 'RENDRE_DECISION_ADMINISTRATION_REJETEE' +// } +// type RendreDecisionAdministrationRejeteeDecisionImplicite = { +// date: CaminoDate +// type: 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE' +// } +// type PublierDecisionAccepteeAuJORF = { +// date: CaminoDate +// type: 'PUBLIER_DECISION_ACCEPTEE_AU_JORF' +// } +// type PublierDecisionAuRecueilDesActesAdministratifs = { +// date: CaminoDate +// type: 'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS' +// } + +type ParticipationDuPublic = { + surface: KM2 + status: EtapeStatutId + type: 'OUVRIR_PARTICIPATION_DU_PUBLIC' +} + +type EnqueteDuPublic = { + surface: KM2 + status: EtapeStatutId + type: 'OUVRIR_ENQUETE_PUBLIQUE' +} +type ProcedureSpecifiqueXStateEvent = + | { type: 'FAIRE_DEMANDE' } + | { type: 'DEPOSER_DEMANDE' } + | { type: 'FAIRE_RECEVABILITE_FAVORABLE' } + | { type: 'FAIRE_RECEVABILITE_DEFAVORABLE' } + | { type: 'FAIRE_DEMANDE_DE_COMPLEMENTS' } + | { type: 'RECEVOIR_COMPLEMENTS' } + | { type: 'FAIRE_DECLARATION_IRRECEVABILITE' } + | { type: 'NOTIFIER_DEMANDEUR' } + | { type: 'RENDRE_AVIS_CGE_IGEDD' } + | { type: 'FAIRE_LETTRE_SAISINE_PREFET' } + | { type: 'RENDRE_AVIS_COLLECTIVITES' } + | { type: 'RENDRE_AVIS_SERVICES_COMMISSIONS' } + | { type: 'RENDRE_AVIS_PREFET' } + | ParticipationDuPublic + | EnqueteDuPublic + | { type: 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE' } +// | RendreDecisionAdministrationAcceptee +// | RendreDecisionAdministrationRejetee +// | RendreDecisionAdministrationRejeteeDecisionImplicite +// | SaisirInformationHistoriqueIncomplete +// | PublierDecisionAccepteeAuJORF +// | PublierDecisionAuRecueilDesActesAdministratifs +// | { type: 'CLASSER_SANS_SUITE' } +// | { type: 'DESISTER_PAR_LE_DEMANDEUR' } +// | { type: 'DEMANDER_INFORMATION' } +// | { type: 'RECEVOIR_INFORMATION' } +// | { type: 'FAIRE_ABROGATION' } + +type Event = ProcedureSpecifiqueXStateEvent['type'] + +const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { + FAIRE_DEMANDE: { db: ETES.demande, mainStep: true }, + DEPOSER_DEMANDE: { db: ETES.depotDeLaDemande, mainStep: true }, + FAIRE_RECEVABILITE_FAVORABLE: { db: { FAVORABLE: ETES.recevabiliteDeLaDemande.FAVORABLE }, mainStep: true }, + FAIRE_RECEVABILITE_DEFAVORABLE: { db: { DEFAVORABLE: ETES.recevabiliteDeLaDemande.DEFAVORABLE }, mainStep: false }, + FAIRE_DEMANDE_DE_COMPLEMENTS: { db: ETES.demandeDeComplements, mainStep: false }, + RECEVOIR_COMPLEMENTS: { db: ETES.receptionDeComplements, mainStep: false }, + FAIRE_DECLARATION_IRRECEVABILITE: { db: ETES.declarationDIrrecevabilite, mainStep: false }, + NOTIFIER_DEMANDEUR: { db: ETES.notificationAuDemandeur, mainStep: false }, + RENDRE_AVIS_CGE_IGEDD: { db: ETES.avisDuConseilGeneralDeLeconomie_CGE_, mainStep: true }, + FAIRE_LETTRE_SAISINE_PREFET: { db: ETES.saisineDuPrefet, mainStep: true }, + RENDRE_AVIS_COLLECTIVITES: { db: ETES.avisDesCollectivites, mainStep: true }, + RENDRE_AVIS_SERVICES_COMMISSIONS: { db: ETES.avisDesServicesEtCommissionsConsultatives, mainStep: true }, + RENDRE_AVIS_PREFET: { db: ETES.avisDuPrefet, mainStep: true }, + OUVRIR_ENQUETE_PUBLIQUE: { db: ETES.ouvertureDeLenquetePublique, mainStep: true }, + OUVRIR_PARTICIPATION_DU_PUBLIC: { db: ETES.participationDuPublic, mainStep: true }, + RENDRE_DECISION_ADMINISTRATION_ACCEPTEE: { db: { ACCEPTE: ETES.decisionDeLadministration.ACCEPTE }, mainStep: true }, + // RECEVOIR_REPONSE_DEMANDEUR: {db: ETES.demandeur} + + // OUVRIR_PARTICIPATION_DU_PUBLIC: { db: ETES.participationDuPublic, mainStep: true }, + // RENDRE_DECISION_ADMINISTRATION_ACCEPTEE: { db: { ACCEPTE: ETES.decisionDeLadministration.ACCEPTE }, mainStep: true }, + // RENDRE_DECISION_ADMINISTRATION_REJETEE: { db: { REJETE: ETES.decisionDeLadministration.REJETE }, mainStep: true }, + // RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE: { db: { REJETE_DECISION_IMPLICITE: ETES.decisionDeLadministration.REJETE_DECISION_IMPLICITE }, mainStep: true }, + // PUBLIER_DECISION_ACCEPTEE_AU_JORF: { db: { FAIT: ETES.publicationDeDecisionAuJORF.FAIT }, mainStep: true }, + // PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS: { db: ETES.publicationDeDecisionAuRecueilDesActesAdministratifs, mainStep: true }, + // CLASSER_SANS_SUITE: { db: ETES.classementSansSuite, mainStep: false }, + // DESISTER_PAR_LE_DEMANDEUR: { db: ETES.desistementDuDemandeur, mainStep: false }, + // DEMANDER_INFORMATION: { db: ETES.demandeDinformations, mainStep: false }, + // RECEVOIR_INFORMATION: { db: ETES.receptionDinformation, mainStep: false }, + // FAIRE_ABROGATION: { db: ETES.abrogationDeLaDecision, mainStep: true }, + // SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE: { db: ETES.informationsHistoriquesIncompletes, mainStep: false }, +} + +// basé sur https://drive.google.com/drive/u/1/folders/1U_in35zSb837xCp_fp31I0vOmb36QguL +export class ProcedureSpecifiqueMachine extends CaminoMachine<ProcedureSpecifiqueContext, ProcedureSpecifiqueXStateEvent> { + constructor(titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId) { + super(procedureSpecifiqueMachine(titreTypeId, demarcheTypeId), trad) + } + + override toPotentialCaminoXStateEvent(event: ProcedureSpecifiqueXStateEvent['type'], date: CaminoDate): ProcedureSpecifiqueXStateEvent[] { + switch (event) { + // case 'FAIRE_DEMANDE': + // case 'NOTIFIER_DEMANDEUR': + // return [ + // { type: event, titreTypeId: 'cxm', demarcheTypeId: 'oct' }, + // { type: event, titreTypeId: 'arm', demarcheTypeId: 'oct' }, + // ] + // case 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE': + // case 'RENDRE_DECISION_ADMINISTRATION_REJETEE': + // case 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE': + // case 'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE': + // case 'PUBLIER_DECISION_ACCEPTEE_AU_JORF': + // case 'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS': + // return [{ type: event, date }] + case 'OUVRIR_ENQUETE_PUBLIQUE': + case 'OUVRIR_PARTICIPATION_DU_PUBLIC': + return [ + { type: event, status: ETAPES_STATUTS.PROGRAMME, surface: km2Validator.parse(0.24) }, + { type: event, status: ETAPES_STATUTS.EN_COURS, surface: km2Validator.parse(0.24) }, + { type: event, status: ETAPES_STATUTS.TERMINE, surface: km2Validator.parse(0.24) }, + { type: event, status: ETAPES_STATUTS.PROGRAMME, surface: km2Validator.parse(0.26) }, + { type: event, status: ETAPES_STATUTS.EN_COURS, surface: km2Validator.parse(0.26) }, + { type: event, status: ETAPES_STATUTS.TERMINE, surface: km2Validator.parse(0.26) }, + ] + default: + return super.toPotentialCaminoXStateEvent(event, date) + } + } +} + +interface ProcedureSpecifiqueContext extends CaminoCommonContext {} +const defaultDemarcheStatut = DemarchesStatutsIds.EnConstruction +const procedureSpecifiqueMachine = (titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId) => + setup({ + types: {} as { context: ProcedureSpecifiqueContext; events: ProcedureSpecifiqueXStateEvent }, + guards: { + isPublique: ({ context }) => context.visibilite === 'publique', + isPerOuConcession: () => [TITRES_TYPES_TYPES_IDS.PERMIS_EXCLUSIF_DE_RECHERCHES, TITRES_TYPES_TYPES_IDS.CONCESSION].includes(getTitreTypeType(titreTypeId)), + hasMiseEnConcurrence: () => + [DEMARCHES_TYPES_IDS.Octroi, DEMARCHES_TYPES_IDS.ExtensionDePerimetre].includes(demarcheTypeId) || + (isDemarcheTypeProlongations(demarcheTypeId) && getTitreTypeType(titreTypeId) === TITRES_TYPES_TYPES_IDS.CONCESSION), + isAxmOuAr: () => TITRES_TYPES_IDS.AUTORISATION_D_EXPLOITATION_METAUX === titreTypeId || TITRES_TYPES_TYPES_IDS.AUTORISATION_DE_RECHERCHE === getTitreTypeType(titreTypeId), + // FIXMACHINE à vérifier et à tester + isEnquetePubliqueRequired: ({ event }) => + ((DEMARCHES_TYPES_IDS.Octroi === demarcheTypeId || isDemarcheTypeProlongations(demarcheTypeId)) && + [ + TITRES_TYPES_IDS.PERMIS_EXCLUSIF_DE_RECHERCHES_GRANULATS_MARINS, + TITRES_TYPES_IDS.CONCESSION_METAUX, + TITRES_TYPES_IDS.CONCESSION_GRANULATS_MARINS, + TITRES_TYPES_IDS.CONCESSION_HYDROCARBURE, + TITRES_TYPES_IDS.CONCESSION_SOUTERRAIN, + TITRES_TYPES_IDS.CONCESSION_GEOTHERMIE, + ].includes(titreTypeId)) || + (titreTypeId === TITRES_TYPES_IDS.AUTORISATION_D_EXPLOITATION_METAUX && (event.type === 'OUVRIR_PARTICIPATION_DU_PUBLIC' || event.type === 'OUVRIR_ENQUETE_PUBLIQUE') && event.surface > 0.25), + isEnquetePubliquePossible: ({ event }) => + titreTypeId === TITRES_TYPES_IDS.AUTORISATION_D_EXPLOITATION_METAUX && (event.type === 'OUVRIR_PARTICIPATION_DU_PUBLIC' || event.type === 'OUVRIR_ENQUETE_PUBLIQUE') && event.surface <= 0.25, + }, + }).createMachine({ + id: 'ProcedureSpecifique', + initial: 'demandeAFaire', + context: { + demarcheStatut: defaultDemarcheStatut, + visibilite: 'confidentielle', + }, + states: { + demandeAFaire: { + on: { + FAIRE_DEMANDE: { + target: 'depotDeLaDemandeAFaire', + actions: assign({ + demarcheStatut: DemarchesStatutsIds.EnInstruction, + }), + }, + }, + }, + depotDeLaDemandeAFaire: { + on: { + DEPOSER_DEMANDE: 'recevabiliteOuInformationDuPrefetEtCollectivitesAFaire', + }, + }, + + recevabiliteOuInformationDuPrefetEtCollectivitesAFaire: { + on: { + // FIXMACHINE + // RENDRE_INFORMATION_DU_PREFET_ET_DES_COLLECTIVITES: { + // target: 'recevabiliteOuInformationDuPrefetEtCollectivitesAFaire', + // guard: 'isPerOuConcession' + // }, + FAIRE_RECEVABILITE_FAVORABLE: 'recevabiliteFavorableFaite', + FAIRE_RECEVABILITE_DEFAVORABLE: 'demandeDeComplementsAFaire', + }, + }, + demandeDeComplementsAFaire: { + on: { + FAIRE_DEMANDE_DE_COMPLEMENTS: 'reponseALaDemandeDeComplements', + }, + }, + // FIXMACHINE brouillonable + reponseALaDemandeDeComplements: { + on: { + RECEVOIR_COMPLEMENTS: 'recevabiliteOuIrrecevabiliteAFaire', + }, + }, + recevabiliteOuIrrecevabiliteAFaire: { + on: { + FAIRE_RECEVABILITE_FAVORABLE: 'recevabiliteFavorableFaite', + FAIRE_RECEVABILITE_DEFAVORABLE: 'demandeDeComplementsAFaire', + FAIRE_DECLARATION_IRRECEVABILITE: { + target: 'finDeMachine', + actions: assign({ + demarcheStatut: DemarchesStatutsIds.Rejete, + }), + }, + }, + }, + recevabiliteFavorableFaite: { + always: [ + { + guard: and([not('hasMiseEnConcurrence'), not('isPublique')]), + actions: assign({ visibilite: 'publique' }), + }, + { + target: 'avisCollectivitesEtServicesEtCommissionsAFaireMachine', + guard: and([not('hasMiseEnConcurrence'), 'isAxmOuAr']), + }, + ], + on: { + // FIXMACHINE ajouter la mise en concurrence + RENDRE_AVIS_CGE_IGEDD: { + // FIXMACHINE ajouter la demande de modification de l'aes + target: 'notificationAuDemandeurAFaire', + guard: and([not('hasMiseEnConcurrence'), not('isAxmOuAr')]), + }, + NOTIFIER_DEMANDEUR: { + target: 'recevabiliteFavorableFaite', + guard: 'isPerOuConcession', + }, + }, + }, + + notificationAuDemandeurAFaire: { + on: { NOTIFIER_DEMANDEUR: 'lettreDeSaisineDuPrefetOuReponseDuDemandeurAFaire' }, + }, + lettreDeSaisineDuPrefetOuReponseDuDemandeurAFaire: { + on: { + // FIXMACHINE brouillon + // FIXMACHINE 'RECEVOIR_REPONSE_DEMANDEUR': 'lettreDeSaisineDuPrefetOuReponseDuDemandeurAFaire', + FAIRE_LETTRE_SAISINE_PREFET: 'avisCollectivitesEtServicesEtCommissionsAFaireMachine', + }, + }, + + avisCollectivitesEtServicesEtCommissionsAFaireMachine: { + type: 'parallel', + states: { + avisARendreMachine: { + initial: 'avisARendre', + states: { + avisARendre: { + type: 'parallel', + + states: { + avisCollectivitesARendreMachine: { + initial: 'avisCollectivitesARendre', + states: { + avisCollectivitesARendre: { + // FIXMACHINE brouillon + on: { RENDRE_AVIS_COLLECTIVITES: 'fin' }, + }, + fin: { type: 'final' }, + }, + }, + avisServicesEtCommissionsRendreMachine: { + initial: 'avisServicesEtCommissionsRendre', + states: { + avisServicesEtCommissionsRendre: { + // FIXMACHINE brouillon + on: { RENDRE_AVIS_SERVICES_COMMISSIONS: 'fin' }, + }, + fin: { type: 'final' }, + }, + }, + }, + onDone: 'avisDuPrefetARendre', + }, + avisDuPrefetARendre: { + // FIXMACHINE gérer l'avis de la commission CDM + on: { RENDRE_AVIS_PREFET: 'fin' }, + }, + fin: { + type: 'final', + }, + }, + }, + participationOuEnqueteDuPublicMachine: { + initial: 'participationOuEnquetePublicAFaire', + states: { + participationOuEnquetePublicAFaire: { + on: { + OUVRIR_ENQUETE_PUBLIQUE: [ + { + target: 'fin', + guard: and([or(['isEnquetePubliqueRequired', 'isEnquetePubliquePossible']), ({ event }) => event.status === ETAPES_STATUTS.TERMINE]), + }, + { + target: 'enAttente', + guard: ({ event }) => event.status !== ETAPES_STATUTS.TERMINE, + }, + ], + OUVRIR_PARTICIPATION_DU_PUBLIC: [ + { + target: 'fin', + guard: and([not('isEnquetePubliqueRequired'), ({ event }) => event.status === ETAPES_STATUTS.TERMINE]), + }, + { + target: 'enAttente', + guard: ({ event }) => event.status !== ETAPES_STATUTS.TERMINE, + }, + ], + }, + }, + enAttente: {}, + fin: { + type: 'final', + }, + }, + }, + }, + onDone: 'decisionAdministrationAFaire', + }, + decisionAdministrationAFaire: { + on: { + RENDRE_DECISION_ADMINISTRATION_ACCEPTEE: 'finDeMachine', + }, + }, + finDeMachine: { + type: 'final', + }, + }, + }) + +// FIXMACHINE questions POH +// - L'irrecevabilité est faisable que après une demande de compléments ? -> OUI +// - C'est une toute nouvelle étape « Information du préfet et des collectivités » ? Est-ce que ça serait pas une fusion d'anciennes étapes ? -> c'est tout nouveau +// - Est-ce que l'information du préfet et des collectivités est faite 2 fois ? -> Non que une fois +// +// - « avisDuConseilGeneralDeLeconomie_CGE_ » ça passe pour l'étape « avis du CGE et de l'IGEDD » ? => Renommer l'étape +// - l'étape « avis du CGE et de l'IGEDD » n'a pas de statut favorable / défavorable ? => C'est une étape d'avis donc c'est FAIT +// - comment on peut avoir une mise en concurrence si la démarche n'est pas publique ? => Modif du logigramme, ça devient publique dés que la mise en concurrence est « en cours » +// - Pour l'enquête et la participation du public, la démarche est déjà publique => Heuuuu non, modif à faire dans le logigramme diff --git a/packages/api/src/business/rules/titre-demarche-public-find.test.ts b/packages/api/src/business/rules/titre-demarche-public-find.test.ts index ed29958ae7ed2c62be977bbfd4ec4df61e5a2633..47b3adbdbb0cc3e20b4954b948b219870eb31b0a 100644 --- a/packages/api/src/business/rules/titre-demarche-public-find.test.ts +++ b/packages/api/src/business/rules/titre-demarche-public-find.test.ts @@ -18,6 +18,7 @@ const etapesBuild = (etapesProps: Partial<ITitreEtape>[]) => contenu: null, ...etapeProps, ordre: i + 1, + date: toCaminoDate('0001-01-01'), }) as unknown as ITitreEtape ) diff --git a/packages/api/src/business/rules/titre-demarche-public-find.ts b/packages/api/src/business/rules/titre-demarche-public-find.ts index 9f93cd92ace74d15db6af9039d2f6ae0a13f2ceb..0316d13780efef468e5b784702832186da5c337c 100644 --- a/packages/api/src/business/rules/titre-demarche-public-find.ts +++ b/packages/api/src/business/rules/titre-demarche-public-find.ts @@ -3,7 +3,7 @@ import { EtapeTypeId } from 'camino-common/src/static/etapesTypes' import { getDomaineId, TitreTypeId } from 'camino-common/src/static/titresTypes' import { getEtapesTDE } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index' import { ITitreEtape, ITitreDemarche } from '../../types' -import { demarcheDefinitionFind } from '../rules-demarches/definitions' +import { machineFind } from '../rules-demarches/definitions' import { titreEtapeForMachineValidator, toMachineEtapes } from '../rules-demarches/machine-common' import { titreEtapesSortAscByOrdre } from '../utils/titre-etapes-sort' import { titreInModificationEnInstance } from './titre-statut-id-find' @@ -154,7 +154,10 @@ const titreDemarchePublicLectureFind = ( * @param titreTypeId - id du type de titre */ -export const titreDemarchePublicFind = (titreDemarche: Pick<ITitreDemarche, 'titreId' | 'demarcheDateDebut' | 'demarcheDateFin' | 'id' | 'typeId' | 'etapes'>, titreTypeId: TitreTypeId) => { +export const titreDemarchePublicFind = ( + titreDemarche: Pick<ITitreDemarche, 'titreId' | 'demarcheDateDebut' | 'demarcheDateFin' | 'id' | 'typeId' | 'etapes'>, + titreTypeId: TitreTypeId +): { publicLecture: boolean; entreprisesLecture: boolean } => { const titreDemarcheEtapes = titreEtapesSortAscByOrdre(titreDemarche.etapes ?? []) // calcule la visibilité publique ou non de la démarche @@ -165,10 +168,10 @@ export const titreDemarchePublicFind = (titreDemarche: Pick<ITitreDemarche, 'tit if (titreDemarche.titreId === 'WQaZgPfDcQw9tFliMgBIDH3Z') { publicLecture = false } else { - const demarcheDefinition = demarcheDefinitionFind(titreTypeId, titreDemarche.typeId, titreDemarcheEtapes, titreDemarche.id) + const machine = machineFind(titreTypeId, titreDemarche.typeId, titreDemarcheEtapes, titreDemarche.id) - if (demarcheDefinition) { - publicLecture = demarcheDefinition.machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes.map(etape => titreEtapeForMachineValidator.parse(etape)))).publique + if (machine) { + publicLecture = machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes.map(etape => titreEtapeForMachineValidator.parse(etape)))).publique } else { const demarcheTypeEtapesTypes = getEtapesTDE(titreTypeId, titreDemarche.typeId) publicLecture = titreDemarcheEtapes.reduce( diff --git a/packages/api/src/business/rules/titre-demarche-statut-id-find.test.ts b/packages/api/src/business/rules/titre-demarche-statut-id-find.test.ts index baa21f81bc5df249499d9ecfeaa618cdf5323649..0a1741b92973877145a4be2a1bf99c650cf778aa 100644 --- a/packages/api/src/business/rules/titre-demarche-statut-id-find.test.ts +++ b/packages/api/src/business/rules/titre-demarche-statut-id-find.test.ts @@ -9,13 +9,18 @@ import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts' import { TitreEtapeForMachine } from '../rules-demarches/machine-common' import { ETAPE_IS_BROUILLON, ETAPE_IS_NOT_BROUILLON } from 'camino-common/src/etape' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes' -const etapesBuild = (etapesProps: Partial<ITitreEtape>[]): TitreEtapeForMachine[] => +import { TitreTypeId } from 'camino-common/src/static/titresTypes' +import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes' +const etapesBuild = (etapesProps: Partial<ITitreEtape>[], demarcheTypeId: DemarcheTypeId = 'oct', titreTypeId: TitreTypeId = 'axm'): TitreEtapeForMachine[] => etapesProps.map( (etapeProps, i) => ({ ...etapeProps, isBrouillon: etapeProps.isBrouillon ?? ETAPE_IS_NOT_BROUILLON, ordre: i + 1, + titreTypeId, + demarcheTypeId, + date: toCaminoDate('0001-01-01'), }) as unknown as TitreEtapeForMachine ) @@ -25,17 +30,21 @@ describe("statut d'une démarche", () => { }) test("une démarche d'octroi sans étape décisive a le statut “indéfini”", () => { - expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'anf' }]), 'pxm', newDemarcheId())).toEqual('ind') + expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'anf' }], 'oct', 'pxm'), 'pxm', newDemarcheId())).toEqual('ind') }) test("une démarche d'octroi dont l'étape de dpu la plus récente est acceptée a le statut “accepté”", () => { expect( titreDemarcheStatutIdFind( 'oct', - etapesBuild([ - { typeId: 'dex', statutId: 'acc' }, - { typeId: 'dpu', statutId: 'acc' }, - ]), + etapesBuild( + [ + { typeId: 'dex', statutId: 'acc' }, + { typeId: 'dpu', statutId: 'acc' }, + ], + 'oct', + 'pxm' + ), 'pxm', newDemarcheId() ) @@ -43,7 +52,7 @@ describe("statut d'une démarche", () => { }) test("une démarche d'octroi d'un titre AXM dont l'étape de dex la plus récente est acceptée a le statut “accepté”", () => { - expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'dex', date: toCaminoDate('2010-01-01'), statutId: 'acc' }]), 'axm', newDemarcheId())).toEqual('acc') + expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'dex', date: toCaminoDate('2010-01-01'), statutId: 'acc' }], 'oct', 'axm'), 'axm', newDemarcheId())).toEqual('acc') }) test("une démarche d'octroi d'un titre ARM dont l'étape de def la plus récente est acceptée a le statut “accepté”", () => { @@ -64,7 +73,7 @@ describe("statut d'une démarche", () => { }) test("une démarche d'octroi d'un titre PRM dont l'étape de rpu la plus récente est acceptée a le statut “accepté”", () => { - expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'rpu', date: toCaminoDate('2010-01-01'), statutId: 'acc' }]), 'prm', newDemarcheId())).toEqual('acc') + expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'rpu', date: toCaminoDate('2010-01-01'), statutId: 'acc' }], 'oct', 'prm'), 'prm', newDemarcheId())).toEqual('acc') }) test("une démarche de prolongation dont l'étape de dpu la plus récente est acceptée a le statut “accepté”", () => { @@ -166,10 +175,14 @@ describe("statut d'une démarche", () => { expect( titreDemarcheStatutIdFind( 'oct', - etapesBuild([ - { typeId: 'mfr', statutId: 'fai' }, - { typeId: 'mdp', statutId: 'fai' }, - ]), + etapesBuild( + [ + { typeId: 'mfr', statutId: 'fai' }, + { typeId: 'mdp', statutId: 'fai' }, + ], + 'oct', + 'arm' + ), 'arm', newDemarcheId() ) diff --git a/packages/api/src/business/rules/titre-demarche-statut-id-find.ts b/packages/api/src/business/rules/titre-demarche-statut-id-find.ts index cc28248481b1d0b11c65b1d58094d6a9a7cee9e1..75e360419999f9fb8c3bb8180d7b20692096a1cc 100644 --- a/packages/api/src/business/rules/titre-demarche-statut-id-find.ts +++ b/packages/api/src/business/rules/titre-demarche-statut-id-find.ts @@ -3,13 +3,14 @@ import { DemarcheId } from 'camino-common/src/demarche' import { titreEtapesSortDescByOrdre } from '../utils/titre-etapes-sort' import { titreEtapePublicationCheck } from './titre-etape-publication-check' -import { demarcheDefinitionFind } from '../rules-demarches/definitions' +import { machineFind } from '../rules-demarches/definitions' import { TitreEtapeForMachine, toMachineEtapes } from '../rules-demarches/machine-common' import { DemarcheStatutId, DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts' import { TitreTypeId } from 'camino-common/src/static/titresTypes' import { DemarcheTypeId, TravauxIds } from 'camino-common/src/static/demarchesTypes' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes' import { isEtapeStatusRejete } from 'camino-common/src/static/etapesStatuts' +import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools' const titreEtapesDecisivesCommunesTypes: EtapeTypeId[] = ['css', 'abd', 'and'] @@ -283,10 +284,10 @@ export const titreDemarcheStatutIdFind = (demarcheTypeId: DemarcheTypeId, titreD return titreDemarcheTravauxStatutIdFind(titreDemarcheEtapes, demarcheTypeId) } - const demarcheDefinition = demarcheDefinitionFind(titreTypeId, demarcheTypeId, titreDemarcheEtapes, demarcheId) + const machine = machineFind(titreTypeId, demarcheTypeId, titreDemarcheEtapes, demarcheId) - if (demarcheDefinition) { - return demarcheDefinition.machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes)).demarcheStatut + if (isNotNullNorUndefined(machine)) { + return machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes)).demarcheStatut } // si la démarche fait l’objet d’une demande diff --git a/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts b/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts index 90da1d1043c77264e336fa16ca6de9ef47db3272..0944ce5d67c0488aec1311e0a3f0463c7f19dd31 100644 --- a/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts +++ b/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts @@ -21,7 +21,7 @@ const titreEtapesFilter = (titreEtapes: ITitreEtape[], date: string) => titreEta * @returns démarches du titre */ -export const titreDemarchesEtapesRebuild = (date: CaminoDate, titreDemarches: ITitreDemarche[], titreTypeId: TitreTypeId) => { +export const titreDemarchesEtapesRebuild = (date: CaminoDate, titreDemarches: ITitreDemarche[], titreTypeId: TitreTypeId): ITitreDemarche[] => { const titreDemarchesRebuilt = titreDemarches.reduce((acc: ITitreDemarche[], td) => { if (!td.etapes) return acc diff --git a/packages/api/src/business/utils/titre-etapes-sort.ts b/packages/api/src/business/utils/titre-etapes-sort.ts index 65fce52b8cda72a13a0346c7ca87b40e6eb44c46..062bbce8b1864a7b50e6309b098c97d3a83943fd 100644 --- a/packages/api/src/business/utils/titre-etapes-sort.ts +++ b/packages/api/src/business/utils/titre-etapes-sort.ts @@ -1,5 +1,5 @@ import { ITitreEtape } from '../../types' -import { demarcheDefinitionFind } from '../rules-demarches/definitions' +import { machineFind } from '../rules-demarches/definitions' import { TitreEtapeForMachine, toMachineEtapes } from '../rules-demarches/machine-common' import { TitreTypeId } from 'camino-common/src/static/titresTypes' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes' @@ -16,10 +16,10 @@ export const titreEtapesSortDescByOrdre = <T extends Pick<ITitreEtape, 'ordre'>> export const titreEtapesSortAscByOrdre = <T extends Pick<ITitreEtape, 'ordre'>>(titreEtapes: T[]): T[] => titreEtapes.toSorted((a, b) => a.ordre! - b.ordre!) // classe les étapes selon leur dates, ordre et etapesTypes.ordre le cas échéant export const titreEtapesSortAscByDate = <T extends TitreEtapeForMachine>(titreEtapes: T[], demarcheId: DemarcheId, demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId): T[] => { - const demarcheDefinition = demarcheDefinitionFind(titreTypeId, demarcheTypeId, titreEtapes, demarcheId) - if (demarcheDefinition) { - const etapes = demarcheDefinition.machine.orderMachine(toMachineEtapes(titreEtapes)) - if (!demarcheDefinition.machine.isEtapesOk(etapes)) { + const machine = machineFind(titreTypeId, demarcheTypeId, titreEtapes, demarcheId) + if (machine) { + const etapes = machine.orderMachine(toMachineEtapes(titreEtapes)) + if (!machine.isEtapesOk(etapes)) { console.error(`impossible de trouver un ordre pour la démarche '${demarcheId}' où ces étapes sont valides ${JSON.stringify(etapes)}`) } diff --git a/packages/api/src/business/validations/titre-demarche-etat-validate.ts b/packages/api/src/business/validations/titre-demarche-etat-validate.ts index 5de2024c69249bdb175b0f7f62055cb5f45e5f0c..80845836d945270ebcf27cae4ee4577cc193d964 100644 --- a/packages/api/src/business/validations/titre-demarche-etat-validate.ts +++ b/packages/api/src/business/validations/titre-demarche-etat-validate.ts @@ -2,7 +2,7 @@ import { DeepReadonly, NonEmptyArray, isNonEmptyArray, isNotNullNorUndefined, isNullOrUndefinedOrEmpty, onlyUnique } from 'camino-common/src/typescript-tools' import type { ITitre, ITitreEtape } from '../../types' -import { DemarcheDefinition, demarcheDefinitionFind } from '../rules-demarches/definitions' +import { machineFind } from '../rules-demarches/definitions' import { Etape, TitreEtapeForMachine, titreEtapeForMachineValidator, toMachineEtapes } from '../rules-demarches/machine-common' import { DemarcheId } from 'camino-common/src/demarche' import { DemarchesTypes, DemarcheTypeId } from 'camino-common/src/static/demarchesTypes' @@ -56,7 +56,7 @@ export const titreDemarcheUpdatedEtatValidate = ( suppression = false ): { valid: true; errors: null } | { valid: false; errors: NonEmptyArray<string> } => { const titreDemarcheEtapesNew = titreDemarcheEtapesBuild(titreEtape, suppression, titreDemarcheEtapes) - const demarcheDefinition = demarcheDefinitionFind(titre.typeId, demarcheTypeId, titreDemarcheEtapesNew, demarcheId) + const machine = machineFind(titre.typeId, demarcheTypeId, titreDemarcheEtapesNew, demarcheId) const titreDemarchesErrors: string[] = [] // vérifie que la démarche existe dans le titre @@ -66,10 +66,10 @@ export const titreDemarcheUpdatedEtatValidate = ( } // on récupère tous les type d'étapes et les statuts associés applicable à la date souhaitée try { - const etapeTypesWithStatusPossibles = getPossiblesEtapesTypes(demarcheDefinition, titre.typeId, demarcheTypeId, titreEtape.typeId, titreEtape.id, titreEtape.date, titreDemarcheEtapes ?? []) + const etapeTypesWithStatusPossibles = getPossiblesEtapesTypes(machine, titre.typeId, demarcheTypeId, titreEtape.typeId, titreEtape.id, titreEtape.date, titreDemarcheEtapes ?? []) if (!etapeTypesWithStatusPossibles.some(({ etapeStatutId, etapeTypeId }) => etapeStatutId === titreEtape.statutId && etapeTypeId === titreEtape.typeId)) { - if (isNotNullNorUndefined(demarcheDefinition)) { + if (isNotNullNorUndefined(machine)) { return { valid: false, errors: ['les étapes de la démarche machine ne sont pas valides'] } } else { return { valid: false, errors: ['les étapes de la démarche TDE ne sont pas valides'] } @@ -80,11 +80,11 @@ export const titreDemarcheUpdatedEtatValidate = ( titreDemarchesErrors.push(e.message) } - if (isNotNullNorUndefined(demarcheDefinition)) { + if (isNotNullNorUndefined(machine)) { // vérifie que toutes les étapes existent dans l’arbre try { const etapes = titreDemarcheEtapesNew.map(etape => titreEtapeForMachineValidator.omit({ id: true, ordre: true }).parse(etape)) - const ok = demarcheDefinition.machine.isEtapesOk(demarcheDefinition.machine.orderMachine(toMachineEtapes(etapes))) + const ok = machine.isEtapesOk(machine.orderMachine(toMachineEtapes(etapes))) if (!ok) { titreDemarchesErrors.push('la démarche machine n’est pas valide') } @@ -102,7 +102,7 @@ export const titreDemarcheUpdatedEtatValidate = ( } export const getPossiblesEtapesTypes = ( - demarcheDefinition: DemarcheDefinition | undefined, + machine: CaminoMachines | undefined, titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId, etapeTypeId: EtapeTypeId | undefined, @@ -111,10 +111,10 @@ export const getPossiblesEtapesTypes = ( demarcheEtapes: Pick<ITitreEtape, 'typeId' | 'date' | 'isBrouillon' | 'id' | 'ordre' | 'statutId' | 'communes'>[] ): EtapeTypeEtapeStatutWithMainStep[] => { const etapesTypes: EtapeTypeEtapeStatutWithMainStep[] = [] - if (isNotNullNorUndefined(demarcheDefinition)) { + if (isNotNullNorUndefined(machine)) { const etapes = demarcheEtapes.map(etape => titreEtapeForMachineValidator.parse(etape)) - etapesTypes.push(...etapesTypesPossibleACetteDateOuALaPlaceDeLEtape(demarcheDefinition.machine, etapes, etapeId ?? null, date)) + etapesTypes.push(...etapesTypesPossibleACetteDateOuALaPlaceDeLEtape(machine, etapes, etapeId ?? null, date)) } else { // si on modifie une étape // vérifie que son type est possible sur la démarche diff --git a/packages/api/src/database/models/entreprises-etablissements.ts b/packages/api/src/database/models/entreprises-etablissements.ts index 438a79b675d95707c39e83da18e94599f3f627d5..7d87c52ef252003cc17fda03965b04462ba03ec2 100644 --- a/packages/api/src/database/models/entreprises-etablissements.ts +++ b/packages/api/src/database/models/entreprises-etablissements.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Modifiers } from 'objection' import { IEntrepriseEtablissement } from '../../types' @@ -5,9 +6,9 @@ import { IEntrepriseEtablissement } from '../../types' interface EntreprisesEtablissements extends IEntrepriseEtablissement {} class EntreprisesEtablissements extends Model { - public static tableName = 'entreprisesEtablissements' + public static override tableName = 'entreprisesEtablissements' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['id', 'entrepriseId', 'dateDebut'], @@ -21,7 +22,7 @@ class EntreprisesEtablissements extends Model { }, } - public static modifiers: Modifiers = { + public static override modifiers: Modifiers = { orderDesc: builder => { builder.orderBy('dateDebut', 'desc') }, diff --git a/packages/api/src/database/models/entreprises.ts b/packages/api/src/database/models/entreprises.ts index 2d41c46d1dd21dcad9897161055c0fc7122ed42a..993ac74a30f8e5aff0de428dc2e986c6d945f72b 100644 --- a/packages/api/src/database/models/entreprises.ts +++ b/packages/api/src/database/models/entreprises.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Pojo } from 'objection' import { IEntreprise } from '../../types' @@ -8,9 +9,9 @@ import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools' interface Entreprises extends IEntreprise {} class Entreprises extends Model { - public static tableName = 'entreprises' + public static override tableName = 'entreprises' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['id', 'nom'], @@ -34,7 +35,7 @@ class Entreprises extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ etablissements: { relation: Model.HasManyRelation, modelClass: EntreprisesEtablissements, @@ -58,7 +59,7 @@ class Entreprises extends Model { }, }) - public $parseJson(json: Pojo) { + public override $parseJson(json: Pojo) { json = super.$parseJson(json) // TODO 2024-06-03 à supprimer et vérifier que l'api sirene a bien des Ids en minuscule (lancer le monthly) if (isNotNullNorUndefined(json.id)) { diff --git a/packages/api/src/database/models/journaux.ts b/packages/api/src/database/models/journaux.ts index 65025434ddc2c0168e7d758c28b52049ab2e8bc4..748276a333043e6709c13aa01024f9b73fd48ff3 100644 --- a/packages/api/src/database/models/journaux.ts +++ b/packages/api/src/database/models/journaux.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model } from 'objection' import { IJournaux } from '../../types' @@ -8,9 +9,9 @@ import Titres from './titres' interface Journaux extends IJournaux {} class Journaux extends Model { - public static tableName = 'journaux' + public static override tableName = 'journaux' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', properties: { @@ -24,7 +25,7 @@ class Journaux extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ utilisateur: { relation: Model.BelongsToOneRelation, modelClass: Utilisateurs, @@ -43,7 +44,7 @@ class Journaux extends Model { }, }) - async $beforeInsert(queryContext: any) { + override async $beforeInsert(queryContext: any) { await super.$beforeInsert(queryContext) this.id = idGenerate() diff --git a/packages/api/src/database/models/titres--titres.ts b/packages/api/src/database/models/titres--titres.ts index bd402a51c59899f9692f7b1f12bccc24848b85f8..ac17882690488c0473490591b34b7b5dffbd5808 100644 --- a/packages/api/src/database/models/titres--titres.ts +++ b/packages/api/src/database/models/titres--titres.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model } from 'objection' import { ITitreTitre } from '../../types' @@ -6,9 +7,9 @@ interface TitreTitre extends ITitreTitre {} interface TitresTitres extends TitreTitre {} class TitresTitres extends Model { - public static tableName = 'titres__titres' + public static override tableName = 'titres__titres' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['titreFromId', 'titreToId'], properties: { @@ -17,7 +18,7 @@ class TitresTitres extends Model { }, } - public static idColumn = ['titreFromId', 'titreToId'] + public static override idColumn = ['titreFromId', 'titreToId'] } export default TitresTitres diff --git a/packages/api/src/database/models/titres-activites.ts b/packages/api/src/database/models/titres-activites.ts index 996222ff72bc4b97b6398e39d67eb96f6c8baef2..ca0a33e0c1924ca0d499d45e575533e40173562a 100644 --- a/packages/api/src/database/models/titres-activites.ts +++ b/packages/api/src/database/models/titres-activites.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Modifiers, Pojo, QueryContext } from 'objection' import { ITitreActivite } from '../../types' @@ -9,9 +10,9 @@ import { isNotNullNorUndefined, isNullOrUndefined } from 'camino-common/src/type interface TitresActivites extends ITitreActivite {} class TitresActivites extends Model { - public static tableName = 'titresActivites' + public static override tableName = 'titresActivites' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['titreId', 'date', 'typeId', 'activiteStatutId', 'periodeId', 'annee'], @@ -32,7 +33,7 @@ class TitresActivites extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ titre: { relation: Model.BelongsToOneRelation, modelClass: Titres, @@ -52,13 +53,13 @@ class TitresActivites extends Model { }, }) - public static modifiers: Modifiers = { + public static override modifiers: Modifiers = { orderDesc: builder => { builder.orderByRaw('date desc') }, } - async $beforeInsert(context: QueryContext) { + override async $beforeInsert(context: QueryContext) { if (isNullOrUndefined(this.id)) { this.id = idGenerate() } @@ -69,14 +70,14 @@ class TitresActivites extends Model { return super.$beforeInsert(context) } - public $parseJson(json: Pojo) { + public override $parseJson(json: Pojo) { delete json.modification json = super.$parseJson(json) return json } - public $formatDatabaseJson(json: Pojo) { + public override $formatDatabaseJson(json: Pojo) { delete json.modification json = super.$formatDatabaseJson(json) diff --git a/packages/api/src/database/models/titres-demarches.ts b/packages/api/src/database/models/titres-demarches.ts index 098648752028dff4de0b9559fc40de2d726c6268..7513cc7ef97aca0fce01098df69f3fa5bde31311 100644 --- a/packages/api/src/database/models/titres-demarches.ts +++ b/packages/api/src/database/models/titres-demarches.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Modifiers, QueryContext } from 'objection' import { ITitreDemarche } from '../../types' @@ -13,9 +14,9 @@ export interface DBTitresDemarches extends ITitreDemarche { interface TitresDemarches extends DBTitresDemarches {} class TitresDemarches extends Model { - public static tableName = 'titresDemarches' + public static override tableName = 'titresDemarches' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['titreId', 'typeId'], @@ -33,7 +34,7 @@ class TitresDemarches extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ titre: { relation: Model.BelongsToOneRelation, modelClass: Titres, @@ -53,13 +54,13 @@ class TitresDemarches extends Model { }, }) - public static modifiers: Modifiers = { + public static override modifiers: Modifiers = { orderDesc: builder => { builder.orderBy('ordre', 'desc') }, } - async $beforeInsert(context: QueryContext) { + override async $beforeInsert(context: QueryContext) { if (isNullOrUndefined(this.id)) { this.id = newDemarcheId() } diff --git a/packages/api/src/database/models/titres-etapes.ts b/packages/api/src/database/models/titres-etapes.ts index 767ad481b69e013879d404560ad6a2a51d582965..66ace38975790daedd6626db99661ae75ef4a5ad 100644 --- a/packages/api/src/database/models/titres-etapes.ts +++ b/packages/api/src/database/models/titres-etapes.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, ModelOptions, Pojo, QueryContext } from 'objection' @@ -16,9 +17,9 @@ export interface DBTitresEtapes extends ITitreEtape { } interface TitresEtapes extends DBTitresEtapes {} class TitresEtapes extends Model { - public static tableName = 'titresEtapes' + public static override tableName = 'titresEtapes' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', // l’id est généré tout seul required: ['titreDemarcheId', 'date'], @@ -53,7 +54,7 @@ class TitresEtapes extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ demarche: { relation: Model.BelongsToOneRelation, modelClass: TitresDemarches, @@ -73,7 +74,7 @@ class TitresEtapes extends Model { }, }) - async $beforeInsert(context: QueryContext) { + override async $beforeInsert(context: QueryContext) { if (!this.id) { this.id = idGenerate() } @@ -90,7 +91,7 @@ class TitresEtapes extends Model { await super.$beforeInsert(context) } - async $beforeUpdate(opt: ModelOptions, context: QueryContext) { + override async $beforeUpdate(opt: ModelOptions, context: QueryContext) { if (isNotNullNorUndefined(this.geojson4326Perimetre)) { // eslint-disable-next-line sql/no-unsafe-query const rawLine = await context.transaction.raw(`select ST_GeomFromGeoJSON('${JSON.stringify(this.geojson4326Perimetre.geometry)}'::text)`) @@ -100,7 +101,7 @@ class TitresEtapes extends Model { return super.$beforeUpdate(opt, context) } - async $afterFind(context: QueryContext) { + override async $afterFind(context: QueryContext) { if (context.fetchHeritage && this.heritageProps) { this.heritageProps = await heritagePropsFormat(this.heritageProps) } @@ -121,7 +122,7 @@ class TitresEtapes extends Model { return this } - public $formatDatabaseJson(json: Pojo) { + public override $formatDatabaseJson(json: Pojo) { delete json.entrepriseDocumentIds delete json.etapeDocuments delete json.etapeAvis @@ -134,7 +135,7 @@ class TitresEtapes extends Model { return json } - public $parseJson(json: Pojo) { + public override $parseJson(json: Pojo) { delete json.modification delete json.suppression json = super.$parseJson(json) diff --git a/packages/api/src/database/models/titres.ts b/packages/api/src/database/models/titres.ts index 4105ff14e58e6a2209a4f396f3a2cc6233c5c34e..05d8aaff8a678aeacba0d7303ad99fb321af8044 100644 --- a/packages/api/src/database/models/titres.ts +++ b/packages/api/src/database/models/titres.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Pojo, QueryContext, ref } from 'objection' import { ITitre } from '../../types' @@ -14,9 +15,9 @@ export interface DBTitre extends ITitre { interface Titres extends DBTitre {} class Titres extends Model { - public static tableName = 'titres' + public static override tableName = 'titres' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['nom', 'typeId'], properties: { @@ -32,7 +33,7 @@ class Titres extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ demarches: { relation: Model.HasManyRelation, modelClass: TitresDemarches, @@ -82,7 +83,7 @@ class Titres extends Model { }, }) - async $beforeInsert(context: QueryContext) { + override async $beforeInsert(context: QueryContext) { if (isNullOrUndefined(this.id)) { this.id = idGenerate() } @@ -94,7 +95,7 @@ class Titres extends Model { return super.$beforeInsert(context) } - $afterFind() { + override $afterFind() { if (this.substancesEtape === null) { this.substances = [] } else if (this.substancesEtape === undefined) { @@ -141,14 +142,14 @@ class Titres extends Model { } } - public $parseJson(json: Pojo) { + public override $parseJson(json: Pojo) { json = titreInsertFormat(json) json = super.$parseJson(json) return json } - public $formatDatabaseJson(json: Pojo) { + public override $formatDatabaseJson(json: Pojo) { json = titreInsertFormat(json) json = super.$formatDatabaseJson(json) diff --git a/packages/api/src/database/models/utilisateurs--titres.ts b/packages/api/src/database/models/utilisateurs--titres.ts index 009451366eae194c68d965469c08559facc00604..08df0387cf7ed7c480bfa12f9d0a5a3a6052fc5e 100644 --- a/packages/api/src/database/models/utilisateurs--titres.ts +++ b/packages/api/src/database/models/utilisateurs--titres.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model } from 'objection' import { IUtilisateurTitre } from '../../types' import Utilisateurs from './utilisateurs' @@ -5,9 +6,9 @@ import Utilisateurs from './utilisateurs' interface UtilisateursTitres extends IUtilisateurTitre {} class UtilisateursTitres extends Model { - public static tableName = 'utilisateurs__titres' + public static override tableName = 'utilisateurs__titres' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['utilisateurId', 'titreId'], @@ -17,9 +18,9 @@ class UtilisateursTitres extends Model { }, } - public static idColumn = ['utilisateurId', 'titreId'] + public static override idColumn = ['utilisateurId', 'titreId'] - static relationMappings = () => ({ + static override relationMappings = () => ({ utilisateur: { relation: Model.BelongsToOneRelation, modelClass: Utilisateurs, diff --git a/packages/api/src/database/models/utilisateurs.ts b/packages/api/src/database/models/utilisateurs.ts index 258f564de7223a9765b40a937b4edfe49629dab8..a3d4d89cbb638c366e2eb3e7f1a5f677e49fd21c 100644 --- a/packages/api/src/database/models/utilisateurs.ts +++ b/packages/api/src/database/models/utilisateurs.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Model, Pojo } from 'objection' import Entreprises from './entreprises' @@ -23,9 +24,9 @@ interface IUtilisateur { interface Utilisateurs extends IUtilisateur {} class Utilisateurs extends Model { - public static tableName = 'utilisateurs' + public static override tableName = 'utilisateurs' - public static jsonSchema = { + public static override jsonSchema = { type: 'object', required: ['id', 'email', 'role'], @@ -42,7 +43,7 @@ class Utilisateurs extends Model { }, } - static relationMappings = () => ({ + static override relationMappings = () => ({ entreprises: { relation: Model.ManyToManyRelation, modelClass: Entreprises, @@ -57,13 +58,13 @@ class Utilisateurs extends Model { }, }) - public $parseJson(json: Pojo) { + public override $parseJson(json: Pojo) { json = super.$parseJson(json) return json } - public $formatDatabaseJson(json: Pojo) { + public override $formatDatabaseJson(json: Pojo) { json = super.$formatDatabaseJson(json) return json diff --git a/packages/api/src/tools/demarches/tde-check.ts b/packages/api/src/tools/demarches/tde-check.ts index 7dc87fe59df487b5c0eb6694bbd054903d6db34c..d0139465c5ebc6604ea67cedb3cbbc3e4836563c 100644 --- a/packages/api/src/tools/demarches/tde-check.ts +++ b/packages/api/src/tools/demarches/tde-check.ts @@ -1,10 +1,11 @@ import { EtapesTypes } from 'camino-common/src/static/etapesTypes' import { isTDEExist } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index' -import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions' +import { machineFind } from '../../business/rules-demarches/definitions' import { titresDemarchesGet } from '../../database/queries/titres-demarches' import { userSuper } from '../../database/user-super' +import { isNullOrUndefined } from 'camino-common/src/typescript-tools' -export const titreTypeDemarcheTypeEtapeTypeCheck = async () => { +export const titreTypeDemarcheTypeEtapeTypeCheck = async (): Promise<void> => { console.info() console.info('- - -') console.info('vérification de TDE avec les démarches en bdd') @@ -24,9 +25,9 @@ export const titreTypeDemarcheTypeEtapeTypeCheck = async () => { let errorsNb = 0 demarches.forEach(d => { - const demarcheDefinition = demarcheDefinitionFind(d.titre!.typeId, d.typeId, d.etapes, d.id) + const machine = machineFind(d.titre!.typeId, d.typeId, d.etapes, d.id) - if (!demarcheDefinition) { + if (isNullOrUndefined(machine)) { d.etapes?.forEach(({ typeId }) => { if (!isTDEExist(d.titre!.typeId, d.typeId, typeId)) { console.info(`erreur sur le titre https://camino.beta.gouv.fr/titres/${d.titre!.id}, TDE inconnu ${d.titre!.typeId} ${d.typeId} ${typeId} (${EtapesTypes[typeId].nom})`) diff --git a/packages/api/src/tools/demarches/tests-creation.ts b/packages/api/src/tools/demarches/tests-creation.ts index 18ed1061c1d98d34a5d3a9355e812f198715b855..384a81619834e388ce32c71e1c90c8a3cef310fc 100644 --- a/packages/api/src/tools/demarches/tests-creation.ts +++ b/packages/api/src/tools/demarches/tests-creation.ts @@ -4,7 +4,7 @@ import { titresDemarchesGet } from '../../database/queries/titres-demarches' import { userSuper } from '../../database/user-super' import { mkdirSync, writeFileSync } from 'fs' import { Etape, titreEtapeForMachineValidator, toMachineEtapes } from '../../business/rules-demarches/machine-common' -import { demarcheDefinitionFind, demarchesDefinitions } from '../../business/rules-demarches/definitions' +import { machineFind, demarchesDefinitions } from '../../business/rules-demarches/definitions' import { dateAddDays, daysBetween, setDayInMonth } from 'camino-common/src/date' import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes' import { toCommuneId } from 'camino-common/src/static/communes' @@ -30,7 +30,7 @@ const writeEtapesForTest = async () => { const toutesLesEtapes = demarches .filter(demarche => demarche.etapes?.length) - .filter(demarche => isNotNullNorUndefined(demarcheDefinitionFind(demarche.titre!.typeId, demarche.typeId, demarche.etapes!, demarche.id))) + .filter(demarche => isNotNullNorUndefined(machineFind(demarche.titre!.typeId, demarche.typeId, demarche.etapes!, demarche.id))) .map((demarche, index) => { const etapes: Etape[] = toMachineEtapes( ( @@ -59,9 +59,10 @@ const writeEtapesForTest = async () => { const firstSaisineDate = etapes.find(etape => etape.etapeTypeId === ETAPES_TYPES.avisDesServicesEtCommissionsConsultatives)?.date ?? etapes[0].date const decalageJour = daysBetween(firstSaisineDate, setDayInMonth(firstSaisineDate, Math.floor(Math.random() * 28))) try { - if (!demarcheDefinition.machine.isEtapesOk(etapes)) { - etapes.splice(0, etapes.length, ...demarcheDefinition.machine.orderMachine(etapes)) - if (!demarcheDefinition.machine.isEtapesOk(etapes)) { + const machine = demarcheDefinition.machine(demarche.titre!.typeId, demarche.typeId) + if (!machine.isEtapesOk(etapes)) { + etapes.splice(0, etapes.length, ...machine.orderMachine(etapes)) + if (!machine.isEtapesOk(etapes)) { console.warn(`https://camino.beta.gouv.fr/titres/${demarche.titreId} => démarche N*${index} (${demarche.id}) "${demarcheDefinition.titreTypeIds.join(' ou ')}/${demarche.typeId}"`) } } diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 6f61185a536170e8b845957baf8ed151360f0091..7d16adcf304f1be1a15620b970655cc73a7faab0 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -16,6 +16,7 @@ "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, + "noImplicitOverride": true, "outDir": "dist", "strict": true, "strictNullChecks": true, diff --git a/packages/common/.eslintignore b/packages/common/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..060e9ebe82a792b942e71082edac8a84eda6c7c2 --- /dev/null +++ b/packages/common/.eslintignore @@ -0,0 +1 @@ +vitest.config.ts diff --git a/packages/common/src/static/__snapshots__/demarchesTypes.test.ts.snap b/packages/common/src/static/__snapshots__/demarchesTypes.test.ts.snap index dcd7c8a000c334b850dee7e41ba4525094d410e0..2ce7ae6cf08aaa521c6eb6b662fa52ace030a84c 100644 --- a/packages/common/src/static/__snapshots__/demarchesTypes.test.ts.snap +++ b/packages/common/src/static/__snapshots__/demarchesTypes.test.ts.snap @@ -303,3 +303,31 @@ exports[`canImpactTitre 1`] = ` "vut - ter -> true", ] `; + +exports[`isDemarcheTypeProlongations 1`] = ` +[ + "amo -> false", + "aom -> false", + "ces -> false", + "con -> false", + "dam -> false", + "dec -> false", + "dep -> false", + "dot -> false", + "exp -> false", + "exs -> false", + "fus -> false", + "mut -> false", + "oct -> false", + "pr1 -> true", + "pr2 -> true", + "pre -> true", + "pro -> true", + "prr -> false", + "ren -> false", + "res -> false", + "ret -> false", + "vct -> false", + "vut -> false", +] +`; diff --git a/packages/common/src/static/demarchesTypes.test.ts b/packages/common/src/static/demarchesTypes.test.ts index 6bc0c5447335a95f07c8601d3ea34302e94af42f..c0060e496015a10e3af3a2c67be0de2050703229 100644 --- a/packages/common/src/static/demarchesTypes.test.ts +++ b/packages/common/src/static/demarchesTypes.test.ts @@ -1,6 +1,6 @@ import { getValues } from '../typescript-tools' import { sortedDemarchesStatuts } from './demarchesStatuts' -import { DEMARCHES_TYPES_IDS, isDemarcheTypeId, isDemarcheTypeOctroi, isDemarcheTypeWithPhase, canImpactTitre } from './demarchesTypes' +import { DEMARCHES_TYPES_IDS, isDemarcheTypeId, isDemarcheTypeOctroi, isDemarcheTypeWithPhase, canImpactTitre, isDemarcheTypeProlongations } from './demarchesTypes' import { test, expect } from 'vitest' test('isDemarcheTypeId', () => { @@ -39,3 +39,10 @@ test('canImpactTitre', () => { }) expect(result).toMatchSnapshot() }) + +test('isDemarcheTypeProlongations', () => { + const result = getValues(DEMARCHES_TYPES_IDS).flatMap(demarcheType => { + return `${demarcheType} -> ${isDemarcheTypeProlongations(demarcheType)}` + }) + expect(result).toMatchSnapshot() +}) diff --git a/packages/common/src/static/demarchesTypes.ts b/packages/common/src/static/demarchesTypes.ts index e745c6d38cde5b92128307ff119d23bdf88228f4..b566d78bb9fa5d6609a50007ca9c619238d05881 100644 --- a/packages/common/src/static/demarchesTypes.ts +++ b/packages/common/src/static/demarchesTypes.ts @@ -284,18 +284,12 @@ export const isDemarcheTypeOctroi = (demarcheTypeId: DemarcheTypeId): boolean => return demarchesTypesOctroi.includes(demarcheTypeId) } -const demarchesTypesWithPhasesAndWithoutDateFin: DemarcheTypeId[] = [ - DEMARCHES_TYPES_IDS.Prolongation, - DEMARCHES_TYPES_IDS.Prolongation1, - DEMARCHES_TYPES_IDS.Prolongation2, - DEMARCHES_TYPES_IDS.ProlongationExceptionnelle, -] export const isDemarcheTypeWithPhase = (demarcheTypeId: DemarcheTypeId): boolean => { if (isDemarcheTypeOctroi(demarcheTypeId)) { return true } - return demarchesTypesWithPhasesAndWithoutDateFin.includes(demarcheTypeId) + return isDemarcheTypeProlongations(demarcheTypeId) } export const sortedDemarchesTypes = Object.values(DemarchesTypes).sort((a, b) => a.nom.localeCompare(b.nom)) @@ -304,6 +298,10 @@ export const isTravaux = (demarcheTypeId: DemarcheTypeId): boolean => { return DemarchesTypes[demarcheTypeId].travaux } +export const isDemarcheTypeProlongations = (demarcheType: DemarcheTypeId): boolean => { + return [DEMARCHES_TYPES_IDS.Prolongation, DEMARCHES_TYPES_IDS.Prolongation1, DEMARCHES_TYPES_IDS.Prolongation2, DEMARCHES_TYPES_IDS.ProlongationExceptionnelle].includes(demarcheType) +} + /** * La démarche a un impact potentiel sur le titre (statut, visibilité administrations…) */ diff --git a/packages/common/src/static/etapesTypes.ts b/packages/common/src/static/etapesTypes.ts index f8ba7066b65f7e6409998384c3a8608f7ea755ca..9de0fd2f3c1c4fa0cb972f32ac5181838568cf95 100644 --- a/packages/common/src/static/etapesTypes.ts +++ b/packages/common/src/static/etapesTypes.ts @@ -4,13 +4,13 @@ import { Definition } from '../definition' import { EtapeBrouillon } from '../etape' // prettier-ignore -const IDS = ['abd', 'aca','aco','and','anf','def','dex','dim', 'dpu', 'dux','ihi', 'mfr','mod','mom','rca','rcb','rcd','rcm','rco','rcs','rie','rif','rim','rpu','sco','acg','apd','ape','apo','app','apu','asl','cac','cim','cod','css','dae','dec','des','ede','edm','epc','epu','esb','mca','mcb','mcd','mcm','mco','mcp','mcr','mcs','mdp','mec','men','meo','mie','mif','mim','mna','mnb','mnc','mnd','mni','mno','mns','mnv','ncl','npp','pfc','pfd','ppu','pqr','rcg','rde','rpe','sas','sca','scg','scl','spe','spo','spp','vfc','vfd','wab','wae','wao','war','wau','wce','wco','wda','wdc','wdd','wde','wdm','wfa','wfd','wfo','wfr','wmm','wmr','wmt','woe','wpa','wpb','wpc','wpo','wpp','wps','wrc','wrd','wre','wrt','wse','wtp', 'asc', 'adc'] as const +const IDS = ['abd', 'aca','aco','and','anf','def','dex','dim', 'dpu', 'dux','ihi', 'mfr','mod','mom','rca','rcb','rcd','rcm','rco','rcs','rie','rif','rim','rpu','sco','acg','apd','ape','apo','app','apu','asl','cac','cim','cod','css','dae','dec','des','ede','edm','epc','epu','esb','mca','mcb','mcd', 'mci','mcm','mco','mcp','mcr','mcs','mdp','mec','men','meo','mie','mif','mim','mna','mnb','mnc','mnd','mni','mno','mns','mnv','ncl','npp','pfc','pfd','ppu','pqr','rcg','rde','rpe','sas','sca','scg','scl','spe','spo','spp','vfc','vfd','wab','wae','wao','war','wau','wce','wco','wda','wdc','wdd','wde','wdm','wfa','wfd','wfo','wfr','wmm','wmr','wmt','woe','wpa','wpb','wpc','wpo','wpp','wps','wrc','wrd','wre','wrt','wse','wtp', 'asc', 'adc'] as const // prettier-ignore const FONDAMENTALES_IDS = ['abd', 'aca','aco','and','anf','def','dex','dim', 'dpu','dux','ihi', 'mfr','mod','mom','rca','rcb','rcd','rcm','rco','rcs','rie','rif','rim','rpu','sco'] as const satisfies Readonly<EtapeTypeIdFondamentaleArray> // prettier-ignore -const NON_FONDAMENTALES_IDS = ['acg','apd','ape','apo','app','apu','asl','cac','cim','cod','css','dae','dec','des','ede','edm','epc','epu','esb','mca','mcb','mcd','mcm','mco','mcp','mcr','mcs','mdp','mec','men','meo','mie','mif','mim','mna','mnb','mnc','mnd','mni','mno','mns','mnv','ncl','npp','pfc','pfd','ppu','pqr','rcg','rde','rpe','sas','sca','scg','scl','spe','spo','spp','vfc','vfd','wab','wae','wao','war','wau','wce','wco','wda','wdc','wdd','wde','wdm','wfa','wfd','wfo','wfr','wmm','wmr','wmt','woe','wpa','wpb','wpc','wpo','wpp','wps','wrc','wrd','wre','wrt','wse','wtp', 'asc', 'adc'] as const satisfies Readonly<EtapeTypeIdNonFondamentale[]> +const NON_FONDAMENTALES_IDS = ['acg','apd','ape','apo','app','apu','asl','cac','cim','cod','css','dae','dec','des','ede','edm','epc','epu','esb','mca','mcb','mcd','mci', 'mcm','mco','mcp','mcr', 'mcs','mdp','mec','men','meo','mie','mif','mim','mna','mnb','mnc','mnd','mni','mno','mns','mnv','ncl','npp','pfc','pfd','ppu','pqr','rcg','rde','rpe','sas','sca','scg','scl','spe','spo','spp','vfc','vfd','wab','wae','wao','war','wau','wce','wco','wda','wdc','wdd','wde','wdm','wfa','wfd','wfo','wfr','wmm','wmr','wmt','woe','wpa','wpb','wpc','wpo','wpp','wps','wrc','wrd','wre','wrt','wse','wtp', 'asc', 'adc'] as const satisfies Readonly<EtapeTypeIdNonFondamentale[]> // Ceci est un test :) ;[...FONDAMENTALES_IDS, ...NON_FONDAMENTALES_IDS] as const satisfies typeof IDS @@ -135,6 +135,7 @@ export const ETAPES_TYPES = { transmissionDuProjetDePrescriptionsAuDemandeur: 'wtp', avisDesServicesEtCommissionsConsultatives: 'asc', avisDesCollectivites: 'adc', + declarationDIrrecevabilite: 'mci', } as const satisfies Record<string, EtapeTypeId> export const etapeTypeIdValidator = z.enum(IDS) @@ -1358,6 +1359,16 @@ export const EtapesTypes = { public_lecture: true, entreprises_lecture: true, }, + mci: { + id: 'mci', + nom: "Déclaration d'irrecevabilité", + description: '', + fondamentale: false, + unique: false, + date_fin: null, + public_lecture: true, + entreprises_lecture: true, + }, } as const satisfies { [key in EtapeTypeId]: EtapeType<key> } type IsFondamentale<T> = T extends EtapeTypeId ? ((typeof EtapesTypes)[T] extends { fondamentale: true } ? T : never) : never diff --git a/packages/common/src/static/etapesTypesEtapesStatuts.ts b/packages/common/src/static/etapesTypesEtapesStatuts.ts index 1e9fd3a33f1f4eea2cc14ec5e26b68f3c61e9035..1d582252f8e53f40ed3963a0adb377947a177707 100644 --- a/packages/common/src/static/etapesTypesEtapesStatuts.ts +++ b/packages/common/src/static/etapesTypesEtapesStatuts.ts @@ -136,6 +136,9 @@ export const EtapesTypesEtapesStatuts = { FAVORABLE: { etapeTypeId: 'mcr', etapeStatutId: 'fav' }, DEFAVORABLE: { etapeTypeId: 'mcr', etapeStatutId: 'def' }, }, + declarationDIrrecevabilite: { + FAIT: { etapeTypeId: 'mci', etapeStatutId: 'fai' }, + }, demandeDeComplements_SaisineDeLaCARM_: { FAIT: { etapeTypeId: 'mcs', etapeStatutId: 'fai' } }, depotDeLaDemande: { FAIT: { etapeTypeId: 'mdp', etapeStatutId: 'fai' } }, avisDeDemandeConcurrente: { FAIT: { etapeTypeId: 'mec', etapeStatutId: 'fai' } }, diff --git a/packages/common/vitest.config.ts b/packages/common/vitest.config.ts index cb8723adec27035b9b26f8cd40a727489f0839c4..7c44a32d7986c73fbef0caafb40647756924dae2 100644 --- a/packages/common/vitest.config.ts +++ b/packages/common/vitest.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ thresholds: { // the endgame is to put thresholds at 100 and never touch it again :) autoUpdate: true, - branches: 89.96, - functions: 79.52, - lines: 96.14, - statements: 96.14, + branches: 90.09, + functions: 79.92, + lines: 96.4, + statements: 96.4, perFile: false, }, },