From 9728b000b48ade5c298a30efff9c2eea53bb98bb Mon Sep 17 00:00:00 2001 From: vmaubert <v.maubert@code-troopers.com> Date: Mon, 12 Jun 2023 10:07:38 +0200 Subject: [PATCH] =?UTF-8?q?feat(prm):=20transforme=20l=E2=80=99arbre=20d?= =?UTF-8?q?=E2=80=99instructions=20des=20octrois=20de=20PRM=20en=20machine?= =?UTF-8?q?=20(#579)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/api/src/api/_format/etapes-types.ts | 2 +- ...ons-permissions-etapes.test.integration.ts | 12 +- .../api/graphql/documents.test.integration.ts | 1 + .../src/api/graphql/resolvers/documents.ts | 17 +- .../src/api/graphql/resolvers/entreprises.ts | 3 +- .../api/src/api/graphql/resolvers/points.ts | 3 +- .../api/graphql/resolvers/titre-demande.ts | 3 +- .../api/graphql/resolvers/titres-activites.ts | 2 +- .../api/graphql/resolvers/titres-etapes.ts | 29 +- .../titres-demarches.test.integration.ts | 4 +- ...titres-etapes-modifier.test.integration.ts | 1 + .../api/graphql/titres.test.integration.ts | 54 +- .../api/rest/entreprises.test.integration.ts | 1 + packages/api/src/api/rest/entreprises.test.ts | 27 +- packages/api/src/api/rest/entreprises.ts | 5 +- packages/api/src/api/rest/etapes.test.ts | 191 ++++- packages/api/src/api/rest/etapes.ts | 29 +- packages/api/src/api/rest/fichiers.ts | 5 +- .../api/src/api/rest/titre-contenu.test.ts | 5 +- .../src/api/rest/titres.test.integration.ts | 19 +- packages/api/src/api/rest/titres.ts | 47 +- packages/api/src/business/daily.ts | 6 +- packages/api/src/business/matrices.test.ts | 7 +- .../titres-activites-update-titres.ts | 5 +- ...apes-areas-update.test.integration.ts.snap | 4 +- .../titres-demarches-depot-create.ts | 2 +- ...titres-demarches-statut-ids-update.test.ts | 43 +- .../titres-demarches-statut-ids-update.ts | 6 +- ...pes-administrations-locales-update.test.ts | 14 +- ...es-etapes-areas-update.test.integration.ts | 6 +- ...-etapes-heritage-contenu-update.queries.ts | 64 ++ ...s-heritage-contenu-update.queries.types.ts | 33 + .../titres-etapes-heritage-contenu-update.ts | 75 +- .../titres-etapes-ordre-update.test.ts | 5 +- .../processes/titres-etapes-ordre-update.ts | 17 +- .../processes/titres-phases-update.test.ts | 34 +- .../titres-statut-ids-update.test.ts | 10 +- .../business/rules-demarches/_utils.test.ts | 89 --- .../rules-demarches/axm/oct.machine.ts | 2 +- .../rules-demarches/definitions.test.ts | 131 +--- .../business/rules-demarches/definitions.ts | 72 +- .../business/rules-demarches/etat-cycles.ts | 27 - .../rules-demarches/machine-common.test.ts | 24 +- .../rules-demarches/machine-common.ts | 40 +- .../src/business/rules-demarches/machines.ts | 13 +- .../business/rules-demarches/prm/oct.cas.json | 1 + .../rules-demarches/prm/oct.machine.test.ts | 167 ++++ .../rules-demarches/prm/oct.machine.ts | 723 ++++++++++++++++++ .../business/rules-demarches/prm/oct.test.ts | 99 --- .../src/business/rules-demarches/prm/oct.ts | 201 ----- .../titre-date-demande-find-demarches.ts | 4 +- ...-demarche-date-fin-duree-find-demarches.ts | 14 +- .../rules/titre-activites-build.test.ts | 9 +- ...-demarche-annulation-date-fin-find.test.ts | 10 +- .../rules/titre-demarche-public-find.test.ts | 114 +-- .../rules/titre-demarche-public-find.ts | 12 +- .../titre-demarche-statut-id-find.test.ts | 7 +- .../rules/titre-demarche-statut-id-find.ts | 13 +- .../rules/titre-etape-prop-find.test.ts | 24 +- .../business/rules/titre-phases-find.test.ts | 200 ++--- .../rules/titre-prop-etape-find.test.ts | 106 +-- .../api/src/business/titre-etape-update.ts | 9 +- .../utils/props-titre-etapes-ids-find.test.ts | 4 +- .../utils/titre-demarches-etapes-rebuild.ts | 4 +- .../titre-etape-heritage-contenu-find.ts | 9 +- .../titre-etape-heritage-props-find.test.ts | 25 +- .../business/utils/titre-etapes-sort.test.ts | 131 ++-- .../src/business/utils/titre-etapes-sort.ts | 63 +- .../utils/titre-slug-and-relations-update.ts | 6 +- .../titre-demarche-etat-validate.test.ts | 114 +-- .../titre-demarche-etat-validate.ts | 95 +-- .../titre-etape-etat-validate.test.ts | 106 --- .../validations/titre-etape-etat-validate.ts | 182 ----- .../titre-etape-updation-validate.test.ts | 10 +- .../titre-etape-updation-validate.ts | 8 +- .../validations/titre-links-validate.ts | 3 +- .../src/database/models/_format/id-create.ts | 10 + .../models/_format/titre-etape-heritage.ts | 5 +- packages/api/src/database/queries/journaux.ts | 3 +- .../permissions/documents.test.integration.ts | 16 +- .../titres-demarches.test.integration.ts | 8 +- .../titres-etapes.test.integration.ts | 8 +- .../permissions/titres.test.integration.ts | 27 +- .../titres-activites.test.integration.ts | 6 +- .../api/src/database/queries/titres-etapes.ts | 8 +- .../api/src/database/queries/titres-titres.ts | 5 +- packages/api/src/database/queries/titres.ts | 6 +- .../20230607092129_etape-ordre-not-null.ts | 8 + .../src/tools/demarches/definitions-check.ts | 4 +- packages/api/src/tools/demarches/tde-check.ts | 4 +- .../api/src/tools/demarches/tests-creation.ts | 57 +- .../tools/documents/files-document-check.ts | 3 +- packages/api/src/tools/geojson.ts | 5 +- .../api/src/tools/phases/tests-creation.ts | 4 +- packages/api/src/types.ts | 16 +- .../_utils/administrations-permissions.ts | 11 +- packages/api/tsconfig.json | 2 +- packages/common/src/demarche.ts | 3 +- packages/common/src/etape.ts | 5 +- packages/common/src/rest.ts | 21 +- .../common/src/static/demarchesStatuts.ts | 7 +- packages/common/src/static/pays.test.ts | 23 +- packages/common/src/static/pays.ts | 4 + packages/common/src/titres.ts | 7 +- .../components/_common/perimetre.stories.tsx | 5 +- .../ui/src/components/_common/perimetre.tsx | 3 +- .../dashboard/pure-onf-dashboard.stories.tsx | 10 +- .../dashboard/pure-ptmg-dashboard.stories.tsx | 10 +- .../ui/src/components/dashboard/testData.ts | 10 +- .../etape/fondamentales-edit.stories.ts | 4 +- .../components/titre/edit-popup.stories.tsx | 5 +- .../src/components/titre/header.stories.tsx | 13 +- packages/ui/src/components/titre/header.tsx | 6 +- .../ui/src/components/titre/infos.stories.tsx | 24 +- packages/ui/src/components/titre/infos.tsx | 10 +- .../components/titre/territoires.stories.tsx | 35 +- .../ui/src/components/titre/territoires.tsx | 7 +- .../src/components/titre/titre-api-client.ts | 26 +- .../titre/titres-link-form-api-client.ts | 14 +- .../titre/titres-link-form.stories.tsx | 18 +- .../src/components/titre/titres-link-form.tsx | 4 +- .../components/titre/titres-link.stories.tsx | 25 +- .../ui/src/utils/titre-etape-edit.test.ts | 7 +- 123 files changed, 2274 insertions(+), 1910 deletions(-) create mode 100644 packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.ts create mode 100644 packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.types.ts delete mode 100644 packages/api/src/business/rules-demarches/_utils.test.ts delete mode 100644 packages/api/src/business/rules-demarches/etat-cycles.ts create mode 100644 packages/api/src/business/rules-demarches/prm/oct.cas.json create mode 100644 packages/api/src/business/rules-demarches/prm/oct.machine.test.ts create mode 100644 packages/api/src/business/rules-demarches/prm/oct.machine.ts delete mode 100644 packages/api/src/business/rules-demarches/prm/oct.test.ts delete mode 100644 packages/api/src/business/rules-demarches/prm/oct.ts delete mode 100644 packages/api/src/business/validations/titre-etape-etat-validate.test.ts delete mode 100644 packages/api/src/business/validations/titre-etape-etat-validate.ts create mode 100644 packages/api/src/knex/migrations/20230607092129_etape-ordre-not-null.ts diff --git a/packages/api/src/api/_format/etapes-types.ts b/packages/api/src/api/_format/etapes-types.ts index aad54eceb..0112b3527 100644 --- a/packages/api/src/api/_format/etapes-types.ts +++ b/packages/api/src/api/_format/etapes-types.ts @@ -97,5 +97,5 @@ export const etapeTypeIsValidCheck = ( titreEtape.typeId = etapeTypeId titreEtape.date = date - return !titreDemarcheUpdatedEtatValidate(date, demarcheType, titre, titreEtape, demarcheId, titreDemarcheEtapes).length + return !titreDemarcheUpdatedEtatValidate(demarcheType, titre, titreEtape, demarcheId, titreDemarcheEtapes).length } diff --git a/packages/api/src/api/graphql/administrations-permissions-etapes.test.integration.ts b/packages/api/src/api/graphql/administrations-permissions-etapes.test.integration.ts index f0e6aa3c6..cfc1ad603 100644 --- a/packages/api/src/api/graphql/administrations-permissions-etapes.test.integration.ts +++ b/packages/api/src/api/graphql/administrations-permissions-etapes.test.integration.ts @@ -70,15 +70,9 @@ describe('Visibilité des étapes', () => { }) describe('Création des étapes', () => { - test.each<[AdministrationId]>([['min-mtes-dgaln-01']])('un utilisateur admin de l’administration $administrationId peut créer une étape $etapeTypeId sur un titre CXM', async administrationId => - creationCheck(dbPool, administrationId, true, 'etapes', 'cxm') - ) + test('un utilisateur admin de l’administration min-mtes-dgaln-01 peut créer une étape $etapeTypeId sur un titre CXM', () => creationCheck(dbPool, 'min-mtes-dgaln-01', true, 'etapes', 'cxm')) - test.each<[AdministrationId]>([['min-mtes-dgaln-01']])('un utilisateur admin de l’administration $administrationId peut créer une étape mfr sur un titre PRM', async administrationId => - creationCheck(dbPool, administrationId, true, 'etapes', 'prm') - ) + test('un utilisateur admin de l’administration "min-mtes-dgaln-01" peut créer une étape mfr sur un titre PRM', () => creationCheck(dbPool, 'min-mtes-dgaln-01', true, 'etapes', 'prm')) - test.each<[AdministrationId]>([['min-mtes-dgaln-01']])('un utilisateur admin de l’administration $administrationId peut créer une étape mfr sur un titre PXM', async administrationId => - creationCheck(dbPool, administrationId, true, 'etapes', 'pxm') - ) + test('un utilisateur admin de l’administration "min-mtes-dgaln-01" peut créer une étape mfr sur un titre PXM', () => creationCheck(dbPool, 'min-mtes-dgaln-01', true, 'etapes', 'pxm')) }) diff --git a/packages/api/src/api/graphql/documents.test.integration.ts b/packages/api/src/api/graphql/documents.test.integration.ts index dcf9a017d..55fe994ee 100644 --- a/packages/api/src/api/graphql/documents.test.integration.ts +++ b/packages/api/src/api/graphql/documents.test.integration.ts @@ -85,6 +85,7 @@ describe('documentSupprimer', () => { { typeId: 'mfr', statutId: 'aco', + ordre: 1, titreDemarcheId: titreDemarche.id, date: toCaminoDate('2021-01-01'), }, diff --git a/packages/api/src/api/graphql/resolvers/documents.ts b/packages/api/src/api/graphql/resolvers/documents.ts index 3e66fee42..5d3c76f1d 100644 --- a/packages/api/src/api/graphql/resolvers/documents.ts +++ b/packages/api/src/api/graphql/resolvers/documents.ts @@ -22,6 +22,7 @@ import { documentFilePathFind } from '../../../tools/documents/document-path-fin import { isBureauDEtudes, isEntreprise, User } from 'camino-common/src/roles.js' import { canCreateOrEditEtape } from 'camino-common/src/permissions/titres-etapes.js' import { newDocumentId } from '../../../database/models/_format/id-create.js' +import { EtapeId } from 'camino-common/src/etape.js' const documentFileCreate = async (document: IDocument, fileUpload: FileUpload) => { const documentFilePath = await documentFilePathFind(document, true) @@ -262,7 +263,14 @@ export const documentSupprimer = async ({ id }: { id: string }, { user }: Contex } } -export const documentsLier = async (context: Context, documentIds: string[], parentId: string, propParentId: 'titreActiviteId' | 'titreEtapeId', oldParent?: { documents?: IDocument[] | null }) => { +export const documentsLier = async ( + context: Context, + documentIds: string[], + + { parentId, propParentId }: { parentId: EtapeId; propParentId: 'titreEtapeId' } | { parentId: string; propParentId: 'titreActiviteId' }, + + oldParent?: { documents?: IDocument[] | null } +) => { if (oldParent?.documents?.length) { // supprime les anciens documents ou ceux qui n'ont pas de fichier const oldDocumentsIds = oldParent.documents.map(d => d.id) @@ -284,8 +292,11 @@ export const documentsLier = async (context: Context, documentIds: string[], par if (document.fichier) { const documentPath = await documentFilePathFind(document) - document[propParentId] = parentId - + if (propParentId === 'titreEtapeId') { + document[propParentId] = parentId + } else { + document[propParentId] = parentId + } const newDocumentPath = await documentFilePathFind(document, true) await fileRename(documentPath, newDocumentPath) diff --git a/packages/api/src/api/graphql/resolvers/entreprises.ts b/packages/api/src/api/graphql/resolvers/entreprises.ts index a01a2b6dc..f7c2537a2 100644 --- a/packages/api/src/api/graphql/resolvers/entreprises.ts +++ b/packages/api/src/api/graphql/resolvers/entreprises.ts @@ -7,6 +7,7 @@ import { titreEtapeGet } from '../../../database/queries/titres-etapes.js' import { fieldsBuild } from './_fields-build.js' import { entrepriseFormat } from '../../_format/entreprises.js' +import { EtapeId } from 'camino-common/src/etape.js' const entreprisesTitresCreation = async (_: never, { user }: Context, info: GraphQLResolveInfo) => { try { @@ -33,7 +34,7 @@ const entreprises = async ( archive, etapeUniquement, }: { - etapeId?: string | null + etapeId?: EtapeId | null page?: number | null intervalle?: number | null ordre?: 'asc' | 'desc' | null diff --git a/packages/api/src/api/graphql/resolvers/points.ts b/packages/api/src/api/graphql/resolvers/points.ts index b49fb9910..ba6d38d23 100644 --- a/packages/api/src/api/graphql/resolvers/points.ts +++ b/packages/api/src/api/graphql/resolvers/points.ts @@ -17,6 +17,7 @@ import { titreDemarcheGet } from '../../../database/queries/titres-demarches.js' import { TitresStatuts } from 'camino-common/src/static/titresStatuts.js' import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools.js' import { SDOMZone, SDOMZoneId, SDOMZoneIds, SDOMZones } from 'camino-common/src/static/sdom.js' +import { EtapeId } from 'camino-common/src/etape.js' const stream2buffer = async (stream: Stream): Promise<Buffer> => { return new Promise<Buffer>((resolve, reject) => { @@ -246,7 +247,7 @@ export const titreEtapePerimetreInformations = async ( { titreEtapeId, }: { - titreEtapeId: string + titreEtapeId: EtapeId }, { user }: Context ): Promise<IPerimetreInformations> => { diff --git a/packages/api/src/api/graphql/resolvers/titre-demande.ts b/packages/api/src/api/graphql/resolvers/titre-demande.ts index f13911ab7..208b0b108 100644 --- a/packages/api/src/api/graphql/resolvers/titre-demande.ts +++ b/packages/api/src/api/graphql/resolvers/titre-demande.ts @@ -18,8 +18,9 @@ import { getDocuments } from 'camino-common/src/static/titresTypes_demarchesType import { toCaminoDate } from 'camino-common/src/date.js' import { getSections, SectionsElement } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' import { DeepReadonly } from 'camino-common/src/typescript-tools.js' +import { TitreId } from 'camino-common/src/titres.js' -export const titreDemandeCreer = async ({ titreDemande }: { titreDemande: ITitreDemande & { titreFromIds?: string[] } }, { user, pool }: Context) => { +export const titreDemandeCreer = async ({ titreDemande }: { titreDemande: ITitreDemande & { titreFromIds?: TitreId[] } }, { user, pool }: Context) => { try { assertsCanCreateTitre(user, titreDemande.typeId) diff --git a/packages/api/src/api/graphql/resolvers/titres-activites.ts b/packages/api/src/api/graphql/resolvers/titres-activites.ts index d38147b98..9d7f51a4b 100644 --- a/packages/api/src/api/graphql/resolvers/titres-activites.ts +++ b/packages/api/src/api/graphql/resolvers/titres-activites.ts @@ -298,7 +298,7 @@ const activiteModifier = async ({ activite }: { activite: ITitreActivite & { doc const fields = fieldsBuild(info) const documentIds = activite.documentIds || [] - await documentsLier(context, documentIds, activite.id, 'titreActiviteId', oldTitreActivite) + await documentsLier(context, documentIds, { parentId: activite.id, propParentId: 'titreActiviteId' }, oldTitreActivite) delete activite.documentIds await titreActiviteUpdateQuery(activite.id, activite) diff --git a/packages/api/src/api/graphql/resolvers/titres-etapes.ts b/packages/api/src/api/graphql/resolvers/titres-etapes.ts index c7d51113a..e90760870 100644 --- a/packages/api/src/api/graphql/resolvers/titres-etapes.ts +++ b/packages/api/src/api/graphql/resolvers/titres-etapes.ts @@ -23,7 +23,7 @@ import { contenuElementFilesCreate, contenuElementFilesDelete, contenuFilesPathG import { documentCreate, documentsGet } from '../../../database/queries/documents.js' import { titreEtapeAdministrationsEmailsSend, titreEtapeUtilisateursEmailsSend } from './_titre-etape-email.js' import { objectClone } from '../../../tools/index.js' -import { geojsonFeatureMultiPolygon } from '../../../tools/geojson.js' +import { geojsonFeatureMultiPolygon, geojsonIntersectsCommunes } from '../../../tools/geojson.js' import { newDocumentId } from '../../../database/models/_format/id-create.js' import fileRename from '../../../tools/file-rename.js' import { documentFilePathFind } from '../../../tools/documents/document-path-find.js' @@ -33,7 +33,7 @@ import { Feature } from 'geojson' import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools.js' import { getDocuments } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/documents.js' import { isBureauDEtudes, isEntreprise, User } from 'camino-common/src/roles.js' -import { CaminoDate, getCurrent, toCaminoDate } from 'camino-common/src/date.js' +import { CaminoDate, toCaminoDate } from 'camino-common/src/date.js' import { SDOMZoneId } from 'camino-common/src/static/sdom.js' import { titreEtapeFormatFields } from '../../_format/_fields.js' import { canCreateOrEditEtape } from 'camino-common/src/permissions/titres-etapes.js' @@ -42,6 +42,7 @@ import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' import { getSections, SectionsElement } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' import { isDocumentTypeId } from 'camino-common/src/static/documentsTypes.js' +import { EtapeId } from 'camino-common/src/etape.js' const statutIdAndDateGet = (etape: ITitreEtape, user: User, depose = false): { date: CaminoDate; statutId: EtapeStatutId } => { const result = { date: etape.date, statutId: etape.statutId } @@ -62,7 +63,7 @@ const statutIdAndDateGet = (etape: ITitreEtape, user: User, depose = false): { d return result } -const etape = async ({ id }: { id: string }, { user }: Context, info: GraphQLResolveInfo) => { +const etape = async ({ id }: { id: EtapeId }, { user }: Context, info: GraphQLResolveInfo) => { try { const fields = fieldsBuild(info) @@ -197,6 +198,7 @@ const etapeCreer = async ({ etape }: { etape: ITitreEtape }, context: Context, i const { statutId, date } = statutIdAndDateGet(etape, user!) etape.statutId = statutId etape.date = date + etape.surface = etape.surface ?? null const { sections, justificatifsTypes } = await specifiquesGet(titreDemarche.titre!.typeId, titreDemarche.typeId, etapeType) @@ -219,6 +221,14 @@ const etapeCreer = async ({ etape }: { etape: ITitreEtape }, context: Context, i console.warn(`utilisation du fallback pour l'étape ${etape.id}`) } sdomZones.push(...geoJsonResult.data) + + const titreEtapeCommu = await geojsonIntersectsCommunes(geojsonFeatures) + if (titreEtapeCommu.fallback) { + console.warn(`utilisation du fallback pour l'étape ${etape.id}`) + } + etape.communes = titreEtapeCommu.data + } else { + etape.communes = [] } const typeId = titreDemarche?.titre?.typeId @@ -226,7 +236,6 @@ const etapeCreer = async ({ etape }: { etape: ITitreEtape }, context: Context, i throw new Error(`le type du titre de la ${titreDemarche.id} n'est pas chargé`) } const rulesErrors = titreEtapeUpdationValidate( - getCurrent(), etape, titreDemarche, titreDemarche.titre, @@ -269,7 +278,7 @@ const etapeCreer = async ({ etape }: { etape: ITitreEtape }, context: Context, i await contenuElementFilesCreate(newFiles, 'demarches', etapeUpdated.id) - await documentsLier(context, documentIds, etapeUpdated.id, 'titreEtapeId') + await documentsLier(context, documentIds, { parentId: etapeUpdated.id, propParentId: 'titreEtapeId' }) try { await titreEtapeUpdateTask(context.pool, etapeUpdated.id, etapeUpdated.titreDemarcheId, user) @@ -394,7 +403,6 @@ const etapeModifier = async ({ etape }: { etape: ITitreEtape }, context: Context throw new Error(`le type du titre de la ${titreDemarche.id} n'est pas chargé`) } const rulesErrors = titreEtapeUpdationValidate( - getCurrent(), etape, titreDemarche, titreDemarche.titre, @@ -415,7 +423,7 @@ const etapeModifier = async ({ etape }: { etape: ITitreEtape }, context: Context if (titreEtapePoints) { etape.points = titreEtapePoints } - await documentsLier(context, documentIds, etape.id, 'titreEtapeId', titreEtapeOld) + await documentsLier(context, documentIds, { parentId: etape.id, propParentId: 'titreEtapeId' }, titreEtapeOld) const { contenu, newFiles } = sectionsContenuAndFilesGet(etape.contenu, sections) etape.contenu = contenu @@ -461,7 +469,7 @@ const etapeModifier = async ({ etape }: { etape: ITitreEtape }, context: Context } } -const etapeDeposer = async ({ id }: { id: string }, { user, pool }: Context, info: GraphQLResolveInfo) => { +const etapeDeposer = async ({ id }: { id: EtapeId }, { user, pool }: Context, info: GraphQLResolveInfo) => { try { if (!user) { throw new Error("l'étape n'existe pas") @@ -589,7 +597,7 @@ const etapeDeposer = async ({ id }: { id: string }, { user, pool }: Context, inf } } -const etapeSupprimer = async ({ id }: { id: string }, { user, pool }: Context, info: GraphQLResolveInfo) => { +const etapeSupprimer = async ({ id }: { id: EtapeId }, { user, pool }: Context, info: GraphQLResolveInfo) => { try { const fields = fieldsBuild(info) @@ -651,8 +659,7 @@ const etapeSupprimer = async ({ id }: { id: string }, { user, pool }: Context, i if (!titreDemarche.titre) throw new Error("le titre n'existe pas") - const currentDate = getCurrent() - const rulesErrors = titreDemarcheUpdatedEtatValidate(currentDate, titreDemarche.type!, titreDemarche.titre, titreEtape, titreDemarche.id, titreDemarche.etapes!, true) + const rulesErrors = titreDemarcheUpdatedEtatValidate(titreDemarche.type!, titreDemarche.titre, titreEtape, titreDemarche.id, titreDemarche.etapes!, true) if (rulesErrors.length) { throw new Error(rulesErrors.join(', ')) diff --git a/packages/api/src/api/graphql/titres-demarches.test.integration.ts b/packages/api/src/api/graphql/titres-demarches.test.integration.ts index 280bd4574..da9f6098d 100644 --- a/packages/api/src/api/graphql/titres-demarches.test.integration.ts +++ b/packages/api/src/api/graphql/titres-demarches.test.integration.ts @@ -8,6 +8,7 @@ import { toCaminoDate } from 'camino-common/src/date.js' import { afterAll, beforeAll, afterEach, describe, test, expect, vi } from 'vitest' import type { Pool } from 'pg' +import { newEtapeId } from '../../database/models/_format/id-create.js' console.info = vi.fn() console.error = vi.fn() @@ -220,10 +221,11 @@ describe('demarcheModifier', () => { await titreEtapeUpsert( { - id: `${demarcheId}-mno01`, + id: newEtapeId(`${demarcheId}-mno01`), typeId: 'mno', titreDemarcheId: demarcheId, statutId: 'acc', + ordre: 1, date: toCaminoDate('2020-01-01'), }, userSuper, diff --git a/packages/api/src/api/graphql/titres-etapes-modifier.test.integration.ts b/packages/api/src/api/graphql/titres-etapes-modifier.test.integration.ts index e43db76ee..bbb9edc0c 100644 --- a/packages/api/src/api/graphql/titres-etapes-modifier.test.integration.ts +++ b/packages/api/src/api/graphql/titres-etapes-modifier.test.integration.ts @@ -62,6 +62,7 @@ async function etapeCreate() { { typeId: 'mfr', statutId: 'fai', + ordre: 1, titreDemarcheId: titreDemarche.id, date: toCaminoDate('2018-01-01'), }, diff --git a/packages/api/src/api/graphql/titres.test.integration.ts b/packages/api/src/api/graphql/titres.test.integration.ts index 8c7fb3a0c..4b72a3feb 100644 --- a/packages/api/src/api/graphql/titres.test.integration.ts +++ b/packages/api/src/api/graphql/titres.test.integration.ts @@ -4,7 +4,7 @@ import { titreCreate } from '../../database/queries/titres.js' import { ADMINISTRATION_IDS } from 'camino-common/src/static/administrations.js' import { ITitre } from '../../types.js' import { userSuper } from '../../database/user-super' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { ACTIVITES_STATUTS_IDS } from 'camino-common/src/static/activitesStatuts.js' @@ -27,7 +27,7 @@ afterAll(async () => { }) const titrePublicLectureFalse: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'arm', publicLecture: false, @@ -35,7 +35,7 @@ const titrePublicLectureFalse: ITitre = { } const titreDemarchesPubliques: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'arm', publicLecture: true, @@ -43,20 +43,20 @@ const titreDemarchesPubliques: ITitre = { demarches: [ { id: newDemarcheId('titre-id-demarche-oct'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', publicLecture: true, }, { id: newDemarcheId('titre-id-demarche-pro'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'pro', publicLecture: false, }, ], } const titreEtapesPubliques: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'arm', publicLecture: true, @@ -64,13 +64,13 @@ const titreEtapesPubliques: ITitre = { demarches: [ { id: newDemarcheId('titre-id-demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', statutId: 'acc', publicLecture: true, etapes: [ { - id: 'titre-id-demarche-id-aof', + id: newEtapeId('titre-id-demarche-id-aof'), typeId: 'aof', ordre: 8, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -78,7 +78,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-eof', + id: newEtapeId('titre-id-demarche-id-eof'), typeId: 'eof', ordre: 7, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -86,7 +86,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-edm', + id: newEtapeId('titre-id-demarche-id-edm'), typeId: 'edm', ordre: 6, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -94,7 +94,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-ede', + id: newEtapeId('titre-id-demarche-id-ede'), typeId: 'ede', ordre: 5, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -102,7 +102,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-pfd', + id: newEtapeId('titre-id-demarche-id-pfd'), typeId: 'pfd', ordre: 4, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -110,7 +110,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-pfc', + id: newEtapeId('titre-id-demarche-id-pfc'), typeId: 'pfc', ordre: 3, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -118,7 +118,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-vfd', + id: newEtapeId('titre-id-demarche-id-vfd'), typeId: 'vfd', ordre: 2, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -126,7 +126,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-vfc', + id: newEtapeId('titre-id-demarche-id-vfc'), typeId: 'vfc', ordre: 1, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -134,7 +134,7 @@ const titreEtapesPubliques: ITitre = { date: toCaminoDate('2020-02-02'), }, { - id: 'titre-id-demarche-id-dpu', + id: newEtapeId('titre-id-demarche-id-dpu'), typeId: 'dpu', ordre: 0, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -148,14 +148,14 @@ const titreEtapesPubliques: ITitre = { } const titreWithActiviteGrp: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'axm', publicLecture: true, propsTitreEtapesIds: { points: 'titre-id-demarche-id-dpu' }, activites: [ { - titreId: 'titre-id', + titreId: newTitreId('titre-id'), id: 'titre-id-grp-2020-03', date: toCaminoDate('2020-10-01'), typeId: 'grp', @@ -187,12 +187,12 @@ const titreWithActiviteGrp: ITitre = { demarches: [ { id: newDemarcheId('titre-id-demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', publicLecture: true, etapes: [ { - id: 'titre-id-demarche-id-dpu', + id: newEtapeId('titre-id-demarche-id-dpu'), typeId: 'dpu', ordre: 0, titreDemarcheId: newDemarcheId('titre-id-demarche-id'), @@ -206,7 +206,7 @@ const titreWithActiviteGrp: ITitre = { } const titreActivites: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'arm', publicLecture: true, @@ -214,7 +214,7 @@ const titreActivites: ITitre = { activites: [ { id: 'titre-id-activites-oct', - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'grp', date: toCaminoDate('2020-01-01'), activiteStatutId: ACTIVITES_STATUTS_IDS.DEPOSE, @@ -243,7 +243,7 @@ const titreActivites: ITitre = { }, { id: 'titre-id-activites-pro', - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'gra', date: toCaminoDate('2020-01-01'), activiteStatutId: ACTIVITES_STATUTS_IDS.DEPOSE, @@ -276,7 +276,7 @@ describe('titre', () => { test('peut voir un titre qui est en "lecture publique" (utilisateur anonyme)', async () => { const titrePublicLecture: ITitre = { - id: 'titre-id', + id: newTitreId('titre-id'), nom: 'mon titre', typeId: 'arm', publicLecture: true, @@ -306,7 +306,7 @@ describe('titre', () => { expect(res.body.errors).toBeUndefined() expect(res.body.data).toMatchObject({ titre: { - id: 'titre-id', + id: newTitreId('titre-id'), demarches: [{ id: 'titre-id-demarche-oct' }], }, }) @@ -321,7 +321,7 @@ describe('titre', () => { expect(res.body.errors).toBeUndefined() expect(res.body.data).toMatchObject({ titre: { - id: 'titre-id', + id: newTitreId('titre-id'), }, }) @@ -335,7 +335,7 @@ describe('titre', () => { expect(res.body.errors).toBeUndefined() expect(res.body.data).toMatchObject({ titre: { - id: 'titre-id', + id: newTitreId('titre-id'), demarches: [ { id: 'titre-id-demarche-id', diff --git a/packages/api/src/api/rest/entreprises.test.integration.ts b/packages/api/src/api/rest/entreprises.test.integration.ts index ae6bf4d13..c0192b337 100644 --- a/packages/api/src/api/rest/entreprises.test.integration.ts +++ b/packages/api/src/api/rest/entreprises.test.integration.ts @@ -288,6 +288,7 @@ describe('getEntrepriseDocument', () => { statutId: 'fai', titreDemarcheId: titreDemarche.id, date: toCaminoDate('2022-01-01'), + ordre: 1, }, userSuper, titre.id diff --git a/packages/api/src/api/rest/entreprises.test.ts b/packages/api/src/api/rest/entreprises.test.ts index 229e3e637..82e8c34db 100644 --- a/packages/api/src/api/rest/entreprises.test.ts +++ b/packages/api/src/api/rest/entreprises.test.ts @@ -3,6 +3,7 @@ import Titres from '../../database/models/titres.js' import { describe, expect, test } from 'vitest' import { newEntrepriseId } from 'camino-common/src/entreprise.js' import { toCommuneId } from 'camino-common/src/static/communes.js' +import { newTitreId } from '../../database/models/_format/id-create.js' const entreprise = { id: newEntrepriseId('entrepriseId'), @@ -49,19 +50,19 @@ describe('construit le corps de la requête pour openFisca', () => { test('avec activités', () => { const activitesAnnuelles = [ - { titreId: 'titre2', contenu: { substancesFiscales: { auru: 39.715 } } }, - { titreId: 'titre3', contenu: { substancesFiscales: { auru: 0 } } }, - { titreId: 'titre1', contenu: { substancesFiscales: { auru: 0 } } }, - { titreId: 'titre4', contenu: { substancesFiscales: { auru: 0 } } }, - { titreId: 'titre5', contenu: { substancesFiscales: { auru: 8.91 } } }, + { titreId: newTitreId('titre2'), contenu: { substancesFiscales: { auru: 39.715 } } }, + { titreId: newTitreId('titre3'), contenu: { substancesFiscales: { auru: 0 } } }, + { titreId: newTitreId('titre1'), contenu: { substancesFiscales: { auru: 0 } } }, + { titreId: newTitreId('titre4'), contenu: { substancesFiscales: { auru: 0 } } }, + { titreId: newTitreId('titre5'), contenu: { substancesFiscales: { auru: 8.91 } } }, ] const activitesTrimestrielles = [ { - titreId: 'titre2', + titreId: newTitreId('titre2'), contenu: { renseignements: { environnement: 7300 } }, }, { - titreId: 'titre3', + titreId: newTitreId('titre3'), contenu: { renseignements: { environnement: 1000 } }, }, ] @@ -76,7 +77,7 @@ describe('construit le corps de la requête pour openFisca', () => { surface: 1006827, }, ], - id: 'titreSansActivite', + id: newTitreId('titreSansActivite'), }, { substances: ['auru', 'scoc'], @@ -88,7 +89,7 @@ describe('construit le corps de la requête pour openFisca', () => { ], titulaires: [entreprise2], amodiataires: [], - id: 'titre1', + id: newTitreId('titre1'), }, { substances: ['auru', 'scoc'], @@ -100,7 +101,7 @@ describe('construit le corps de la requête pour openFisca', () => { surface: 19805494, }, ], - id: 'titre2', + id: newTitreId('titre2'), }, { substances: ['auru', 'scoc'], @@ -112,7 +113,7 @@ describe('construit le corps de la requête pour openFisca', () => { surface: 5143845, }, ], - id: 'titre3', + id: newTitreId('titre3'), }, { substances: ['auru', 'scoc'], @@ -124,7 +125,7 @@ describe('construit le corps de la requête pour openFisca', () => { surface: 7676552, }, ], - id: 'titre4', + id: newTitreId('titre4'), }, { substances: ['auru', 'scoc'], @@ -136,7 +137,7 @@ describe('construit le corps de la requête pour openFisca', () => { surface: 35604009, }, ], - id: 'titre5', + id: newTitreId('titre5'), }, ] diff --git a/packages/api/src/api/rest/entreprises.ts b/packages/api/src/api/rest/entreprises.ts index ce403fef9..27e405571 100644 --- a/packages/api/src/api/rest/entreprises.ts +++ b/packages/api/src/api/rest/entreprises.ts @@ -46,6 +46,7 @@ import fileRename from '../../tools/file-rename.js' import { newDocumentId } from '../../database/models/_format/id-create.js' import { FICHIERS_TYPES } from 'camino-common/src/static/documentsTypes.js' import { dbQueryAndValidate } from '../../pg-database.js' +import { isGuyane } from 'camino-common/src/static/pays.js' const conversion = (substanceFiscale: SubstanceFiscale, quantite: IContenuValeur): number => { if (typeof quantite !== 'number') { @@ -112,9 +113,7 @@ export const bodyBuilder = ( const titreGuyannais = titre.communes .map(({ id }) => toDepartementId(id)) .filter(isNotNullNorUndefined) - .some(departementId => { - return Regions[Departements[departementId].regionId].paysId === 'GF' - }) + .some(departementId => isGuyane(Regions[Departements[departementId].regionId].paysId)) if (!titre.substances) { throw new Error(`les substances du titre ${activite.titreId} ne sont pas chargées`) diff --git a/packages/api/src/api/rest/etapes.test.ts b/packages/api/src/api/rest/etapes.test.ts index 263cbe3d7..380f0783d 100644 --- a/packages/api/src/api/rest/etapes.test.ts +++ b/packages/api/src/api/rest/etapes.test.ts @@ -1,132 +1,182 @@ -import { etapesTypesPossibleACetteDateOuALaPlaceDeLEtape, TitreEtapeForMachine } from './etapes.js' +import { etapesTypesPossibleACetteDateOuALaPlaceDeLEtape } from './etapes.js' import { ArmOctMachine } from '../../business/rules-demarches/arm/oct.machine.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test, vi } from 'vitest' import { onlyUnique } from 'camino-common/src/typescript-tools.js' +import { newEtapeId } from '../../database/models/_format/id-create.js' +import { TitreEtapeForMachine } from '../../business/rules-demarches/machine-common.js' describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { const etapes: TitreEtapeForMachine[] = [ { - id: 'etapeId16', + id: newEtapeId('etapeId16'), typeId: 'sco', statutId: 'fai', ordre: 16, date: toCaminoDate('2020-08-17'), contenu: { arm: { mecanise: true } }, + communes: [], + surface: null, }, { - id: 'etapeId1', + id: newEtapeId('etapeId1'), typeId: 'mfr', statutId: 'fai', ordre: 1, date: toCaminoDate('2019-09-19'), contenu: { arm: { mecanise: true, franchissements: 19 } }, + communes: [], + surface: null, }, { - id: 'etapeId5', + id: newEtapeId('etapeId5'), typeId: 'mcp', statutId: 'com', ordre: 5, date: toCaminoDate('2019-11-27'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId10', + id: newEtapeId('etapeId10'), typeId: 'aof', statutId: 'fav', ordre: 10, date: toCaminoDate('2019-12-04'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId9', + id: newEtapeId('etapeId9'), typeId: 'eof', statutId: 'fai', ordre: 9, date: toCaminoDate('2019-12-04'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId14', + id: newEtapeId('etapeId14'), typeId: 'pfc', statutId: 'fai', ordre: 14, date: toCaminoDate('2020-05-22'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId8', + id: newEtapeId('etapeId8'), typeId: 'mcr', statutId: 'fav', ordre: 8, date: toCaminoDate('2019-12-04'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId4', + id: newEtapeId('etapeId4'), typeId: 'pfd', statutId: 'fai', ordre: 4, date: toCaminoDate('2019-11-20'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId15', + id: newEtapeId('etapeId15'), typeId: 'vfc', statutId: 'fai', ordre: 15, date: toCaminoDate('2020-05-22'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId13', + id: newEtapeId('etapeId13'), typeId: 'mnb', statutId: 'fai', ordre: 13, date: toCaminoDate('2020-05-18'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId12', + id: newEtapeId('etapeId12'), typeId: 'aca', statutId: 'fav', ordre: 12, date: toCaminoDate('2020-05-13'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId6', + id: newEtapeId('etapeId6'), typeId: 'rde', statutId: 'fav', ordre: 6, date: toCaminoDate('2019-12-04'), + communes: [], + surface: null, contenu: { arm: { franchissements: 19 } }, }, { - id: 'etapeId2', + id: newEtapeId('etapeId2'), typeId: 'mdp', statutId: 'fai', ordre: 2, date: toCaminoDate('2019-09-20'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId7', + id: newEtapeId('etapeId7'), typeId: 'vfd', statutId: 'fai', ordre: 7, date: toCaminoDate('2019-12-04'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId11', + id: newEtapeId('etapeId11'), typeId: 'sca', statutId: 'fai', ordre: 11, date: toCaminoDate('2020-05-04'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId3', + id: newEtapeId('etapeId3'), typeId: 'dae', statutId: 'exe', ordre: 3, date: toCaminoDate('2019-10-11'), + contenu: null, + communes: [], + surface: null, }, { - id: 'etapeId17', + id: newEtapeId('etapeId17'), typeId: 'aco', statutId: 'fai', ordre: 17, date: toCaminoDate('2022-05-05'), + contenu: null, + communes: [], + surface: null, }, ] @@ -166,19 +216,24 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { test('peut faire une dae, une rde et pfd AVANT la mfr', () => { const etapes: TitreEtapeForMachine[] = [ { - id: 'idMfr', - + id: newEtapeId('idMfr'), + ordre: 1, typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2022-05-16'), contenu: { arm: { mecanise: true, franchissements: 2 } }, + communes: [], + surface: null, }, { - id: 'idMdp', - + id: newEtapeId('idMdp'), + ordre: 2, typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2022-05-17'), + contenu: null, + communes: [], + surface: null, }, ] @@ -191,17 +246,24 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { test('peut faire que une pfd AVANT la mfr non mecanisee', () => { const etapes: TitreEtapeForMachine[] = [ { - id: 'idMfr', + id: newEtapeId('idMfr'), + ordre: 1, typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2022-05-16'), contenu: { arm: { mecanise: false } }, + communes: [], + surface: null, }, { - id: 'idMdp', + id: newEtapeId('idMdp'), + ordre: 2, typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2022-05-17'), + contenu: null, + communes: [], + surface: null, }, ] @@ -215,7 +277,7 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { console.warn = vi.fn() const etapes: TitreEtapeForMachine[] = [ { - id: 'idMfr', + id: newEtapeId('idMfr'), date: toCaminoDate('2021-11-02'), typeId: 'mfr', statutId: 'fai', @@ -226,9 +288,11 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { }, }, ordre: 3, + communes: [], + surface: null, }, { - id: 'idrcm', + id: newEtapeId('idrcm'), date: toCaminoDate('2021-11-17'), typeId: 'rcm', statutId: 'fai', @@ -239,86 +303,120 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { }, }, ordre: 7, + communes: [], + surface: null, }, { - id: 'idMcp', + id: newEtapeId('idMcp'), date: toCaminoDate('2021-11-05'), typeId: 'mcp', statutId: 'inc', ordre: 5, + contenu: null, + communes: [], + surface: null, }, { - id: 'idmcp', + id: newEtapeId('idmcp'), date: toCaminoDate('2021-11-17'), typeId: 'mcp', statutId: 'com', ordre: 8, + contenu: null, + communes: [], + surface: null, }, { - id: 'ideof', + id: newEtapeId('ideof'), date: toCaminoDate('2021-11-22'), typeId: 'eof', statutId: 'fai', ordre: 11, + contenu: null, + communes: [], + surface: null, }, { - id: 'iddae', + id: newEtapeId('iddae'), date: toCaminoDate('2021-10-15'), typeId: 'dae', statutId: 'exe', ordre: 1, + contenu: null, + communes: [], + surface: null, }, { - id: 'idmcr', + id: newEtapeId('idmcr'), date: toCaminoDate('2021-11-22'), typeId: 'mcr', statutId: 'fav', contenu: null, ordre: 10, + communes: [], + surface: null, }, { - id: 'idmcb', + id: newEtapeId('idmcb'), date: toCaminoDate('2021-12-09'), typeId: 'mcb', statutId: 'fai', ordre: 13, + contenu: null, + communes: [], + surface: null, }, { - id: 'idedm', + id: newEtapeId('idedm'), date: toCaminoDate('2021-11-30'), typeId: 'edm', statutId: 'fav', ordre: 12, + contenu: null, + communes: [], + surface: null, }, { - id: 'idvfd', + id: newEtapeId('idvfd'), date: toCaminoDate('2021-11-19'), typeId: 'vfd', statutId: 'fai', ordre: 9, + contenu: null, + communes: [], + surface: null, }, { - id: 'idpfd', + id: newEtapeId('idpfd'), date: toCaminoDate('2021-10-26'), typeId: 'pfd', statutId: 'fai', ordre: 2, + contenu: null, + communes: [], + surface: null, }, { - id: 'idmdp', + id: newEtapeId('idmdp'), date: toCaminoDate('2021-11-02'), typeId: 'mdp', statutId: 'fai', ordre: 4, + contenu: null, + communes: [], + surface: null, }, { - id: 'idmcm', + id: newEtapeId('idmcm'), date: toCaminoDate('2021-11-05'), typeId: 'mcm', statutId: 'fai', ordre: 6, + contenu: null, + communes: [], + surface: null, }, ] @@ -331,7 +429,7 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { test('peut faire une completude (mcp) le même jour que le dépôt (mdp) de la demande', () => { const etapes: TitreEtapeForMachine[] = [ { - id: 'id3', + id: newEtapeId('id3'), typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2022-06-23'), @@ -342,29 +440,40 @@ describe('etapesTypesPossibleACetteDateOuALaPlaceDeLEtape', function () { }, }, ordre: 3, + communes: [], + surface: null, }, { - id: 'id1', + id: newEtapeId('id1'), typeId: 'dae', statutId: 'exe', date: toCaminoDate('2021-06-22'), ordre: 1, + contenu: null, + communes: [], + surface: null, }, { - id: 'id4', + id: newEtapeId('id4'), typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2022-07-01'), ordre: 4, + contenu: null, + communes: [], + surface: null, }, { - id: 'id2', + id: newEtapeId('id2'), typeId: 'pfd', statutId: 'fai', date: toCaminoDate('2021-07-05'), ordre: 2, + contenu: null, + communes: [], + surface: null, }, ] diff --git a/packages/api/src/api/rest/etapes.ts b/packages/api/src/api/rest/etapes.ts index b8e2601ba..21a1f55f4 100644 --- a/packages/api/src/api/rest/etapes.ts +++ b/packages/api/src/api/rest/etapes.ts @@ -1,21 +1,20 @@ import { z } from 'zod' import { CaminoRequest, CustomResponse } from './express-type.js' -import { EtapeTypeEtapeStatutWithMainStep } from 'camino-common/src/etape.js' +import { EtapeTypeEtapeStatutWithMainStep, etapeIdValidator, EtapeId } from 'camino-common/src/etape.js' import { DemarcheId, demarcheIdValidator } from 'camino-common/src/demarche.js' import { constants } from 'http2' import { CaminoDate, caminoDateValidator } from 'camino-common/src/date.js' import { titreDemarcheGet } from '../../database/queries/titres-demarches.js' import { userSuper } from '../../database/user-super.js' import { titreEtapeGet } from '../../database/queries/titres-etapes.js' -import { demarcheDefinitionFind, isDemarcheDefinitionMachine } from '../../business/rules-demarches/definitions.js' -import { ITitreEtape } from '../../types.js' +import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions.js' import { etapeTypeIsValidCheck } from '../_format/etapes-types.js' import { User } from 'camino-common/src/roles.js' import { canCreateOrEditEtape } from 'camino-common/src/permissions/titres-etapes.js' import { TitresStatutIds } from 'camino-common/src/static/titresStatuts.js' import { CaminoMachines } from '../../business/rules-demarches/machines.js' import { titreEtapesSortAscByOrdre } from '../../business/utils/titre-etapes-sort.js' -import { Etape, toMachineEtapes } from '../../business/rules-demarches/machine-common.js' +import { Etape, TitreEtapeForMachine, titreEtapeForMachineValidator, toMachineEtapes } from '../../business/rules-demarches/machine-common.js' import { EtapesTypes, EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { onlyUnique } from 'camino-common/src/typescript-tools.js' import { getEtapesTDE } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index.js' @@ -28,7 +27,7 @@ export const getEtapesTypesEtapesStatusWithMainStep = async (req: CaminoRequest, res: CustomResponse<EtapeTypeEtapeStatutWithMainStep[]>): Promise<void> => { const demarcheIdParsed = demarcheIdValidator.safeParse(req.params.demarcheId) const dateParsed = caminoDateValidator.safeParse(req.params.date) - const etapeIdParsed = z.optional(z.string()).safeParse(req.query.etapeId) + const etapeIdParsed = z.optional(etapeIdValidator).safeParse(req.query.etapeId) const user = req.auth if (!demarcheIdParsed.success || !dateParsed.success || !etapeIdParsed.success) { @@ -44,7 +43,7 @@ export const getEtapesTypesEtapesStatusWithMainStep = } } -const demarcheEtapesTypesGet = async (titreDemarcheId: DemarcheId, date: CaminoDate, titreEtapeId: string | null, user: User) => { +const demarcheEtapesTypesGet = async (titreDemarcheId: DemarcheId, date: CaminoDate, titreEtapeId: EtapeId | null, user: User) => { const titreDemarche = await titreDemarcheGet( titreDemarcheId, { @@ -82,24 +81,21 @@ const demarcheEtapesTypesGet = async (titreDemarcheId: DemarcheId, date: CaminoD } } - // si il existe un arbre d’instructions pour cette démarche, - // on laisse l’arbre traiter l’unicité des étapes const demarcheDefinition = demarcheDefinitionFind(titre.typeId, titreDemarche.typeId, titreDemarche.etapes, titreDemarche.id) const etapesTypes: EtapeTypeEtapeStatutWithMainStep[] = [] - if (isDemarcheDefinitionMachine(demarcheDefinition)) { + if (demarcheDefinition) { if (!titreDemarche.etapes) throw new Error('les étapes ne sont pas chargées') - etapesTypes.push(...etapesTypesPossibleACetteDateOuALaPlaceDeLEtape(demarcheDefinition.machine, titreDemarche.etapes, titreEtapeId, date)) + const etapes = titreDemarche.etapes.map(etape => titreEtapeForMachineValidator.parse(etape)) + etapesTypes.push(...etapesTypesPossibleACetteDateOuALaPlaceDeLEtape(demarcheDefinition.machine, etapes, titreEtapeId, date)) } else { // dans un premier temps on récupère toutes les étapes possibles pour cette démarche let etapesTypesTDE = getEtapesTDE(titre.typeId, titreDemarche.typeId) - if (!demarcheDefinition) { - const etapeTypesExistants = titreDemarche.etapes?.map(({ typeId }) => typeId) ?? [] - etapesTypesTDE = etapesTypesTDE - .filter(typeId => !etapeTypesExistants.includes(typeId) || !EtapesTypes[typeId].unique) - .filter(etapeTypeId => etapeTypeIsValidCheck(etapeTypeId, date, titre, titreDemarche.type!, titreDemarche.id, titreDemarche.etapes, titreEtape)) - } + const etapeTypesExistants = titreDemarche.etapes?.map(({ typeId }) => typeId) ?? [] + etapesTypesTDE = etapesTypesTDE + .filter(typeId => !etapeTypesExistants.includes(typeId) || !EtapesTypes[typeId].unique) + .filter(etapeTypeId => etapeTypeIsValidCheck(etapeTypeId, date, titre, titreDemarche.type!, titreDemarche.id, titreDemarche.etapes, titreEtape)) etapesTypes.push(...etapesTypesTDE.flatMap(etapeTypeId => getEtapesStatuts(etapeTypeId).map(etapeStatut => ({ etapeTypeId, etapeStatutId: etapeStatut.id, mainStep: false })))) } @@ -120,7 +116,6 @@ const demarcheEtapesTypesGet = async (titreDemarcheId: DemarcheId, date: CaminoD ) } -export type TitreEtapeForMachine = Pick<ITitreEtape, 'ordre' | 'id' | 'typeId' | 'statutId' | 'date' | 'contenu'> // VISIBLE_FOR_TESTING export const etapesTypesPossibleACetteDateOuALaPlaceDeLEtape = ( machine: CaminoMachines, diff --git a/packages/api/src/api/rest/fichiers.ts b/packages/api/src/api/rest/fichiers.ts index 8f24cc190..af1755f01 100644 --- a/packages/api/src/api/rest/fichiers.ts +++ b/packages/api/src/api/rest/fichiers.ts @@ -10,10 +10,11 @@ import { statSync, readFileSync } from 'fs' import { User } from 'camino-common/src/roles' import { DOWNLOAD_FORMATS } from 'camino-common/src/rest.js' import { Pool } from 'pg' +import { EtapeId } from 'camino-common/src/etape.js' export const etapeTelecharger = (_pool: Pool) => - async ({ params: { etapeId } }: { params: { etapeId?: string } }, user: User) => { + async ({ params: { etapeId } }: { params: { etapeId?: EtapeId } }, user: User) => { if (!etapeId) { throw new Error("id d'étape absent") } @@ -146,7 +147,7 @@ const etapeIdPathGet = (etapeId: string, fichierNom: string, contenu: IContenuVa export const etapeFichier = (_pool: Pool) => - async ({ params: { etapeId, fichierNom } }: { params: { etapeId?: string; fichierNom?: string } }, user: User) => { + async ({ params: { etapeId, fichierNom } }: { params: { etapeId?: EtapeId; fichierNom?: string } }, user: User) => { if (!etapeId) { throw new Error('id de l’étape absent') } diff --git a/packages/api/src/api/rest/titre-contenu.test.ts b/packages/api/src/api/rest/titre-contenu.test.ts index d821d6c1f..cec13b60e 100644 --- a/packages/api/src/api/rest/titre-contenu.test.ts +++ b/packages/api/src/api/rest/titre-contenu.test.ts @@ -1,3 +1,4 @@ +import { newEtapeId } from '../../database/models/_format/id-create.js' import { contenuFormat, titreSectionsGet } from './titre-contenu.js' import { describe, test, expect } from 'vitest' describe('formatage du contenu', () => { @@ -11,7 +12,7 @@ describe('formatage du contenu', () => { { etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), contenu: { section: { prop1: 'valeur 1', @@ -75,7 +76,7 @@ describe('titreSectionsGet', () => { typeId: 'oct', etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), typeId: 'mfr', contenu: { arm: { diff --git a/packages/api/src/api/rest/titres.test.integration.ts b/packages/api/src/api/rest/titres.test.integration.ts index b2c638a50..73216f556 100644 --- a/packages/api/src/api/rest/titres.test.integration.ts +++ b/packages/api/src/api/rest/titres.test.integration.ts @@ -14,18 +14,19 @@ import { newEntrepriseId } from 'camino-common/src/entreprise.js' import type { Pool } from 'pg' import { createJournalCreate } from '../../database/queries/journaux.js' import { dbQueryAndValidate } from '../../pg-database.js' -import { idGenerate } from '../../database/models/_format/id-create.js' +import { idGenerate, newTitreId } from '../../database/models/_format/id-create.js' import { constants } from 'http2' import { toCommuneId } from 'camino-common/src/static/communes.js' import { z } from 'zod' import { insertCommune } from '../../database/queries/communes.queries.js' +import { TitreId } from 'camino-common/src/titres.js' console.info = vi.fn() console.error = vi.fn() let knex: Knex<any, unknown[]> let dbPool: Pool -let titreId1: string | null = null +let titreId1: TitreId | null = null beforeAll(async () => { const { knex: knexInstance, pool } = await dbManager.populateDb() dbPool = pool @@ -295,7 +296,7 @@ describe('titresLiaisons', () => { }) describe('titreModifier', () => { - let id = '' + let id = newTitreId('') beforeEach(async () => { const titre = await titreCreate( @@ -377,7 +378,7 @@ describe('titreModifier', () => { }) describe('titreSupprimer', () => { - let id = '' + let id = newTitreId('') beforeEach(async () => { const titre = await titreCreate( @@ -404,20 +405,20 @@ describe('titreSupprimer', () => { }) test('ne peut pas supprimer un titre inexistant (utilisateur super)', async () => { - const tested = await restDeleteCall(dbPool, '/rest/titres/:titreId', { titreId: 'toto' }, userSuper) + const tested = await restDeleteCall(dbPool, '/rest/titres/:titreId', { titreId: newTitreId('toto') }, userSuper) expect(tested.statusCode).toBe(404) }) }) describe('getTitre', () => { test('ne peut pas récupérer un titre (utilisateur non super)', async () => { - const tested = await restCall(dbPool, '/rest/titres/:titreId', { titreId: 'not existing' }, undefined) + const tested = await restCall(dbPool, '/rest/titres/:titreId', { titreId: newTitreId('not existing') }, undefined) expect(tested.statusCode).toBe(403) }) test('ne peut pas récupérer un titre inexistant', async () => { - const tested = await restCall(dbPool, '/rest/titres/:titreId', { titreId: 'not existing' }, userSuper) + const tested = await restCall(dbPool, '/rest/titres/:titreId', { titreId: newTitreId('not existing') }, userSuper) expect(tested.statusCode).toBe(404) }) @@ -528,12 +529,12 @@ test('utilisateurTitreAbonner', async () => { }) test('peut récupérer les communes d’un titre', async () => { - let tested = await restCall(dbPool, '/rest/titres/:id/communes', { id: titreId1 ?? '' }, userSuper) + let tested = await restCall(dbPool, '/rest/titres/:id/communes', { id: newTitreId(titreId1 ?? '') }, userSuper) expect(tested.statusCode).toBe(200) expect(tested.body).toEqual([{ id: '97300', nom: 'Une ville en Guyane' }]) - tested = await restCall(dbPool, '/rest/titres/:id/communes', { id: titreId1 ?? '' }, undefined) + tested = await restCall(dbPool, '/rest/titres/:id/communes', { id: newTitreId(titreId1 ?? '') }, undefined) expect(tested.statusCode).toBe(403) }) diff --git a/packages/api/src/api/rest/titres.ts b/packages/api/src/api/rest/titres.ts index f1acd4613..04b79a89a 100644 --- a/packages/api/src/api/rest/titres.ts +++ b/packages/api/src/api/rest/titres.ts @@ -17,8 +17,9 @@ import { titrePtmgValidator, titreLinksValidator, utilisateurTitreAbonneValidator, + titreIdValidator, } from 'camino-common/src/titres.js' -import { demarcheDefinitionFind, isDemarcheDefinitionMachine } from '../../business/rules-demarches/definitions.js' +import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions.js' import { CaminoRequest, CustomResponse } from './express-type.js' import { userSuper } from '../../database/user-super.js' import { NotNullableKeys, onlyUnique } from 'camino-common/src/typescript-tools.js' @@ -27,7 +28,7 @@ import { titreAdministrationsGet } from '../_format/titres.js' import { canDeleteTitre, canLinkTitres } from 'camino-common/src/permissions/titres.js' import { linkTitres } from '../../database/queries/titres-titres.js' import { checkTitreLinks } from '../../business/validations/titre-links-validate.js' -import { toMachineEtapes } from '../../business/rules-demarches/machine-common.js' +import { titreEtapeForMachineValidator, toMachineEtapes } from '../../business/rules-demarches/machine-common.js' import { TitreReference } from 'camino-common/src/titres-references.js' import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts.js' import { ETAPES_TYPES, EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' @@ -40,6 +41,7 @@ import { getLastJournal, getTitre as getTitreDb, lastJournalGetValidator, getTit import type { Pool } from 'pg' import { dbQueryAndValidate } from '../../pg-database.js' import { Commune, communeValidator } from 'camino-common/src/static/communes.js' +import { z } from 'zod' const etapesAMasquer = [ ETAPES_TYPES.classementSansSuite, @@ -160,8 +162,8 @@ async function titresArmAvecOctroi(user: User, administrationId: AdministrationI } const dd = demarcheDefinitionFind(titre.typeId, octARM.typeId, octARM.etapes, octARM.id) - const hasMachine = isDemarcheDefinitionMachine(dd) - const blockedByMe: boolean = hasMachine && dd.machine.whoIsBlocking(toMachineEtapes(octARM.etapes)).includes(administrationId) + const etapes = octARM.etapes.map(etape => titreEtapeForMachineValidator.parse(etape)) + const blockedByMe: boolean = dd !== undefined && dd.machine.whoIsBlocking(toMachineEtapes(etapes)).includes(administrationId) // TODO 2022-06-08 wait for typescript to get better at type interpolation return { @@ -306,10 +308,11 @@ export const titresDREAL = (_pool: Pool) => async (req: CaminoRequest, res: Cust if (demarcheLaPlusRecente.statutId === DemarchesStatutsIds.EnConstruction) { return null } else { - const etapesDerniereDemarche = toMachineEtapes(demarcheLaPlusRecente.etapes) + 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 (isDemarcheDefinitionMachine(dd)) { + if (dd) { try { enAttenteDeDREAL = dd.machine.whoIsBlocking(etapesDerniereDemarche).includes(user.administrationId) const nextEtapes = dd.machine.possibleNextEtapes(etapesDerniereDemarche, getCurrent()) @@ -359,25 +362,23 @@ export const titresDREAL = (_pool: Pool) => async (req: CaminoRequest, res: Cust } } } -const isStringArray = (stuff: any): stuff is string[] => { - return stuff instanceof Array && stuff.every(value => typeof value === 'string') -} + export const postTitreLiaisons = (_pool: Pool) => async (req: CaminoRequest, res: CustomResponse<TitreLinks>) => { const user = req.auth - const titreId = req.params.id - const titreFromIds = req.body + const titreId = titreIdValidator.safeParse(req.params.id) + const titreFromIds = z.array(titreIdValidator).safeParse(req.body) - if (!isStringArray(titreFromIds)) { + if (!titreFromIds.success) { throw new Error(`un tableau est attendu en corps de message : '${titreFromIds}'`) } - if (!titreId) { + if (!titreId.success) { throw new Error('le paramètre id est obligatoire') } const titre = await titreGet( - titreId, + titreId.data, { fields: { pointsEtape: { id: {} }, @@ -396,15 +397,15 @@ export const postTitreLiaisons = (_pool: Pool) => async (req: CaminoRequest, res throw new Error('les démarches ne sont pas chargées') } - const titresFrom = await titresGet({ ids: titreFromIds }, { fields: { id: {} } }, user) + const titresFrom = await titresGet({ ids: titreFromIds.data }, { fields: { id: {} } }, user) - checkTitreLinks(titre, titreFromIds, titresFrom, titre.demarches) + checkTitreLinks(titre, titreFromIds.data, titresFrom, titre.demarches) - await linkTitres({ linkTo: titreId, linkFrom: titreFromIds }) + await linkTitres({ linkTo: titreId.data, linkFrom: titreFromIds.data }) res.json({ - amont: await titreLinksGet(titreId, 'titreFromId', user), - aval: await titreLinksGet(titreId, 'titreToId', user), + amont: await titreLinksGet(titreId.data, 'titreFromId', user), + aval: await titreLinksGet(titreId.data, 'titreToId', user), }) } export const getTitreLiaisons = (_pool: Pool) => async (req: CaminoRequest, res: CustomResponse<TitreLinks>) => { @@ -459,12 +460,12 @@ const titreLinksGet = async (titreId: string, link: 'titreToId' | 'titreFromId', export const removeTitre = (_pool: Pool) => async (req: CaminoRequest, res: CustomResponse<void>) => { const user = req.auth - const titreId: string | undefined = req.params.titreId - if (!titreId) { + const titreId = titreIdValidator.safeParse(req.params.titreId) + if (!titreId.success) { res.sendStatus(constants.HTTP_STATUS_BAD_REQUEST) } else { const titreOld = await titreGet( - titreId, + titreId.data, { fields: { demarches: { etapes: { id: {} } }, @@ -479,7 +480,7 @@ export const removeTitre = (_pool: Pool) => async (req: CaminoRequest, res: Cust } else if (!canDeleteTitre(user)) { res.sendStatus(constants.HTTP_STATUS_FORBIDDEN) } else { - await titreArchive(titreId) + await titreArchive(titreId.data) res.sendStatus(constants.HTTP_STATUS_NO_CONTENT) } } diff --git a/packages/api/src/business/daily.ts b/packages/api/src/business/daily.ts index 5cab8f444..3e1f6b0d5 100644 --- a/packages/api/src/business/daily.ts +++ b/packages/api/src/business/daily.ts @@ -30,11 +30,11 @@ export const daily = async (pool: Pool) => { console.info('- - -') console.info('mise à jour quotidienne') - const titresEtapesOrdreUpdated = await titresEtapesOrdreUpdate(userSuper) + const titresEtapesOrdreUpdated = await titresEtapesOrdreUpdate(pool, userSuper) const titresEtapesHeritagePropsUpdated = await titresEtapesHeritagePropsUpdate(userSuper) - const titresEtapesHeritageContenuUpdated = await titresEtapesHeritageContenuUpdate(userSuper) + const titresEtapesHeritageContenuUpdated = await titresEtapesHeritageContenuUpdate(pool, userSuper) - const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate() + const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(pool) const titresDemarchesOrdreUpdated = await titresDemarchesOrdreUpdate() const [titresDemarchesDatesUpdated = []] = await titresDemarchesDatesUpdate(pool) const titresDemarchesPublicUpdated = await titresDemarchesPublicUpdate() diff --git a/packages/api/src/business/matrices.test.ts b/packages/api/src/business/matrices.test.ts index 3f3384ee5..414a96930 100644 --- a/packages/api/src/business/matrices.test.ts +++ b/packages/api/src/business/matrices.test.ts @@ -4,6 +4,7 @@ import { newEntrepriseId } from 'camino-common/src/entreprise.js' import { describe, expect, test } from 'vitest' import { checkCodePostal } from 'camino-common/src/static/departement.js' import { toCommuneId } from 'camino-common/src/static/communes.js' +import { newTitreId } from '../database/models/_format/id-create.js' describe('matrices', () => { test('buildMatrices', () => { const openFiscaResponse = { @@ -84,7 +85,7 @@ describe('matrices', () => { } const titres: Pick<ITitre, 'id' | 'slug' | 'titulaires' | 'communes'>[] = [ { - id: 'titre1', + id: newTitreId('titre1'), titulaires: [ { id: newEntrepriseId(''), @@ -101,7 +102,7 @@ describe('matrices', () => { ], }, { - id: 'titre2', + id: newTitreId('titre2'), titulaires: [ { id: newEntrepriseId(''), @@ -121,7 +122,7 @@ describe('matrices', () => { ], }, { - id: 'titre3', + id: newTitreId('titre3'), titulaires: [ { id: newEntrepriseId(''), diff --git a/packages/api/src/business/processes/__mocks__/titres-activites-update-titres.ts b/packages/api/src/business/processes/__mocks__/titres-activites-update-titres.ts index 92a5b5960..134d50ce8 100644 --- a/packages/api/src/business/processes/__mocks__/titres-activites-update-titres.ts +++ b/packages/api/src/business/processes/__mocks__/titres-activites-update-titres.ts @@ -1,9 +1,10 @@ +import { newTitreId } from '../../../database/models/_format/id-create.js' import ActivitesTypes from '../../../database/models/activites-types.js' import Titres from '../../../database/models/titres.js' const titresSansActivite = [ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), activites: [], titulaires: [{ utilisateurs: [{ email: 'email' }] }], }, @@ -11,7 +12,7 @@ const titresSansActivite = [ const titresToutesActivites = [ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), activites: [ { annee: 2018, periodeId: 1 }, { annee: 2018, periodeId: 2 }, diff --git a/packages/api/src/business/processes/__snapshots__/titres-etapes-areas-update.test.integration.ts.snap b/packages/api/src/business/processes/__snapshots__/titres-etapes-areas-update.test.integration.ts.snap index 98e5f5e78..14a374a47 100644 --- a/packages/api/src/business/processes/__snapshots__/titres-etapes-areas-update.test.integration.ts.snap +++ b/packages/api/src/business/processes/__snapshots__/titres-etapes-areas-update.test.integration.ts.snap @@ -29,7 +29,7 @@ exports[`titresEtapesAreasUpdate > met à jour les communes, forêts et zone du "heritageProps": null, "id": "titreEtapeIdUniquePourMiseAJourAreas", "incertitudes": null, - "ordre": null, + "ordre": 0, "sdomZones": [ "1", ], @@ -95,7 +95,7 @@ exports[`titresEtapesAreasUpdate > met à jour les communes, forêts et zone du "heritageProps": null, "id": "titreEtapeIdUniquePourMiseAJourAreas", "incertitudes": null, - "ordre": null, + "ordre": 0, "sdomZones": [ "1", ], 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 47e3ad614..52bea47ee 100644 --- a/packages/api/src/business/processes/titres-demarches-depot-create.ts +++ b/packages/api/src/business/processes/titres-demarches-depot-create.ts @@ -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) - // On peut déposer automatiquement seulement les démarches qui possèdent un arbre d’instructions + // 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') { // Si on a pas de demande faite diff --git a/packages/api/src/business/processes/titres-demarches-statut-ids-update.test.ts b/packages/api/src/business/processes/titres-demarches-statut-ids-update.test.ts index ca7b1a871..431d6e0c0 100644 --- a/packages/api/src/business/processes/titres-demarches-statut-ids-update.test.ts +++ b/packages/api/src/business/processes/titres-demarches-statut-ids-update.test.ts @@ -1,8 +1,9 @@ import { titresDemarchesStatutIdUpdate } from './titres-demarches-statut-ids-update.js' import { vi, describe, expect, test } from 'vitest' import { getDemarches } from './titres-etapes-heritage-contenu-update.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' +import { Pool } from 'pg' vi.mock('./titres-etapes-heritage-contenu-update', () => ({ getDemarches: vi.fn().mockResolvedValue(true), @@ -21,31 +22,37 @@ describe("statut des démarches d'un titre", () => { getDemarchesMock.mockResolvedValue({ [newDemarcheId('')]: { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), titreTypeId: 'cxh', typeId: 'oct', statutId: 'rej', etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', - titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), typeId: 'dpu', statutId: 'acc', ordre: 2, date: toCaminoDate('1988-03-11'), + communes: [], + contenu: {}, + heritageContenu: {}, + surface: null, }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', - titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), typeId: 'dex', statutId: 'acc', ordre: 1, date: toCaminoDate('1988-03-06'), + communes: [], + contenu: {}, + heritageContenu: {}, + surface: null, }, ], }, }) - const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate() + const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(undefined as unknown as Pool) expect(titresDemarchesStatutUpdated.length).toEqual(1) }) @@ -54,31 +61,37 @@ describe("statut des démarches d'un titre", () => { getDemarchesMock.mockResolvedValue({ [newDemarcheId('')]: { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), titreTypeId: 'cxh', typeId: 'oct', statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', - titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), typeId: 'dpu', statutId: 'acc', ordre: 2, date: toCaminoDate('1988-03-11'), + communes: [], + contenu: {}, + heritageContenu: {}, + surface: null, }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', - titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), typeId: 'dex', statutId: 'acc', ordre: 1, date: toCaminoDate('1988-03-06'), + communes: [], + contenu: {}, + heritageContenu: {}, + surface: null, }, ], }, }) - const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate() + const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(undefined as unknown as Pool) expect(titresDemarchesStatutUpdated.length).toEqual(0) }) @@ -87,14 +100,14 @@ describe("statut des démarches d'un titre", () => { getDemarchesMock.mockResolvedValue({ [newDemarcheId('')]: { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), titreTypeId: 'cxh', typeId: 'oct', statutId: 'ind', etapes: [], }, }) - const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate() + const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(undefined as unknown as Pool) expect(titresDemarchesStatutUpdated.length).toEqual(0) }) }) diff --git a/packages/api/src/business/processes/titres-demarches-statut-ids-update.ts b/packages/api/src/business/processes/titres-demarches-statut-ids-update.ts index 6334abcb5..56b7879ee 100644 --- a/packages/api/src/business/processes/titres-demarches-statut-ids-update.ts +++ b/packages/api/src/business/processes/titres-demarches-statut-ids-update.ts @@ -1,14 +1,16 @@ +import { TitreId } from 'camino-common/src/titres.js' import { titreDemarcheUpdate } from '../../database/queries/titres-demarches.js' import { titreDemarcheStatutIdFind } from '../rules/titre-demarche-statut-id-find.js' import { titreEtapesSortAscByOrdre } from '../utils/titre-etapes-sort.js' import { getDemarches } from './titres-etapes-heritage-contenu-update.js' +import { Pool } from 'pg' // met à jour le statut des démarches d'un titre -export const titresDemarchesStatutIdUpdate = async (titresId?: string) => { +export const titresDemarchesStatutIdUpdate = async (pool: Pool, titresId?: TitreId) => { console.info() console.info('statut des démarches…') - const titresDemarches = await getDemarches(undefined, titresId) + const titresDemarches = await getDemarches(pool, undefined, titresId) // TODO: forcer la présence des démarches sur le titre // https://stackoverflow.com/questions/40510611/typescript-interface-require-one-of-two-properties-to-exist/49725198#49725198 diff --git a/packages/api/src/business/processes/titres-etapes-administrations-locales-update.test.ts b/packages/api/src/business/processes/titres-etapes-administrations-locales-update.test.ts index 94f2d4133..e42e7dfce 100644 --- a/packages/api/src/business/processes/titres-etapes-administrations-locales-update.test.ts +++ b/packages/api/src/business/processes/titres-etapes-administrations-locales-update.test.ts @@ -2,7 +2,7 @@ import { titresEtapesAdministrationsLocalesUpdate } from './titres-etapes-admini import { titresEtapesGet } from '../../database/queries/titres-etapes.js' import { ICommune, ITitreEtape } from '../../types.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId } from '../../database/models/_format/id-create.js' import { ADMINISTRATION_IDS } from 'camino-common/src/static/administrations.js' import { toCaminoDate } from 'camino-common/src/date.js' import { vi, describe, expect, test } from 'vitest' @@ -30,7 +30,7 @@ describe("administrations d'une étape", () => { test('ajoute des administrations dans deux étapes', async () => { const titresEtapesCommunes: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId(), statutId: 'fai', date: toCaminoDate('2022-01-01'), @@ -43,7 +43,7 @@ describe("administrations d'une étape", () => { ], }, { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId(), statutId: 'fai', date: toCaminoDate('2022-01-01'), @@ -66,7 +66,7 @@ describe("administrations d'une étape", () => { test("n'ajoute pas deux fois une administration en doublon ", async () => { const titresEtapesCommunesMemeCommune: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -89,7 +89,7 @@ describe("administrations d'une étape", () => { test("ne met pas à jour les administrations d'une étape qui n'a pas de commune", async () => { const titresEtapesCommunesVides: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -107,7 +107,7 @@ describe("administrations d'une étape", () => { test("n'ajoute pas d'administration si elle existe déjà dans l'étape", async () => { const titreEtape: ITitreEtape = { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId(), statutId: 'fai', date: toCaminoDate('2022-01-01'), @@ -127,7 +127,7 @@ describe("administrations d'une étape", () => { const titreEtape: ITitreEtape = { statutId: 'fai', date: toCaminoDate('2022-01-01'), - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', communes: [] as ICommune[], diff --git a/packages/api/src/business/processes/titres-etapes-areas-update.test.integration.ts b/packages/api/src/business/processes/titres-etapes-areas-update.test.integration.ts index 3fa244240..e3bb44f28 100644 --- a/packages/api/src/business/processes/titres-etapes-areas-update.test.integration.ts +++ b/packages/api/src/business/processes/titres-etapes-areas-update.test.integration.ts @@ -7,7 +7,7 @@ import TitresEtapes from '../../database/models/titres-etapes.js' import TitresPoints from '../../database/models/titres-points.js' import { titresEtapesAreasUpdate } from './titres-etapes-areas-update.js' import { BaisieuxPerimetre, foret2BranchesPerimetre, foretReginaPerimetre, SaintEliePerimetre, SinnamaryPerimetre } from './__mocks__/titres-etapes-areas-update.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { SDOMZoneIds } from 'camino-common/src/static/sdom.js' import { toCaminoDate } from 'camino-common/src/date.js' import { vi, beforeAll, afterAll, describe, test, expect } from 'vitest' @@ -52,7 +52,7 @@ describe('titresEtapesAreasUpdate', () => { // Pour simplifier le test, on utilise des forêts en tant que zone de sdom await knex!.raw(`insert into sdom_zones_postgis (id, geometry) values ('${SDOMZoneIds.Zone1}','${foret2BranchesPerimetre}')`) await knex!.raw(`insert into sdom_zones_postgis (id, geometry) values ('${SDOMZoneIds.Zone2}','${foretReginaPerimetre}')`) - const titreId = 'titreIdUniquePourMiseAJourAreas' + const titreId = newTitreId('titreIdUniquePourMiseAJourAreas') await Titres.query().insert({ id: titreId, slug: `slug-${titreId}`, @@ -72,7 +72,7 @@ describe('titresEtapesAreasUpdate', () => { }, ]) - const titreEtapeId = 'titreEtapeIdUniquePourMiseAJourAreas' + const titreEtapeId = newEtapeId('titreEtapeIdUniquePourMiseAJourAreas') await TitresEtapes.query().insert([ { id: titreEtapeId, diff --git a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.ts b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.ts new file mode 100644 index 000000000..870551e3c --- /dev/null +++ b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.ts @@ -0,0 +1,64 @@ +import { sql } from '@pgtyped/runtime' +import { IGetEtapesByDemarcheQuery } from './titres-etapes-heritage-contenu-update.queries.types' +import { Redefine } from '../../pg-database' +import { caminoDateValidator } from 'camino-common/src/date.js' +import { DemarcheId, demarcheIdValidator } from 'camino-common/src/demarche.js' +import { demarcheStatutIdValidator } from 'camino-common/src/static/demarchesStatuts.js' +import { demarcheTypeIdValidator } from 'camino-common/src/static/demarchesTypes.js' +import { etapeStatutIdValidator } from 'camino-common/src/static/etapesStatuts.js' +import { titreTypeIdValidator } from 'camino-common/src/static/titresTypes.js' +import { etapeTypeIdValidator } from 'camino-common/src/static/etapesTypes.js' +import { TitreId, titreIdValidator } from 'camino-common/src/titres.js' +import { etapeIdValidator } from 'camino-common/src/etape.js' +import { z } from 'zod' +import { communeIdValidator } from 'camino-common/src/static/communes.js' + +export const getEtapesByDemarcheValidator = z.object({ + contenu: z.any(), + date: caminoDateValidator, + demarche_id: demarcheIdValidator, + demarche_statut_id: demarcheStatutIdValidator, + demarche_type_id: demarcheTypeIdValidator, + heritage_contenu: z.any(), + id: etapeIdValidator, + ordre: z.number(), + statut_id: etapeStatutIdValidator, + titre_id: titreIdValidator, + titre_type_id: titreTypeIdValidator, + communes: z.array(z.object({ id: communeIdValidator })), + surface: z.number().nullable(), + type_id: etapeTypeIdValidator, +}) + +export const getEtapesByDemarche = sql<Redefine<IGetEtapesByDemarcheQuery, { demarcheId?: DemarcheId; titreId?: TitreId }, z.infer<typeof getEtapesByDemarcheValidator>>>` +SELECT + titre.id as titre_id, + titre.type_id as titre_type_id, + etape.id, + etape.ordre, + etape.type_id, + etape.statut_id, + etape.date, + etape.contenu, + etape.surface, + etape.heritage_contenu, + demarche.id as demarche_id, + demarche.type_id as demarche_type_id, + demarche.statut_id as demarche_statut_id, + etape.communes as communes +from + titres_etapes etape + join titres_demarches demarche on etape.titre_demarche_id = demarche.id + join titres titre on demarche.titre_id = titre.id +where + etape.archive = false + and demarche.archive = false + and titre.archive = false + and ($ demarcheId::text IS NULL + or demarche.id = $ demarcheId) + and ($ titreId::text IS NULL + or titre.id = $ titreId) +order by + demarche.id, + etape.ordre +` diff --git a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.types.ts b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.types.ts new file mode 100644 index 000000000..919cedc7b --- /dev/null +++ b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.queries.types.ts @@ -0,0 +1,33 @@ +/** Types generated for queries found in "src/business/processes/titres-etapes-heritage-contenu-update.queries.ts" */ +export type Json = null | boolean | number | string | Json[] | { [key: string]: Json }; + +/** 'GetEtapesByDemarche' parameters type */ +export interface IGetEtapesByDemarcheParams { + demarcheId?: string | null | void; + titreId?: string | null | void; +} + +/** 'GetEtapesByDemarche' return type */ +export interface IGetEtapesByDemarcheResult { + communes: Json; + contenu: Json | null; + date: string; + demarche_id: string; + demarche_statut_id: string; + demarche_type_id: string; + heritage_contenu: Json | null; + id: string; + ordre: number; + statut_id: string; + surface: number | null; + titre_id: string; + titre_type_id: string; + type_id: string; +} + +/** 'GetEtapesByDemarche' query type */ +export interface IGetEtapesByDemarcheQuery { + params: IGetEtapesByDemarcheParams; + result: IGetEtapesByDemarcheResult; +} + diff --git a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts index 7a460cd15..05b27ddd7 100644 --- a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts +++ b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts @@ -1,57 +1,43 @@ /* eslint-disable sql/no-unsafe-query */ -import { IContenu, IHeritageContenu, ITitreEtape } from '../../types.js' - import { titreEtapeUpdate } from '../../database/queries/titres-etapes.js' import { titreEtapeHeritageContenuFind } from '../utils/titre-etape-heritage-contenu-find.js' import { titreEtapesSortAscByOrdre, titreEtapesSortDescByOrdre } from '../utils/titre-etapes-sort.js' -import { UserNotNull } from 'camino-common/src/roles' +import { UserNotNull } from 'camino-common/src/roles.js' import { getSections, Section } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' -import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts.js' -import { CaminoDate } from 'camino-common/src/date.js' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' -import { knex } from '../../knex.js' import { DeepReadonly } from 'camino-common/src/typescript-tools.js' import { DemarcheStatutId } from 'camino-common/src/static/demarchesStatuts.js' import { DemarcheId } from 'camino-common/src/demarche.js' +import { Pool } from 'pg' +import { dbQueryAndValidate } from '../../pg-database.js' +import { getEtapesByDemarche, getEtapesByDemarcheValidator } from './titres-etapes-heritage-contenu-update.queries.js' +import { TitreId } from 'camino-common/src/titres.js' +import { TitreEtapeForMachine } from '../rules-demarches/machine-common.js' + +export const getDemarches = async ( + pool: Pool, + demarcheId?: DemarcheId, + titreId?: TitreId +): Promise<{ + [key: DemarcheId]: { + etapes: TitreEtapeForMachine[] + id: DemarcheId + typeId: DemarcheTypeId + titreTypeId: TitreTypeId + titreId: TitreId + statutId: DemarcheStatutId + } +}> => { + const etapes = await dbQueryAndValidate(getEtapesByDemarche, { demarcheId, titreId }, pool, getEtapesByDemarcheValidator) -export const getDemarches = async (demarcheId?: DemarcheId, titreId?: string) => { - const etapes: { - rows: { - titre_id: string - titre_type_id: TitreTypeId - id: string - ordre: number - type_id: EtapeTypeId - statut_id: EtapeStatutId - date: CaminoDate - contenu: IContenu - heritage_contenu: IHeritageContenu - demarche_id: DemarcheId - demarche_type_id: DemarcheTypeId - demarche_statut_id: DemarcheStatutId - }[] - } = - await knex.raw(`SELECT titre.id as titre_id, titre.type_id as titre_type_id, etape.id, etape.ordre, etape.type_id, etape.statut_id, etape.date, etape.contenu, etape.heritage_contenu, demarche.id as demarche_id, demarche.type_id as demarche_type_id, demarche.statut_id as demarche_statut_id - from titres_etapes etape - join titres_demarches demarche on etape.titre_demarche_id = demarche.id - join titres titre on demarche.titre_id = titre.id - where etape.archive = false - and demarche.archive = false - and titre.archive = false - ${demarcheId ? `and demarche.id = '${demarcheId}'` : ''} - ${titreId ? `and titre.id = '${titreId}'` : ''} - - order by demarche.id, etape.ordre`) - - return etapes.rows.reduce<{ + return etapes.reduce<{ [key: DemarcheId]: { - etapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'heritageContenu' | 'titreDemarcheId'>[] + etapes: TitreEtapeForMachine[] id: DemarcheId typeId: DemarcheTypeId titreTypeId: TitreTypeId - titreId: string + titreId: TitreId statutId: DemarcheStatutId } }>((acc, row) => { @@ -74,17 +60,18 @@ export const getDemarches = async (demarcheId?: DemarcheId, titreId?: string) => date: row.date, contenu: row.contenu, heritageContenu: row.heritage_contenu, - titreDemarcheId: row.demarche_id, + communes: row.communes, + surface: row.surface, }) return acc }, {}) } -export const titresEtapesHeritageContenuUpdate = async (user: UserNotNull, demarcheId?: DemarcheId) => { +export const titresEtapesHeritageContenuUpdate = async (pool: Pool, user: UserNotNull, demarcheId?: DemarcheId) => { console.info() console.info('héritage des contenus des étapes…') - const titresDemarches = await getDemarches(demarcheId) + const titresDemarches = await getDemarches(pool, demarcheId) // lorsqu'une étape est mise à jour par un utilisateur, // l'objet heritageContenu reçu ne contient pas d'id d'étape @@ -125,8 +112,8 @@ export const titresEtapesHeritageContenuUpdate = async (user: UserNotNull, demar titresEtapesIdsUpdated.push(titreEtape.id) - titreEtape.contenu = contenu - titreEtape.heritageContenu = heritageContenu + titreEtape.contenu = contenu ?? null + titreEtape.heritageContenu = heritageContenu ?? null } } } diff --git a/packages/api/src/business/processes/titres-etapes-ordre-update.test.ts b/packages/api/src/business/processes/titres-etapes-ordre-update.test.ts index b8eaffc56..fe23143b0 100644 --- a/packages/api/src/business/processes/titres-etapes-ordre-update.test.ts +++ b/packages/api/src/business/processes/titres-etapes-ordre-update.test.ts @@ -4,6 +4,7 @@ import { titreEtapeUpdate } from '../../database/queries/titres-etapes.js' import TitresDemarches from '../../database/models/titres-demarches.js' import { userSuper } from '../../database/user-super.js' import { vi, afterEach, describe, expect, test } from 'vitest' +import { newEtapeId } from '../../database/models/_format/id-create.js' vi.mock('../../database/queries/titres-etapes', () => ({ titreEtapeUpdate: vi.fn().mockResolvedValue(true), })) @@ -11,8 +12,8 @@ vi.mock('../../database/queries/titres-etapes', () => ({ const titresDemarchesEtapes = { '': { etapes: [ - { ordre: 1, date: '1988-03-06' }, - { ordre: 1, date: '1988-03-08' }, + { id: newEtapeId(), ordre: 1, date: '1988-03-06', typeId: 'aac', statutId: 'acc', surface: 0, communes: null }, + { id: newEtapeId(), ordre: 1, date: '1988-03-08', typeId: 'aac', statutId: 'acc', surface: 0, communes: null }, ], titre: null, } as TitresDemarches, diff --git a/packages/api/src/business/processes/titres-etapes-ordre-update.ts b/packages/api/src/business/processes/titres-etapes-ordre-update.ts index 5e5c7a660..be941df3d 100644 --- a/packages/api/src/business/processes/titres-etapes-ordre-update.ts +++ b/packages/api/src/business/processes/titres-etapes-ordre-update.ts @@ -1,5 +1,3 @@ -import { ITitreEtape } from '../../types.js' - import { titreEtapeUpdate } from '../../database/queries/titres-etapes.js' import { titreEtapesSortAscByDate } from '../utils/titre-etapes-sort.js' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' @@ -7,12 +5,15 @@ import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { getDemarches } from './titres-etapes-heritage-contenu-update.js' import { UserNotNull } from 'camino-common/src/roles.js' import { DemarcheId } from 'camino-common/src/demarche.js' +import { Pool } from 'pg' +import { TitreId } from 'camino-common/src/titres.js' +import { TitreEtapeForMachine, titreEtapeForMachineValidator } from '../rules-demarches/machine-common.js' -export const titresEtapesOrdreUpdate = async (user: UserNotNull, demarcheId?: DemarcheId) => { +export const titresEtapesOrdreUpdate = async (pool: Pool, user: UserNotNull, demarcheId?: DemarcheId) => { console.info() console.info('ordre des étapes…') - const titresDemarches = await getDemarches(demarcheId) + const titresDemarches = await getDemarches(pool, demarcheId) return titresEtapesOrdreUpdateVisibleForTesting(user, titresDemarches) } @@ -21,11 +22,11 @@ export const titresEtapesOrdreUpdateVisibleForTesting = async ( user: UserNotNull, titresDemarches: { [key: DemarcheId]: { - etapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] + etapes: TitreEtapeForMachine[] id: DemarcheId typeId: DemarcheTypeId titreTypeId: TitreTypeId - titreId: string + titreId: TitreId } } ): Promise<string[]> => { @@ -33,7 +34,9 @@ export const titresEtapesOrdreUpdateVisibleForTesting = async ( for (const titreDemarche of Object.values(titresDemarches)) { if (titreDemarche.etapes) { - const etapes = titreEtapesSortAscByDate(titreDemarche.etapes, titreDemarche.id, titreDemarche.typeId, titreDemarche.titreTypeId) + const etapesMachine = titreDemarche.etapes.map(etape => titreEtapeForMachineValidator.parse(etape)) + + const etapes = titreEtapesSortAscByDate(etapesMachine, titreDemarche.id, titreDemarche.typeId, titreDemarche.titreTypeId) for (let index = 0; index < etapes.length; index++) { const titreEtape = etapes[index] if (titreEtape.ordre !== index + 1) { diff --git a/packages/api/src/business/processes/titres-phases-update.test.ts b/packages/api/src/business/processes/titres-phases-update.test.ts index b68316b04..1b1763a6a 100644 --- a/packages/api/src/business/processes/titres-phases-update.test.ts +++ b/packages/api/src/business/processes/titres-phases-update.test.ts @@ -3,7 +3,7 @@ import { titresGet } from '../../database/queries/titres.js' import { vi, afterEach, describe, expect, test } from 'vitest' import { toCaminoDate } from 'camino-common/src/date.js' import { ITitre } from '../../types.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { dbQueryAndValidate } from '../../pg-database.js' import { Pool } from 'pg' import { updateDatesDemarcheDb } from './titres-phases-update.queries.js' @@ -34,20 +34,20 @@ describe("phases d'un titre", () => { test('met à jour un titre dont une phase est créée', async () => { titresGetMock.mockResolvedValue([ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), nom: 'nom', typeId: 'cxh', propsTitreEtapesIds: {}, demarches: [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -56,7 +56,7 @@ describe("phases d'un titre", () => { dateFin: toCaminoDate('2500-01-01'), }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dex', statutId: 'acc', @@ -84,14 +84,14 @@ describe("phases d'un titre", () => { test('met à jour un titre dont une phase est modifiée', async () => { titresGetMock.mockResolvedValue([ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), nom: 'nom', typeId: 'cxh', propsTitreEtapesIds: {}, demarches: [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, @@ -99,7 +99,7 @@ describe("phases d'un titre", () => { demarcheDateDebut: toCaminoDate('2300-01-01'), etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -108,7 +108,7 @@ describe("phases d'un titre", () => { dateFin: toCaminoDate('2500-01-01'), }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dex', statutId: 'acc', @@ -135,14 +135,14 @@ describe("phases d'un titre", () => { test('met à jour un titre dont une phase est supprimée', async () => { titresGetMock.mockResolvedValue([ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), nom: 'test', typeId: 'cxh', propsTitreEtapesIds: {}, demarches: [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', demarcheDateDebut: toCaminoDate('2200-01-01'), @@ -163,14 +163,14 @@ describe("phases d'un titre", () => { test("ne met pas à jour un titre si aucune phase n'est modifiée", async () => { titresGetMock.mockResolvedValue([ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), nom: 'nom', propsTitreEtapesIds: {}, typeId: 'cxh', demarches: [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, @@ -178,7 +178,7 @@ describe("phases d'un titre", () => { demarcheDateDebut: toCaminoDate('2200-01-01'), etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -187,7 +187,7 @@ describe("phases d'un titre", () => { dateFin: toCaminoDate('2500-01-01'), }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dex', statutId: 'acc', @@ -209,14 +209,14 @@ describe("phases d'un titre", () => { test("ne met pas à jour un titre si aucune phase n'existe", async () => { titresGetMock.mockResolvedValue([ { - id: 'h-cx-courdemanges-1988', + id: newTitreId('h-cx-courdemanges-1988'), nom: 'nom', typeId: 'cxh', propsTitreEtapesIds: {}, demarches: [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, diff --git a/packages/api/src/business/processes/titres-statut-ids-update.test.ts b/packages/api/src/business/processes/titres-statut-ids-update.test.ts index 2a2f0158f..2d193b856 100644 --- a/packages/api/src/business/processes/titres-statut-ids-update.test.ts +++ b/packages/api/src/business/processes/titres-statut-ids-update.test.ts @@ -2,7 +2,7 @@ import { titresStatutIdsUpdate } from './titres-statut-ids-update.js' import { titresGet } from '../../database/queries/titres.js' import { vi, describe, expect, test, beforeEach } from 'vitest' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' vi.mock('../../database/queries/titres', () => ({ __esModule: true, @@ -22,7 +22,7 @@ describe("statut d'un titre", () => { test('met à jour un titre si son statut est obsolète', async () => { titresGetMock.mockResolvedValue([ { - id: 'm-pr-saint-pierre-1914', + id: newTitreId('m-pr-saint-pierre-1914'), nom: 'unused', typeId: 'prm', propsTitreEtapesIds: {}, @@ -30,7 +30,7 @@ describe("statut d'un titre", () => { demarches: [ { id: newDemarcheId('m-pr-saint-pierre-1914-oct01'), - titreId: 'm-pr-saint-pierre-1914', + titreId: newTitreId('m-pr-saint-pierre-1914'), typeId: 'oct', statutId: 'acc', ordre: 1, @@ -49,7 +49,7 @@ describe("statut d'un titre", () => { test("ne met pas à jour le statut d'un titre", async () => { titresGetMock.mockResolvedValue([ { - id: 'm-pr-saint-pierre-2014', + id: newTitreId('m-pr-saint-pierre-2014'), nom: 'nom', typeId: 'prm', titreStatutId: 'val', @@ -57,7 +57,7 @@ describe("statut d'un titre", () => { demarches: [ { id: newDemarcheId('m-pr-saint-pierre-2014-oct01'), - titreId: 'm-pr-saint-pierre-2014', + titreId: newTitreId('m-pr-saint-pierre-2014'), typeId: 'oct', statutId: 'acc', ordre: 1, diff --git a/packages/api/src/business/rules-demarches/_utils.test.ts b/packages/api/src/business/rules-demarches/_utils.test.ts deleted file mode 100644 index 43d0b2de8..000000000 --- a/packages/api/src/business/rules-demarches/_utils.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import fs from 'fs' -import decamelize from 'decamelize' -import camelcase from 'camelcase' - -import { IEtapeType, ITitre, ITitreDemarche, ITitreEtape, ITitreType, ITitreTypeDemarcheTypeEtapeType } from '../../types.js' - -import { titreDemarcheEtatValidate } from '../validations/titre-demarche-etat-validate.js' -import { demarcheDefinitionFind, isDemarcheDefinitionRestriction } from './definitions.js' -import { contenusTitreEtapesIdsFind } from '../utils/props-titre-etapes-ids-find.js' -import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' -import { CaminoDate, toCaminoDate } from 'camino-common/src/date.js' -import { vi, expect, test } from 'vitest' -import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' -test('teste EtatsValidate', () => { - const octEtatsValidate = demarcheEtatsValidate('oct', 'prm', toCaminoDate('2021-01-01')) - - expect(octEtatsValidate).toBeTruthy() - expect(octEtatsValidate([], {})).toHaveLength(0) -}) - -vi.mock('../../database/models/_format/titre-contenu', () => ({ - __esModule: true, - titreContenuFormat: vi.fn(), -})) - -vi.mock('../utils/props-titre-etapes-ids-find', () => ({ - __esModule: true, - contenusTitreEtapesIdsFind: vi.fn(), -})) - -const contenusTitreEtapesIdsFindMock = vi.mocked(contenusTitreEtapesIdsFind, true) - -const elementsGet = <T>(fileName: string): T[] => { - fileName = decamelize(fileName, { separator: '-' }) - const filePath = `./sources/${fileName}` - const results = JSON.parse(fs.readFileSync(filePath).toString()) - - return results.map((result: any) => - Object.keys(result).reduce((acc: { [key: string]: any }, key) => { - acc[camelcase(key)] = result[key] - - return acc - }, {}) - ) -} - -export const etapesTypesGet = (demarcheTypeId: string, titreTypeId: string) => { - const titresTypesDemarchesTypesEtapesTypes = elementsGet<ITitreTypeDemarcheTypeEtapeType>('titres-types--demarches-types--etapes-types.json').filter( - tde => tde.titreTypeId === titreTypeId && tde.demarcheTypeId === demarcheTypeId - ) - - return elementsGet<IEtapeType>('etapes-types.json').reduce((acc, etapeType) => { - const tde = titresTypesDemarchesTypesEtapesTypes.find(tde => tde.etapeTypeId === etapeType.id) - - if (tde) { - etapeType.titreTypeId = tde.titreTypeId - etapeType.ordre = tde.ordre - acc.push(etapeType) - } - - return acc - }, [] as IEtapeType[]) -} - -export const demarcheEtatsValidate = (demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId, date: CaminoDate) => { - return (titreDemarcheEtapes: Partial<ITitreEtape>[], titre: Partial<ITitre> = {}) => { - contenusTitreEtapesIdsFindMock.mockReturnValue({}) - - const demarcheDefinitions = demarcheDefinitionFind(titreTypeId, demarcheTypeId, [{ typeId: 'mfr', date }], newDemarcheId()) - if (!isDemarcheDefinitionRestriction(demarcheDefinitions)) { - throw new Error('cette démarche n’a pas de restrictions') - } - const demarcheDefinitionRestrictions = demarcheDefinitions!.restrictions - - const titreDemarche = { typeId: demarcheTypeId } as ITitreDemarche - titre = { - ...titre, - typeId: titreTypeId, - type: { - id: titreTypeId, - contenuIds: [], - } as unknown as ITitreType, - demarches: [titreDemarche] as ITitreDemarche[], - } - - return titreDemarcheEtatValidate(date, demarcheDefinitionRestrictions!, demarcheTypeId, titreDemarche, titreDemarcheEtapes as ITitreEtape[], titre as ITitre) - } -} 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 6839a08fa..13e9dff56 100644 --- a/packages/api/src/business/rules-demarches/axm/oct.machine.ts +++ b/packages/api/src/business/rules-demarches/axm/oct.machine.ts @@ -683,7 +683,7 @@ const axmOctMachine = createMachine<AxmContext, AXMOctXStateEvent>({ publicationsEtNotificationsMachine: { type: 'parallel', states: { - notificationDuDemadeurMachine: { + notificationDuDemandeurMachine: { initial: 'notificationDuDemandeurAFaire', states: { notificationDuDemandeurAFaire: { diff --git a/packages/api/src/business/rules-demarches/definitions.test.ts b/packages/api/src/business/rules-demarches/definitions.test.ts index ffcd1363c..c4274bab3 100644 --- a/packages/api/src/business/rules-demarches/definitions.test.ts +++ b/packages/api/src/business/rules-demarches/definitions.test.ts @@ -1,123 +1,20 @@ -import { demarchesDefinitions, IEtapeTypeIdCondition, isDemarcheDefinitionMachine, isDemarcheDefinitionRestriction } from './definitions.js' -import { ArmOctMachine } from './arm/oct.machine.js' -import { expect, test } from 'vitest' -import { toCaminoDate } from 'camino-common/src/date.js' -import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' -import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' -import { getEtapesTDE } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index.js' -import { EtapesTypes, isEtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -import { etatsDefinitionPrmOct } from './prm/oct.js' +import { test, expect } from 'vitest' +import { demarcheDefinitionFind } from './definitions' +import { toCaminoDate } from 'camino-common/src/date' +import { newDemarcheId } from '../../database/models/_format/id-create' -test('isDemarcheDefinitionMachine', () => { - expect( - isDemarcheDefinitionMachine({ - titreTypeId: 'pxm', - demarcheTypeIds: [], - dateDebut: toCaminoDate('2022-01-01'), - machine: new ArmOctMachine(), - }) - ).toBe(true) - expect( - isDemarcheDefinitionMachine({ - titreTypeId: 'pxm', - demarcheTypeIds: [], - dateDebut: toCaminoDate('2022-01-01'), - restrictions: etatsDefinitionPrmOct, - }) - ).toBe(false) - expect(isDemarcheDefinitionMachine(undefined)).toBe(false) +test('demarcheDefinitionFind retourne une machine', () => { + expect(demarcheDefinitionFind('prm', 'oct', [{ date: toCaminoDate('2023-06-07'), typeId: 'mdp' }], newDemarcheId('demarcheId'))).not.toBeUndefined() }) -test('isDemarcheDefinitionRestriction', () => { - expect( - isDemarcheDefinitionRestriction({ - titreTypeId: 'pxm', - demarcheTypeIds: [], - dateDebut: toCaminoDate('2022-01-01'), - machine: new ArmOctMachine(), - }) - ).toBe(false) - expect( - isDemarcheDefinitionRestriction({ - titreTypeId: 'pxm', - demarcheTypeIds: [], - dateDebut: toCaminoDate('2022-01-01'), - restrictions: etatsDefinitionPrmOct, - }) - ).toBe(true) -}) - -test('tdeValidate', () => { - const etapeTypeIdsGet = (contraintes?: IEtapeTypeIdCondition[][]) => { - const etapeTypeIds = [] as string[] - if (contraintes?.length) { - contraintes.forEach(contrainte => { - contrainte.forEach(c => { - if (c.etapeTypeId) { - etapeTypeIds.push(c.etapeTypeId) - } - }) - }) - } - - return etapeTypeIds - } - - const etapesTypesIdsGet = (titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId) => getEtapesTDE(titreTypeId, demarcheTypeId).filter(etapeTypeId => !EtapesTypes[etapeTypeId].dateFin) - - const errors: string[] = [] - - const definitionsWithRestrictions = demarchesDefinitions.filter(isDemarcheDefinitionRestriction) - - for (const demarcheDefinition of definitionsWithRestrictions) { - for (const demarcheTypeId of demarcheDefinition.demarcheTypeIds) { - const demarcheEtatsEtapeTypeIds = Object.keys(demarcheDefinition.restrictions) - .filter(isEtapeTypeId) - .reduce((acc, etapeTypeId) => { - acc.push(etapeTypeId) - const restriction = demarcheDefinition.restrictions[etapeTypeId] - if (restriction?.separation) { - acc.push(...restriction.separation) - } - acc.push(...etapeTypeIdsGet(restriction?.avant ?? [])) - acc.push(...etapeTypeIdsGet(restriction?.apres ?? [])) - acc.push(...etapeTypeIdsGet(restriction?.justeApres ?? [])) - return acc - }, [] as string[]) - .map(type => type.split('-')[0]) - - const tdeEtapeTypeIds = etapesTypesIdsGet(demarcheDefinition.titreTypeId, demarcheTypeId) - - // on vérifie que toutes les étapes définies dans l’arbre existent dans TDE - demarcheEtatsEtapeTypeIds.forEach(demarcheEtatsEtapeTypeId => { - if (!tdeEtapeTypeIds.includes(demarcheEtatsEtapeTypeId)) { - errors.push(`titre "${demarcheDefinition.titreTypeId}" démarche "${demarcheTypeId}" étape "${demarcheEtatsEtapeTypeId}" présent dans l’arbre d’instructions mais pas dans TDE`) - } - }) - - // on vérifie que toutes les étapes définies dans TDE existent dans l’arbre - tdeEtapeTypeIds.forEach(tdeEtapeTypeId => { - if (!demarcheEtatsEtapeTypeIds.includes(tdeEtapeTypeId)) { - errors.push(`titre "${demarcheDefinition.titreTypeId}" démarche "${demarcheTypeId}" étape "${tdeEtapeTypeId}" présent dans TDE mais pas dans l’arbre d’instructions`) - } - }) - } - } - - // on vérifie qu’il existe un bloc dans l’arbre par étapes définies dans TDE - for (const demarcheDefinition of definitionsWithRestrictions) { - for (const demarcheTypeId of demarcheDefinition.demarcheTypeIds) { - const demarcheEtatsEtapeTypeIds = Object.keys(demarcheDefinition.restrictions) - - const tdeEtapeTypeIds = etapesTypesIdsGet(demarcheDefinition.titreTypeId, demarcheTypeId) +test("demarcheDefinitionFind retourne une machine quand il n'y a pas d'étape", () => { + expect(demarcheDefinitionFind('prm', 'oct', [], newDemarcheId('demarcheId'))).not.toBeUndefined() +}) - tdeEtapeTypeIds.forEach(tdeEtapeTypeId => { - if (!demarcheEtatsEtapeTypeIds.includes(tdeEtapeTypeId)) { - errors.push(`bloc manquant "${tdeEtapeTypeId}" dans l’arbre des démarches "${demarcheTypeId}" des titres "${demarcheDefinition.titreTypeId}"`) - } - }) - } - } +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'))).toBeUndefined() +}) - expect(errors).toStrictEqual([]) +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'))).toBeUndefined() }) diff --git a/packages/api/src/business/rules-demarches/definitions.ts b/packages/api/src/business/rules-demarches/definitions.ts index 2b1a0c853..54379d68b 100644 --- a/packages/api/src/business/rules-demarches/definitions.ts +++ b/packages/api/src/business/rules-demarches/definitions.ts @@ -1,6 +1,5 @@ -import { IContenuValeur, ITitreEtape } from '../../types.js' +import { ITitreEtape } from '../../types.js' import { DemarcheId } from 'camino-common/src/demarche.js' -import { etatsDefinitionPrmOct } from './prm/oct.js' import { titreDemarcheDepotDemandeDateFind } from '../rules/titre-demarche-depot-demande-date-find.js' import { CaminoMachines } from './machines.js' import { ArmOctMachine } from './arm/oct.machine.js' @@ -11,37 +10,8 @@ import { newDemarcheId } from '../../database/models/_format/id-create.js' import { CaminoDate, toCaminoDate } from 'camino-common/src/date.js' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' -import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { ArmRenProMachine } from './arm/ren-pro.machine.js' - -export interface IEtapeTypeIdCondition { - etapeTypeId?: string - statutId?: string - titre?: ITitreCondition - contextCheck?: (_etapes: ITitreEtape[]) => boolean -} - -export type IDemarcheDefinitionRestrictions = { [key in EtapeTypeId]?: IDemarcheDefinitionRestrictionsProps } - -export interface IDemarcheDefinitionRestrictionsProps { - separation?: string[] - final?: boolean - avant?: IEtapeTypeIdCondition[][] - apres?: IEtapeTypeIdCondition[][] - justeApres: IEtapeTypeIdCondition[][] -} - -export interface IDemarcheDefinitionRestrictionsElements extends IDemarcheDefinitionRestrictionsProps { - etapeTypeId?: string -} -export type IDemarcheDefinition = DemarcheDefinitionRestriction | DemarcheDefinitionMachine - -export const isDemarcheDefinitionRestriction = (dd: IDemarcheDefinition | undefined): dd is DemarcheDefinitionRestriction => { - return dd !== undefined && 'restrictions' in dd -} -export const isDemarcheDefinitionMachine = (dd: IDemarcheDefinition | undefined): dd is DemarcheDefinitionMachine => { - return dd !== undefined && 'machine' in dd -} +import { PrmOctMachine } from './prm/oct.machine.js' interface DemarcheDefinitionCommon { titreTypeId: TitreTypeId @@ -49,33 +19,12 @@ interface DemarcheDefinitionCommon { dateDebut: CaminoDate demarcheIdExceptions?: DemarcheId[] } -export interface DemarcheDefinitionRestriction extends DemarcheDefinitionCommon { - restrictions: IDemarcheDefinitionRestrictions -} -export interface DemarcheDefinitionMachine extends DemarcheDefinitionCommon { +export interface DemarcheDefinition extends DemarcheDefinitionCommon { machine: CaminoMachines } -type IContenuOperation = { - valeur: IContenuValeur - operation?: 'NOT_EQUAL' | 'EQUAL' -} - -export interface IContenuElementCondition { - [id: string]: IContenuOperation | undefined -} - -interface IContenuCondition { - [id: string]: IContenuElementCondition -} - -export interface ITitreCondition { - statutId?: string - contenu: IContenuCondition -} - const plusVieilleDateEnBase = toCaminoDate('1717-01-09') -export const demarchesDefinitions: IDemarcheDefinition[] = [ +export const demarchesDefinitions: DemarcheDefinition[] = [ { titreTypeId: 'arm', demarcheTypeIds: ['oct'], @@ -91,8 +40,17 @@ export const demarchesDefinitions: IDemarcheDefinition[] = [ { titreTypeId: 'prm', demarcheTypeIds: ['oct'], - restrictions: etatsDefinitionPrmOct, + machine: new PrmOctMachine(), dateDebut: toCaminoDate('2019-10-31'), + demarcheIdExceptions: [ + newDemarcheId('FfJTtP9EEfvf3VZy81hpF7ms'), + newDemarcheId('lynG9hx3x05LaqpySr0qxeca'), + newDemarcheId('xjvFNG3I8YOv2xLw6FQJjTab'), + newDemarcheId('fWlR3sADjURm21wM2j7UZF3R'), + newDemarcheId('eySDrrpK4KKukIw3II3nk3G1'), + newDemarcheId('PYrSWWMeDDDYfJfgWa09LVlp'), + newDemarcheId('R0XYcNUZrJFzZ8DghumpwqXw'), + ], }, { titreTypeId: 'axm', @@ -152,7 +110,7 @@ export const demarcheDefinitionFind = ( demarcheTypeId: DemarcheTypeId, titreEtapes: Pick<ITitreEtape, 'date' | 'typeId'>[] | undefined, demarcheId: DemarcheId -): IDemarcheDefinition | undefined => { +): DemarcheDefinition | undefined => { const date = titreDemarcheDepotDemandeDateFind(titreEtapes) const definition = demarchesDefinitions diff --git a/packages/api/src/business/rules-demarches/etat-cycles.ts b/packages/api/src/business/rules-demarches/etat-cycles.ts deleted file mode 100644 index f363b1f4f..000000000 --- a/packages/api/src/business/rules-demarches/etat-cycles.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { IDemarcheDefinitionRestrictionsElements } from './definitions.js' - -const etatCycleGet = (etapeTypeIdDefinition: IDemarcheDefinitionRestrictionsElements, demandeEtapeTypeId: string, receptionEtapeTypeId: string) => { - const newEtapeTypeIdDefinition = Object.assign({}, etapeTypeIdDefinition) - delete newEtapeTypeIdDefinition.etapeTypeId - - return { - [demandeEtapeTypeId]: { - avant: [[{ etapeTypeId: etapeTypeIdDefinition.etapeTypeId }]], - justeApres: [...etapeTypeIdDefinition.justeApres, [{ etapeTypeId: receptionEtapeTypeId }]], - }, - [receptionEtapeTypeId]: { - justeApres: [[{ etapeTypeId: demandeEtapeTypeId }]], - }, - [etapeTypeIdDefinition.etapeTypeId!]: { - ...newEtapeTypeIdDefinition, - avant: [[{ etapeTypeId: etapeTypeIdDefinition.etapeTypeId }]], - justeApres: [...etapeTypeIdDefinition.justeApres, [{ etapeTypeId: receptionEtapeTypeId }]], - }, - } -} - -const etatInformationsGet = (mifId: string, rifId: string, etapeTypeIdDefinition: IDemarcheDefinitionRestrictionsElements) => etatCycleGet(etapeTypeIdDefinition, mifId, rifId) - -const etatComplementsGet = (mcoId: string, rcoId: string, etapeTypeIdDefinition: IDemarcheDefinitionRestrictionsElements) => etatCycleGet(etapeTypeIdDefinition, mcoId, rcoId) - -export { etatInformationsGet, etatComplementsGet } diff --git a/packages/api/src/business/rules-demarches/machine-common.test.ts b/packages/api/src/business/rules-demarches/machine-common.test.ts index 4cd1d2c47..57268f147 100644 --- a/packages/api/src/business/rules-demarches/machine-common.test.ts +++ b/packages/api/src/business/rules-demarches/machine-common.test.ts @@ -1,7 +1,8 @@ import { toCaminoDate } from 'camino-common/src/date.js' -import { ITitreEtape } from '../../types.js' -import { toMachineEtapes } from './machine-common.js' -import { describe, expect, test } from 'vitest' +import { TitreEtapeForMachine, toMachineEtapes } from './machine-common.js' +import { describe, expect, test, vi } from 'vitest' + +console.error = vi.fn() describe('toMachineEtapes', () => { test('transforme une étape de la bdd en étape de machine', () => { expect( @@ -10,6 +11,10 @@ describe('toMachineEtapes', () => { typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2022-01-01'), + communes: [], + ordre: 0, + surface: null, + contenu: null, }, ]) ).toEqual([ @@ -27,6 +32,9 @@ describe('toMachineEtapes', () => { statutId: 'fai', date: toCaminoDate('2022-01-01'), contenu: { arm: { mecanise: true } }, + communes: [], + ordre: 0, + surface: null, }, ]) ).toEqual([ @@ -47,8 +55,7 @@ describe('toMachineEtapes', () => { typeId: 'iii', statutId: 'fai', date: '2022-01-01', - titreDemarcheId: 'idDemarche', - } as unknown as ITitreEtape, + } as unknown as TitreEtapeForMachine, ]) ).toThrowErrorMatchingInlineSnapshot(`"l'état iii est inconnu"`) }) @@ -61,11 +68,8 @@ describe('toMachineEtapes', () => { typeId: 'mfr', statutId: 'ffi', date: '2022-01-01', - titreDemarcheId: 'idDemarche', - } as unknown as ITitreEtape, + } as unknown as TitreEtapeForMachine, ]) - ).toThrowErrorMatchingInlineSnapshot( - `"le status ffi est inconnu, {\\"id\\":\\"id\\",\\"typeId\\":\\"mfr\\",\\"statutId\\":\\"ffi\\",\\"date\\":\\"2022-01-01\\",\\"titreDemarcheId\\":\\"idDemarche\\"}"` - ) + ).toThrowErrorMatchingInlineSnapshot(`"le status ffi est inconnu, {\\"id\\":\\"id\\",\\"typeId\\":\\"mfr\\",\\"statutId\\":\\"ffi\\",\\"date\\":\\"2022-01-01\\"}"`) }) }) diff --git a/packages/api/src/business/rules-demarches/machine-common.ts b/packages/api/src/business/rules-demarches/machine-common.ts index 68ee18dd6..d0c787f25 100644 --- a/packages/api/src/business/rules-demarches/machine-common.ts +++ b/packages/api/src/business/rules-demarches/machine-common.ts @@ -1,17 +1,24 @@ import { IContenu, ITitreEtape } from '../../types.js' -import { EtapeStatutId, EtapeStatutKey, ETAPES_STATUTS, isStatut } from 'camino-common/src/static/etapesStatuts.js' -import { EtapeTypeId, isEtapeTypeId } from 'camino-common/src/static/etapesTypes.js' +import { EtapeStatutId, EtapeStatutKey, ETAPES_STATUTS, isStatut, etapeStatutIdValidator } from 'camino-common/src/static/etapesStatuts.js' +import { EtapeTypeId, etapeTypeIdValidator, isEtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { ADMINISTRATION_IDS } from 'camino-common/src/static/administrations.js' import { EtapeTypeEtapeStatut } from 'camino-common/src/static/etapesTypesEtapesStatuts.js' import { DemarcheStatutId } from 'camino-common/src/static/demarchesStatuts.js' -import { CaminoDate } from 'camino-common/src/date.js' - +import { CaminoDate, caminoDateValidator } from 'camino-common/src/date.js' +import { Departements, toDepartementId } from 'camino-common/src/static/departement.js' +import { Regions } from 'camino-common/src/static/region.js' +import { PaysId } from 'camino-common/src/static/pays.js' +import { communeIdValidator } from 'camino-common/src/static/communes.js' +import { z } from 'zod' +import { etapeIdValidator } from 'camino-common/src/etape.js' export interface Etape { // TODO 2022-07-28 : ceci pourrait être réduit en utilisant les états de 'trad' etapeTypeId: EtapeTypeId etapeStatutId: EtapeStatutId date: CaminoDate contenu?: IContenu + paysId?: PaysId + surface?: number } export interface CaminoCommonContext { @@ -19,7 +26,22 @@ export interface CaminoCommonContext { visibilite: 'confidentielle' | 'publique' } -export const toMachineEtapes = (etapes: Pick<ITitreEtape, 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu'>[]): Etape[] => { +export const titreEtapeForMachineValidator = z.object({ + ordre: z.number(), + id: etapeIdValidator, + typeId: etapeTypeIdValidator, + statutId: etapeStatutIdValidator, + date: caminoDateValidator, + contenu: z.any().nullable(), + heritageContenu: z.any().nullable(), + communes: z.array(z.object({ id: communeIdValidator })).nullable(), + surface: z.number().nullable(), +}) + +export type TitreEtapeForMachine = z.infer<typeof titreEtapeForMachineValidator> +export const isTitreEtapeForMachine = (etape: Omit<ITitreEtape, 'titreDemarcheId'>): etape is TitreEtapeForMachine => titreEtapeForMachineValidator.safeParse(etape).success + +export const toMachineEtapes = (etapes: (Pick<Partial<TitreEtapeForMachine>, 'ordre'> & Omit<TitreEtapeForMachine, 'id' | 'ordre'>)[]): Etape[] => { // FIXME si on appelle titreEtapesSortAscByOrdre on se retrouve avec une grosse dépendance cyclique return etapes .slice() @@ -27,7 +49,7 @@ export const toMachineEtapes = (etapes: Pick<ITitreEtape, 'ordre' | 'typeId' | ' .map(dbEtape => toMachineEtape(dbEtape)) } -const toMachineEtape = (dbEtape: Pick<ITitreEtape, 'typeId' | 'statutId' | 'date' | 'contenu'>): Etape => { +const toMachineEtape = (dbEtape: Omit<TitreEtapeForMachine, 'id' | 'ordre'>): Etape => { let typeId if (isEtapeTypeId(dbEtape.typeId)) { typeId = dbEtape.typeId @@ -50,6 +72,12 @@ const toMachineEtape = (dbEtape: Pick<ITitreEtape, 'typeId' | 'statutId' | 'date if (dbEtape.contenu) { machineEtape.contenu = dbEtape.contenu } + if (dbEtape.communes?.length) { + machineEtape.paysId = Regions[Departements[toDepartementId(dbEtape.communes[0].id)].regionId].paysId + } + if (dbEtape.surface !== null) { + machineEtape.surface = dbEtape.surface + } return machineEtape } diff --git a/packages/api/src/business/rules-demarches/machines.ts b/packages/api/src/business/rules-demarches/machines.ts index f2b5ce503..343c0c77a 100644 --- a/packages/api/src/business/rules-demarches/machines.ts +++ b/packages/api/src/business/rules-demarches/machines.ts @@ -1,7 +1,8 @@ -import { ArmOctMachine } from './arm/oct.machine.js' -import { ArmRenProMachine } from './arm/ren-pro.machine.js' -import { AxmOctMachine } from './axm/oct.machine.js' -import { AxmProMachine } from './axm/pro.machine.js' -import { PxgOctMachine } from './pxg/oct.machine.js' +import type { ArmOctMachine } from './arm/oct.machine.js' +import type { ArmRenProMachine } from './arm/ren-pro.machine.js' +import type { AxmOctMachine } from './axm/oct.machine.js' +import type { AxmProMachine } from './axm/pro.machine.js' +import type { PrmOctMachine } from './prm/oct.machine.js' +import type { PxgOctMachine } from './pxg/oct.machine.js' -export type CaminoMachines = ArmOctMachine | AxmOctMachine | PxgOctMachine | AxmProMachine | ArmRenProMachine +export type CaminoMachines = ArmOctMachine | AxmOctMachine | PxgOctMachine | AxmProMachine | ArmRenProMachine | PrmOctMachine diff --git a/packages/api/src/business/rules-demarches/prm/oct.cas.json b/packages/api/src/business/rules-demarches/prm/oct.cas.json new file mode 100644 index 000000000..ff1f58577 --- /dev/null +++ b/packages/api/src/business/rules-demarches/prm/oct.cas.json @@ -0,0 +1 @@ +[{"id":0,"demarcheStatutId":"ins","demarchePublique":true,"etapes":[{"date":"2022-08-13","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"},{"date":"2022-08-13","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2022-08-16","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2022-12-06","etapeTypeId":"mcr","etapeStatutId":"fav"},{"date":"2022-12-12","etapeTypeId":"anf","etapeStatutId":"ter","paysId":"FR"},{"date":"2023-04-28","etapeTypeId":"ppu","etapeStatutId":"pro"}]},{"id":1,"demarcheStatutId":"eco","demarchePublique":false,"etapes":[{"date":"2022-12-07","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"}]},{"id":2,"demarcheStatutId":"ins","demarchePublique":true,"etapes":[{"date":"2023-02-17","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"},{"date":"2023-03-05","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2023-03-19","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2023-04-07","etapeTypeId":"mcr","etapeStatutId":"fav"},{"date":"2023-04-18","etapeTypeId":"anf","etapeStatutId":"enc","paysId":"FR"}]},{"id":3,"demarcheStatutId":"dep","demarchePublique":false,"etapes":[{"date":"2022-04-19","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"GF"},{"date":"2022-05-10","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2022-05-16","etapeTypeId":"spp","etapeStatutId":"fai"}]},{"id":4,"demarcheStatutId":"dep","demarchePublique":false,"etapes":[{"date":"2019-11-24","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"GF"},{"date":"2019-12-22","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2020-02-18","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2020-06-22","etapeTypeId":"mif","etapeStatutId":"fai"},{"date":"2020-07-28","etapeTypeId":"rif","etapeStatutId":"fai"}]},{"id":5,"demarcheStatutId":"dep","demarchePublique":false,"etapes":[{"date":"2019-10-31","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"GF"},{"date":"2019-11-28","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2020-01-25","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2020-05-30","etapeTypeId":"mif","etapeStatutId":"fai"},{"date":"2020-07-04","etapeTypeId":"rif","etapeStatutId":"fai"}]},{"id":6,"demarcheStatutId":"dep","demarchePublique":false,"etapes":[{"date":"2020-10-15","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"GF"},{"date":"2020-12-10","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2021-01-11","etapeTypeId":"spp","etapeStatutId":"fai"}]},{"id":7,"demarcheStatutId":"ins","demarchePublique":true,"etapes":[{"date":"2022-07-25","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"},{"date":"2022-07-25","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2022-08-22","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2022-10-10","etapeTypeId":"mcr","etapeStatutId":"fav"},{"date":"2022-11-30","etapeTypeId":"anf","etapeStatutId":"ter","paysId":"FR"},{"date":"2023-01-22","etapeTypeId":"ppu","etapeStatutId":"fai"}]},{"id":8,"demarcheStatutId":"ins","demarchePublique":true,"etapes":[{"date":"2022-04-16","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"},{"date":"2022-05-13","etapeTypeId":"mdp","etapeStatutId":"fai"},{"date":"2022-06-22","etapeTypeId":"spp","etapeStatutId":"fai"},{"date":"2022-10-07","etapeTypeId":"mcr","etapeStatutId":"fav"},{"date":"2023-01-14","etapeTypeId":"anf","etapeStatutId":"fai","paysId":"FR"}]},{"id":9,"demarcheStatutId":"eco","demarchePublique":false,"etapes":[{"date":"2023-03-14","etapeTypeId":"mfr","etapeStatutId":"fai","paysId":"FR"}]}] \ No newline at end of file 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 new file mode 100644 index 000000000..18584e278 --- /dev/null +++ b/packages/api/src/business/rules-demarches/prm/oct.machine.test.ts @@ -0,0 +1,167 @@ +import { interpretMachine, orderAndInterpretMachine } from '../machine-test-helper.js' +import { PrmOctMachine } from './oct.machine.js' +import { EtapesTypesEtapesStatuts as ETES } from 'camino-common/src/static/etapesTypesEtapesStatuts.js' +import { toCaminoDate } from 'camino-common/src/date.js' +import { describe, expect, test } from 'vitest' +import { PAYS_IDS } from 'camino-common/src/static/pays.js' +const etapesProd = require('./oct.cas.json') + +describe('vérifie l’arbre d’octroi de PRM', () => { + const prmOctMachine = new PrmOctMachine() + test('peut créer une demande d’octroi de PRM complète en Métropole', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['République Française'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisDeLOfficeNationalDesForets.FAVORABLE, date: toCaminoDate('2022-04-20') }, + { ...ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisDuPrefet.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.ouvertureDeLaParticipationDuPublic.FAIT, date: toCaminoDate('2022-05-18') }, + { ...ETES.clotureDeLaParticipationDuPublic.TERMINE, date: toCaminoDate('2022-05-19') }, + { ...ETES.consultationDesAdministrationsCentrales.FAIT, date: toCaminoDate('2022-05-21') }, + { ...ETES.saisineDuConseilGeneralDeLeconomie_CGE_.FAIT, date: toCaminoDate('2022-05-22') }, + { ...ETES.rapportDuConseilGeneralDeLeconomie_CGE_.FAVORABLE, date: toCaminoDate('2022-05-23') }, + { ...ETES.avisDuConseilGeneralDeLeconomie_CGE_.FAVORABLE, date: toCaminoDate('2022-05-24') }, + { ...ETES.saisineDeLautoriteSignataire.FAIT, date: toCaminoDate('2022-05-25') }, + { ...ETES.decisionDeLadministration.ACCEPTE, date: toCaminoDate('2022-05-26') }, + { ...ETES.publicationDeDecisionAuJORF.ACCEPTE, date: toCaminoDate('2022-05-27') }, + { ...ETES.notificationDesCollectivitesLocales.FAIT, date: toCaminoDate('2022-05-28') }, + { ...ETES.publicationDeDecisionAuRecueilDesActesAdministratifs.FAIT, date: toCaminoDate('2022-05-29') }, + { ...ETES.publicationDansUnJournalLocalOuNational.FAIT, date: toCaminoDate('2022-05-30') }, + { ...ETES.notificationAuDemandeur.FAIT, date: toCaminoDate('2022-05-31') }, + { ...ETES.notificationAuPrefet.FAIT, date: toCaminoDate('2022-05-31') }, + ] + const service = orderAndInterpretMachine(prmOctMachine, etapes) + expect(service).canOnlyTransitionTo({ machine: prmOctMachine, date: toCaminoDate('2022-07-01') }, []) + expect(prmOctMachine.demarcheStatut(etapes)).toMatchInlineSnapshot(` + { + "demarcheStatut": "acc", + "publique": true, + } + `) + }) + + test('peut créer une demande d’octroi de PRM en Guyane', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['Département de la Guyane'], surface: 200 }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.saisineDesCollectivitesLocales.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisDunMaire.FAVORABLE, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisDeLOfficeNationalDesForets.FAVORABLE, date: toCaminoDate('2022-04-20') }, + { ...ETES.avisDeLaCommissionDepartementaleDesMines_CDM_.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisDuPrefet.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.ouvertureDeLaParticipationDuPublic.FAIT, date: toCaminoDate('2022-05-18') }, + { ...ETES.clotureDeLaParticipationDuPublic.TERMINE, date: toCaminoDate('2022-05-19') }, + ] + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).not.toThrowError() + }) + + test('peut créer une demande d’octroi de PRM en Outre mer (hors Guyane)', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['Wallis-et-Futuna'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisDeLOfficeNationalDesForets.FAVORABLE, date: toCaminoDate('2022-04-20') }, + { ...ETES.avisDeLaCommissionDepartementaleDesMines_CDM_.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisDuPrefet.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.ouvertureDeLaParticipationDuPublic.FAIT, date: toCaminoDate('2022-05-18') }, + { ...ETES.clotureDeLaParticipationDuPublic.TERMINE, date: toCaminoDate('2022-05-19') }, + ] + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).not.toThrowError() + }) + + test('ne peut pas faire l’avis de la DREAL si la saisine des services a été faite dans les 30 jours', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['République Française'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, date: toCaminoDate('2022-04-20') }, + ] + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).toThrowErrorMatchingInlineSnapshot( + '"Error: cannot execute step: \'{\\"etapeTypeId\\":\\"apd\\",\\"etapeStatutId\\":\\"fav\\",\\"ordre\\":1,\\"date\\":\\"2022-04-20\\"}\' after \'[\\"mfr_fai\\",\\"mdp_fai\\",\\"spp_fai\\",\\"mcr_fav\\",\\"anf_fai\\",\\"ssr_fai\\"]\'. The event {\\"type\\":\\"RENDRE_RAPPORT_DREAL\\",\\"date\\":\\"2022-04-20\\"} should be one of \'RENDRE_AVIS_SERVICE_ADMINISTRATIF_CIVIL_LOCAL,RENDRE_AVIS_AUTORITE_MILITAIRE,RENDRE_AVIS_DES_DTT,RENDRE_AVIS_PARC_NATUREL_REGIONAL,RENDRE_AVIS_PARC_NATIONAL,RENDRE_AVIS_AGENCE_REGIONALE_SANTE_ARS,RENDRE_AVIS_ONF,RENDRE_AVIS_INSTITUT_NATIONAL_ORIGINE_ET_QUALITE_INAO,RENDRE_AVIS_DIRECTION_REGIONALE_AFFAIRES_CULTURELLES,RENDRE_AVIS_DIRECTION_REGIONALE_FINANCES_PUBLIQUES,MODIFIER_DEMANDE,DEMANDER_INFORMATIONS,RECEVOIR_INFORMATIONS,DESISTER_PAR_LE_DEMANDEUR,CLASSER_SANS_SUITE,DEPOSER_DEMANDE_CONCURRENTE\'"' + ) + }) + + test('ne peut pas faire 2 saisines des services', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['République Française'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + ] + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).toThrowErrorMatchingInlineSnapshot( + '"Error: cannot execute step: \'{\\"etapeTypeId\\":\\"ssr\\",\\"etapeStatutId\\":\\"fai\\",\\"ordre\\":1,\\"date\\":\\"2022-04-19\\"}\' after \'[\\"mfr_fai\\",\\"mdp_fai\\",\\"spp_fai\\",\\"mcr_fav\\",\\"anf_fai\\",\\"ssr_fai\\"]\'. The event {\\"type\\":\\"FAIRE_SAISINE_DES_SERVICES\\",\\"date\\":\\"2022-04-19\\"} should be one of \'RENDRE_AVIS_SERVICE_ADMINISTRATIF_CIVIL_LOCAL,RENDRE_AVIS_AUTORITE_MILITAIRE,RENDRE_AVIS_DES_DTT,RENDRE_AVIS_PARC_NATUREL_REGIONAL,RENDRE_AVIS_PARC_NATIONAL,RENDRE_AVIS_AGENCE_REGIONALE_SANTE_ARS,RENDRE_AVIS_ONF,RENDRE_AVIS_INSTITUT_NATIONAL_ORIGINE_ET_QUALITE_INAO,RENDRE_AVIS_DIRECTION_REGIONALE_AFFAIRES_CULTURELLES,RENDRE_AVIS_DIRECTION_REGIONALE_FINANCES_PUBLIQUES,MODIFIER_DEMANDE,DEMANDER_INFORMATIONS,RECEVOIR_INFORMATIONS,DESISTER_PAR_LE_DEMANDEUR,CLASSER_SANS_SUITE,DEPOSER_DEMANDE_CONCURRENTE\'"' + ) + }) + + test('ne peut pas ouvrir la participation du public si la mise en concurrence n’est pas terminée', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['République Française'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.ouvertureDeLaParticipationDuPublic.FAIT, date: toCaminoDate('2022-04-19') }, + ] + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).toThrowErrorMatchingInlineSnapshot( + '"Error: cannot execute step: \'{\\"etapeTypeId\\":\\"ppu\\",\\"etapeStatutId\\":\\"fai\\",\\"ordre\\":2,\\"date\\":\\"2022-04-19\\"}\' after \'[\\"mfr_fai\\",\\"mdp_fai\\",\\"spp_fai\\",\\"mcr_fav\\",\\"anf_fai\\"]\'. The event {\\"type\\":\\"OUVRIR_PARTICIPATION_DU_PUBLIC\\",\\"date\\":\\"2022-04-19\\"} should be one of \'MODIFIER_DEMANDE,DEMANDER_INFORMATIONS,RECEVOIR_INFORMATIONS,DESISTER_PAR_LE_DEMANDEUR,CLASSER_SANS_SUITE,FAIRE_SAISINE_DES_SERVICES,DEPOSER_DEMANDE_CONCURRENTE\'"' + ) + }) + + test('ne peut pas créer une "rpu" après une "dex" rejetée', () => { + const etapes = [ + { ...ETES.demande.FAIT, date: toCaminoDate('2022-04-14'), paysId: PAYS_IDS['République Française'] }, + { ...ETES.depotDeLaDemande.FAIT, date: toCaminoDate('2022-04-15') }, + { ...ETES.saisineDuPrefet.FAIT, date: toCaminoDate('2022-04-16') }, + { ...ETES.recevabiliteDeLaDemande.FAVORABLE, date: toCaminoDate('2022-04-17') }, + { ...ETES.avisDeMiseEnConcurrenceAuJORF.FAIT, date: toCaminoDate('2022-04-18') }, + { ...ETES.saisineDesServices.FAIT, date: toCaminoDate('2022-04-19') }, + { ...ETES.avisDeLOfficeNationalDesForets.FAVORABLE, date: toCaminoDate('2022-04-20') }, + { ...ETES.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.avisDuPrefet.FAVORABLE, date: toCaminoDate('2022-05-20') }, + { ...ETES.ouvertureDeLaParticipationDuPublic.FAIT, date: toCaminoDate('2022-05-18') }, + { ...ETES.clotureDeLaParticipationDuPublic.TERMINE, date: toCaminoDate('2022-05-19') }, + { ...ETES.consultationDesAdministrationsCentrales.FAIT, date: toCaminoDate('2022-05-21') }, + { ...ETES.saisineDuConseilGeneralDeLeconomie_CGE_.FAIT, date: toCaminoDate('2022-05-22') }, + { ...ETES.rapportDuConseilGeneralDeLeconomie_CGE_.FAVORABLE, date: toCaminoDate('2022-05-23') }, + { ...ETES.avisDuConseilGeneralDeLeconomie_CGE_.FAVORABLE, date: toCaminoDate('2022-05-24') }, + { ...ETES.saisineDeLautoriteSignataire.FAIT, date: toCaminoDate('2022-05-25') }, + { ...ETES.decisionDeLadministration.REJETE, date: toCaminoDate('2022-05-26') }, + { ...ETES.notificationAuPrefet.FAIT, date: toCaminoDate('2022-05-31') }, + { ...ETES.notificationAuDemandeur.FAIT, date: toCaminoDate('2022-06-01') }, + { ...ETES.publicationDeDecisionAuRecueilDesActesAdministratifs.FAIT, date: toCaminoDate('2022-06-01') }, + ] + + expect(() => orderAndInterpretMachine(prmOctMachine, etapes)).toThrowErrorMatchingInlineSnapshot( + '"Error: cannot execute step: \'{\\"etapeTypeId\\":\\"rpu\\",\\"etapeStatutId\\":\\"fai\\",\\"ordre\\":3,\\"date\\":\\"2022-06-01\\"}\' after \'[\\"mfr_fai\\",\\"mdp_fai\\",\\"spp_fai\\",\\"mcr_fav\\",\\"anf_fai\\",\\"ssr_fai\\",\\"aof_fav\\",\\"ppu_fai\\",\\"ppc_ter\\",\\"apd_fav\\",\\"app_fav\\",\\"cac_fai\\",\\"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_ANNULATION_PAR_JUGE_ADMINISTRATIF,RENDRE_DECISION_ABROGATION,RENDRE_DECISION_RETRAIT\'"' + ) + }) + + // pour regénérer le oct.cas.json: `npm run test:generate-data -w packages/api` + test.each(etapesProd as any[])('cas réel N°$id', demarche => { + // ici les étapes sont déjà ordonnées + interpretMachine(prmOctMachine, demarche.etapes) + expect(prmOctMachine.demarcheStatut(demarche.etapes)).toStrictEqual({ + demarcheStatut: demarche.demarcheStatutId, + publique: demarche.demarchePublique, + }) + }) +}) diff --git a/packages/api/src/business/rules-demarches/prm/oct.machine.ts b/packages/api/src/business/rules-demarches/prm/oct.machine.ts new file mode 100644 index 000000000..126d6ebb7 --- /dev/null +++ b/packages/api/src/business/rules-demarches/prm/oct.machine.ts @@ -0,0 +1,723 @@ +import { assign, createMachine } from 'xstate' +import { EtapesTypesEtapesStatuts } from 'camino-common/src/static/etapesTypesEtapesStatuts.js' +import { CaminoMachine } from '../machine-helper.js' +import { CaminoCommonContext, DBEtat, Etape } from '../machine-common.js' +import { DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts.js' +import { CaminoDate, dateAddMonths, daysBetween } from 'camino-common/src/date.js' +import { PAYS_IDS, PaysId, isGuyane, isMetropole, isOutreMer } from 'camino-common/src/static/pays.js' + +type RendreAvisMiseEnConcurrentJORF = { + date: CaminoDate + type: 'RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF' +} + +type OuvrirParticipationDuPublic = { + date: CaminoDate + type: 'OUVRIR_PARTICIPATION_DU_PUBLIC' +} + +type FaireSaisineDesServices = { + date: CaminoDate + type: 'FAIRE_SAISINE_DES_SERVICES' +} + +type RendreAvisCDM = { + date: CaminoDate + type: 'RENDRE_AVIS_CDM' +} + +type RendreRapportDREAL = { + date: CaminoDate + type: 'RENDRE_RAPPORT_DREAL' +} + +type FaireDemande = { + type: 'FAIRE_DEMANDE' + paysId: PaysId + surface: number +} + +export type XStateEvent = + | FaireDemande + | { type: 'DEPOSER_DEMANDE' } + | { type: 'FAIRE_SAISINE_PREFET' } + | { type: 'DEMANDER_COMPLEMENTS_POUR_RECEVABILITE' } + | { type: 'RECEVOIR_COMPLEMENTS_POUR_RECEVABILITE' } + | { type: 'FAIRE_RECEVABILITE_DEMANDE_FAVORABLE' } + | { type: 'FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE' } + | RendreAvisMiseEnConcurrentJORF + | { type: 'DEPOSER_DEMANDE_CONCURRENTE' } + | OuvrirParticipationDuPublic + | { type: 'CLOTURER_PARTICIPATION_DU_PUBLIC' } + | FaireSaisineDesServices + | { type: 'RENDRE_AVIS_ONF' } + | { type: 'RENDRE_AVIS_SERVICE_ADMINISTRATIF_CIVIL_LOCAL' } + | { type: 'RENDRE_AVIS_AUTORITE_MILITAIRE' } + | { type: 'RENDRE_AVIS_DES_DTT' } + | { type: 'RENDRE_AVIS_PARC_NATUREL_REGIONAL' } + | { type: 'RENDRE_AVIS_PARC_NATIONAL' } + | { type: 'RENDRE_AVIS_AGENCE_REGIONALE_SANTE_ARS' } + | { type: 'RENDRE_AVIS_INSTITUT_NATIONAL_ORIGINE_ET_QUALITE_INAO' } + | { type: 'RENDRE_AVIS_DIRECTION_REGIONALE_AFFAIRES_CULTURELLES' } + | { type: 'RENDRE_AVIS_DIRECTION_REGIONALE_FINANCES_PUBLIQUES' } + | { type: 'RENDRE_AVIS_POLICE_EAU' } + | RendreAvisCDM + | RendreRapportDREAL + | { type: 'RENDRE_AVIS_PREFET' } + | { type: 'FAIRE_SAISINE_DES_COLLECTIVITES_LOCALES' } + | { type: 'RENDRE_AVIS_DU_MAIRE' } + | { type: 'FAIRE_RAPPORT_ADMINISTRATION_CENTRALE' } + | { type: 'FAIRE_SAISINE_CONSEIL_GENERAL_CHARGE_DES_MINES' } + | { type: 'FAIRE_RAPPORT_CONSEIL_GENERAL_CHARGE_DES_MINES' } + | { type: 'RENDRE_AVIS_CONSEIL_GENERAL_CHARGE_DES_MINES' } + | { type: 'FAIRE_SAISINE_AUTORITE_SIGNATAIRE' } + | { type: 'RENDRE_DECISION_ADMINISTRATION_ACCEPTE' } + | { type: 'RENDRE_DECISION_ADMINISTRATION_REJETE' } + | { type: 'FAIRE_PUBLICATION_AU_JORF' } + | { type: 'NOTIFIER_PREFET' } + | { type: 'NOTIFIER_DEMANDEUR' } + | { type: 'PUBLIER_DECISIONS_RECUEIL_ACTES_ADMINISTRATIFS' } + | { type: 'PUBLIER_DANS_UN_JOURNAL_LOCAL_OU_NATIONAL' } + | { type: 'NOTIFIER_COLLECTIVITES_LOCALES' } + | { type: 'RENDRE_DECISION_ANNULATION_PAR_JUGE_ADMINISTRATIF' } + | { type: 'RENDRE_DECISION_ABROGATION' } + | { type: 'RENDRE_DECISION_RETRAIT' } + | { type: 'DESISTER_PAR_LE_DEMANDEUR' } + | { type: 'CLASSER_SANS_SUITE' } + | { type: 'MODIFIER_DEMANDE' } + | { type: 'DEMANDER_INFORMATIONS' } + | { type: 'RECEVOIR_INFORMATIONS' } + +export type Event = XStateEvent['type'] + +const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = { + FAIRE_DEMANDE: { db: EtapesTypesEtapesStatuts.demande, mainStep: true }, + DEPOSER_DEMANDE: { db: EtapesTypesEtapesStatuts.depotDeLaDemande, mainStep: true }, + FAIRE_SAISINE_PREFET: { db: EtapesTypesEtapesStatuts.saisineDuPrefet, mainStep: true }, + DEMANDER_COMPLEMENTS_POUR_RECEVABILITE: { db: EtapesTypesEtapesStatuts.demandeDeComplements_RecevabiliteDeLaDemande_, mainStep: false }, + RECEVOIR_COMPLEMENTS_POUR_RECEVABILITE: { db: EtapesTypesEtapesStatuts.receptionDeComplements_RecevabiliteDeLaDemande_, mainStep: false }, + FAIRE_RECEVABILITE_DEMANDE_FAVORABLE: { + db: { + FAVORABLE: EtapesTypesEtapesStatuts.recevabiliteDeLaDemande.FAVORABLE, + }, + mainStep: true, + }, + FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE: { + db: { + DEFAVORABLE: EtapesTypesEtapesStatuts.recevabiliteDeLaDemande.DEFAVORABLE, + }, + mainStep: true, + }, + RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF: { db: EtapesTypesEtapesStatuts.avisDeMiseEnConcurrenceAuJORF, mainStep: true }, + DEPOSER_DEMANDE_CONCURRENTE: { db: EtapesTypesEtapesStatuts.avisDeDemandeConcurrente, mainStep: false }, + OUVRIR_PARTICIPATION_DU_PUBLIC: { db: EtapesTypesEtapesStatuts.ouvertureDeLaParticipationDuPublic, mainStep: true }, + CLOTURER_PARTICIPATION_DU_PUBLIC: { db: EtapesTypesEtapesStatuts.clotureDeLaParticipationDuPublic, mainStep: true }, + FAIRE_SAISINE_DES_SERVICES: { db: EtapesTypesEtapesStatuts.saisineDesServices, mainStep: true }, + RENDRE_AVIS_ONF: { db: EtapesTypesEtapesStatuts.avisDeLOfficeNationalDesForets, mainStep: false }, + RENDRE_AVIS_SERVICE_ADMINISTRATIF_CIVIL_LOCAL: { db: EtapesTypesEtapesStatuts.avisDunServiceAdministratifLocal, mainStep: false }, + RENDRE_AVIS_AUTORITE_MILITAIRE: { db: EtapesTypesEtapesStatuts.avisDeLautoriteMilitaire, mainStep: false }, + RENDRE_AVIS_DES_DTT: { db: EtapesTypesEtapesStatuts.avisDeLaDirectionDepartementaleDesTerritoiresEtDeLaMerDDT_M_, mainStep: false }, + RENDRE_AVIS_PARC_NATUREL_REGIONAL: { db: EtapesTypesEtapesStatuts.avisDuParcNaturelRegional, mainStep: false }, + RENDRE_AVIS_PARC_NATIONAL: { db: EtapesTypesEtapesStatuts.avisDuParcNational, mainStep: false }, + RENDRE_AVIS_AGENCE_REGIONALE_SANTE_ARS: { db: EtapesTypesEtapesStatuts.avisDeLagenceRegionaleDeSante, mainStep: false }, + RENDRE_AVIS_INSTITUT_NATIONAL_ORIGINE_ET_QUALITE_INAO: { db: EtapesTypesEtapesStatuts.avisDeLInstitutNationalDeLorigineEtDeLaQualite, mainStep: false }, + RENDRE_AVIS_DIRECTION_REGIONALE_AFFAIRES_CULTURELLES: { db: EtapesTypesEtapesStatuts.avisDeDirectionRegionaleDesAffairesCulturelles, mainStep: false }, + RENDRE_AVIS_DIRECTION_REGIONALE_FINANCES_PUBLIQUES: { db: EtapesTypesEtapesStatuts.avisDeLaDirectionRegionaleDesFinancesPubliques, mainStep: false }, + RENDRE_AVIS_POLICE_EAU: { db: EtapesTypesEtapesStatuts.expertiseDREALOuDGTMServiceEau, mainStep: false }, + + RENDRE_AVIS_CDM: { db: EtapesTypesEtapesStatuts.avisDeLaCommissionDepartementaleDesMines_CDM_, mainStep: true }, + RENDRE_RAPPORT_DREAL: { db: EtapesTypesEtapesStatuts.avisEtRapportDuDirecteurRegionalChargeDeLenvironnementDeLamenagementEtDuLogement, mainStep: true }, + RENDRE_AVIS_PREFET: { db: EtapesTypesEtapesStatuts.avisDuPrefet, mainStep: true }, + FAIRE_SAISINE_DES_COLLECTIVITES_LOCALES: { db: EtapesTypesEtapesStatuts.saisineDesCollectivitesLocales, mainStep: true }, + RENDRE_AVIS_DU_MAIRE: { db: EtapesTypesEtapesStatuts.avisDunMaire, mainStep: true }, + FAIRE_RAPPORT_ADMINISTRATION_CENTRALE: { db: EtapesTypesEtapesStatuts.consultationDesAdministrationsCentrales, mainStep: true }, + FAIRE_SAISINE_CONSEIL_GENERAL_CHARGE_DES_MINES: { db: EtapesTypesEtapesStatuts.saisineDuConseilGeneralDeLeconomie_CGE_, mainStep: true }, + FAIRE_RAPPORT_CONSEIL_GENERAL_CHARGE_DES_MINES: { db: EtapesTypesEtapesStatuts.rapportDuConseilGeneralDeLeconomie_CGE_, mainStep: true }, + RENDRE_AVIS_CONSEIL_GENERAL_CHARGE_DES_MINES: { db: EtapesTypesEtapesStatuts.avisDuConseilGeneralDeLeconomie_CGE_, mainStep: true }, + FAIRE_SAISINE_AUTORITE_SIGNATAIRE: { db: EtapesTypesEtapesStatuts.saisineDeLautoriteSignataire, mainStep: true }, + RENDRE_DECISION_ADMINISTRATION_ACCEPTE: { db: { ACCEPTE: EtapesTypesEtapesStatuts.decisionDeLadministration.ACCEPTE }, mainStep: true }, + RENDRE_DECISION_ADMINISTRATION_REJETE: { db: { REJETE: EtapesTypesEtapesStatuts.decisionDeLadministration.REJETE }, mainStep: true }, + FAIRE_PUBLICATION_AU_JORF: { db: EtapesTypesEtapesStatuts.publicationDeDecisionAuJORF, mainStep: true }, + NOTIFIER_PREFET: { db: EtapesTypesEtapesStatuts.notificationAuPrefet, mainStep: true }, + NOTIFIER_DEMANDEUR: { db: EtapesTypesEtapesStatuts.notificationAuDemandeur, mainStep: true }, + PUBLIER_DECISIONS_RECUEIL_ACTES_ADMINISTRATIFS: { db: EtapesTypesEtapesStatuts.publicationDeDecisionAuRecueilDesActesAdministratifs, mainStep: true }, + PUBLIER_DANS_UN_JOURNAL_LOCAL_OU_NATIONAL: { db: EtapesTypesEtapesStatuts.publicationDansUnJournalLocalOuNational, mainStep: true }, + NOTIFIER_COLLECTIVITES_LOCALES: { db: EtapesTypesEtapesStatuts.notificationDesCollectivitesLocales, mainStep: true }, + RENDRE_DECISION_ANNULATION_PAR_JUGE_ADMINISTRATIF: { db: { REJETE: EtapesTypesEtapesStatuts.decisionDuJugeAdministratif.REJETE }, mainStep: true }, + RENDRE_DECISION_ABROGATION: { db: EtapesTypesEtapesStatuts.abrogationDeLaDecision, mainStep: true }, + RENDRE_DECISION_RETRAIT: { db: EtapesTypesEtapesStatuts.retraitDeLaDecision, mainStep: true }, + DESISTER_PAR_LE_DEMANDEUR: { db: EtapesTypesEtapesStatuts.desistementDuDemandeur, mainStep: false }, + CLASSER_SANS_SUITE: { db: EtapesTypesEtapesStatuts.classementSansSuite, mainStep: false }, + MODIFIER_DEMANDE: { db: EtapesTypesEtapesStatuts.modificationDeLaDemande, mainStep: false }, + DEMANDER_INFORMATIONS: { db: EtapesTypesEtapesStatuts.demandeDinformations, mainStep: false }, + RECEVOIR_INFORMATIONS: { db: EtapesTypesEtapesStatuts.receptionDinformation, mainStep: false }, +} as const + +// Related to https://github.com/Microsoft/TypeScript/issues/12870 +export 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> { + constructor() { + super(prmOctMachine, trad) + } + + toPotentialCaminoXStateEvent(event: XStateEvent['type'], date: CaminoDate): XStateEvent[] { + switch (event) { + case 'RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF': + case 'OUVRIR_PARTICIPATION_DU_PUBLIC': + case 'FAIRE_SAISINE_DES_SERVICES': + case 'RENDRE_AVIS_CDM': + case 'RENDRE_RAPPORT_DREAL': + return [{ type: event, date }] + case 'FAIRE_DEMANDE': + return [ + { type: event, paysId: PAYS_IDS['Département de la Guyane'], surface: SUPERFICIE_MAX_POUR_EXONERATION_AVIS_MISE_EN_CONCURRENCE_AU_JORF + 1 }, + { type: event, paysId: PAYS_IDS['Département de la Guyane'], surface: SUPERFICIE_MAX_POUR_EXONERATION_AVIS_MISE_EN_CONCURRENCE_AU_JORF - 1 }, + { type: event, paysId: PAYS_IDS['Wallis-et-Futuna'], surface: 0 }, + { type: event, paysId: PAYS_IDS['République Française'], 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: event }] + } + } + + 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 'OUVRIR_PARTICIPATION_DU_PUBLIC': + case 'FAIRE_SAISINE_DES_SERVICES': + case 'RENDRE_AVIS_CDM': + case 'RENDRE_RAPPORT_DREAL': + return { type: eventFromEntry, date: etape.date } + case 'FAIRE_DEMANDE': + if (!etape.paysId) { + console.error(`paysId is mandatory in etape ${JSON.stringify(etape)}`) + + return { type: eventFromEntry, 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)}`) + } + + 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 } + } + } + throw new Error(`no event from ${JSON.stringify(etape)}`) + } +} + +interface PrmOctContext extends CaminoCommonContext { + dateAvisMiseEnConcurrentJorf: CaminoDate | null + dateSaisineDesServices: CaminoDate | null + paysId: PaysId | null + surface: number | null +} + +const peutOuvrirParticipationDuPublic = (context: PrmOctContext, event: OuvrirParticipationDuPublic): boolean => { + return estExempteDeLaMiseEnConcurrence(context) || (context.dateAvisMiseEnConcurrentJorf !== null && daysBetween(dateAddMonths(context.dateAvisMiseEnConcurrentJorf, 1), event.date) >= 0) +} + +const peutRendreRapportDREAL = (context: PrmOctContext, event: RendreRapportDREAL): boolean => { + return isMetropole(context.paysId) && !!context.dateSaisineDesServices && daysBetween(dateAddMonths(context.dateSaisineDesServices, 1), event.date) >= 0 +} + +const peutRendreAvisCDM = (context: PrmOctContext, event: RendreAvisCDM): boolean => { + return isOutreMer(context.paysId) && !!context.dateSaisineDesServices && daysBetween(dateAddMonths(context.dateSaisineDesServices, 1), event.date) >= 0 +} + +const estExempteDeLaMiseEnConcurrence = (context: PrmOctContext): boolean => { + if (isGuyane(context.paysId)) { + if (context.surface === null) { + throw new Error('la surface est obligatoire quand on est en Guyane') + } + + return context.surface < SUPERFICIE_MAX_POUR_EXONERATION_AVIS_MISE_EN_CONCURRENCE_AU_JORF + } + + return false +} + +const prmOctMachine = createMachine<PrmOctContext, XStateEvent>({ + predictableActionArguments: true, + id: 'oct', + initial: 'demandeAFaire', + context: { + dateAvisMiseEnConcurrentJorf: null, + dateSaisineDesServices: null, + visibilite: 'confidentielle', + demarcheStatut: DemarchesStatutsIds.EnConstruction, + paysId: null, + surface: null, + }, + on: { + MODIFIER_DEMANDE: { + actions: () => ({}), + cond: context => context.demarcheStatut === DemarchesStatutsIds.EnInstruction || context.demarcheStatut === DemarchesStatutsIds.Depose, + }, + DEMANDER_INFORMATIONS: { + actions: () => ({}), + cond: context => context.demarcheStatut === DemarchesStatutsIds.EnInstruction || context.demarcheStatut === DemarchesStatutsIds.Depose, + }, + RECEVOIR_INFORMATIONS: { + actions: () => ({}), + cond: context => context.demarcheStatut === DemarchesStatutsIds.EnInstruction || context.demarcheStatut === DemarchesStatutsIds.Depose, + }, + DESISTER_PAR_LE_DEMANDEUR: { + target: 'done', + cond: context => context.demarcheStatut === DemarchesStatutsIds.EnInstruction || context.demarcheStatut === DemarchesStatutsIds.Depose, + actions: assign<CaminoCommonContext, { type: 'DESISTER_PAR_LE_DEMANDEUR' }>({ + demarcheStatut: DemarchesStatutsIds.Desiste, + visibilite: 'publique', + }), + }, + CLASSER_SANS_SUITE: { + target: 'done', + cond: context => context.demarcheStatut === DemarchesStatutsIds.EnInstruction, + actions: assign<CaminoCommonContext, { type: 'CLASSER_SANS_SUITE' }>({ + demarcheStatut: DemarchesStatutsIds.ClasseSansSuite, + visibilite: 'publique', + }), + }, + }, + states: { + demandeAFaire: { + on: { + FAIRE_DEMANDE: { + target: 'depotDeLaDemandeAFaire', + actions: assign<PrmOctContext, FaireDemande>({ + paysId: (_context, event) => { + return event.paysId + }, + surface: (_context, event) => { + return event.surface + }, + }), + }, + }, + }, + depotDeLaDemandeAFaire: { + on: { + DEPOSER_DEMANDE: { + target: 'saisineDuPrefetAFaire', + actions: assign<CaminoCommonContext, { type: 'DEPOSER_DEMANDE' }>({ + demarcheStatut: DemarchesStatutsIds.Depose, + }), + }, + }, + }, + saisineDuPrefetAFaire: { + on: { + FAIRE_SAISINE_PREFET: 'recevabiliteDeLaDemandeAFaire', + }, + }, + recevabiliteDeLaDemandeAFaire: { + on: { + DEMANDER_COMPLEMENTS_POUR_RECEVABILITE: 'complementsPourRecevabiliteAFaire', + FAIRE_RECEVABILITE_DEMANDE_FAVORABLE: { + target: 'avisDeMiseEnConcurrenceAuJORFAFaire', + actions: assign<CaminoCommonContext, { type: 'FAIRE_RECEVABILITE_DEMANDE_FAVORABLE' }>({ + demarcheStatut: DemarchesStatutsIds.EnInstruction, + visibilite: 'publique', + }), + }, + FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE: 'recevabiliteDeLaDemandeAFaire', + }, + }, + complementsPourRecevabiliteAFaire: { + on: { + RECEVOIR_COMPLEMENTS_POUR_RECEVABILITE: 'recevabiliteDeLaDemandeAFaire', + FAIRE_RECEVABILITE_DEMANDE_FAVORABLE: { + target: 'avisDeMiseEnConcurrenceAuJORFAFaire', + actions: assign<CaminoCommonContext, { type: 'FAIRE_RECEVABILITE_DEMANDE_FAVORABLE' }>({ + demarcheStatut: DemarchesStatutsIds.EnInstruction, + visibilite: 'publique', + }), + }, + FAIRE_RECEVABILITE_DEMANDE_DEFAVORABLE: 'complementsPourRecevabiliteAFaire', + }, + }, + avisDeMiseEnConcurrenceAuJORFAFaire: { + always: { + cond: estExempteDeLaMiseEnConcurrence, + target: 'saisinesEtMiseEnConcurrence', + }, + on: { + RENDRE_AVIS_DE_MISE_EN_CONCURRENCE_AU_JORF: { + target: 'saisinesEtMiseEnConcurrence', + actions: assign<PrmOctContext, RendreAvisMiseEnConcurrentJORF>({ + dateAvisMiseEnConcurrentJorf: (_context, event) => { + return event.date + }, + }), + }, + }, + }, + saisinesEtMiseEnConcurrence: { + type: 'parallel', + states: { + saisinesEtAvisAFaire: { + initial: 'saisinesMachine', + states: { + saisinesMachine: { + type: 'parallel', + states: { + saisineDesCollectivitesLocalesMachine: { + initial: 'saisineDesCollectivitesLocalesAFaire', + states: { + saisineDesCollectivitesLocalesAFaire: { + always: { + cond: (context: PrmOctContext) => !isGuyane(context.paysId), + target: 'done', + }, + on: { + FAIRE_SAISINE_DES_COLLECTIVITES_LOCALES: 'avisDuMaireARendre', + }, + }, + avisDuMaireARendre: { + on: { + RENDRE_AVIS_DU_MAIRE: 'done', + }, + }, + done: { type: 'final' }, + }, + }, + saisineDesServicesMachine: { + initial: 'saisineDesServicesAFaire', + states: { + saisineDesServicesAFaire: { + on: { + FAIRE_SAISINE_DES_SERVICES: { + target: 'avisDesServicesARendre', + actions: assign<PrmOctContext, FaireSaisineDesServices>({ + dateSaisineDesServices: (_context, event) => event.date, + }), + }, + }, + }, + avisDesServicesARendre: { + type: 'parallel', + + states: { + rendreAvisDrealAFaire: { + on: { + RENDRE_AVIS_CDM: { target: '#rapportDREALAFaire', cond: peutRendreAvisCDM }, + RENDRE_RAPPORT_DREAL: { target: '#avisPrefetARendre', cond: peutRendreRapportDREAL }, + }, + }, + avisServiceAdministratifCivilLocal: { + initial: 'avisServiceAdministratifCivilLocalARendre', + states: { + avisServiceAdministratifCivilLocalARendre: { + on: { RENDRE_AVIS_SERVICE_ADMINISTRATIF_CIVIL_LOCAL: 'avisServiceAdministratifCivilLocalRendu' }, + }, + avisServiceAdministratifCivilLocalRendu: { type: 'final' }, + }, + }, + avisAutoriteMilitaire: { + initial: 'avisAutoriteMilitaireARendre', + states: { + avisAutoriteMilitaireARendre: { + on: { RENDRE_AVIS_AUTORITE_MILITAIRE: 'avisAutoriteMilitaireRendu' }, + }, + avisAutoriteMilitaireRendu: { type: 'final' }, + }, + }, + avisDesDDT: { + initial: 'avisDesDDTARendre', + states: { + avisDesDDTARendre: { + on: { + RENDRE_AVIS_DES_DTT: { target: 'avisDesDDTRendu', cond: (context: PrmOctContext) => !isGuyane(context.paysId) }, + RENDRE_AVIS_POLICE_EAU: { target: 'avisDesDDTRendu', cond: (context: PrmOctContext) => isGuyane(context.paysId) }, + }, + }, + avisDesDDTRendu: { type: 'final' }, + }, + }, + avisParcNaturelRegional: { + initial: 'avisParcNaturelRegionalARendre', + states: { + avisParcNaturelRegionalARendre: { + on: { RENDRE_AVIS_PARC_NATUREL_REGIONAL: 'avisParcNaturelRegionalRendu' }, + }, + avisParcNaturelRegionalRendu: { type: 'final' }, + }, + }, + avisParcNational: { + initial: 'avisParcNationalARendre', + states: { + avisParcNationalARendre: { + on: { RENDRE_AVIS_PARC_NATIONAL: 'avisParcNationalRendu' }, + }, + avisParcNationalRendu: { type: 'final' }, + }, + }, + avisAgenceRegionaleSanteARS: { + initial: 'avisAgenceRegionaleSanteARSARendre', + states: { + avisAgenceRegionaleSanteARSARendre: { + on: { RENDRE_AVIS_AGENCE_REGIONALE_SANTE_ARS: 'avisAgenceRegionaleSanteARSRendu' }, + }, + avisAgenceRegionaleSanteARSRendu: { type: 'final' }, + }, + }, + avisONF: { + initial: 'avisONFARendre', + states: { + avisONFARendre: { + on: { RENDRE_AVIS_ONF: 'avisONFRendu' }, + }, + avisONFRendu: { type: 'final' }, + }, + }, + avisInstitutNationalOrigineEtQualiteINAO: { + initial: 'avisInstitutNationalOrigineEtQualiteINAOARendre', + states: { + avisInstitutNationalOrigineEtQualiteINAOARendre: { + on: { RENDRE_AVIS_INSTITUT_NATIONAL_ORIGINE_ET_QUALITE_INAO: 'avisInstitutNationalOrigineEtQualiteINAORendu' }, + }, + avisInstitutNationalOrigineEtQualiteINAORendu: { type: 'final' }, + }, + }, + avisDirectionRegionaleAffairesCulturelles: { + initial: 'avisDirectionRegionaleAffairesCulturellesARendre', + states: { + avisDirectionRegionaleAffairesCulturellesARendre: { + on: { RENDRE_AVIS_DIRECTION_REGIONALE_AFFAIRES_CULTURELLES: 'avisDirectionRegionaleAffairesCulturellesRendu' }, + }, + avisDirectionRegionaleAffairesCulturellesRendu: { type: 'final' }, + }, + }, + avisDirectionRegionaleFinancesPubliques: { + initial: 'avisDirectionRegionaleFinancesPubliquesARendre', + states: { + avisDirectionRegionaleFinancesPubliquesARendre: { + on: { RENDRE_AVIS_DIRECTION_REGIONALE_FINANCES_PUBLIQUES: 'avisDirectionRegionaleFinancesPubliquesRendu' }, + }, + avisDirectionRegionaleFinancesPubliquesRendu: { type: 'final' }, + }, + }, + }, + onDone: 'avisDesServicesRendus', + }, + avisDesServicesRendus: { type: 'final' }, + }, + }, + }, + onDone: 'avisCommissionDepartementaleDesMinesEnGuyaneEtOutreMerOuRapportDeLaDREALARendre', + }, + avisCommissionDepartementaleDesMinesEnGuyaneEtOutreMerOuRapportDeLaDREALARendre: { + always: [ + { + target: 'avisCommissionDepartementaleDesMinesEnGuyaneEtOutreMerARendre', + cond: (context: PrmOctContext) => isOutreMer(context.paysId), + }, + { + target: 'rapportDREALAFaire', + cond: (context: PrmOctContext) => isMetropole(context.paysId), + }, + ], + }, + avisCommissionDepartementaleDesMinesEnGuyaneEtOutreMerARendre: { + on: { + RENDRE_AVIS_CDM: 'rapportDREALAFaire', + }, + }, + rapportDREALAFaire: { + id: 'rapportDREALAFaire', + on: { + RENDRE_RAPPORT_DREAL: 'avisPrefetARendre', + }, + }, + avisPrefetARendre: { + id: 'avisPrefetARendre', + on: { + RENDRE_AVIS_PREFET: 'done', + }, + }, + done: { type: 'final' }, + }, + }, + miseEnConcurrenceMachine: { + initial: 'participationDuPublicPasEncorePossible', + states: { + participationDuPublicPasEncorePossible: { + on: { + DEPOSER_DEMANDE_CONCURRENTE: { target: 'participationDuPublicPasEncorePossible', cond: context => !estExempteDeLaMiseEnConcurrence(context) }, + OUVRIR_PARTICIPATION_DU_PUBLIC: { target: 'clotureParticipationDuPublicAFaire', cond: peutOuvrirParticipationDuPublic }, + }, + }, + clotureParticipationDuPublicAFaire: { + on: { + CLOTURER_PARTICIPATION_DU_PUBLIC: 'done', + }, + }, + done: { type: 'final' }, + }, + }, + }, + onDone: 'rapportAdministrationCentraleAFaire', + }, + rapportAdministrationCentraleAFaire: { + on: { + FAIRE_RAPPORT_ADMINISTRATION_CENTRALE: 'saisineDuConseilGeneralChargeDesMinesAFaire', + }, + }, + saisineDuConseilGeneralChargeDesMinesAFaire: { + on: { + FAIRE_SAISINE_CONSEIL_GENERAL_CHARGE_DES_MINES: 'rapportDuConseilGeneralDesMinesAFaire', + }, + }, + rapportDuConseilGeneralDesMinesAFaire: { + on: { + FAIRE_RAPPORT_CONSEIL_GENERAL_CHARGE_DES_MINES: 'avisDuConseilGeneralDesMinesARendre', + }, + }, + avisDuConseilGeneralDesMinesARendre: { + on: { + RENDRE_AVIS_CONSEIL_GENERAL_CHARGE_DES_MINES: 'saisineDeLAutoriteSignataireAFaire', + }, + }, + saisineDeLAutoriteSignataireAFaire: { + on: { + FAIRE_SAISINE_AUTORITE_SIGNATAIRE: 'decisionDeLAdministrationARendre', + }, + }, + decisionDeLAdministrationARendre: { + on: { + RENDRE_DECISION_ADMINISTRATION_ACCEPTE: { + target: 'publicationAuJORFAFaire', + actions: assign<PrmOctContext, { type: 'RENDRE_DECISION_ADMINISTRATION_ACCEPTE' }>({ + demarcheStatut: DemarchesStatutsIds.Accepte, + }), + }, + RENDRE_DECISION_ADMINISTRATION_REJETE: { + target: 'decisionsEtNotificationsRejetAFaire', + actions: assign<PrmOctContext, { type: 'RENDRE_DECISION_ADMINISTRATION_REJETE' }>({ + demarcheStatut: DemarchesStatutsIds.Rejete, + }), + }, + }, + }, + publicationAuJORFAFaire: { + on: { + FAIRE_PUBLICATION_AU_JORF: 'notificationsAFaire', + }, + }, + notificationsAFaire: { + type: 'parallel', + states: { + notificationDuPrefetMachine: { + initial: 'notificationDuPrefetAFaire', + states: { + notificationDuPrefetAFaire: { + on: { NOTIFIER_PREFET: 'notificationDuPrefetFaite' }, + }, + notificationDuPrefetFaite: { type: 'final' }, + }, + }, + notificationDuDemandeurMachine: { + initial: 'notificationDuDemandeurAFaire', + states: { + notificationDuDemandeurAFaire: { + on: { NOTIFIER_DEMANDEUR: 'notificationDuDemandeurFaite' }, + }, + notificationDuDemandeurFaite: { type: 'final' }, + }, + }, + publicationDecisionsRecueilActesAdministratifsMachine: { + initial: 'publicationDecisionsRecueilActesAdministratifsAFaire', + states: { + publicationDecisionsRecueilActesAdministratifsAFaire: { + on: { + PUBLIER_DECISIONS_RECUEIL_ACTES_ADMINISTRATIFS: 'publicationDecisionsRecueilActesAdministratifsFaite', + }, + }, + publicationDecisionsRecueilActesAdministratifsFaite: { + type: 'final', + }, + }, + }, + publicationDansUnJournalLocalOuNationalMachine: { + initial: 'publicationDansUnJournalLocalOuNationalAFaire', + states: { + publicationDansUnJournalLocalOuNationalAFaire: { + on: { + PUBLIER_DANS_UN_JOURNAL_LOCAL_OU_NATIONAL: 'publicationDansUnJournalLocalOuNationalFaite', + }, + }, + publicationDansUnJournalLocalOuNationalFaite: { type: 'final' }, + }, + }, + notificationDesCollectivitesLocalesMachine: { + initial: 'notificationDesCollectivitesLocalesAFaire', + states: { + notificationDesCollectivitesLocalesAFaire: { + on: { + NOTIFIER_COLLECTIVITES_LOCALES: 'notificationDesCollectivitesLocalesFaite', + }, + }, + notificationDesCollectivitesLocalesFaite: { type: 'final' }, + }, + }, + }, + onDone: 'done', + }, + decisionsEtNotificationsRejetAFaire: { + type: 'parallel', + states: { + notificationsMachine: { + initial: 'notificationDuPrefetAFaire', + states: { + notificationDuPrefetAFaire: { + on: { NOTIFIER_PREFET: 'notificationDuDemandeurAFaire' }, + }, + notificationDuDemandeurAFaire: { + on: { NOTIFIER_DEMANDEUR: 'notificationDuDemandeurFaite' }, + }, + notificationDuDemandeurFaite: { type: 'final' }, + }, + }, + decisionsMachine: { + initial: 'decisionARendre', + states: { + decisionARendre: { + on: { + RENDRE_DECISION_ANNULATION_PAR_JUGE_ADMINISTRATIF: 'done', + RENDRE_DECISION_ABROGATION: 'publicationAuJORFAFaire', + RENDRE_DECISION_RETRAIT: 'publicationAuJORFAFaire', + }, + }, + publicationAuJORFAFaire: { + on: { + FAIRE_PUBLICATION_AU_JORF: 'done', + }, + }, + done: { type: 'final' }, + }, + }, + }, + onDone: 'done', + }, + done: { type: 'final' }, + }, +}) diff --git a/packages/api/src/business/rules-demarches/prm/oct.test.ts b/packages/api/src/business/rules-demarches/prm/oct.test.ts deleted file mode 100644 index 2c1384b62..000000000 --- a/packages/api/src/business/rules-demarches/prm/oct.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { toCaminoDate } from 'camino-common/src/date.js' -import { demarcheEtatsValidate } from '../_utils.test.js' -import { describe, expect, test } from 'vitest' -describe('vérifie l’arbre d’octroi d’une PRM', () => { - const octEtatsValidate = demarcheEtatsValidate('oct', 'prm', toCaminoDate('2020-01-01')) - - test('ne peut pas créer une "rpu" après une "dex" rejetée', () => { - expect( - octEtatsValidate([ - { typeId: 'mfr', date: toCaminoDate('2020-01-01') }, - { typeId: 'mdp', date: toCaminoDate('2020-01-02') }, - { typeId: 'spp', date: toCaminoDate('2020-01-03') }, - { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-04') }, - { typeId: 'anf', date: toCaminoDate('2020-01-05') }, - { typeId: 'mec', date: toCaminoDate('2020-01-06') }, - { typeId: 'ppu', date: toCaminoDate('2020-01-07') }, - { typeId: 'ppc', date: toCaminoDate('2020-01-08') }, - { typeId: 'scl', date: toCaminoDate('2020-01-07') }, - { typeId: 'ssr', date: toCaminoDate('2020-01-07') }, - { typeId: 'spo', date: toCaminoDate('2020-01-08') }, - { typeId: 'apo', date: toCaminoDate('2020-01-09') }, - { typeId: 'apd', date: toCaminoDate('2020-01-10') }, - { typeId: 'app', date: toCaminoDate('2020-01-11') }, - { typeId: 'scg', date: toCaminoDate('2020-01-12') }, - { typeId: 'rcg', date: toCaminoDate('2020-01-13') }, - { typeId: 'acg', date: toCaminoDate('2020-01-14') }, - { typeId: 'sas', date: toCaminoDate('2020-01-15') }, - { typeId: 'dex', statutId: 'rej', date: toCaminoDate('2020-01-16') }, - { typeId: 'npp', date: toCaminoDate('2020-01-17') }, - { typeId: 'mno', date: toCaminoDate('2020-01-18') }, - { typeId: 'rpu', date: toCaminoDate('2020-01-19') }, - ]) - ).toMatchInlineSnapshot(` - [ - "l’étape \\"rpu\\" n’est pas possible après \\"ssr\\", \\"scl\\", \\"spo\\", \\"apo\\", \\"npp\\", \\"mno\\"", - ] - `) - }) - - test('peut créer une "rpu" après une "dex" acceptée', () => { - expect( - octEtatsValidate([ - { typeId: 'mfr', date: toCaminoDate('2020-01-01') }, - { typeId: 'mdp', date: toCaminoDate('2020-01-02') }, - { typeId: 'spp', date: toCaminoDate('2020-01-03') }, - { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-04') }, - { typeId: 'anf', date: toCaminoDate('2020-01-05') }, - { typeId: 'mec', date: toCaminoDate('2020-01-06') }, - { typeId: 'ppu', date: toCaminoDate('2020-01-07') }, - { typeId: 'ppc', date: toCaminoDate('2020-01-08') }, - { typeId: 'scl', date: toCaminoDate('2020-01-07') }, - { typeId: 'ssr', date: toCaminoDate('2020-01-07') }, - { typeId: 'spo', date: toCaminoDate('2020-01-08') }, - { typeId: 'apo', date: toCaminoDate('2020-01-09') }, - { typeId: 'apd', date: toCaminoDate('2020-01-10') }, - { typeId: 'app', date: toCaminoDate('2020-01-11') }, - { typeId: 'scg', date: toCaminoDate('2020-01-12') }, - { typeId: 'rcg', date: toCaminoDate('2020-01-13') }, - { typeId: 'acg', date: toCaminoDate('2020-01-14') }, - { typeId: 'sas', date: toCaminoDate('2020-01-15') }, - { typeId: 'dex', statutId: 'acc', date: toCaminoDate('2020-01-16') }, - { typeId: 'dpu', statutId: 'acc', date: toCaminoDate('2020-01-17') }, - { typeId: 'npp', date: toCaminoDate('2020-01-18') }, - { typeId: 'mno', date: toCaminoDate('2020-01-19') }, - { typeId: 'rpu', date: toCaminoDate('2020-01-19') }, - ]) - ).toHaveLength(0) - }) - - test('peut créer une participation du public (ppu) directement après une recevabilité de la demande fav (mcr)', () => { - expect( - octEtatsValidate([ - { typeId: 'mfr', date: toCaminoDate('2020-01-01') }, - { typeId: 'mdp', date: toCaminoDate('2020-01-02') }, - { typeId: 'spp', date: toCaminoDate('2020-01-03') }, - { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-04') }, - { typeId: 'ppu', date: toCaminoDate('2020-01-07') }, - ]) - ).toHaveLength(0) - }) - - test('la saisine de la commission départementale des mines (spo) est optionnelle', () => { - expect( - octEtatsValidate([ - { typeId: 'mfr', date: toCaminoDate('2020-01-01') }, - { typeId: 'mdp', date: toCaminoDate('2020-01-02') }, - { typeId: 'spp', date: toCaminoDate('2020-01-03') }, - { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-04') }, - { typeId: 'anf', date: toCaminoDate('2020-01-05') }, - { typeId: 'mec', date: toCaminoDate('2020-01-06') }, - { typeId: 'ppu', date: toCaminoDate('2020-01-07') }, - { typeId: 'ppc', date: toCaminoDate('2020-01-08') }, - { typeId: 'scl', date: toCaminoDate('2020-01-07') }, - { typeId: 'ssr', date: toCaminoDate('2020-01-07') }, - { typeId: 'apd', date: toCaminoDate('2020-01-09') }, - ]) - ).toHaveLength(0) - }) -}) diff --git a/packages/api/src/business/rules-demarches/prm/oct.ts b/packages/api/src/business/rules-demarches/prm/oct.ts deleted file mode 100644 index 88ad2bfb0..000000000 --- a/packages/api/src/business/rules-demarches/prm/oct.ts +++ /dev/null @@ -1,201 +0,0 @@ -// https://cacoo.com/diagrams/mdAnl7m9V2ViBlxA/C4063 - -import { IDemarcheDefinitionRestrictions } from '../definitions.js' - -const etatsDefinitionPrmOct: IDemarcheDefinitionRestrictions = { - mfr: { - justeApres: [[]], - }, - mdp: { - justeApres: [[{ etapeTypeId: 'mfr' }]], - }, - nis: { - apres: [[{ etapeTypeId: 'mdp' }]], - justeApres: [], - final: false, - }, - mod: { - justeApres: [[]], - apres: [[{ etapeTypeId: 'mdp' }]], - avant: [[{ etapeTypeId: 'dex' }]], - final: false, - }, - mif: { - justeApres: [[]], - apres: [[{ etapeTypeId: 'mdp' }]], - avant: [[{ etapeTypeId: 'dex' }]], - final: false, - }, - rif: { - justeApres: [[{ etapeTypeId: 'mif' }]], - avant: [[{ etapeTypeId: 'sas' }]], - final: false, - }, - spp: { - justeApres: [[{ etapeTypeId: 'mdp' }]], - }, - mcr: { - separation: ['scg'], - justeApres: [[{ etapeTypeId: 'spp' }], [{ etapeTypeId: 'rco' }]], - }, - mco: { - justeApres: [[{ etapeTypeId: 'mcr', statutId: 'def' }], [{ etapeTypeId: 'rco' }]], - }, - rco: { justeApres: [[{ etapeTypeId: 'mco' }]] }, - anf: { - justeApres: [[{ etapeTypeId: 'mcr', statutId: 'fav' }]], - }, - mec: { - justeApres: [[{ etapeTypeId: 'anf' }]], - }, - scl: { - separation: ['apo', 'spo', 'apd'], - avant: [[{ etapeTypeId: 'scl' }]], - justeApres: [[{ etapeTypeId: 'mcr', statutId: 'fav' }], [{ etapeTypeId: 'anf' }], [{ etapeTypeId: 'mec' }]], - }, - ama: { - justeApres: [[{ etapeTypeId: 'scl' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - aep: { - justeApres: [[{ etapeTypeId: 'scl' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - acl: { - justeApres: [[{ etapeTypeId: 'scl' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - ssr: { - separation: ['apo', 'spo', 'apd'], - avant: [[{ etapeTypeId: 'ssr' }]], - justeApres: [[{ etapeTypeId: 'mcr', statutId: 'fav' }], [{ etapeTypeId: 'anf' }], [{ etapeTypeId: 'mec' }]], - }, - apl: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - apm: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - pnr: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - apn: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - ars: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }]], - }, - afp: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }]], - }, - aac: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }]], - }, - aof: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - aop: { - justeApres: [[{ etapeTypeId: 'ssr' }]], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - }, - spo: { - justeApres: [], - avant: [[{ etapeTypeId: 'apo' }], [{ etapeTypeId: 'spo' }], [{ etapeTypeId: 'apd' }]], - apres: [[{ etapeTypeId: 'scl' }, { etapeTypeId: 'ssr' }]], - }, - apo: { - justeApres: [], - avant: [[{ etapeTypeId: 'apo' }]], - apres: [[{ etapeTypeId: 'scl' }, { etapeTypeId: 'ssr' }]], - }, - apd: { - justeApres: [], - avant: [[{ etapeTypeId: 'apd' }]], - apres: [[{ etapeTypeId: 'scl' }, { etapeTypeId: 'ssr' }]], - }, - app: { justeApres: [[{ etapeTypeId: 'apd' }]] }, - ppu: { - justeApres: [[{ etapeTypeId: 'mcr', statutId: 'fav' }], [{ etapeTypeId: 'anf' }], [{ etapeTypeId: 'mec' }]], - avant: [[{ etapeTypeId: 'ppu' }]], - }, - ppc: { justeApres: [[{ etapeTypeId: 'ppu' }]] }, - scg: { - justeApres: [[{ etapeTypeId: 'app' }, { etapeTypeId: 'ppc' }]], - }, - rcg: { - justeApres: [[{ etapeTypeId: 'scg' }]], - }, - acg: { justeApres: [[{ etapeTypeId: 'rcg' }]] }, - sas: { justeApres: [[{ etapeTypeId: 'acg' }]] }, - dex: { justeApres: [[{ etapeTypeId: 'sas' }]] }, - dpu: { - justeApres: [[{ etapeTypeId: 'dex', statutId: 'acc' }], [{ etapeTypeId: 'abd' }], [{ etapeTypeId: 'rtd' }]], - }, - npp: { - justeApres: [[{ etapeTypeId: 'dex', statutId: 'rej' }], [{ etapeTypeId: 'dpu', statutId: 'acc' }]], - avant: [[{ etapeTypeId: 'abd' }], [{ etapeTypeId: 'rtd' }]], - }, - mno: { - apres: [[{ etapeTypeId: 'npp' }]], - avant: [[{ etapeTypeId: 'mno' }]], - justeApres: [], - }, - rpu: { - apres: [[{ etapeTypeId: 'dex', statutId: 'acc' }, { etapeTypeId: 'npp' }]], - avant: [[{ etapeTypeId: 'rpu' }]], - justeApres: [], - }, - ncl: { - apres: [[{ etapeTypeId: 'dex', statutId: 'acc' }, { etapeTypeId: 'npp' }]], - avant: [[{ etapeTypeId: 'ncl' }]], - justeApres: [], - }, - pqr: { - apres: [[{ etapeTypeId: 'dex', statutId: 'acc' }, { etapeTypeId: 'npp' }]], - avant: [[{ etapeTypeId: 'pqr' }]], - justeApres: [], - }, - dim: { - justeApres: [[{ etapeTypeId: 'mdp' }]], - avant: [[{ etapeTypeId: 'dex' }]], - }, - and: { - justeApres: [[{ etapeTypeId: 'dim' }], [{ etapeTypeId: 'dex' }]], - final: true, - }, - abd: { - justeApres: [[{ etapeTypeId: 'dex' }]], - avant: [[{ etapeTypeId: 'and' }], [{ etapeTypeId: 'rtd' }]], - }, - rtd: { - justeApres: [[{ etapeTypeId: 'dex' }]], - avant: [[{ etapeTypeId: 'and' }], [{ etapeTypeId: 'abd' }]], - }, - des: { - justeApres: [[]], - avant: [[{ etapeTypeId: 'dex' }], [{ etapeTypeId: 'css' }], [{ etapeTypeId: 'dim' }]], - final: true, - apres: [[{ etapeTypeId: 'mdp' }]], - }, - css: { - justeApres: [[]], - avant: [[{ etapeTypeId: 'dex' }], [{ etapeTypeId: 'des' }], [{ etapeTypeId: 'dim' }]], - final: true, - apres: [[{ etapeTypeId: 'mdp' }]], - }, - edm: { - justeApres: [[]], - avant: [[{ etapeTypeId: 'mfr' }]], - apres: [[{ etapeTypeId: 'mfr' }]], - }, -} - -export { etatsDefinitionPrmOct } diff --git a/packages/api/src/business/rules/__mocks__/titre-date-demande-find-demarches.ts b/packages/api/src/business/rules/__mocks__/titre-date-demande-find-demarches.ts index 37f8dee28..0430a0b05 100644 --- a/packages/api/src/business/rules/__mocks__/titre-date-demande-find-demarches.ts +++ b/packages/api/src/business/rules/__mocks__/titre-date-demande-find-demarches.ts @@ -1,5 +1,5 @@ import { ITitreDemarche } from '../../../types.js' -import { newDemarcheId } from '../../../database/models/_format/id-create.js' +import { newDemarcheId, newTitreId } from '../../../database/models/_format/id-create.js' const titreDemarcheOctEtapeMen = [ { @@ -24,7 +24,7 @@ const titreDemarcheOctEtapeMen = [ const titreDemarcheOctSansEtapes = [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, diff --git a/packages/api/src/business/rules/__mocks__/titre-demarche-date-fin-duree-find-demarches.ts b/packages/api/src/business/rules/__mocks__/titre-demarche-date-fin-duree-find-demarches.ts index f7e35b4b8..5d28a1fa6 100644 --- a/packages/api/src/business/rules/__mocks__/titre-demarche-date-fin-duree-find-demarches.ts +++ b/packages/api/src/business/rules/__mocks__/titre-demarche-date-fin-duree-find-demarches.ts @@ -1,5 +1,5 @@ import { ITitreDemarche } from '../../../types.js' -import { newDemarcheId } from '../../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' const titreDemarchesOctDateFin = [ @@ -102,13 +102,13 @@ const titreDemarchesOctDateDebut = [ const titreDemarchesOctDureeZero = [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dex', statutId: 'acc', @@ -124,13 +124,13 @@ const titreDemarchesOctDureeZero = [ const titreDemarchesOctIhiDureeZero = [ { id: newDemarcheId('h-cx-courdemanges-1988-oct01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-ihi01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-ihi01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'ihi', statutId: 'acc', @@ -566,13 +566,13 @@ const titreDemarchesRenPointsVideDex = [ const titreDemarchesRenPointsVideNiDpuNiDex = [ { id: newDemarcheId('h-cx-courdemanges-1988-ren01'), - titreId: 'h-cx-courdemanges-1988', + titreId: newTitreId('h-cx-courdemanges-1988'), typeId: 'ren', statutId: 'acc', ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1988-ren01-mfr01', + id: newEtapeId('h-cx-courdemanges-1988-ren01-mfr01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-ren01'), typeId: 'mfr', statutId: 'acc', diff --git a/packages/api/src/business/rules/titre-activites-build.test.ts b/packages/api/src/business/rules/titre-activites-build.test.ts index 6ce682c0f..9039dd2ee 100644 --- a/packages/api/src/business/rules/titre-activites-build.test.ts +++ b/packages/api/src/business/rules/titre-activites-build.test.ts @@ -4,7 +4,7 @@ import { titreActivitesBuild } from './titre-activites-build.js' import { describe, expect, test } from 'vitest' import { toCaminoDate } from 'camino-common/src/date.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { ACTIVITES_TYPES_IDS } from 'camino-common/src/static/activitesTypes.js' describe("construction des activités d'un titre", () => { const aujourdhui = toCaminoDate('2021-01-01') @@ -51,19 +51,22 @@ describe("construction des activités d'un titre", () => { const titreActivitesA = titreActivitesBuild(ACTIVITES_TYPES_IDS["rapport d'exploitation (permis et concessions M)"], [2018], aujourdhui, 'titre-id', 'pxm', [ { id: newDemarcheId('demarche-id'), - titreId: 'titreId', + titreId: newTitreId('titreId'), statutId: 'acc', typeId: 'oct', demarcheDateDebut: toCaminoDate('2018-01-01'), demarcheDateFin: toCaminoDate('2018-12-31'), etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), date: toCaminoDate('2018-01-01'), typeId: 'dpu', statutId: 'fai', substances: ['auru', 'nacl'], + surface: null, + ordre: 1, + communes: null, }, ], }, diff --git a/packages/api/src/business/rules/titre-demarche-annulation-date-fin-find.test.ts b/packages/api/src/business/rules/titre-demarche-annulation-date-fin-find.test.ts index 59491a137..4fbe6ff3d 100644 --- a/packages/api/src/business/rules/titre-demarche-annulation-date-fin-find.test.ts +++ b/packages/api/src/business/rules/titre-demarche-annulation-date-fin-find.test.ts @@ -1,14 +1,14 @@ import { ITitreEtape } from '../../types.js' import { titreDemarcheAnnulationDateFinFind } from './titre-demarche-annulation-date-fin-find.js' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test } from 'vitest' describe("date de fin d'une démarche d'annulation", () => { test.each<EtapeTypeId>(['dex', 'dux', 'dim'])("retourne la date d'une démarche d'annulation si elle n'a pas de date de fin pour une %p", typeId => { const titreDemarcheAnnulationEtapes: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-ret01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-ret01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-ret01'), typeId, statutId: 'acc', @@ -22,7 +22,7 @@ describe("date de fin d'une démarche d'annulation", () => { test.each<EtapeTypeId>(['dex', 'dux', 'dim'])("retourne la date de fin d'une démarche d'annulation si elle existe pour une %p", typeId => { const titreDemarcheAnnulationEtapesDateFin: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-ret01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-ret01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-ret01'), typeId, statutId: 'acc', @@ -38,7 +38,7 @@ describe("date de fin d'une démarche d'annulation", () => { // TODO 2022-05-10, c'est étrange, on va à l'encontre de typescript ici. Soit le typage est faux, soit le test ne sert à rien const titreDemarcheAnnulationEtapesSansDate: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-ret01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-ret01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-ret01'), typeId: 'dex', statutId: 'acc', @@ -54,7 +54,7 @@ describe("date de fin d'une démarche d'annulation", () => { test("retourne la date de fin d'une ACO si elle existe", () => { const titreDemarcheACOFaitEtapesDateFin: ITitreEtape[] = [ { - id: 'h-cx-courdemanges-1988-ret01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-ret01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-ret01'), typeId: 'aco', statutId: 'fai', 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 ae514e4bc..0f857fb47 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 @@ -2,7 +2,7 @@ import { ITitreEtape } from '../../types.js' import { titreDemarchePublicFind } from './titre-demarche-public-find.js' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test } from 'vitest' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' @@ -10,6 +10,10 @@ const etapesBuild = (etapesProps: Partial<ITitreEtape>[]) => etapesProps.map( (etapeProps, i) => ({ + id: newEtapeId(`${i}+1`), + communes: null, + surface: null, + contenu: null, ...etapeProps, ordre: i + 1, } as unknown as ITitreEtape) @@ -18,7 +22,10 @@ const etapesBuild = (etapesProps: Partial<ITitreEtape>[]) => describe("publicité d'une démarche", () => { test("une démarche sans étape n'est pas publique", () => { expect( - titreDemarchePublicFind({ id: newDemarcheId(), typeId: 'oct', etapes: [], titreId: 'titreId', demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01') }, 'arm') + titreDemarchePublicFind( + { id: newDemarcheId(), typeId: 'oct', etapes: [], titreId: newTitreId('titreId'), demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01') }, + 'arm' + ) ).toMatchObject({ publicLecture: false, entreprisesLecture: false, @@ -32,7 +39,7 @@ describe("publicité d'une démarche", () => { id: newDemarcheId(), typeId: 'oct', etapes: etapesBuild([{ typeId: 'dae' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), }, @@ -50,7 +57,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'spp' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -66,7 +73,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'spp' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -82,7 +89,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'spp' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -98,7 +105,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'mfr' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -114,7 +121,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'dex', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arg' ) @@ -130,7 +137,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'css' }, { typeId: 'mfr' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -146,7 +153,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'mcr', date: toCaminoDate('2000-01-01') }, { typeId: 'css' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'axm' ) @@ -162,7 +169,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'sca', date: toCaminoDate('2000-01-01') }, { typeId: 'css' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -178,7 +185,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'des', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -194,7 +201,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'des', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'axm' ) @@ -210,7 +217,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'mcr' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'cxf' ) @@ -226,7 +233,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'mcr', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -242,7 +249,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'mcr' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'cxf' ) @@ -258,7 +265,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'anf' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -274,7 +281,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'apu' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -290,7 +297,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'ane' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -306,7 +313,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'ppu' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -322,7 +329,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'def', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -338,7 +345,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'aca', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -354,7 +361,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'sca', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -370,7 +377,7 @@ describe("publicité d'une démarche", () => { demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2021-01-01'), etapes: etapesBuild([{ typeId: 'dim', statutId: 'acc' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -389,7 +396,7 @@ describe("publicité d'une démarche", () => { { typeId: 'anf', statutId: 'fai' }, { typeId: 'dim', statutId: 'rej' }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'cxf' ) @@ -405,7 +412,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'dex', statutId: 'rej' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -424,7 +431,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mcr', date: toCaminoDate('2000-01-01') }, { typeId: 'dex', statutId: 'rej' }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'axm' ) @@ -440,7 +447,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'dex', statutId: 'acc', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'axm' ) @@ -456,7 +463,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'dpu', statutId: 'acc' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -472,7 +479,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'dux' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -488,7 +495,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'dup' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -504,7 +511,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'rpu' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -520,7 +527,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2001-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'sco', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -536,7 +543,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'sco', date: toCaminoDate('2000-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -552,7 +559,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'and', statutId: 'fav' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -568,7 +575,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'and', statutId: 'fai' }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -584,7 +591,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2017-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -600,7 +607,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2020-01-01') }, { typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2020-01-02') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -616,7 +623,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'mcr', date: toCaminoDate('2017-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -634,7 +641,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2020-01-02') }, { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-03') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -653,7 +660,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mcr', date: toCaminoDate('2017-01-01') }, { typeId: 'eof', date: toCaminoDate('2017-01-01') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -671,7 +678,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-03') }, { typeId: 'eof', statutId: 'fai', date: toCaminoDate('2020-01-05') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -687,7 +694,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'css', date: toCaminoDate('2017-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -705,7 +712,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mcr', statutId: 'fav', date: toCaminoDate('2020-01-03') }, { typeId: 'css', statutId: 'fai', date: toCaminoDate('2020-01-05') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -722,7 +729,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'des', date: toCaminoDate('2017-01-01') }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -740,7 +747,7 @@ describe("publicité d'une démarche", () => { { typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2020-01-02') }, { typeId: 'des', statutId: 'fai', date: toCaminoDate('2020-01-05') }, ]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'arm' ) @@ -758,7 +765,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: etapeTypeId }]), - titreId: 'titreId', + titreId: newTitreId('titreId'), }, 'pcc' ) @@ -775,7 +782,7 @@ describe("publicité d'une démarche", () => { demarcheDateFin: toCaminoDate('2021-01-01'), id: newDemarcheId(), etapes: etapesBuild([{ typeId: 'ane' }]), - titreId: 'WQaZgPfDcQw9tFliMgBIDH3Z', + titreId: newTitreId('WQaZgPfDcQw9tFliMgBIDH3Z'), }, 'pcc' ) @@ -785,7 +792,14 @@ describe("publicité d'une démarche", () => { test('la demarche d’une prolongation déposée d’un PRM en survie provisoire est public ', () => { expect( titreDemarchePublicFind( - { id: newDemarcheId(), typeId: 'pr1', demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: null, etapes: etapesBuild([{ typeId: 'mfr' }, { typeId: 'mdp' }]), titreId: 'titreId' }, + { + id: newDemarcheId(), + typeId: 'pr1', + demarcheDateDebut: toCaminoDate('2020-01-01'), + demarcheDateFin: null, + etapes: etapesBuild([{ typeId: 'mfr' }, { typeId: 'mdp' }]), + titreId: newTitreId('titreId'), + }, 'prm' ) ).toMatchObject({ publicLecture: true }) @@ -794,7 +808,7 @@ describe("publicité d'une démarche", () => { test('la demarche d’une prolongation non déposée d’un PRM en survie provisoire n’est pas public ', () => { expect( titreDemarchePublicFind( - { id: newDemarcheId(), typeId: 'pr1', demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: null, etapes: etapesBuild([{ typeId: 'mfr' }]), titreId: 'titreId' }, + { id: newDemarcheId(), typeId: 'pr1', demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: null, etapes: etapesBuild([{ typeId: 'mfr' }]), titreId: newTitreId('titreId') }, 'prm' ) ).toMatchObject({ publicLecture: false }) 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 28b41b305..e9f155c30 100644 --- a/packages/api/src/business/rules/titre-demarche-public-find.ts +++ b/packages/api/src/business/rules/titre-demarche-public-find.ts @@ -3,15 +3,15 @@ import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { getDomaineId, TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { getEtapesTDE } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index.js' import { ITitreEtape, ITitreDemarche } from '../../types.js' -import { demarcheDefinitionFind, isDemarcheDefinitionMachine } from '../rules-demarches/definitions.js' -import { toMachineEtapes } from '../rules-demarches/machine-common.js' +import { demarcheDefinitionFind } from '../rules-demarches/definitions.js' +import { titreEtapeForMachineValidator, toMachineEtapes } from '../rules-demarches/machine-common.js' import { titreEtapesSortAscByOrdre } from '../utils/titre-etapes-sort.js' import { titreInSurvieProvisoire } from './titre-statut-id-find.js' const titreDemarchePublicLectureFind = ( publicLecture: boolean, demarcheTypeId: DemarcheTypeId, demarcheTypeEtapesTypes: readonly EtapeTypeId[], - titreEtape: ITitreEtape, + titreEtape: Pick<ITitreEtape, 'typeId' | 'statutId'>, demarche: Pick<ITitreDemarche, 'demarcheDateFin' | 'demarcheDateDebut'>, titreTypeId?: TitreTypeId ) => { @@ -164,12 +164,10 @@ export const titreDemarchePublicFind = (titreDemarche: Pick<ITitreDemarche, 'tit if (titreDemarche.titreId === 'WQaZgPfDcQw9tFliMgBIDH3Z') { publicLecture = false } else { - // si il existe un arbre d’instructions pour cette démarche, - // on laisse l’arbre traiter l’unicité des étapes const demarcheDefinition = demarcheDefinitionFind(titreTypeId, titreDemarche.typeId, titreDemarcheEtapes, titreDemarche.id) - if (isDemarcheDefinitionMachine(demarcheDefinition)) { - publicLecture = demarcheDefinition.machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes)).publique + if (demarcheDefinition) { + publicLecture = demarcheDefinition.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 cf0e422ad..38d01362a 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 @@ -6,13 +6,14 @@ import { newDemarcheId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test } from 'vitest' import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts.js' -const etapesBuild = (etapesProps: Partial<ITitreEtape>[]) => +import { TitreEtapeForMachine } from '../rules-demarches/machine-common.js' +const etapesBuild = (etapesProps: Partial<ITitreEtape>[]): TitreEtapeForMachine[] => etapesProps.map( (etapeProps, i) => ({ ...etapeProps, ordre: i + 1, - } as unknown as ITitreEtape) + } as unknown as TitreEtapeForMachine) ) describe("statut d'une démarche", () => { @@ -60,7 +61,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', statutId: 'acc' }]), 'prm', newDemarcheId())).toEqual('acc') + expect(titreDemarcheStatutIdFind('oct', etapesBuild([{ typeId: 'rpu', date: toCaminoDate('2010-01-01'), statutId: 'acc' }]), '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é”", () => { 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 2c1108b4b..a58d5c9da 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,8 +3,8 @@ import { DemarcheId } from 'camino-common/src/demarche.js' import { titreEtapesSortDescByOrdre } from '../utils/titre-etapes-sort.js' import { titreEtapePublicationCheck } from './titre-etape-publication-check.js' -import { demarcheDefinitionFind, isDemarcheDefinitionMachine } from '../rules-demarches/definitions.js' -import { toMachineEtapes } from '../rules-demarches/machine-common.js' +import { demarcheDefinitionFind } from '../rules-demarches/definitions.js' +import { TitreEtapeForMachine, toMachineEtapes } from '../rules-demarches/machine-common.js' import { DemarcheStatutId, DemarchesStatutsIds } from 'camino-common/src/static/demarchesStatuts.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { DemarcheTypeId, TravauxIds } from 'camino-common/src/static/demarchesTypes.js' @@ -293,12 +293,7 @@ const titreDemarcheTravauxStatutIdFind = (titreDemarcheEtapes: Pick<ITitreEtape, * @param titreTypeId - id du type de titre */ -export const titreDemarcheStatutIdFind = ( - demarcheTypeId: DemarcheTypeId, - titreDemarcheEtapes: Pick<ITitreEtape, 'typeId' | 'date' | 'ordre' | 'statutId' | 'contenu'>[], - titreTypeId: TitreTypeId, - demarcheId: DemarcheId -): DemarcheStatutId => { +export const titreDemarcheStatutIdFind = (demarcheTypeId: DemarcheTypeId, titreDemarcheEtapes: TitreEtapeForMachine[], titreTypeId: TitreTypeId, demarcheId: DemarcheId): DemarcheStatutId => { // si la démarche ne contient pas d'étapes // -> le statut est indétrminé if (!titreDemarcheEtapes.length) return DemarchesStatutsIds.Indetermine @@ -310,7 +305,7 @@ export const titreDemarcheStatutIdFind = ( const demarcheDefinition = demarcheDefinitionFind(titreTypeId, demarcheTypeId, titreDemarcheEtapes, demarcheId) - if (isDemarcheDefinitionMachine(demarcheDefinition)) { + if (demarcheDefinition) { return demarcheDefinition.machine.demarcheStatut(toMachineEtapes(titreDemarcheEtapes)).demarcheStatut } diff --git a/packages/api/src/business/rules/titre-etape-prop-find.test.ts b/packages/api/src/business/rules/titre-etape-prop-find.test.ts index 7ffd1f2b4..0cd7ffa81 100644 --- a/packages/api/src/business/rules/titre-etape-prop-find.test.ts +++ b/packages/api/src/business/rules/titre-etape-prop-find.test.ts @@ -29,15 +29,23 @@ describe("valeur d'une propriété pour une étape", () => { etapes: [ { id: 'demarche-01-etape-01', + typeId: 'aac', statutId: 'acc', - date: '1000-01-01', + date: toCaminoDate('1000-01-01'), titulaires: [], + ordre: 1, + communes: null, + surface: null, }, { id: 'demarche-01-etape-02', + typeId: 'aac', statutId: 'acc', - date: '1000-01-01', + date: toCaminoDate('1000-01-01'), titulaires: [{ id: 'fr-xxxxxxxxx' }], + ordre: 1, + communes: null, + surface: null, }, ], }, @@ -60,6 +68,11 @@ describe("valeur d'une propriété pour une étape", () => { etapes: [ { id: 'demarche-01-etape-01', + typeId: 'aac', + statutId: 'acc', + surface: 0, + ordre: 1, + communes: null, date: '1000-01-01', }, ], @@ -71,8 +84,11 @@ describe("valeur d'une propriété pour une étape", () => { { id: 'demarche-02-etape-01', date: '1000-01-01', + typeId: 'aac', statutId: 'acc', surface: 0, + ordre: 1, + communes: null, }, ], }, @@ -98,6 +114,10 @@ describe("valeur d'une propriété pour une étape", () => { date: '1000-01-01', statutId: 'acc', titulaires: null, + typeId: 'aac', + surface: 0, + ordre: 1, + communes: null, }, ], }, diff --git a/packages/api/src/business/rules/titre-phases-find.test.ts b/packages/api/src/business/rules/titre-phases-find.test.ts index 81c568554..7cd0baca4 100644 --- a/packages/api/src/business/rules/titre-phases-find.test.ts +++ b/packages/api/src/business/rules/titre-phases-find.test.ts @@ -2,7 +2,7 @@ import { ITitreDemarche } from '../../types.js' import { DemarcheId } from 'camino-common/src/demarche.js' import { titrePhasesFind, TitreDemarchePhaseFind } from './titre-phases-find.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { CaminoDate, toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test } from 'vitest' import { DEMARCHES_TYPES_IDS } from 'camino-common/src/static/demarchesTypes' @@ -20,7 +20,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreid', + titreId: newTitreId('titreid'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -59,7 +59,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -76,7 +76,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-ax-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -107,7 +107,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('m-pr-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -138,7 +138,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -179,7 +179,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -204,7 +204,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-pro01'), typeId: 'pro', statutId: 'acc', @@ -248,7 +248,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -273,7 +273,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-ren01'), typeId: 'ren', statutId: 'acc', @@ -311,7 +311,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'oct', statutId: 'acc', @@ -336,7 +336,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'titreId', + titreId: newTitreId('titreId'), id: newDemarcheId('h-cx-courdemanges-1988-ren01'), typeId: 'ren', statutId: 'acc', @@ -355,7 +355,7 @@ describe("phases d'une démarche", () => { statutId: 'acc', ordre: 1, date: toCaminoDate('2019-01-02'), - points: [{ id: 'point' }], + points: [{ id: newEtapeId('point') }], }, ], }, @@ -371,7 +371,7 @@ describe("phases d'une démarche", () => { }) test('cas sans date de fin et avec plein de css', () => { - const titreId = 'titreId' + const titreId = newTitreId('titreId') const demarcheId1 = newDemarcheId('demarcheId1') const demarcheId2 = newDemarcheId('demarcheId2') const demarcheId3 = newDemarcheId('demarcheId3') @@ -391,9 +391,9 @@ describe("phases d'une démarche", () => { typeId: 'mut', statutId: 'cls', etapes: [ - { titreDemarcheId: demarcheId1, id: '3', ordre: 1, date: toCaminoDate('2016-12-28'), duree: 1920, surface: 5.51, typeId: 'mfr', statutId: 'fai' }, - { titreDemarcheId: demarcheId1, id: '1', ordre: 2, date: toCaminoDate('2016-12-28'), typeId: 'mdp', statutId: 'fai' }, - { titreDemarcheId: demarcheId1, id: '2', ordre: 3, date: toCaminoDate('2017-04-07'), typeId: 'css', statutId: 'fai' }, + { titreDemarcheId: demarcheId1, id: newEtapeId('3'), ordre: 1, date: toCaminoDate('2016-12-28'), duree: 1920, surface: 5.51, typeId: 'mfr', statutId: 'fai' }, + { titreDemarcheId: demarcheId1, id: newEtapeId('1'), ordre: 2, date: toCaminoDate('2016-12-28'), typeId: 'mdp', statutId: 'fai' }, + { titreDemarcheId: demarcheId1, id: newEtapeId('2'), ordre: 3, date: toCaminoDate('2017-04-07'), typeId: 'css', statutId: 'fai' }, ], }, { @@ -403,9 +403,9 @@ describe("phases d'une démarche", () => { typeId: 'pro', statutId: 'cls', etapes: [ - { titreDemarcheId: demarcheId2, id: '4', ordre: 1, date: toCaminoDate('2016-12-28'), duree: 1920, surface: 5.51, typeId: 'mfr', statutId: 'fai' }, - { titreDemarcheId: demarcheId2, id: '5', ordre: 2, date: toCaminoDate('2016-12-28'), typeId: 'mdp', statutId: 'fai' }, - { titreDemarcheId: demarcheId2, id: '6', ordre: 3, date: toCaminoDate('2017-04-07'), typeId: 'css', statutId: 'fai' }, + { titreDemarcheId: demarcheId2, id: newEtapeId('4'), ordre: 1, date: toCaminoDate('2016-12-28'), duree: 1920, surface: 5.51, typeId: 'mfr', statutId: 'fai' }, + { titreDemarcheId: demarcheId2, id: newEtapeId('5'), ordre: 2, date: toCaminoDate('2016-12-28'), typeId: 'mdp', statutId: 'fai' }, + { titreDemarcheId: demarcheId2, id: newEtapeId('6'), ordre: 3, date: toCaminoDate('2017-04-07'), typeId: 'css', statutId: 'fai' }, ], }, { @@ -415,9 +415,9 @@ describe("phases d'une démarche", () => { typeId: 'dam', statutId: 'ins', etapes: [ - { id: '7', titreDemarcheId: demarcheId3, ordre: 3, date: toCaminoDate('2014-12-23'), typeId: 'wpp', statutId: 'fai' }, - { id: '8', titreDemarcheId: demarcheId3, ordre: 1, date: toCaminoDate('2013-08-01'), typeId: 'wfd', statutId: 'fai' }, - { id: '9', titreDemarcheId: demarcheId3, ordre: 2, date: toCaminoDate('2014-08-25'), typeId: 'wre', statutId: 'fav' }, + { id: newEtapeId('7'), titreDemarcheId: demarcheId3, ordre: 3, date: toCaminoDate('2014-12-23'), typeId: 'wpp', statutId: 'fai' }, + { id: newEtapeId('8'), titreDemarcheId: demarcheId3, ordre: 1, date: toCaminoDate('2013-08-01'), typeId: 'wfd', statutId: 'fai' }, + { id: newEtapeId('9'), titreDemarcheId: demarcheId3, ordre: 2, date: toCaminoDate('2014-08-25'), typeId: 'wre', statutId: 'fav' }, ], }, { @@ -427,8 +427,8 @@ describe("phases d'une démarche", () => { typeId: 'mut', statutId: 'acc', etapes: [ - { id: '10', titreDemarcheId: demarcheId4, ordre: 1, date: toCaminoDate('2002-12-24'), typeId: 'dex', statutId: 'acc' }, - { titreDemarcheId: demarcheId4, id: '11', ordre: 2, date: toCaminoDate('2003-01-08'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('10'), titreDemarcheId: demarcheId4, ordre: 1, date: toCaminoDate('2002-12-24'), typeId: 'dex', statutId: 'acc' }, + { titreDemarcheId: demarcheId4, id: newEtapeId('11'), ordre: 2, date: toCaminoDate('2003-01-08'), typeId: 'dpu', statutId: 'acc' }, ], }, { @@ -438,8 +438,8 @@ describe("phases d'une démarche", () => { typeId: 'mut', statutId: 'acc', etapes: [ - { id: '12', titreDemarcheId: demarcheId5, ordre: 1, date: toCaminoDate('2000-09-26'), typeId: 'dex', statutId: 'acc' }, - { id: '13', titreDemarcheId: demarcheId5, ordre: 2, date: toCaminoDate('2000-10-06'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('12'), titreDemarcheId: demarcheId5, ordre: 1, date: toCaminoDate('2000-09-26'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('13'), titreDemarcheId: demarcheId5, ordre: 2, date: toCaminoDate('2000-10-06'), typeId: 'dpu', statutId: 'acc' }, ], }, { @@ -449,8 +449,8 @@ describe("phases d'une démarche", () => { typeId: 'mut', statutId: 'acc', etapes: [ - { id: 'id', titreDemarcheId: demarcheId6, ordre: 1, date: toCaminoDate('1975-11-24'), typeId: 'dex', statutId: 'acc' }, - { id: '15', titreDemarcheId: demarcheId6, ordre: 2, date: toCaminoDate('1975-11-27'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('id'), titreDemarcheId: demarcheId6, ordre: 1, date: toCaminoDate('1975-11-24'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('15'), titreDemarcheId: demarcheId6, ordre: 2, date: toCaminoDate('1975-11-27'), typeId: 'dpu', statutId: 'acc' }, ], }, { @@ -461,8 +461,8 @@ describe("phases d'une démarche", () => { statutId: 'acc', etapes: [ - { id: '16', titreDemarcheId: demarcheId7, ordre: 1, date: toCaminoDate('1970-11-16'), typeId: 'dex', statutId: 'acc' }, - { id: '17', titreDemarcheId: demarcheId7, ordre: 2, date: toCaminoDate('1970-11-19'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('16'), titreDemarcheId: demarcheId7, ordre: 1, date: toCaminoDate('1970-11-16'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('17'), titreDemarcheId: demarcheId7, ordre: 2, date: toCaminoDate('1970-11-19'), typeId: 'dpu', statutId: 'acc' }, ], }, { @@ -472,8 +472,8 @@ describe("phases d'une démarche", () => { typeId: 'mut', statutId: 'acc', etapes: [ - { id: '18', titreDemarcheId: demarcheId8, ordre: 2, date: toCaminoDate('1949-08-31'), typeId: 'dpu', statutId: 'acc' }, - { id: '19', titreDemarcheId: demarcheId8, ordre: 1, date: toCaminoDate('1949-08-23'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('18'), titreDemarcheId: demarcheId8, ordre: 2, date: toCaminoDate('1949-08-31'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('19'), titreDemarcheId: demarcheId8, ordre: 1, date: toCaminoDate('1949-08-23'), typeId: 'dex', statutId: 'acc' }, ], }, { @@ -483,8 +483,8 @@ describe("phases d'une démarche", () => { typeId: 'exp', statutId: 'acc', etapes: [ - { id: '20', titreDemarcheId: demarcheId9, ordre: 1, date: toCaminoDate('1889-02-27'), typeId: 'dex', statutId: 'acc' }, - { id: '21', titreDemarcheId: demarcheId9, ordre: 2, date: toCaminoDate('1889-02-27'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('20'), titreDemarcheId: demarcheId9, ordre: 1, date: toCaminoDate('1889-02-27'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('21'), titreDemarcheId: demarcheId9, ordre: 2, date: toCaminoDate('1889-02-27'), typeId: 'dpu', statutId: 'acc' }, ], }, { @@ -494,8 +494,8 @@ describe("phases d'une démarche", () => { typeId: 'exp', statutId: 'acc', etapes: [ - { id: '22', titreDemarcheId: demarcheId10, ordre: 2, date: toCaminoDate('1879-11-14'), typeId: 'dpu', statutId: 'acc' }, - { id: '23', titreDemarcheId: demarcheId10, ordre: 1, date: toCaminoDate('1879-07-26'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('22'), titreDemarcheId: demarcheId10, ordre: 2, date: toCaminoDate('1879-11-14'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('23'), titreDemarcheId: demarcheId10, ordre: 1, date: toCaminoDate('1879-07-26'), typeId: 'dex', statutId: 'acc' }, ], }, { @@ -505,8 +505,8 @@ describe("phases d'une démarche", () => { typeId: 'oct', statutId: 'acc', etapes: [ - { id: '24', titreDemarcheId: demarcheId11, ordre: 1, date: toCaminoDate('1858-03-24'), typeId: 'dex', statutId: 'acc' }, - { id: '25', titreDemarcheId: demarcheId11, ordre: 2, date: toCaminoDate('1858-03-24'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('24'), titreDemarcheId: demarcheId11, ordre: 1, date: toCaminoDate('1858-03-24'), typeId: 'dex', statutId: 'acc' }, + { id: newEtapeId('25'), titreDemarcheId: demarcheId11, ordre: 2, date: toCaminoDate('1858-03-24'), typeId: 'dpu', statutId: 'acc' }, ], }, ] @@ -521,7 +521,7 @@ describe("phases d'une démarche", () => { }) test('cas de survie provisoire avec la prolongation en classement sans suite après la fin de l’octroi', () => { - const titreId = 'titreId' + const titreId = newTitreId('titreId') const demarcheIdOctroi = newDemarcheId('demarcheIdOctroi') const demarcheIdProlongation = newDemarcheId('demarcheIdProlongation') const demarches: ITitreDemarche[] = [ @@ -532,9 +532,9 @@ describe("phases d'une démarche", () => { typeId: 'pro', statutId: 'cls', etapes: [ - { titreDemarcheId: demarcheIdProlongation, id: '2', ordre: 3, date: toCaminoDate('2011-04-07'), typeId: 'css', statutId: 'fai' }, - { titreDemarcheId: demarcheIdProlongation, id: '1', ordre: 2, date: toCaminoDate('2008-12-28'), typeId: 'mdp', statutId: 'fai' }, - { titreDemarcheId: demarcheIdProlongation, id: '3', ordre: 1, date: toCaminoDate('2008-12-28'), duree: 60, typeId: 'mfr', statutId: 'fai' }, + { titreDemarcheId: demarcheIdProlongation, id: newEtapeId('2'), ordre: 3, date: toCaminoDate('2011-04-07'), typeId: 'css', statutId: 'fai' }, + { titreDemarcheId: demarcheIdProlongation, id: newEtapeId('1'), ordre: 2, date: toCaminoDate('2008-12-28'), typeId: 'mdp', statutId: 'fai' }, + { titreDemarcheId: demarcheIdProlongation, id: newEtapeId('3'), ordre: 1, date: toCaminoDate('2008-12-28'), duree: 60, typeId: 'mfr', statutId: 'fai' }, ], }, { @@ -544,8 +544,8 @@ describe("phases d'une démarche", () => { typeId: 'oct', statutId: 'acc', etapes: [ - { id: '24', titreDemarcheId: demarcheIdOctroi, ordre: 1, date: toCaminoDate('2000-03-24'), typeId: 'dex', statutId: 'acc', duree: 120 }, - { id: '25', titreDemarcheId: demarcheIdOctroi, ordre: 2, date: toCaminoDate('2000-03-24'), typeId: 'dpu', statutId: 'acc' }, + { id: newEtapeId('24'), titreDemarcheId: demarcheIdOctroi, ordre: 1, date: toCaminoDate('2000-03-24'), typeId: 'dex', statutId: 'acc', duree: 120 }, + { id: newEtapeId('25'), titreDemarcheId: demarcheIdOctroi, ordre: 2, date: toCaminoDate('2000-03-24'), typeId: 'dpu', statutId: 'acc' }, ], }, ] @@ -564,7 +564,7 @@ describe("phases d'une démarche", () => { }) test('un octroi rejeté ne génère pas de phase', () => { - const titreId = 'titreId' + const titreId = newTitreId('titreId') const demarcheIdOctroi = newDemarcheId('demarcheIdOctroi') const demarches: ITitreDemarche[] = [ { @@ -574,8 +574,8 @@ describe("phases d'une démarche", () => { typeId: 'oct', statutId: 'acc', etapes: [ - { id: '24', titreDemarcheId: demarcheIdOctroi, ordre: 1, date: toCaminoDate('2000-03-24'), typeId: 'dex', statutId: 'acc', duree: 120 }, - { id: '25', titreDemarcheId: demarcheIdOctroi, ordre: 2, date: toCaminoDate('2000-03-24'), typeId: 'dpu', statutId: 'rej' }, + { id: newEtapeId('24'), titreDemarcheId: demarcheIdOctroi, ordre: 1, date: toCaminoDate('2000-03-24'), typeId: 'dex', statutId: 'acc', duree: 120 }, + { id: newEtapeId('25'), titreDemarcheId: demarcheIdOctroi, ordre: 2, date: toCaminoDate('2000-03-24'), typeId: 'dpu', statutId: 'rej' }, ], }, ] @@ -588,13 +588,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -602,7 +602,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('1970-09-17'), }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -613,14 +613,14 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId2'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'mut', statutId: 'acc', ordre: 2, slug: 'm-cx-pontaubert-1970-mut01', etapes: [ { - id: 'demarcheId2EtapeId2', + id: newEtapeId('demarcheId2EtapeId2'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dpu', statutId: 'acc', @@ -630,7 +630,7 @@ describe("phases d'une démarche", () => { duree: 600, }, { - id: 'demarcheId2EtapeId1', + id: newEtapeId('demarcheId2EtapeId1'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dex', statutId: 'acc', @@ -642,13 +642,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId3'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'ren', statutId: 'acc', ordre: 3, etapes: [ { - id: 'demarcheId3etapeId1', + id: newEtapeId('demarcheId3etapeId1'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'mfr', statutId: 'fai', @@ -656,7 +656,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2019-10-22'), }, { - id: 'demarcheId3etapeId2', + id: newEtapeId('demarcheId3etapeId2'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'mdp', statutId: 'fai', @@ -664,7 +664,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2019-11-20'), }, { - id: 'demarcheId3etapeId5', + id: newEtapeId('demarcheId3etapeId5'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'dex', statutId: 'acc', @@ -672,7 +672,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2022-05-09'), }, { - id: 'demarcheId3etapeId6', + id: newEtapeId('demarcheId3etapeId6'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'dpu', statutId: 'acc', @@ -680,7 +680,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2022-05-09'), }, { - id: 'demarcheId3etapeId3', + id: newEtapeId('demarcheId3etapeId3'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'apd', statutId: 'fav', @@ -688,7 +688,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2020-05-11'), }, { - id: 'demarcheId3etapeId4', + id: newEtapeId('demarcheId3etapeId4'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'app', statutId: 'fav', @@ -718,13 +718,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -732,7 +732,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('1970-09-17'), }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -743,13 +743,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId2'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'mut', statutId: 'acc', ordre: 2, etapes: [ { - id: 'demarcheId2EtapeId2', + id: newEtapeId('demarcheId2EtapeId2'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dpu', statutId: 'acc', @@ -759,7 +759,7 @@ describe("phases d'une démarche", () => { duree: 600, }, { - id: 'demarcheId2EtapeId1', + id: newEtapeId('demarcheId2EtapeId1'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dex', statutId: 'acc', @@ -771,13 +771,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId3'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'ren', statutId: 'acc', ordre: 3, etapes: [ { - id: 'demarcheId3etapeId1', + id: newEtapeId('demarcheId3etapeId1'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'mfr', statutId: 'fai', @@ -785,7 +785,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2019-10-22'), }, { - id: 'demarcheId3etapeId2', + id: newEtapeId('demarcheId3etapeId2'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'mdp', statutId: 'fai', @@ -793,7 +793,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2019-11-20'), }, { - id: 'demarcheId3etapeId3', + id: newEtapeId('demarcheId3etapeId3'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'apd', statutId: 'fav', @@ -801,7 +801,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2020-05-11'), }, { - id: 'demarcheId3etapeId5', + id: newEtapeId('demarcheId3etapeId5'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'dim', statutId: 'acc', @@ -809,7 +809,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2022-05-09'), }, { - id: 'demarcheId3etapeId4', + id: newEtapeId('demarcheId3etapeId4'), titreDemarcheId: newDemarcheId('demarcheId3'), typeId: 'app', statutId: 'fav', @@ -839,13 +839,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -853,7 +853,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('1968-01-24'), }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -864,13 +864,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId2'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: DEMARCHES_TYPES_IDS.ExtensionDePerimetre, statutId: 'acc', ordre: 2, etapes: [ { - id: 'demarcheId2EtapeId2', + id: newEtapeId('demarcheId2EtapeId2'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dpu', statutId: 'acc', @@ -879,7 +879,7 @@ describe("phases d'une démarche", () => { dateFin: toCaminoDate('2031-09-13'), }, { - id: 'demarcheId2EtapeId1', + id: newEtapeId('demarcheId2EtapeId1'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'dex', statutId: 'acc', @@ -908,13 +908,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -923,7 +923,7 @@ describe("phases d'une démarche", () => { duree: 60, }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -934,13 +934,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId2'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: DEMARCHES_TYPES_IDS.Prolongation1, statutId: DemarchesStatutsIds.EnConstruction, ordre: 2, etapes: [ { - id: 'demarcheId2EtapeId2', + id: newEtapeId('demarcheId2EtapeId2'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'mfr', statutId: 'fai', @@ -970,13 +970,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -985,7 +985,7 @@ describe("phases d'une démarche", () => { duree: 60, }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -996,13 +996,13 @@ describe("phases d'une démarche", () => { }, { id: newDemarcheId('demarcheId2'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: DEMARCHES_TYPES_IDS.Prolongation1, statutId: DemarchesStatutsIds.EnConstruction, ordre: 2, etapes: [ { - id: 'demarcheId2EtapeId2', + id: newEtapeId('demarcheId2EtapeId2'), titreDemarcheId: newDemarcheId('demarcheId2'), typeId: 'mfr', statutId: ETAPES_STATUTS.EN_CONSTRUCTION, @@ -1028,13 +1028,13 @@ describe("phases d'une démarche", () => { const demarches: ITitreDemarche[] = [ { id: newDemarcheId('demarcheId1'), - titreId: 'titreId', + titreId: newTitreId('titreId'), typeId: 'oct', statutId: 'acc', ordre: 1, etapes: [ { - id: 'demarcheId1etapeId3', + id: newEtapeId('demarcheId1etapeId3'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'rej', @@ -1042,7 +1042,7 @@ describe("phases d'une démarche", () => { date: toCaminoDate('2018-11-11'), }, { - id: 'demarcheId1etapeId2', + id: newEtapeId('demarcheId1etapeId2'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dpu', statutId: 'acc', @@ -1051,7 +1051,7 @@ describe("phases d'une démarche", () => { duree: 60, }, { - id: 'demarcheId1etapeId1', + id: newEtapeId('demarcheId1etapeId1'), titreDemarcheId: newDemarcheId('demarcheId1'), typeId: 'dex', statutId: 'acc', @@ -1072,7 +1072,7 @@ describe("phases d'une démarche", () => { }) test("2 démarches avec des phases en cours ne génère qu'une seule phase en modification en instance", () => { - const titreId = 'titreId' + const titreId = newTitreId('titreId') const demarcheId1 = newDemarcheId('demarcheId1') const demarcheId2 = newDemarcheId('demarcheId2') const demarcheId3 = newDemarcheId('demarcheId3') @@ -1374,7 +1374,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'nJ10z3Z74xi9OTh4oG6YXQBo', + titreId: newTitreId('nJ10z3Z74xi9OTh4oG6YXQBo'), statutId: 'acc', ordre: 1, typeId: 'oct', @@ -1405,7 +1405,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'EW9cDeM6PfXS4TPznkjsNZVO', + titreId: newTitreId('EW9cDeM6PfXS4TPznkjsNZVO'), statutId: 'rej', ordre: 2, typeId: 'pr1', @@ -1437,7 +1437,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'o3RzmZvqZcKMNmaE3nwXdvkE', + titreId: newTitreId('o3RzmZvqZcKMNmaE3nwXdvkE'), statutId: 'acc', ordre: 1, typeId: 'oct', @@ -1468,7 +1468,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'Mef8FKNlX0WtohaO9wGOMQZs', + titreId: newTitreId('Mef8FKNlX0WtohaO9wGOMQZs'), statutId: 'des', ordre: 2, typeId: 'pr1', @@ -1503,7 +1503,7 @@ describe("phases d'une démarche", () => { titrePhasesFind( [ { - titreId: 'nJ10z3Z74xi9OTh4oG6YXQBo', + titreId: newTitreId('nJ10z3Z74xi9OTh4oG6YXQBo'), statutId: 'acc', ordre: 1, typeId: 'oct', @@ -1534,7 +1534,7 @@ describe("phases d'une démarche", () => { ], }, { - titreId: 'EW9cDeM6PfXS4TPznkjsNZVO', + titreId: newTitreId('EW9cDeM6PfXS4TPznkjsNZVO'), statutId: 'rej', ordre: 2, typeId: 'pr1', diff --git a/packages/api/src/business/rules/titre-prop-etape-find.test.ts b/packages/api/src/business/rules/titre-prop-etape-find.test.ts index 5b4cd9cb8..4952c614c 100644 --- a/packages/api/src/business/rules/titre-prop-etape-find.test.ts +++ b/packages/api/src/business/rules/titre-prop-etape-find.test.ts @@ -1,7 +1,7 @@ import { ITitreDemarche, IPropId, ITitreEtape, ITitrePoint, ICommune } from '../../types.js' import { titreContenuTitreEtapeFind, titrePropTitreEtapeFind } from './titre-prop-etape-find.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, expect, test } from 'vitest' import { TitresStatutIds } from 'camino-common/src/static/titresStatuts.js' @@ -23,7 +23,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1989-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1989-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1989-oct01'), typeId: 'dpu', statutId: 'acc', @@ -32,7 +32,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [1, 2, 3] as unknown as ITitrePoint[], }, { - id: 'h-cx-courdemanges-1989-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1989-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1989-oct01'), typeId: 'dex', statutId: 'acc', @@ -48,7 +48,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1989-mut01-dpu01', + id: newEtapeId('h-cx-courdemanges-1989-mut01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1989-mut01'), typeId: 'dpu', statutId: 'acc', @@ -56,7 +56,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, }, { - id: 'h-cx-courdemanges-1989-mut01-dex01', + id: newEtapeId('h-cx-courdemanges-1989-mut01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1989-mut01'), typeId: 'dex', date: toCaminoDate('1989-02-02'), @@ -83,7 +83,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1988-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dpu', statutId: 'acc', @@ -92,7 +92,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [], }, { - id: 'h-cx-courdemanges-1988-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1988-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1988-oct01'), typeId: 'dex', date: toCaminoDate('1989-01-01'), @@ -119,7 +119,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1986-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1986-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-oct01'), typeId: 'dpu', date: toCaminoDate('1986-01-02'), @@ -127,7 +127,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, }, { - id: 'h-cx-courdemanges-1986-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1986-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-oct01'), typeId: 'dex', statutId: 'acc', @@ -143,7 +143,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1986-mut01-dpu01', + id: newEtapeId('h-cx-courdemanges-1986-mut01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-mut01'), typeId: 'dpu', statutId: 'acc', @@ -152,7 +152,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [1, 2, 3] as unknown as ITitrePoint[], }, { - id: 'h-cx-courdemanges-1986-mut01-dex01', + id: newEtapeId('h-cx-courdemanges-1986-mut01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-mut01'), typeId: 'dex', statutId: 'acc', @@ -179,7 +179,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1986-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1986-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-oct01'), typeId: 'dpu', statutId: 'acc', @@ -187,7 +187,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { date: toCaminoDate('1986-01-02'), }, { - id: 'h-cx-courdemanges-1986-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1986-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-oct01'), typeId: 'dex', statutId: 'acc', @@ -203,7 +203,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1986-mut01-dpu01', + id: newEtapeId('h-cx-courdemanges-1986-mut01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-mut01'), typeId: 'dpu', statutId: 'acc', @@ -212,7 +212,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { date: toCaminoDate('1986-02-02'), }, { - id: 'h-cx-courdemanges-1986-mut01-dex01', + id: newEtapeId('h-cx-courdemanges-1986-mut01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1986-mut01'), typeId: 'dex', statutId: 'acc', @@ -240,7 +240,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1985-mut01-dpu01', + id: newEtapeId('h-cx-courdemanges-1985-mut01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1985-mut01'), typeId: 'dpu', statutId: 'acc', @@ -249,7 +249,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [1, 2, 3] as unknown as ITitrePoint[], }, { - id: 'h-cx-courdemanges-1985-mut01-dex01', + id: newEtapeId('h-cx-courdemanges-1985-mut01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1985-mut01'), typeId: 'dex', date: toCaminoDate('1985-01-01'), @@ -264,7 +264,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'ins', etapes: [ { - id: 'h-cx-courdemanges-1985-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1985-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1985-oct01'), typeId: 'dpu', statutId: 'acc', @@ -273,7 +273,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [1, 2, 3] as unknown as ITitrePoint[], }, { - id: 'h-cx-courdemanges-1985-oct01-dex01', + id: newEtapeId('h-cx-courdemanges-1985-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1985-oct01'), typeId: 'dex', statutId: 'acc', @@ -300,7 +300,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1984-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1984-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1984-oct01'), typeId: 'dpu', statutId: 'rej', @@ -309,7 +309,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { points: [1, 2, 3] as unknown as undefined, }, { - id: newDemarcheId('h-cx-courdemanges-1984-oct01-dex01'), + id: newEtapeId('h-cx-courdemanges-1984-oct01-dex01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1984-oct01'), date: toCaminoDate('1984-01-01'), typeId: 'dex', @@ -336,7 +336,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1983-oct01-mfr01', + id: newEtapeId('h-cx-courdemanges-1983-oct01-mfr01'), date: toCaminoDate('1983-01-01'), titreDemarcheId: newDemarcheId(newDemarcheId('h-cx-courdemanges-1983-oct01')), typeId: 'mfr', @@ -344,7 +344,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 1, points: [ { - id: 'id', + id: newEtapeId('id'), titreEtapeId: 'h-cx-courdemanges-1983-oct01-mfr01', groupe: 1, contour: 1, @@ -374,7 +374,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'ins', etapes: [ { - id: 'h-cx-courdemanges-1981-pro01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-pro01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-pro01'), typeId: 'dpu', statutId: 'acc', @@ -390,7 +390,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-oct01'), typeId: 'dpu', date: toCaminoDate('1981-01-01'), @@ -417,7 +417,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'ins', etapes: [ { - id: 'h-cx-courdemanges-1981-pro01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-pro01-dpu01'), titreDemarcheId: newDemarcheId(newDemarcheId('h-cx-courdemanges-1981-pro01')), date: '1981-01-01', typeId: ETAPES_TYPES.publicationDeDecisionAuJORF, @@ -432,7 +432,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-oct01'), typeId: 'dpu', date: toCaminoDate('1981-01-01'), @@ -459,7 +459,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'ins', etapes: [ { - id: 'h-cx-courdemanges-1981-mut01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-mut01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-mut01'), typeId: 'dpu', statutId: 'acc', @@ -475,7 +475,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-oct01'), typeId: 'dpu', date: toCaminoDate('1981-01-01'), @@ -505,7 +505,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1981-pro01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-pro01-dpu01'), date: toCaminoDate('1981-01-01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-pro01'), typeId: 'aac', @@ -525,7 +525,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 1, etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-oct01'), typeId: 'dpu', statutId: 'acc', @@ -558,7 +558,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 2, etapes: [ { - id: 'h-cx-courdemanges-1981-pro01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-pro01-dpu01'), date: toCaminoDate('1981-01-01'), titreDemarcheId: newDemarcheId(newDemarcheId('h-cx-courdemanges-1981-pro01')), typeId: 'aac', @@ -579,7 +579,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { ordre: 1, etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId(newDemarcheId('h-cx-courdemanges-1981-oct01')), typeId: 'dpu', statutId: 'acc', @@ -611,7 +611,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1982-oct01-mfr01', + id: newEtapeId('h-cx-courdemanges-1982-oct01-mfr01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1982-oct01'), typeId: 'mfr', statutId: 'aco', @@ -645,7 +645,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { demarcheDateFin: toCaminoDate('2018-12-31'), etapes: [ { - id: 'h-cx-courdemanges-1982-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1982-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1982-oct01'), typeId: 'dpu', statutId: 'acc', @@ -675,7 +675,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1982-amo01-dpu01', + id: newEtapeId('h-cx-courdemanges-1982-amo01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1982-amo01'), typeId: 'dpu', statutId: 'acc', @@ -712,7 +712,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-amo01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-amo01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-amo01'), typeId: 'dpu', statutId: 'acc', @@ -728,7 +728,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-pro01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-pro01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-pro01'), typeId: 'dpu', date: toCaminoDate('1981-01-01'), @@ -743,7 +743,7 @@ describe("id de l'étape d'une propriété valide (dé-normalise)", () => { statutId: 'acc', etapes: [ { - id: 'h-cx-courdemanges-1981-oct01-dpu01', + id: newEtapeId('h-cx-courdemanges-1981-oct01-dpu01'), titreDemarcheId: newDemarcheId('h-cx-courdemanges-1981-oct01'), date: toCaminoDate('1981-01-01'), typeId: 'dpu', @@ -764,7 +764,7 @@ describe("id de l'étape qui a un contenu", () => { const etape1 = titreContenuTitreEtapeFind( currentDate, { sectionId: 'arm', elementId: 'mecanisee' }, - [{ id: newDemarcheId('demarche-id'), etapes: [{ id: 'etape-id' }] }] as ITitreDemarche[], + [{ id: newDemarcheId('demarche-id'), etapes: [{ id: newEtapeId('etape-id') }] }] as ITitreDemarche[], 'val' ) @@ -775,7 +775,7 @@ describe("id de l'étape qui a un contenu", () => { { id: newDemarcheId('demarche-id'), statutId: 'acc', - etapes: [{ id: 'etape-id', statutId: 'fai' }], + etapes: [{ id: newEtapeId('etape-id'), statutId: 'fai' }], }, ] as ITitreDemarche[], 'val' @@ -789,13 +789,13 @@ describe("id de l'étape qui a un contenu", () => { [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'pro', demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2020-01-02'), etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'dpu', date: toCaminoDate('2020-01-01'), @@ -820,11 +820,11 @@ describe("id de l'étape qui a un contenu", () => { [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'dpu', date: toCaminoDate('2020-01-03'), @@ -835,11 +835,11 @@ describe("id de l'étape qui a un contenu", () => { }, { id: newDemarcheId('demarche-id-2'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'pro', etapes: [ { - id: 'etape-id-2', + id: newEtapeId('etape-id-2'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'dex', date: toCaminoDate('2020-01-01'), @@ -857,11 +857,11 @@ describe("id de l'étape qui a un contenu", () => { [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'pro', etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'dpu', date: toCaminoDate('2020-01-01'), @@ -885,11 +885,11 @@ describe("id de l'étape qui a un contenu", () => { [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'mfr', date: toCaminoDate('2020-01-03'), @@ -911,11 +911,11 @@ describe("id de l'étape qui a un contenu", () => { [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', etapes: [ { - id: 'etape-id', + id: newEtapeId('etape-id'), titreDemarcheId: newDemarcheId('demarche-id'), typeId: 'mfr', date: toCaminoDate('2020-01-03'), diff --git a/packages/api/src/business/titre-etape-update.ts b/packages/api/src/business/titre-etape-update.ts index 1276c507f..331238c40 100644 --- a/packages/api/src/business/titre-etape-update.ts +++ b/packages/api/src/business/titre-etape-update.ts @@ -1,5 +1,6 @@ import { titreDemarcheGet } from '../database/queries/titres-demarches.js' import type { DemarcheId } from 'camino-common/src/demarche.js' +import type { EtapeId } from 'camino-common/src/etape.js' import { titresActivitesUpdate } from './processes/titres-activites-update.js' import { titresDemarchesPublicUpdate } from './processes/titres-demarches-public-update.js' @@ -24,7 +25,7 @@ import { titresEtapesDepotCreate } from './processes/titres-demarches-depot-crea import type { UserNotNull } from 'camino-common/src/roles.js' import type { Pool } from 'pg' -const titreEtapeUpdate = async (pool: Pool, titreEtapeId: string | null, titreDemarcheId: DemarcheId, user: UserNotNull) => { +const titreEtapeUpdate = async (pool: Pool, titreEtapeId: EtapeId | null, titreDemarcheId: DemarcheId, user: UserNotNull) => { try { console.info() console.info('- - -') @@ -42,13 +43,13 @@ const titreEtapeUpdate = async (pool: Pool, titreEtapeId: string | null, titreDe throw new Error(`la démarche ${titreDemarche} n'existe pas`) } - const titresEtapesOrdreUpdated = await titresEtapesOrdreUpdate(user, titreDemarcheId) + const titresEtapesOrdreUpdated = await titresEtapesOrdreUpdate(pool, user, titreDemarcheId) const titresEtapesHeritagePropsUpdated = await titresEtapesHeritagePropsUpdate(user, [titreDemarcheId]) - const titresEtapesHeritageContenuUpdated = await titresEtapesHeritageContenuUpdate(user, titreDemarcheId) + const titresEtapesHeritageContenuUpdated = await titresEtapesHeritageContenuUpdate(pool, user, titreDemarcheId) const titreId = titreDemarche.titreId - const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(titreId) + const titresDemarchesStatutUpdated = await titresDemarchesStatutIdUpdate(pool, titreId) const titresDemarchesOrdreUpdated = await titresDemarchesOrdreUpdate([titreId]) const [titresDemarchesDatesUpdated = []] = await titresDemarchesDatesUpdate(pool, [titreId]) const titresDemarchesPublicUpdated = await titresDemarchesPublicUpdate([titreId]) diff --git a/packages/api/src/business/utils/props-titre-etapes-ids-find.test.ts b/packages/api/src/business/utils/props-titre-etapes-ids-find.test.ts index 0c39e2138..c968c8b5b 100644 --- a/packages/api/src/business/utils/props-titre-etapes-ids-find.test.ts +++ b/packages/api/src/business/utils/props-titre-etapes-ids-find.test.ts @@ -1,5 +1,5 @@ import { contenusTitreEtapesIdsFind } from './props-titre-etapes-ids-find.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newTitreId } from '../../database/models/_format/id-create.js' import { toCaminoDate } from 'camino-common/src/date.js' import { describe, test, expect } from 'vitest' @@ -12,7 +12,7 @@ describe("liste des propriétés et les étapes qui en sont à l'origine", () => [ { id: newDemarcheId('demarche-id'), - titreId: 'titre-id', + titreId: newTitreId('titre-id'), typeId: 'oct', statutId: 'acc', etapes: [], 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 cfec1515a..3687e31e3 100644 --- a/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts +++ b/packages/api/src/business/utils/titre-demarches-etapes-rebuild.ts @@ -3,6 +3,7 @@ import { titreDemarcheStatutIdFind } from '../rules/titre-demarche-statut-id-fin import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { titrePhasesFind } from '../rules/titre-phases-find.js' import { CaminoDate } from 'camino-common/src/date.js' +import { titreEtapeForMachineValidator } from '../rules-demarches/machine-common.js' /** * Filtre les étapes antérieures à une date @@ -31,7 +32,8 @@ export const titreDemarchesEtapesRebuild = (date: CaminoDate, titreDemarches: IT titreDemarche.etapes = titreEtapesFiltered - titreDemarche.statutId = titreDemarcheStatutIdFind(titreDemarche.typeId, titreDemarche.etapes, titreTypeId, titreDemarche.id) + const etapes = titreDemarche.etapes.map(etape => titreEtapeForMachineValidator.parse(etape)) + titreDemarche.statutId = titreDemarcheStatutIdFind(titreDemarche.typeId, etapes, titreTypeId, titreDemarche.id) acc.push(titreDemarche) } diff --git a/packages/api/src/business/utils/titre-etape-heritage-contenu-find.ts b/packages/api/src/business/utils/titre-etape-heritage-contenu-find.ts index 6079e6e7e..a188ce3d9 100644 --- a/packages/api/src/business/utils/titre-etape-heritage-contenu-find.ts +++ b/packages/api/src/business/utils/titre-etape-heritage-contenu-find.ts @@ -3,7 +3,12 @@ import { IContenuValeur, Index, ITitreEtape } from '../../types.js' import { DeepReadonly } from 'camino-common/src/typescript-tools.js' import { Section } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' -export const heritageContenuFind = (sectionId: string, elementId: string, titreEtape: Pick<ITitreEtape, 'contenu' | 'heritageContenu'>, prevTitreEtape?: ITitreEtape | null) => { +export const heritageContenuFind = ( + sectionId: string, + elementId: string, + titreEtape: Pick<ITitreEtape, 'contenu' | 'heritageContenu'>, + prevTitreEtape?: Pick<ITitreEtape, 'id' | 'contenu' | 'heritageContenu'> | null +) => { let hasChanged = false let value = (titreEtape.contenu && titreEtape.contenu[sectionId] && titreEtape.contenu[sectionId][elementId]) as IContenuValeur @@ -45,7 +50,7 @@ export const heritageContenuFind = (sectionId: string, elementId: string, titreE } export const titreEtapeHeritageContenuFind = ( - titreEtapes: ITitreEtape[], + titreEtapes: Omit<ITitreEtape, 'titreDemarcheId'>[], titreEtape: Pick<ITitreEtape, 'id' | 'contenu' | 'heritageContenu'>, etapeSectionsDictionary: Index<DeepReadonly<Section[]>> ) => { diff --git a/packages/api/src/business/utils/titre-etape-heritage-props-find.test.ts b/packages/api/src/business/utils/titre-etape-heritage-props-find.test.ts index 45d323c11..f5ec08b6c 100644 --- a/packages/api/src/business/utils/titre-etape-heritage-props-find.test.ts +++ b/packages/api/src/business/utils/titre-etape-heritage-props-find.test.ts @@ -4,6 +4,7 @@ import { titreEtapeHeritagePropsFind, titreEtapePropsIds } from './titre-etape-h import { objectClone } from '../../tools/index.js' import { describe, test, expect } from 'vitest' +import { newEtapeId } from '../../database/models/_format/id-create.js' /* eslint-disable @typescript-eslint/ban-ts-comment */ @@ -44,7 +45,7 @@ describe('retourne l’étape en fonction de son héritage', () => { titreEtape.heritageProps![propId].actif = true // @ts-ignore titreEtape[propId] = etapeValeur - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') const titreEtapeNew = objectClone(titreEtape) as ITitreEtape // @ts-ignore @@ -70,7 +71,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.titulaires.actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) expect(titreEtapeHeritagePropsFind(titreEtape, titreEtapePrecedente)).toEqual({ @@ -93,7 +94,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps![propId].actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) // @ts-ignore titreEtape[propId] = [{ id: 'haha' }, { id: 'toto' }] @@ -121,7 +122,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.substances.actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) titreEtape.substances = ['nacl', 'arge'] @@ -148,7 +149,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.titulaires.actif = true titreEtape.titulaires = [{ id: 'haha' }, { id: 'toto' }] as IEntreprise[] - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) const titreEtapeNew = objectClone(titreEtape) as ITitreEtape @@ -172,7 +173,7 @@ describe('retourne l’étape en fonction de son héritage', () => { } as ITitreEtape const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) const titreEtapeNew = objectClone(titreEtape) as ITitreEtape @@ -197,7 +198,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.points.actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) expect(titreEtapeHeritagePropsFind(titreEtape, titreEtapePrecedente)).toEqual({ @@ -222,7 +223,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.points.actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtape.points = [ { id: '3', coordonnees: { x: 1, y: 2 } }, { id: '4', coordonnees: { x: 2, y: 4 } }, @@ -253,7 +254,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.surface.actif = true titreEtape.incertitudes = {} - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) const newTitreEtape = objectClone(titreEtape) as ITitreEtape @@ -278,7 +279,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.surface.actif = true titreEtape.incertitudes = { surface: true } - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) const newTitreEtape = objectClone(titreEtape) as ITitreEtape @@ -304,7 +305,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) as ITitreEtape titreEtape.heritageProps!.surface.actif = true titreEtape.incertitudes = null - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) const newTitreEtape = objectClone(titreEtape) as ITitreEtape @@ -328,7 +329,7 @@ describe('retourne l’étape en fonction de son héritage', () => { const titreEtape = objectClone(titreEtapePrecedente) titreEtape.heritageProps!.surface.actif = true - titreEtape.id = 'titreEtapeId' + titreEtape.id = newEtapeId('titreEtapeId') titreEtape.incertitudes = { date: true } titreEtapePropsIds.forEach(prop => (titreEtape.heritageProps![prop].etapeId = titreEtapePrecedente.id)) diff --git a/packages/api/src/business/utils/titre-etapes-sort.test.ts b/packages/api/src/business/utils/titre-etapes-sort.test.ts index 8862ef586..2341121f6 100644 --- a/packages/api/src/business/utils/titre-etapes-sort.test.ts +++ b/packages/api/src/business/utils/titre-etapes-sort.test.ts @@ -1,22 +1,21 @@ -import { ITitreEtape } from '../../types.js' - import { titreEtapesSortAscByDate, titreEtapesSortAscByOrdre, titreEtapesSortDescByOrdre } from './titre-etapes-sort.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId } from '../../database/models/_format/id-create.js' import { vi, describe, test, expect } from 'vitest' import { toCaminoDate } from 'camino-common/src/date.js' import { DEMARCHES_TYPES_IDS } from 'camino-common/src/static/demarchesTypes.js' import { TITRES_TYPES_IDS } from 'camino-common/src/static/titresTypes.js' import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes.js' +import { TitreEtapeForMachine } from '../rules-demarches/machine-common.js' const titreEtapesSortedDescResult = [ { typeId: 'dpu', ordre: 2, date: '1988-03-11' }, { typeId: 'dex', ordre: 1, date: '1988-03-06' }, -] as ITitreEtape[] +] as TitreEtapeForMachine[] const titreEtapesSortedAsc = [ { typeId: 'dex', ordre: 1, date: '1988-03-06' }, { typeId: 'dpu', ordre: 2, date: '1988-03-11' }, -] as ITitreEtape[] +] as TitreEtapeForMachine[] const titreEtapesSortedDesc = titreEtapesSortedAsc.slice().reverse() @@ -49,22 +48,26 @@ describe('trie les étapes', () => { }) test('des étapes avec les mêmes dates organisées par ordre décroissant sont triées par ordre croissant', () => { - const titreEtapesMemesDatesOrdreDesc: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] = [ + const titreEtapesMemesDatesOrdreDesc: TitreEtapeForMachine[] = [ { - id: '1', + id: newEtapeId('1'), typeId: 'dex', ordre: 2, date: toCaminoDate('1988-03-06'), - titreDemarcheId: newDemarcheId(), statutId: 'fai', + communes: [], + contenu: {}, + surface: null, }, { - id: '2', + id: newEtapeId('2'), typeId: 'dpu', ordre: 1, date: toCaminoDate('1988-03-06'), - titreDemarcheId: newDemarcheId(), statutId: 'fav', + communes: [], + contenu: {}, + surface: null, }, ] @@ -75,30 +78,36 @@ describe('trie les étapes', () => { test('des étapes avec les mêmes dates sont triées par ordre de type croissant', () => { const titreDemarcheId = newDemarcheId('1') - const titreEtapesMemesDatesOrdreEtapesTypesDesc: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] = [ + const titreEtapesMemesDatesOrdreEtapesTypesDesc: TitreEtapeForMachine[] = [ { - id: '1', + id: newEtapeId('1'), typeId: ETAPES_TYPES.initiationDeLaDemarcheDeRetrait, ordre: 2, date: toCaminoDate('1988-03-06'), - titreDemarcheId, statutId: 'fav', + communes: [], + contenu: {}, + surface: null, }, { - id: '2', + id: newEtapeId('2'), typeId: ETAPES_TYPES.classementSansSuite, ordre: 2, date: toCaminoDate('1988-03-06'), - titreDemarcheId, statutId: 'fav', + communes: [], + contenu: {}, + surface: null, }, { - id: '3', + id: newEtapeId('3'), typeId: ETAPES_TYPES.decisionAdministrative, ordre: 2, date: toCaminoDate('1988-03-06'), - titreDemarcheId, statutId: 'fav', + communes: [], + contenu: {}, + surface: null, }, ] expect(titreEtapesSortAscByDate(titreEtapesMemesDatesOrdreEtapesTypesDesc, titreDemarcheId, DEMARCHES_TYPES_IDS.Retrait, TITRES_TYPES_IDS.AUTORISATION_D_EXPLOITATION_METAUX)).toMatchObject([ @@ -107,47 +116,53 @@ describe('trie les étapes', () => { ordre: 2, date: '1988-03-06', statutId: 'fav', - titreDemarcheId, }, { typeId: ETAPES_TYPES.decisionAdministrative, ordre: 2, date: '1988-03-06', statutId: 'fav', - titreDemarcheId, }, { typeId: ETAPES_TYPES.classementSansSuite, ordre: 2, date: '1988-03-06', statutId: 'fav', - titreDemarcheId, }, ]) }) test('tri selon l’arbre si les étapes ont la même date', () => { - const etapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] = [ + const etapes: TitreEtapeForMachine[] = [ { - id: '1', + id: newEtapeId('1'), typeId: 'pfd', + ordre: 1, date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + communes: [], + contenu: {}, + surface: null, }, { - id: '2', + id: newEtapeId('2'), typeId: 'mfr', + ordre: 2, date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + communes: [], + contenu: {}, + surface: null, }, { - id: '3', + id: newEtapeId('3'), typeId: 'mdp', + ordre: 3, date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + communes: [], + contenu: {}, }, ] @@ -158,29 +173,38 @@ describe('trie les étapes', () => { }) test("retourne une erreur si le type d'étape est absent dans la définition", () => { - const etapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] = [ + const etapes: TitreEtapeForMachine[] = [ { - id: '1', + id: newEtapeId('1'), typeId: 'mcr', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + ordre: 1, + communes: [], + contenu: null, }, { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore typeId: 'bof', - id: '2', + id: newEtapeId('2'), date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + ordre: 2, + communes: [], + contenu: null, }, { - id: '3', + id: newEtapeId('3'), typeId: 'vfd', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + ordre: 3, + communes: [], + contenu: null, }, ] @@ -190,42 +214,57 @@ describe('trie les étapes', () => { }) test('utilise l’id pour trier des étapes totalement identiques', () => { - const secondMcd: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'> = { - id: 'mcd2', + const secondMcd: TitreEtapeForMachine = { + id: newEtapeId('mcd2'), typeId: 'mcd', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + ordre: 5, + contenu: {}, + communes: [], } - const etapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[] = [ + const etapes: TitreEtapeForMachine[] = [ { - id: 'mfr', + id: newEtapeId('mfr'), + ordre: 1, typeId: 'mfr', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + contenu: {}, + communes: [], }, { - id: 'mdp', + id: newEtapeId('mdp'), + ordre: 2, typeId: 'mdp', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + contenu: {}, + communes: [], }, { - id: 'mcd', + id: newEtapeId('mcd'), + ordre: 3, typeId: 'mcd', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + contenu: {}, + communes: [], }, { - id: 'rcd', + id: newEtapeId('rcd'), + ordre: 4, typeId: 'rcd', date: toCaminoDate('2020-01-01'), statutId: 'fai', - titreDemarcheId: newDemarcheId(), + surface: null, + contenu: {}, + communes: [], }, secondMcd, ] diff --git a/packages/api/src/business/utils/titre-etapes-sort.ts b/packages/api/src/business/utils/titre-etapes-sort.ts index d173378b3..efab1ddc2 100644 --- a/packages/api/src/business/utils/titre-etapes-sort.ts +++ b/packages/api/src/business/utils/titre-etapes-sort.ts @@ -1,6 +1,6 @@ import { ITitreEtape } from '../../types.js' -import { demarcheDefinitionFind, IDemarcheDefinitionRestrictions, isDemarcheDefinitionMachine } from '../rules-demarches/definitions.js' -import { toMachineEtapes } from '../rules-demarches/machine-common.js' +import { demarcheDefinitionFind } from '../rules-demarches/definitions.js' +import { TitreEtapeForMachine, toMachineEtapes } from '../rules-demarches/machine-common.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' import { getEtapesTDE } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index.js' @@ -13,19 +13,12 @@ export const titreEtapesSortDescByOrdre = <T extends Pick<ITitreEtape, 'ordre'>> export const titreEtapesSortAscByOrdre = <T extends Pick<ITitreEtape, 'ordre'>>(titreEtapes: T[]): T[] => titreEtapes.slice().sort((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 Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>>( - titreEtapes: T[], - demarcheId: DemarcheId, - demarcheTypeId: DemarcheTypeId, - titreTypeId: TitreTypeId -): T[] => { - let demarcheDefinitionRestrictions = undefined as IDemarcheDefinitionRestrictions | undefined - +export const titreEtapesSortAscByDate = <T extends TitreEtapeForMachine>(titreEtapes: T[], demarcheId: DemarcheId, demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId): T[] => { const demarcheDefinition = demarcheDefinitionFind(titreTypeId, demarcheTypeId, titreEtapes, demarcheId) - if (isDemarcheDefinitionMachine(demarcheDefinition)) { + if (demarcheDefinition) { const etapes = demarcheDefinition.machine.orderMachine(toMachineEtapes(titreEtapes)) if (!demarcheDefinition.machine.isEtapesOk(etapes)) { - console.error(`impossible de trouver un ordre pour la démarche '${titreEtapes[0]?.titreDemarcheId}' où ces étapes sont valides ${JSON.stringify(etapes)}`) + console.error(`impossible de trouver un ordre pour la démarche '${demarcheId}' où ces étapes sont valides ${JSON.stringify(etapes)}`) } const result: T[] = [] @@ -39,8 +32,6 @@ export const titreEtapesSortAscByDate = <T extends Pick<ITitreEtape, 'id' | 'ord return result } else { - demarcheDefinitionRestrictions = demarcheDefinition?.restrictions - return titreEtapes.slice().sort((a, b) => { const dateA = new Date(a.date) const dateB = new Date(b.date) @@ -48,50 +39,6 @@ export const titreEtapesSortAscByDate = <T extends Pick<ITitreEtape, 'id' | 'ord if (dateA < dateB) return -1 if (dateA > dateB) return 1 - // si les deux étapes ont la même date - - // on utilise l'arbre pour trouver quelle étape provoque l’autre - - if (demarcheDefinition && demarcheDefinitionRestrictions) { - const bRestriction = demarcheDefinitionRestrictions[b.typeId] - - if (!bRestriction) { - console.error(`${demarcheId}: impossible de trier l’étape car son type ${b.typeId} n’existe pas dans les définitions`) - - return -1 - } - - const aRestriction = demarcheDefinitionRestrictions[a.typeId] - - if (!aRestriction) { - console.error(`${demarcheId}: impossible de trier l’étape car son type ${a.typeId} n’existe pas dans les définitions`) - - return -1 - } - - const bJusteApresA = bRestriction.justeApres.flat(2).find(b => b.etapeTypeId === a.typeId) - - const aJusteApresB = aRestriction.justeApres.flat(2).find(a => a.etapeTypeId === b.typeId) - - if (bJusteApresA && !aJusteApresB) { - return -1 - } - - if (aJusteApresB && !bJusteApresA) { - return 1 - } - - if (aRestriction.final) { - return 1 - } - - if (bRestriction.final) { - return -1 - } - } - - // on utilise l'ordre du type d'étape - const etapes = getEtapesTDE(titreTypeId, demarcheTypeId) const aTypeIndex = etapes.findIndex(e => e === a.typeId) diff --git a/packages/api/src/business/utils/titre-slug-and-relations-update.ts b/packages/api/src/business/utils/titre-slug-and-relations-update.ts index 945afd601..c82bab9df 100644 --- a/packages/api/src/business/utils/titre-slug-and-relations-update.ts +++ b/packages/api/src/business/utils/titre-slug-and-relations-update.ts @@ -16,6 +16,7 @@ import { titrePointReferenceUpdate, titrePointUpdate } from '../../database/quer import { titreActiviteUpdate } from '../../database/queries/titres-activites.js' import { UserNotNull } from 'camino-common/src/roles' import { getDomaineId, getTitreTypeType } from 'camino-common/src/static/titresTypes.js' +import { TitreId } from 'camino-common/src/titres.js' const titreSlugFind = (titre: ITitre) => { const { typeId, nom } = titre @@ -48,7 +49,7 @@ const titreActiviteSlugFind = (titreActivite: ITitreActivite, titre: ITitre) => interface ITitreRelation<T extends string | DemarcheId = string> { name: string slugFind: (...args: any[]) => string - update: ((id: T, element: { slug: string }, user: UserNotNull) => Promise<{ id: T }>) | ((id: T, element: { slug: string }, user: UserNotNull, titreId: string) => Promise<{ id: T }>) + update: ((id: T, element: { slug: string }, user: UserNotNull) => Promise<{ id: T }>) | ((id: T, element: { slug: string }, user: UserNotNull, titreId: TitreId) => Promise<{ id: T }>) relations?: ITitreRelation[] } @@ -61,6 +62,7 @@ const titreRelations: (ITitreRelation<DemarcheId> | ITitreRelation)[] = [ { name: 'etapes', slugFind: titreDemarcheEtapeSlugFind, + // @ts-ignore update: titreEtapeUpdate, relations: [ { @@ -86,7 +88,7 @@ const titreRelations: (ITitreRelation<DemarcheId> | ITitreRelation)[] = [ }, ] -const relationsSlugsUpdate = async (parent: any, relations: (ITitreRelation<DemarcheId> | ITitreRelation)[], titreId: string): Promise<boolean> => { +const relationsSlugsUpdate = async (parent: any, relations: (ITitreRelation<DemarcheId> | ITitreRelation)[], titreId: TitreId): Promise<boolean> => { let hasChanged = false for (const relation of relations) { for (const element of parent[relation.name]) { diff --git a/packages/api/src/business/validations/titre-demarche-etat-validate.test.ts b/packages/api/src/business/validations/titre-demarche-etat-validate.test.ts index 5f16aac3d..44fd7a786 100644 --- a/packages/api/src/business/validations/titre-demarche-etat-validate.test.ts +++ b/packages/api/src/business/validations/titre-demarche-etat-validate.test.ts @@ -1,16 +1,16 @@ import { IDemarcheType, ITitre, ITitreEtape, ITitreType } from '../../types.js' import { titreDemarcheUpdatedEtatValidate } from './titre-demarche-etat-validate.js' -import { newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newEtapeId } from '../../database/models/_format/id-create.js' import { EtapesTypesEtapesStatuts } from 'camino-common/src/static/etapesTypesEtapesStatuts.js' -import { describe, test, expect } from 'vitest' +import { describe, test, expect, vi } from 'vitest' import { toCaminoDate } from 'camino-common/src/date.js' +import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -const currentDate = toCaminoDate('2023-04-06') +console.warn = vi.fn() describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ajoute une étape à une démarche vide', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -20,7 +20,7 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { typeId: 'mfr', date: '2030-01-01' } as ITitreEtape, + { typeId: 'mfr', date: '2030-01-01' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), null ) @@ -30,7 +30,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ajoute une étape à une démarche qui contient déjà une étape', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -40,10 +39,10 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'pro' }, { typeId: 'oct' }], } as ITitre, - { typeId: 'mdp', statutId: 'fai', date: '2022-05-04' } as ITitreEtape, + { id: newEtapeId(), typeId: 'mdp', statutId: 'fai', date: toCaminoDate('2022-05-04'), communes: null, contenu: null, ordre: 1, surface: null }, newDemarcheId(), - [{ id: '1', typeId: 'mfr', statutId: 'fai', date: '2022-05-03' }] as ITitreEtape[] + [{ id: newEtapeId('1'), typeId: 'mfr', statutId: 'fai', date: toCaminoDate('2022-05-03'), communes: null, contenu: null, ordre: 1, surface: null }] ) expect(valid).toHaveLength(0) @@ -51,7 +50,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('modifie une étape à une démarche', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -62,17 +60,21 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { demarches: [{ typeId: 'oct' }], } as ITitre, { - id: '1', + id: newEtapeId('1'), typeId: 'mfr', statutId: 'fai', - date: '2022-05-04', - } as ITitreEtape, + date: toCaminoDate('2022-05-04'), + communes: null, + contenu: null, + ordre: 1, + surface: null, + }, newDemarcheId(), [ - { id: '1', typeId: 'mfr', date: '2022-05-03', statutId: 'fai' }, - { id: '2', typeId: 'mdp', date: '2022-05-04', statutId: 'fai' }, - ] as ITitreEtape[] + { id: newEtapeId('1'), typeId: 'mfr', date: toCaminoDate('2022-05-03'), statutId: 'fai', communes: null, contenu: null, ordre: 1, surface: null }, + { id: newEtapeId('2'), typeId: 'mdp', date: toCaminoDate('2022-05-04'), statutId: 'fai', communes: null, contenu: null, ordre: 2, surface: null }, + ] ) expect(valid).toHaveLength(0) @@ -80,7 +82,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('l’ajout d’une étape d’une démarche historique est valide', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -90,10 +91,10 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { id: '1', typeId: 'mfr' } as ITitreEtape, + { id: '1', typeId: 'mfr' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [{ id: '1', typeId: 'mfr', date: '2000-01-01' }] as ITitreEtape[], + [{ id: '1', typeId: 'mfr', date: '2000-01-01' }] as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>[], false ) @@ -102,7 +103,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('l’ajout d’une étape d’une démarche sans étape est valide', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -112,10 +112,10 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { id: '1', typeId: 'mfr' } as ITitreEtape, + { id: '1', typeId: 'mfr' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [] as ITitreEtape[] + [] ) expect(valid).toHaveLength(0) @@ -124,7 +124,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test("retourne une erreur si la démarche en cours de modification n'existe pas", () => { expect(() => titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -134,16 +133,15 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'pro' }], } as ITitre, - { id: '1', typeId: 'mfr' } as ITitreEtape, + { id: '1', typeId: 'mfr' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [] as ITitreEtape[] + [] ) ).toThrow() expect(() => titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -152,17 +150,16 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { contenuIds: [], } as unknown as ITitreType, } as ITitre, - { id: '1', typeId: 'mfr' } as ITitreEtape, + { id: '1', typeId: 'mfr' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [] as ITitreEtape[] + [] ) ).toThrow() }) test('supprime une étape', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -172,19 +169,18 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { id: '1', typeId: 'mfr' } as ITitreEtape, + { id: '1', typeId: 'mfr' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [{ id: '1', typeId: 'mfr' }] as ITitreEtape[], + [{ id: '1', typeId: 'mfr' }] as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>[], true ) expect(valid).toHaveLength(0) }) - test("ajoute une étape sans statut à une démarche sans arbre d'instruction", () => { + test('ajoute une étape sans statut à une démarche sans machine', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct', nom: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -203,16 +199,15 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { }, ], } as ITitre, - { typeId: 'mfr', date: '1030-01-01' } as ITitreEtape, + { typeId: 'mfr', date: '1030-01-01' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId() ) expect(valid).toHaveLength(0) }) - test("ajoute une étape à une démarche sans arbre d'instruction", () => { + test('ajoute une étape à une démarche sans machine', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct', nom: 'oct' } as IDemarcheType, { typeId: 'arm', @@ -231,7 +226,7 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { }, ], } as ITitre, - { typeId: 'mfr', date: '1030-01-01', statutId: 'fai' } as ITitreEtape, + { typeId: 'mfr', date: '1030-01-01', statutId: 'fai' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId() ) @@ -240,7 +235,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ajoute une demande en construction à une démarche vide', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'axm', @@ -250,7 +244,7 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { typeId: 'mfr', statutId: 'aco', date: '2030-01-01' } as ITitreEtape, + { typeId: 'mfr', statutId: 'aco', date: '2030-01-01' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId() ) @@ -259,7 +253,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ajoute une demande en construction à une démarche qui contient déjà une étape', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'axm', @@ -269,10 +262,10 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { typeId: 'mfr', statutId: 'aco' } as ITitreEtape, + { typeId: 'mfr', statutId: 'aco' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), - [{ id: '1', typeId: 'dae', statutId: 'exe' }] as ITitreEtape[] + [{ id: '1', typeId: 'dae', statutId: 'exe' }] as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>[] ) expect(valid).toHaveLength(0) @@ -280,7 +273,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('modifie une demande en construction à une démarche', () => { const valid = titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'axm', @@ -290,13 +282,13 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { id: '1', typeId: 'mfr', statutId: 'aco' } as ITitreEtape, + { id: '1', typeId: 'mfr', statutId: 'aco' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), [ { id: '1', typeId: 'mfr', statutId: 'aco' }, { id: '2', typeId: 'dae' }, - ] as ITitreEtape[] + ] as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>[] ) expect(valid).toHaveLength(0) @@ -305,7 +297,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ne peut pas ajouter une 2ème demande en construction à une démarche', () => { expect( titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'axm', @@ -315,13 +306,13 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { } as unknown as ITitreType, demarches: [{ typeId: 'oct' }], } as ITitre, - { id: '3', typeId: 'mfr', statutId: 'aco' } as ITitreEtape, + { id: '3', typeId: 'mfr', statutId: 'aco' } as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>, newDemarcheId(), [ { id: '1', typeId: 'mfr', statutId: 'aco' }, { id: '2', typeId: 'dae' }, - ] as ITitreEtape[] + ] as Pick<Required<ITitreEtape>, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId' | 'communes'>[] ) ).toContain('il y a déjà une demande en construction') }) @@ -329,7 +320,6 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { test('ne peut pas ajouter étape de type inconnu sur une machine', () => { expect( titreDemarcheUpdatedEtatValidate( - currentDate, { id: 'oct' } as IDemarcheType, { typeId: 'axm', @@ -340,26 +330,38 @@ describe('teste titreDemarcheUpdatedEtatValidate', () => { demarches: [{ typeId: 'oct' }], } as ITitre, { - typeId: 'aaa', - date: '2022-01-01', + typeId: 'aaa' as EtapeTypeId, + date: toCaminoDate('2022-01-01'), statutId: 'fai', - } as unknown as ITitreEtape, + communes: null, + contenu: null, + ordre: 1, + surface: null, + }, newDemarcheId(), [ { - id: '1', + id: newEtapeId('1'), typeId: EtapesTypesEtapesStatuts.demande.EN_CONSTRUCTION.etapeTypeId, statutId: EtapesTypesEtapesStatuts.demande.EN_CONSTRUCTION.etapeStatutId, - date: '2021-01-01', + date: toCaminoDate('2021-01-01'), + communes: null, + contenu: null, + ordre: 1, + surface: null, }, { - id: '2', + id: newEtapeId('2'), typeId: EtapesTypesEtapesStatuts.decisionDeLaMissionAutoriteEnvironnementale_ExamenAuCasParCasDuProjet_.REQUIS.etapeTypeId, statutId: EtapesTypesEtapesStatuts.decisionDeLaMissionAutoriteEnvironnementale_ExamenAuCasParCasDuProjet_.REQUIS.etapeStatutId, - date: '2021-01-02', + date: toCaminoDate('2021-01-02'), + communes: null, + contenu: null, + ordre: 1, + surface: null, }, - ] as ITitreEtape[] + ] ) ).toContain('la démarche n’est pas valide') }) 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 bb44560ee..430fed690 100644 --- a/packages/api/src/business/validations/titre-demarche-etat-validate.ts +++ b/packages/api/src/business/validations/titre-demarche-etat-validate.ts @@ -1,19 +1,12 @@ // valide la date et la position de l'étape en fonction des autres étapes -import type { ITitre, ITitreEtape, IDemarcheType, ITitreDemarche } from '../../types.js' - -import { demarcheDefinitionFind, IDemarcheDefinitionRestrictions, isDemarcheDefinitionMachine } from '../rules-demarches/definitions.js' -import { contenusTitreEtapesIdsFind } from '../utils/props-titre-etapes-ids-find.js' -import { titreEtapesSortAscByDate } from '../utils/titre-etapes-sort.js' -import { titreEtapeEtatValidate } from './titre-etape-etat-validate.js' -import { objectClone } from '../../tools/index.js' -import { toMachineEtapes } from '../rules-demarches/machine-common.js' +import type { ITitre, ITitreEtape, IDemarcheType } from '../../types.js' + +import { demarcheDefinitionFind } from '../rules-demarches/definitions.js' +import { titreEtapeForMachineValidator, toMachineEtapes } from '../rules-demarches/machine-common.js' import { titreEtapeTypeAndStatusValidate } from './titre-etape-type-and-status-validate.js' -import { contenuFormat } from '../../api/rest/titre-contenu.js' -import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes.js' -import { CaminoDate } from 'camino-common/src/date.js' import { DemarcheId } from 'camino-common/src/demarche.js' -const titreDemarcheEtapesBuild = <T extends Pick<ITitreEtape, 'id'>>(titreEtape: T, suppression: boolean, titreDemarcheEtapes?: T[] | null): T[] => { +const titreDemarcheEtapesBuild = <T extends Pick<Partial<ITitreEtape>, 'id'>>(titreEtape: T, suppression: boolean, titreDemarcheEtapes?: T[] | null): T[] => { if (!titreDemarcheEtapes?.length) { return [titreEtape] } @@ -41,56 +34,14 @@ const titreDemarcheEtapesBuild = <T extends Pick<ITitreEtape, 'id'>>(titreEtape: return titreEtapes } -// vérifie que la démarche est valide par rapport aux définitions des types d'étape -export const titreDemarcheEtatValidate = ( - date: CaminoDate, - demarcheDefinitionRestrictions: IDemarcheDefinitionRestrictions, - demarcheTypeId: DemarcheTypeId, - titreDemarche: ITitreDemarche, - titreEtapes: Pick<ITitreEtape, 'id' | 'ordre' | 'typeId' | 'statutId' | 'date' | 'contenu' | 'titreDemarcheId'>[], - titre: ITitre -) => { - // Si on tente d’insérer ou de modifier une étape, il faut regarder - // qu’on puisse la mettre avec son nouveau etapeTypeId à la nouvelle date souhaitée - // et que les étapes après celle-ci soient toujours possibles - - titreEtapes = titreEtapesSortAscByDate(titreEtapes, titreDemarche.id, demarcheTypeId, titre.typeId) - - // on copie la démarche car on va les modifier en ajoutant les étapes une à une - const demarche = objectClone(titreDemarche) - - for (let i = 0; i < titreEtapes.length; i++) { - // On doit recalculer les sections de titre pour chaque étape, - // car elles ont peut-être été modifiées après l’étape en cours - const etapes = titreEtapes.slice(0, i) - demarche.etapes = etapes - - const contenusTitreEtapesIds = contenusTitreEtapesIdsFind(date, titre.titreStatutId!, [demarche], titre.type!.contenuIds) - - let contenu = null - if (contenusTitreEtapesIds) { - contenu = contenuFormat({ demarches: [demarche], contenusTitreEtapesIds }) - } - - const titreEtapeErrors = titreEtapeEtatValidate(demarcheDefinitionRestrictions, titreEtapes[i].typeId!, etapes, contenu) - - if (titreEtapeErrors.length) { - return titreEtapeErrors - } - } - - return [] -} - // vérifie que la modification de la démarche // est valide par rapport aux définitions des types d'étape export const titreDemarcheUpdatedEtatValidate = ( - date: CaminoDate, demarcheType: IDemarcheType, titre: ITitre, - titreEtape: Pick<ITitreEtape, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId'>, + titreEtape: Pick<Partial<ITitreEtape>, 'id'> & Pick<ITitreEtape, 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'communes' | 'surface'>, demarcheId: DemarcheId, - titreDemarcheEtapes?: Pick<ITitreEtape, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'titreDemarcheId'>[] | null, + titreDemarcheEtapes?: Pick<ITitreEtape, 'id' | 'statutId' | 'typeId' | 'date' | 'ordre' | 'contenu' | 'communes' | 'surface'>[] | null, suppression = false ): string[] => { let titreDemarcheEtapesNew = titreDemarcheEtapesBuild(titreEtape, suppression, titreDemarcheEtapes) @@ -102,7 +53,7 @@ export const titreDemarcheUpdatedEtatValidate = ( if (!titreDemarche) { throw new Error('le titre ne contient pas la démarche en cours de modification') } - // pas de validation pour les démarches qui n'ont pas d'arbre d’instructions + // pas de validation pour les démarches qui n'ont pas de machine if (!demarcheDefinition) { if (!titreEtape.statutId) { return [] @@ -135,31 +86,15 @@ export const titreDemarcheUpdatedEtatValidate = ( } // vérifie que toutes les étapes existent dans l’arbre - if (isDemarcheDefinitionMachine(demarcheDefinition)) { - try { - const ok = demarcheDefinition.machine.isEtapesOk(demarcheDefinition.machine.orderMachine(toMachineEtapes(titreDemarcheEtapesNew))) - if (!ok) { - titreDemarchesErrors.push('la démarche n’est pas valide') - } - } catch (e) { - console.warn('une erreur est survenue', e) + try { + const etapes = titreDemarcheEtapesNew.map(etape => titreEtapeForMachineValidator.omit({ id: true }).partial({ ordre: true }).parse(etape)) + const ok = demarcheDefinition.machine.isEtapesOk(demarcheDefinition.machine.orderMachine(toMachineEtapes(etapes))) + if (!ok) { titreDemarchesErrors.push('la démarche n’est pas valide') } - } else { - if (titreEtape.statutId) { - // le type d'étape correspond à la démarche et au type de titre - const titreEtapeTypeAndStatusErrors = titreEtapeTypeAndStatusValidate(titreEtape.typeId, titreEtape.statutId, titreDemarche.type!.etapesTypes, titreDemarche.type!.nom) - titreDemarchesErrors.push(...titreEtapeTypeAndStatusErrors) - } - const etapeTypeIdsValid = Object.keys(demarcheDefinition.restrictions) - - const etapeInconnue = titreDemarcheEtapesNew.find(etape => !etapeTypeIdsValid.includes(etape.typeId!)) - if (etapeInconnue) { - return [`l’étape ${etapeInconnue.typeId} n’existe pas dans l’arbre`] - } - - // On vérifie que la nouvelle démarche respecte son arbre d’instructions - titreDemarchesErrors.push(...titreDemarcheEtatValidate(date, demarcheDefinition.restrictions, demarcheType.id, titreDemarche, titreDemarcheEtapesNew, titre)) + } catch (e) { + console.warn('une erreur est survenue', e) + titreDemarchesErrors.push('la démarche n’est pas valide') } return titreDemarchesErrors diff --git a/packages/api/src/business/validations/titre-etape-etat-validate.test.ts b/packages/api/src/business/validations/titre-etape-etat-validate.test.ts deleted file mode 100644 index 381d7a3aa..000000000 --- a/packages/api/src/business/validations/titre-etape-etat-validate.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ITitreEtape } from '../../types.js' - -import { etapesSuivantesEnAttenteGet, titreEtapeTypeIdRestrictionsFind } from './titre-etape-etat-validate.js' -import { etatInformationsGet } from '../rules-demarches/etat-cycles.js' -import { describe, test, expect } from 'vitest' -describe('teste etapesSuivantesEnAttenteGet', () => { - test('retourne les 2 dernières étapes des chemins parallèles', () => { - const etapes = [{ typeId: 'mfr' }, { typeId: 'mdp' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - mfr: { justeApres: [] }, - mdp: { justeApres: [] }, - mno: { - justeApres: [[{ etapeTypeId: 'mfr' }, { etapeTypeId: 'mdp' }]], - }, - }) - expect(etapesEnAttente).toHaveLength(2) - expect(etapesEnAttente[0]).toEqual({ typeId: 'mfr' }) - expect(etapesEnAttente[1]).toEqual({ typeId: 'mdp' }) - }) - - test('retourne la dernière étape après la fusion de 2 chemins parallèles', () => { - const etapes = [{ typeId: 'mfr' }, { typeId: 'mcp' }, { typeId: 'mno' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - mfr: { justeApres: [] }, - mcp: { justeApres: [] }, - mno: { - justeApres: [[{ etapeTypeId: 'mfr' }, { etapeTypeId: 'mcp' }]], - }, - }) - expect(etapesEnAttente).toHaveLength(1) - expect(etapesEnAttente[0]).toEqual({ typeId: 'mno' }) - }) - test('retourne l’étape sur le premier chemin et l’étape sur le chemin commun', () => { - const etapes = [{ typeId: 'ide' }, { typeId: 'mno' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - ide: { separation: ['css'], justeApres: [] }, - mno: { - justeApres: [[{ etapeTypeId: 'ide' }]], - }, - mfr: { - justeApres: [[{ etapeTypeId: 'ide' }]], - }, - css: { - justeApres: [[{ etapeTypeId: 'mno' }, { etapeTypeId: 'mfr' }]], - }, - }) - expect(etapesEnAttente).toHaveLength(2) - expect(etapesEnAttente[0]).toEqual({ typeId: 'ide' }) - expect(etapesEnAttente[1]).toEqual({ typeId: 'mno' }) - }) - test('retourne l’étape sur la dernière étape sur le chemin commun', () => { - const etapes = [{ typeId: 'ide' }, { typeId: 'mno' }, { typeId: 'mfr' }, { typeId: 'css' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - ide: { separation: ['css'], justeApres: [] }, - mno: { - justeApres: [[{ etapeTypeId: 'ide' }]], - }, - mfr: { - justeApres: [[{ etapeTypeId: 'ide' }]], - }, - css: { - justeApres: [[{ etapeTypeId: 'mno' }, { etapeTypeId: 'mfr' }]], - }, - }) - expect(etapesEnAttente).toHaveLength(1) - expect(etapesEnAttente[0]).toEqual({ typeId: 'css' }) - }) - test('retourne seulement l’étape "rif" dés qu’une demande d’info a commencé', () => { - const etapes = [{ typeId: 'vfd' }, { typeId: 'mif-mcr' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - vfd: { justeApres: [] }, - ...etatInformationsGet('mif-mcr', 'rif-mcr', { - etapeTypeId: 'mcr', - separation: ['eof'], - justeApres: [[{ etapeTypeId: 'vfd' }]], - }), - }) - expect(etapesEnAttente).toHaveLength(1) - expect(etapesEnAttente[0]).toEqual({ typeId: 'mif-mcr' }) - }) - - test('retourne la dernière étape sur le chemin commun à la fin du démarche', () => { - const etapes = [{ typeId: 'dex' }, { typeId: 'mno' }] as ITitreEtape[] - const etapesEnAttente = etapesSuivantesEnAttenteGet(etapes, etapes, [], { - dex: { justeApres: [], separation: [] }, - mno: { - justeApres: [[{ etapeTypeId: 'dex' }]], - }, - mfr: { - justeApres: [[{ etapeTypeId: 'dex' }]], - }, - mcp: { - justeApres: [[{ etapeTypeId: 'dex' }]], - }, - }) - expect(etapesEnAttente).toHaveLength(2) - expect(etapesEnAttente[0]).toEqual({ typeId: 'dex' }) - }) -}) - -describe('teste titreEtapeTypeIdRestrictionsFind', () => { - test('émet une erreur si l’étape est inconnue', () => { - // @ts-ignore - expect(() => titreEtapeTypeIdRestrictionsFind({ dex: { justeApres: [], separation: [] } }, 'aaa')).toThrowError() - }) -}) diff --git a/packages/api/src/business/validations/titre-etape-etat-validate.ts b/packages/api/src/business/validations/titre-etape-etat-validate.ts deleted file mode 100644 index 7c5a50ae0..000000000 --- a/packages/api/src/business/validations/titre-etape-etat-validate.ts +++ /dev/null @@ -1,182 +0,0 @@ -// valide la date et la position de l'étape en fonction des autres étapes -import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' -import { ITitreEtape, IContenu, Index } from '../../types.js' - -import { ITitreCondition, IContenuElementCondition, IEtapeTypeIdCondition, IDemarcheDefinitionRestrictions, IDemarcheDefinitionRestrictionsProps } from '../rules-demarches/definitions.js' - -const contenuConditionMatch = (condition: IContenuElementCondition, obj: Index<any> | null, keys: string[] | null = null) => { - // si les conditions sont testées plusieurs fois, (dans une boucle par ex) - // alors les clés de l'objet de condition peuvent être passées optionnellement - // pour ne pas les recalculer à chaque fois - const conditionKeys = keys || Object.keys(condition) - - return conditionKeys.every(k => { - const contenuElementCondition = condition[k] - - let contenuValeur = obj ? obj[k] : undefined - if (!contenuValeur) { - if (typeof contenuElementCondition?.valeur === 'number') { - contenuValeur = 0 - } else if (typeof contenuElementCondition?.valeur === 'boolean') { - contenuValeur = false - } - } - - switch (contenuElementCondition?.operation) { - case 'NOT_EQUAL': - return contenuElementCondition.valeur !== contenuValeur - default: - return contenuElementCondition?.valeur === contenuValeur - } - }) -} - -const sameContenuCheck = (conditionTitre: ITitreCondition, contenu: IContenu | null) => - conditionTitre.contenu && Object.keys(conditionTitre.contenu).every(key => contenuConditionMatch(conditionTitre.contenu[key], contenu ? contenu[key] : null)) - -const titreEtapeTypeIdRestrictionsFind = (demarcheDefinitionRestrictions: IDemarcheDefinitionRestrictions, etapeTypeId: EtapeTypeId) => { - const etapeTypeIdDefinitions = demarcheDefinitionRestrictions[etapeTypeId] - - if (etapeTypeIdDefinitions) { - return etapeTypeIdDefinitions - } - - throw new Error(`l’étape ${etapeTypeId} n’existe pas dans cet arbre d’instructions`) -} - -const etapesEnAttenteGet = (etapeTypeIdDefinitions: IDemarcheDefinitionRestrictions, titreDemarcheEtapes: ITitreEtape[]) => { - return etapesSuivantesEnAttenteGet(titreDemarcheEtapes, titreDemarcheEtapes, [], etapeTypeIdDefinitions) -} - -const etapesSuivantesEnAttenteGet = ( - titreDemarcheEtapes: ITitreEtape[], - titreDemarcheEtapesSuivantes: ITitreEtape[], - etapesEnAttente: ITitreEtape[], - etapeTypeIdDefinitions: IDemarcheDefinitionRestrictions -): ITitreEtape[] => { - if (!titreDemarcheEtapesSuivantes || !titreDemarcheEtapesSuivantes.length) { - return etapesEnAttente - } - - const etapeCourante = titreDemarcheEtapesSuivantes.slice(0, 1)[0] - const etapesSuivantes = titreDemarcheEtapesSuivantes.slice(1) - - if (!etapesEnAttente || !etapesEnAttente.length) { - return etapesSuivantesEnAttenteGet(titreDemarcheEtapes, etapesSuivantes, [etapeCourante], etapeTypeIdDefinitions) - } - - const etapeCouranteConditions = etapeTypeIdDefinitions[etapeCourante.typeId] as IDemarcheDefinitionRestrictionsProps - - // on cherche quelles étapes en attente ont permis d’atteindre cette étape - if (etapeCouranteConditions.justeApres) { - etapesEnAttente.forEach(etape => { - const predicatCheck = etapeCouranteConditions!.justeApres!.flat().find(c => c?.etapeTypeId === etape.typeId) - - if (predicatCheck) { - // si cette étape a permis d’atteindre l’étape courante, alors on la remplace dans les étapes en attente - etapesEnAttente = etapesEnAttente.filter(e => { - const etapeSeparationHas = etapeTypeIdDefinitions[e.typeId] - - if (etapeSeparationHas && etapeSeparationHas.separation) { - return !etapeSeparationHas.separation!.includes(etapeCourante.typeId!) - } - - return e.typeId !== etape.typeId - }) - } - }) - } - - if (etapeCouranteConditions.apres) { - titreDemarcheEtapes.forEach(etape => { - const predicatCheck = etapeCouranteConditions.apres!.flat().find(c => c?.etapeTypeId === etape.typeId) - - if (predicatCheck) { - if ((etapeCouranteConditions.justeApres.length && etapeCouranteConditions.justeApres[0].length) || !etapeCouranteConditions.final) { - etapesEnAttente = etapesEnAttente.filter( - e => - !etapeCouranteConditions.justeApres - .flatMap(d => d) - .map(a => a.etapeTypeId) - .includes(e.typeId!) - ) - } else { - // Si c’est une étape sans de « justeAprès », c’est que c’est une interruption de la démarche - etapesEnAttente = [] - } - } - }) - } - etapesEnAttente.push(etapeCourante) - - return etapesSuivantesEnAttenteGet(titreDemarcheEtapes, etapesSuivantes, etapesEnAttente, etapeTypeIdDefinitions) -} - -const etapeTypeIdConditionsCheck = (contenu: IContenu | null, titreEtapesEnAttente: ITitreEtape[], conditions: IEtapeTypeIdCondition[][], titreDemarcheEtapes: ITitreEtape[]) => - conditions.some(condition => - condition.every(c => { - if (c.titre && !sameContenuCheck(c.titre, contenu)) { - return false - } - - if (c.contextCheck && !c.contextCheck(titreDemarcheEtapes)) { - return false - } - - return titreEtapesEnAttente.find(etape => { - let result = true - - if (c.etapeTypeId) { - result = result && c.etapeTypeId === etape.typeId - } - if (c.statutId) { - result = result && c.statutId === etape.statutId - } - - return result - }) - }) - ) - -const etapesEnAttenteToString = (titreEtapesEnAttente: ITitreEtape[]) => - titreEtapesEnAttente - .map(t => (t.type ? t.type.nom : t.typeId)) - .map(t => `"${t}"`) - .join(', ') - -const titreEtapeEtatValidate = (etapeTypeIdDefinitions: IDemarcheDefinitionRestrictions, etapeTypeId: EtapeTypeId, titreDemarcheEtapes: ITitreEtape[], contenu: IContenu | null) => { - const errors = [] - const titreEtapesEnAttente = etapesEnAttenteGet(etapeTypeIdDefinitions, titreDemarcheEtapes) - - if (titreEtapesEnAttente.find(e => e.typeId === etapeTypeId)) { - errors.push(`l’étape "${etapeTypeId}" ne peut-être effecutée 2 fois d’affilée`) - } - - const titreEtapeRestrictions = titreEtapeTypeIdRestrictionsFind(etapeTypeIdDefinitions, etapeTypeId) - - const { avant, apres, justeApres } = titreEtapeRestrictions - - if (!errors.length && avant && etapeTypeIdConditionsCheck(contenu, titreDemarcheEtapes, avant, titreDemarcheEtapes)) { - errors.push(`l’étape "${etapeTypeId}" n’est plus possible après ${etapesEnAttenteToString(titreEtapesEnAttente)}`) - } - - if (!errors.length && apres && !etapeTypeIdConditionsCheck(contenu, titreDemarcheEtapes, apres, titreDemarcheEtapes)) { - errors.push(`l’étape "${etapeTypeId}" n’est pas possible après ${etapesEnAttenteToString(titreEtapesEnAttente)}`) - } - - if (!errors.length && justeApres.length && !etapeTypeIdConditionsCheck(contenu, titreEtapesEnAttente, justeApres, titreDemarcheEtapes)) { - errors.push(`l’étape "${etapeTypeId}" n’est pas possible juste après ${etapesEnAttenteToString(titreEtapesEnAttente)}`) - } - - if (!errors.length) { - if (!justeApres.length || justeApres.some(c => !c.length)) { - if (titreDemarcheEtapes.map(e => e.typeId).includes(etapeTypeId)) { - errors.push(`l’étape "${etapeTypeId}" existe déjà`) - } - } - } - - return errors -} - -export { titreEtapeEtatValidate, etapesSuivantesEnAttenteGet, titreEtapeTypeIdRestrictionsFind } diff --git a/packages/api/src/business/validations/titre-etape-updation-validate.test.ts b/packages/api/src/business/validations/titre-etape-updation-validate.test.ts index 44d67aafd..7582620ec 100644 --- a/packages/api/src/business/validations/titre-etape-updation-validate.test.ts +++ b/packages/api/src/business/validations/titre-etape-updation-validate.test.ts @@ -6,9 +6,7 @@ import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { userSuper } from '../../database/user-super.js' import { describe, test, expect } from 'vitest' -import { toCaminoDate } from 'camino-common/src/date.js' -const currentDate = toCaminoDate('2023-04-06') describe('valide l’étape avant de l’enregistrer', () => { test.each<[SubstanceLegaleId[], EtapeTypeId, TitreTypeId, boolean]>([ [[], 'mfr', 'arm', true], @@ -124,7 +122,7 @@ describe('valide l’étape avant de l’enregistrer', () => { typeId: 'arm', } as unknown as ITitre - let errors = titreEtapeUpdationValidate(currentDate, titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) + let errors = titreEtapeUpdationValidate(titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) expect(errors).not.toContain("une autorisation de recherche ne peut pas inclure d'amodiataires") expect(errors).not.toContain("une autorisation d'exploitation ne peut pas inclure d'amodiataires") @@ -133,7 +131,7 @@ describe('valide l’étape avant de l’enregistrer', () => { amodiataires: [{ id: 'foo', nom: 'bar', operateur: true }], } as unknown as ITitreEtape - errors = titreEtapeUpdationValidate(currentDate, titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) + errors = titreEtapeUpdationValidate(titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) expect(errors).toContain("une autorisation de recherche ne peut pas inclure d'amodiataires") // // AXM @@ -147,7 +145,7 @@ describe('valide l’étape avant de l’enregistrer', () => { typeId: 'axm', } as unknown as ITitre - errors = titreEtapeUpdationValidate(currentDate, titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) + errors = titreEtapeUpdationValidate(titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) expect(errors).not.toContain("une autorisation d'exploitation ne peut pas inclure d'amodiataires") expect(errors).not.toContain("une autorisation de recherche ne peut pas inclure d'amodiataires") @@ -156,7 +154,7 @@ describe('valide l’étape avant de l’enregistrer', () => { amodiataires: [{ id: 'foo', nom: 'bar', operateur: true }], } as unknown as ITitreEtape - errors = titreEtapeUpdationValidate(currentDate, titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) + errors = titreEtapeUpdationValidate(titreEtape, titreDemarche, titre, [], [], [], [], [], [], userSuper) expect(errors).toContain("une autorisation d'exploitation ne peut pas inclure d'amodiataires") }) }) diff --git a/packages/api/src/business/validations/titre-etape-updation-validate.ts b/packages/api/src/business/validations/titre-etape-updation-validate.ts index ae3b28ba4..3d2803446 100644 --- a/packages/api/src/business/validations/titre-etape-updation-validate.ts +++ b/packages/api/src/business/validations/titre-etape-updation-validate.ts @@ -16,7 +16,6 @@ import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { DocumentType, DocumentsTypes } from 'camino-common/src/static/documentsTypes.js' import { User } from 'camino-common/src/roles.js' import { SDOMZoneId } from 'camino-common/src/static/sdom.js' -import { CaminoDate } from 'camino-common/src/date.js' import { getSections, Section } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' import { DeepReadonly } from 'camino-common/src/typescript-tools.js' const numberProps = ['duree', 'surface'] as unknown as [keyof ITitreEtape] @@ -24,7 +23,6 @@ const numberProps = ['duree', 'surface'] as unknown as [keyof ITitreEtape] const dateProps = ['date', 'dateDebut', 'dateFin'] as unknown as [keyof ITitreEtape] export const titreEtapeUpdationValidate = ( - date: CaminoDate, titreEtape: ITitreEtape, titreDemarche: ITitreDemarche, titre: ITitre, @@ -123,7 +121,7 @@ export const titreEtapeUpdationValidate = ( return errors } - return titreEtapeUpdationBusinessValidate(date, titreEtape, titreDemarche, titre) + return titreEtapeUpdationBusinessValidate(titreEtape, titreDemarche, titre) } export const titreEtapeCompleteValidate = ( @@ -208,11 +206,11 @@ export const titreEtapeCompleteValidate = ( return errors } -const titreEtapeUpdationBusinessValidate = (date: CaminoDate, titreEtape: ITitreEtape, titreDemarche: ITitreDemarche, titre: ITitre) => { +const titreEtapeUpdationBusinessValidate = (titreEtape: ITitreEtape, titreDemarche: ITitreDemarche, titre: ITitre) => { const errors = [] // 1. la date de l'étape est possible // en fonction de l'ordre des types d'étapes de la démarche - const demarcheUpdatedErrors = titreDemarcheUpdatedEtatValidate(date, titreDemarche.type!, titre, titreEtape, titreDemarche.id, titreDemarche.etapes!) + const demarcheUpdatedErrors = titreDemarcheUpdatedEtatValidate(titreDemarche.type!, titre, titreEtape, titreDemarche.id, titreDemarche.etapes!) if (demarcheUpdatedErrors.length) { errors.push(...demarcheUpdatedErrors) } diff --git a/packages/api/src/business/validations/titre-links-validate.ts b/packages/api/src/business/validations/titre-links-validate.ts index 32672d4ee..ed10d5ed7 100644 --- a/packages/api/src/business/validations/titre-links-validate.ts +++ b/packages/api/src/business/validations/titre-links-validate.ts @@ -1,7 +1,8 @@ +import { TitreId } from 'camino-common/src/titres.js' import { ITitre, ITitreDemarche } from '../../types.js' import { getLinkConfig } from 'camino-common/src/permissions/titres.js' -export const checkTitreLinks = (titre: Pick<ITitre, 'typeId'>, titreFromIds: string[], titresFrom: ITitre[], demarches: ITitreDemarche[]) => { +export const checkTitreLinks = (titre: Pick<ITitre, 'typeId'>, titreFromIds: TitreId[], titresFrom: ITitre[], demarches: ITitreDemarche[]) => { const linkConfig = getLinkConfig(titre.typeId, demarches) if (!linkConfig) { throw new Error('ce titre ne peut pas être lié à d’autres titres') diff --git a/packages/api/src/database/models/_format/id-create.ts b/packages/api/src/database/models/_format/id-create.ts index 9d07f3475..e04d74a1f 100644 --- a/packages/api/src/database/models/_format/id-create.ts +++ b/packages/api/src/database/models/_format/id-create.ts @@ -3,6 +3,8 @@ import { CaminoDate } from 'camino-common/src/date.js' import { DocumentId, documentIdValidator } from 'camino-common/src/entreprise.js' import { DocumentTypeId } from 'camino-common/src/static/documentsTypes.js' import { randomBytes } from 'node:crypto' +import { TitreId } from 'camino-common/src/titres.js' +import { EtapeId } from 'camino-common/src/etape.js' export const idGenerate = <T extends string = string>(): T => randomBytes(12).toString('hex') as T @@ -12,6 +14,14 @@ export const newDemarcheId = (value: string = idGenerate()): DemarcheId => { return value as DemarcheId } +export const newTitreId = (value: string = idGenerate()): TitreId => { + return value as TitreId +} + +export const newEtapeId = (value: string = idGenerate()): EtapeId => { + return value as EtapeId +} + export const newDocumentId = (date: CaminoDate, documentTypeId: DocumentTypeId): DocumentId => { const hash = randomBytes(4).toString('hex') diff --git a/packages/api/src/database/models/_format/titre-etape-heritage.ts b/packages/api/src/database/models/_format/titre-etape-heritage.ts index 64b2a91c9..10bebfbd4 100644 --- a/packages/api/src/database/models/_format/titre-etape-heritage.ts +++ b/packages/api/src/database/models/_format/titre-etape-heritage.ts @@ -1,6 +1,7 @@ import { IHeritageProps, IFields, IHeritageContenu } from '../../../types.js' import { userSuper } from '../../user-super.js' import { titreEtapeGet } from '../../queries/titres-etapes.js' +import { newEtapeId } from './id-create.js' const heritagePropsFormat = async (heritageProps: IHeritageProps) => { for (const propId of Object.keys(heritageProps)) { @@ -12,7 +13,7 @@ const heritagePropsFormat = async (heritageProps: IHeritageProps) => { fields[propId] = { id: {} } } - const titreEtape = await titreEtapeGet(heritageProps[propId].etapeId!, { fields }, userSuper) + const titreEtape = await titreEtapeGet(newEtapeId(heritageProps[propId].etapeId!), { fields }, userSuper) heritageProps[propId].etape = titreEtape } @@ -27,7 +28,7 @@ const heritageContenuFormat = async (heritageContenu: IHeritageContenu) => { if (heritageContenu[sectionId]) { for (const elementId of Object.keys(heritageContenu[sectionId])) { if (heritageContenu[sectionId][elementId].etapeId) { - const titreEtape = await titreEtapeGet(heritageContenu[sectionId][elementId].etapeId!, { fields }, userSuper) + const titreEtape = await titreEtapeGet(newEtapeId(heritageContenu[sectionId][elementId].etapeId!), { fields }, userSuper) heritageContenu[sectionId][elementId].etape = titreEtape } diff --git a/packages/api/src/database/queries/journaux.ts b/packages/api/src/database/queries/journaux.ts index 984f47ee0..b3c6feb7c 100644 --- a/packages/api/src/database/queries/journaux.ts +++ b/packages/api/src/database/queries/journaux.ts @@ -8,6 +8,7 @@ import { fieldsFormat } from './graph/fields-format.js' import options from './_options.js' import { IJournauxQueryParams } from '../../api/graphql/resolvers/journaux.js' import { User } from 'camino-common/src/roles' +import { TitreId } from 'camino-common/src/titres.js' const diffPatcher = create({ // on filtre certaines proprietés qu’on ne souhaite pas voir apparaitre dans les journaux @@ -91,7 +92,7 @@ export const upsertJournalCreate = async <T extends Model>( options: UpsertGraphOptions, relations: RelationExpression<T>, userId: string, - titreId: string + titreId: TitreId ): Promise<T> => { const oldValue = id ? await model.query().findById(id).withGraphFetched(relations).returning('*') : undefined diff --git a/packages/api/src/database/queries/permissions/documents.test.integration.ts b/packages/api/src/database/queries/permissions/documents.test.integration.ts index e859d510e..26d861680 100644 --- a/packages/api/src/database/queries/permissions/documents.test.integration.ts +++ b/packages/api/src/database/queries/permissions/documents.test.integration.ts @@ -10,7 +10,7 @@ import Document from '../../models/documents.js' import { documentCreate, documentGet } from '../documents.js' import { etapeTypeDocumentTypeUsedCheck } from './documents.js' import { Knex } from 'knex' -import { newDemarcheId, newDocumentId } from '../../models/_format/id-create.js' +import { newDemarcheId, newDocumentId, newEtapeId, newTitreId } from '../../models/_format/id-create.js' import { getCurrent, toCaminoDate } from 'camino-common/src/date.js' import { expect, test, describe, afterAll, beforeAll, vi } from 'vitest' import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts.js' @@ -45,7 +45,7 @@ describe('documentSupprimer', () => { }) await TitresEtapes.query().insertGraph({ - id: 'titreEtapeId', + id: newEtapeId('titreEtapeId'), typeId: 'dpu', titreDemarcheId: newDemarcheId('titreDemarcheId'), date: toCaminoDate('2022-01-01'), @@ -57,7 +57,7 @@ describe('documentSupprimer', () => { id: documentId, typeId: 'dec', date: toCaminoDate('2023-01-12'), - titreEtapeId: 'titreEtapeId', + titreEtapeId: newEtapeId('titreEtapeId'), }) const documentRes = await documentGet(documentId, {}, userSuper) @@ -88,7 +88,7 @@ describe('documentSupprimer', () => { await TitresActivites.query().insertGraph({ id: 'titreActiviteId', typeId: 'grx', - titreId: '', + titreId: newTitreId(''), date: getCurrent(), activiteStatutId, periodeId: 1, @@ -129,7 +129,7 @@ describe('etapeTypeDocumentTypeUsedCheck', () => { }) await TitresEtapes.query().insertGraph({ - id: 'titreEtapeId', + id: newEtapeId('titreEtapeId'), typeId: 'dpu', titreDemarcheId: newDemarcheId('titreDemarcheId'), date: toCaminoDate('2022-01-01'), @@ -141,7 +141,7 @@ describe('etapeTypeDocumentTypeUsedCheck', () => { id: documentId, typeId: 'dec', date: toCaminoDate('2023-01-12'), - titreEtapeId: 'titreEtapeId', + titreEtapeId: newEtapeId('titreEtapeId'), }) const check = await etapeTypeDocumentTypeUsedCheck('dpu', 'dec') @@ -162,7 +162,7 @@ describe('etapeTypeDocumentTypeUsedCheck', () => { }) await TitresEtapes.query().insertGraph({ - id: 'titreEtapeId', + id: newEtapeId('titreEtapeId'), typeId: 'dpu', titreDemarcheId: newDemarcheId('titreDemarcheId'), date: toCaminoDate('2022-01-01'), @@ -174,7 +174,7 @@ describe('etapeTypeDocumentTypeUsedCheck', () => { id: documentId, typeId: 'arr', date: toCaminoDate('2023-01-12'), - titreEtapeId: 'titreEtapeId', + titreEtapeId: newEtapeId('titreEtapeId'), }) const check = await etapeTypeDocumentTypeUsedCheck('dpu', 'dec') diff --git a/packages/api/src/database/queries/permissions/titres-demarches.test.integration.ts b/packages/api/src/database/queries/permissions/titres-demarches.test.integration.ts index af7d0e050..da9f46939 100644 --- a/packages/api/src/database/queries/permissions/titres-demarches.test.integration.ts +++ b/packages/api/src/database/queries/permissions/titres-demarches.test.integration.ts @@ -1,7 +1,7 @@ import { dbManager } from '../../../../tests/db-manager.js' import Titres from '../../models/titres.js' -import { idGenerate, newDemarcheId } from '../../models/_format/id-create.js' +import { newDemarcheId, newTitreId } from '../../models/_format/id-create.js' import { userSuper } from '../../user-super.js' import TitresDemarches from '../../models/titres-demarches.js' import { titreDemarcheSuppressionSelectQuery, titresDemarchesQueryModify } from './titres-demarches.js' @@ -51,7 +51,7 @@ describe('titresDemarchesQueryModify', () => { [{ role: 'defaut' }, false], [undefined, false], ])('un utilisateur $user peut supprimer $suppression une démarche qui n’a pas d’étape', async (user, suppression) => { - const titreId = idGenerate() + const titreId = newTitreId() await Titres.query().insert([ { id: titreId, @@ -107,7 +107,7 @@ describe('titresDemarchesQueryModify', () => { [{ role: 'defaut' }, false], [undefined, false], ])('un utilisateur $role peut supprimer une démarche qui a au moins une étape', async (user, suppression) => { - const titreId = idGenerate() + const titreId = newTitreId() await Titres.query().insert([ { id: titreId, @@ -157,7 +157,7 @@ describe('titresDemarchesQueryModify', () => { }) describe('titresDemarchesArchive', () => { test('Vérifie si le statut archivé masque la démarche du titre', async () => { - const titreId = idGenerate() + const titreId = newTitreId() await Titres.query().insert([ { id: titreId, diff --git a/packages/api/src/database/queries/permissions/titres-etapes.test.integration.ts b/packages/api/src/database/queries/permissions/titres-etapes.test.integration.ts index 7a2538454..41ca6abde 100644 --- a/packages/api/src/database/queries/permissions/titres-etapes.test.integration.ts +++ b/packages/api/src/database/queries/permissions/titres-etapes.test.integration.ts @@ -1,7 +1,7 @@ import { dbManager } from '../../../../tests/db-manager.js' import Titres from '../../models/titres.js' -import { idGenerate, newDemarcheId } from '../../models/_format/id-create.js' +import { newDemarcheId, newEtapeId, newTitreId } from '../../models/_format/id-create.js' import { userSuper } from '../../user-super.js' import TitresEtapes from '../../models/titres-etapes.js' import { titresEtapesQueryModify } from './titres-etapes.js' @@ -22,7 +22,7 @@ afterAll(async () => { describe('titresEtapesQueryModify', () => { describe('titresEtapesArchive', () => { test("Vérifie si le statut archivé masque l'étape de la démarche", async () => { - const titreId = idGenerate() + const titreId = newTitreId() await Titres.query().insert([ { id: titreId, @@ -41,8 +41,8 @@ describe('titresEtapesQueryModify', () => { titreId, archive: false, }) - const titreEtapeId = idGenerate() - const archivedTitreEtapeId = idGenerate() + const titreEtapeId = newEtapeId() + const archivedTitreEtapeId = newEtapeId() await TitresEtapes.query().insert([ { id: titreEtapeId, diff --git a/packages/api/src/database/queries/permissions/titres.test.integration.ts b/packages/api/src/database/queries/permissions/titres.test.integration.ts index c3800462c..a39a91d5f 100644 --- a/packages/api/src/database/queries/permissions/titres.test.integration.ts +++ b/packages/api/src/database/queries/permissions/titres.test.integration.ts @@ -3,7 +3,7 @@ import { IEntreprise, ITitre, ITitreDemarche } from '../../../types.js' import { dbManager } from '../../../../tests/db-manager.js' import Titres from '../../models/titres.js' -import { idGenerate } from '../../models/_format/id-create.js' +import { idGenerate, newDemarcheId, newEtapeId, newTitreId } from '../../models/_format/id-create.js' import { titresArmEnDemandeQuery, titresConfidentielSelect, titresModificationSelectQuery, titresQueryModify, titresVisibleByEntrepriseQuery } from './titres.js' import { userSuper } from '../../user-super.js' import { AdministrationRole } from 'camino-common/src/roles.js' @@ -15,6 +15,7 @@ import { DemarcheStatutId } from 'camino-common/src/static/demarchesStatuts.js' import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts.js' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { testBlankUser, TestUser } from 'camino-common/src/tests-utils' +import { toCaminoDate } from 'camino-common/src/date.js' console.info = vi.fn() console.error = vi.fn() @@ -39,7 +40,9 @@ describe('titresQueryModify', () => { nom: 'monEntrepriseNom', } as IEntreprise - const etapeId = idGenerate() + const id = newTitreId() + const demarcheId = newDemarcheId() + const etapeId = newEtapeId() const mockTitre: Omit<ITitre, 'id'> = { nom: 'titre1', @@ -48,11 +51,14 @@ describe('titresQueryModify', () => { propsTitreEtapesIds: { titulaires: etapeId }, demarches: [ { + id: demarcheId, + titreId: id, typeId: 'oct', etapes: [ { id: etapeId, - date: '2020-01-01', + titreDemarcheId: demarcheId, + date: toCaminoDate('2020-01-01'), typeId: 'mfr', statutId: 'fai', titulaires: withTitulaire ? [mockEntreprise1] : [], @@ -174,9 +180,9 @@ describe('titresQueryModify', () => { nom: 'monEntrepriseNom', } as IEntreprise - const etapeId = idGenerate() - - const id = idGenerate() + const etapeId = newEtapeId() + const demarcheId = newDemarcheId() + const id = newTitreId() const mockTitre: ITitre = { id, @@ -188,12 +194,15 @@ describe('titresQueryModify', () => { propsTitreEtapesIds: { titulaires: etapeId }, demarches: [ { + id: demarcheId, + titreId: id, typeId: 'oct', statutId: 'ins', etapes: [ { id: etapeId, - date: '2020-01-01', + titreDemarcheId: demarcheId, + date: toCaminoDate('2020-01-01'), typeId: 'mcr', statutId: 'fav', titulaires: withTitulaire ? [mockEntreprise1] : [], @@ -294,8 +303,8 @@ describe('titresQueryModify', () => { describe('titresArchive', () => { test('Vérifie si le statut archivé masque le titre', async () => { - const archivedTitreId = idGenerate() - const titreId = idGenerate() + const archivedTitreId = newTitreId() + const titreId = newTitreId() await Titres.query().insert([ { id: archivedTitreId, diff --git a/packages/api/src/database/queries/titres-activites.test.integration.ts b/packages/api/src/database/queries/titres-activites.test.integration.ts index 3f8ac8869..e39bffe13 100644 --- a/packages/api/src/database/queries/titres-activites.test.integration.ts +++ b/packages/api/src/database/queries/titres-activites.test.integration.ts @@ -1,7 +1,7 @@ import { titresActivitesGet } from './titres-activites.js' import TitresActivites from '../models/titres-activites.js' import { dbManager } from '../../../tests/db-manager.js' -import { idGenerate } from '../models/_format/id-create.js' +import { newTitreId } from '../models/_format/id-create.js' import Titres from '../models/titres.js' import { UserNotNull } from 'camino-common/src/roles.js' import { beforeAll, expect, afterAll, test, describe, vi } from 'vitest' @@ -19,11 +19,11 @@ describe('teste les requêtes sur les activités', () => { test('vérifie que le filtrage fonctionne pour les administrations', async () => { await TitresActivites.query().delete() - const titreId = idGenerate() + const titreId = newTitreId() await Titres.query().insert({ id: titreId, - nom: idGenerate(), + nom: titreId, titreStatutId: 'val', typeId: 'arm', }) diff --git a/packages/api/src/database/queries/titres-etapes.ts b/packages/api/src/database/queries/titres-etapes.ts index b4a143021..71c5df1d9 100644 --- a/packages/api/src/database/queries/titres-etapes.ts +++ b/packages/api/src/database/queries/titres-etapes.ts @@ -8,6 +8,8 @@ import TitresEtapesJustificatifs from '../models/titres-etapes-justificatifs.js' import { titresEtapesQueryModify } from './permissions/titres-etapes.js' import { createJournalCreate, patchJournalCreate, upsertJournalCreate } from './journaux.js' import { User, UserNotNull } from 'camino-common/src/roles' +import { TitreId } from 'camino-common/src/titres.js' +import { EtapeId } from 'camino-common/src/etape.js' const titresEtapesQueryBuild = ({ fields }: { fields?: IFields }, user: User) => { const graph = fields ? graphBuild(fields, 'etapes', fieldsFormat) : options.titresEtapes.graph @@ -22,7 +24,7 @@ const titresEtapesQueryBuild = ({ fields }: { fields?: IFields }, user: User) => } // utilisé dans le daily et le resolver des documents uniquement -const titreEtapeGet = async (titreEtapeId: string, { fields, fetchHeritage }: { fields?: IFields; fetchHeritage?: boolean }, user: User) => { +const titreEtapeGet = async (titreEtapeId: EtapeId, { fields, fetchHeritage }: { fields?: IFields; fetchHeritage?: boolean }, user: User) => { const q = titresEtapesQueryBuild({ fields }, user) q.context({ fetchHeritage }) @@ -76,11 +78,11 @@ const titreEtapeCreate = async (titreEtape: Omit<ITitreEtape, 'id'>, user: UserN return newValue } -const titreEtapeUpdate = async (id: string, titreEtape: Partial<DBTitresEtapes>, user: UserNotNull, titreId: string): Promise<TitresEtapes> => { +const titreEtapeUpdate = async (id: EtapeId, titreEtape: Partial<DBTitresEtapes>, user: UserNotNull, titreId: TitreId): Promise<TitresEtapes> => { return patchJournalCreate<TitresEtapes>(id, titreEtape, TitresEtapes, user.id, titreId) } -const titreEtapeUpsert = async (titreEtape: Partial<Pick<ITitreEtape, 'id'>> & Omit<ITitreEtape, 'id'>, user: UserNotNull, titreId: string) => +const titreEtapeUpsert = async (titreEtape: Partial<Pick<ITitreEtape, 'id'>> & Omit<ITitreEtape, 'id'>, user: UserNotNull, titreId: TitreId) => upsertJournalCreate<TitresEtapes>(titreEtape.id, titreEtape, TitresEtapes, options.titresEtapes.update, options.titresEtapes.graph, user.id, titreId) const titresEtapesJustificatifsUpsert = async (titresEtapesJustificatifs: ITitreEtapeJustificatif[]) => diff --git a/packages/api/src/database/queries/titres-titres.ts b/packages/api/src/database/queries/titres-titres.ts index 42c82752b..10cb98706 100644 --- a/packages/api/src/database/queries/titres-titres.ts +++ b/packages/api/src/database/queries/titres-titres.ts @@ -1,8 +1,9 @@ import TitresTitres from '../models/titres--titres.js' +import { TitreId } from 'camino-common/src/titres.js' interface LinkTitre { - linkTo: string - linkFrom: string[] + linkTo: TitreId + linkFrom: TitreId[] } export const linkTitres = async (link: LinkTitre): Promise<void> => { await TitresTitres.query().where('titreToId', link.linkTo).delete() diff --git a/packages/api/src/database/queries/titres.ts b/packages/api/src/database/queries/titres.ts index eb36e9105..eba7f7c5b 100644 --- a/packages/api/src/database/queries/titres.ts +++ b/packages/api/src/database/queries/titres.ts @@ -16,7 +16,7 @@ import { User } from 'camino-common/src/roles' import { DepartementId } from 'camino-common/src/static/departement.js' import { RegionId } from 'camino-common/src/static/region.js' import { FacadesMaritimes } from 'camino-common/src/static/facades.js' -import { EditableTitre } from 'camino-common/src/titres.js' +import { EditableTitre, TitreId } from 'camino-common/src/titres.js' /** * Construit la requête pour récupérer certains champs de titres filtrés @@ -290,9 +290,9 @@ const titreCreate = async (titre: Omit<ITitre, 'id'>, { fields }: { fields?: IFi return Titres.query().withGraphFetched(graph).insertGraph(titre, options.titres.update) } -const titreUpdate = async (id: string, titre: Partial<DBTitre>) => Titres.query().patchAndFetchById(id, { ...titre, id }) +const titreUpdate = async (id: TitreId, titre: Partial<DBTitre>) => Titres.query().patchAndFetchById(id, { ...titre, id }) -export const titreArchive = async (id: string) => { +export const titreArchive = async (id: TitreId) => { // archive le titre await titreUpdate(id, { archive: true }) diff --git a/packages/api/src/knex/migrations/20230607092129_etape-ordre-not-null.ts b/packages/api/src/knex/migrations/20230607092129_etape-ordre-not-null.ts new file mode 100644 index 000000000..f2adbb4aa --- /dev/null +++ b/packages/api/src/knex/migrations/20230607092129_etape-ordre-not-null.ts @@ -0,0 +1,8 @@ +import { Knex } from 'knex' + +export const up = async (knex: Knex) => { + await knex.raw('ALTER TABLE titres_etapes ALTER COLUMN ordre SET NOT NULL') + await knex.raw('ALTER TABLE titres_etapes ALTER COLUMN ordre SET DEFAULT 0') +} + +export const down = () => ({}) diff --git a/packages/api/src/tools/demarches/definitions-check.ts b/packages/api/src/tools/demarches/definitions-check.ts index 6884b02dc..bb2351bf9 100644 --- a/packages/api/src/tools/demarches/definitions-check.ts +++ b/packages/api/src/tools/demarches/definitions-check.ts @@ -2,11 +2,9 @@ import { demarchesDefinitions } from '../../business/rules-demarches/definitions import { titresDemarchesGet } from '../../database/queries/titres-demarches.js' import { titreDemarcheUpdatedEtatValidate } from '../../business/validations/titre-demarche-etat-validate.js' import { userSuper } from '../../database/user-super.js' -import { getCurrent } from 'camino-common/src/date.js' const demarchesValidate = async () => { const errors = [] as string[] - const currentDate = getCurrent() for (const demarcheDefinition of demarchesDefinitions) { for (const demarcheTypeId of demarcheDefinition.demarcheTypeIds) { const demarches = await titresDemarchesGet( @@ -29,7 +27,7 @@ const demarchesValidate = async () => { .filter(demarche => demarche.etapes?.length) .forEach(demarche => { try { - const errs = titreDemarcheUpdatedEtatValidate(currentDate, demarche.type!, demarche.titre!, demarche.etapes![0], demarche.id, demarche.etapes!) + const errs = titreDemarcheUpdatedEtatValidate(demarche.type!, demarche.titre!, demarche.etapes![0], demarche.id, demarche.etapes!) if (errs.length) { errors.push(`https://camino.beta.gouv.fr/titres/${demarche.titreId} => démarche "${demarche.typeId}" : ${errs}`) diff --git a/packages/api/src/tools/demarches/tde-check.ts b/packages/api/src/tools/demarches/tde-check.ts index cbe50e424..a4ead88b9 100644 --- a/packages/api/src/tools/demarches/tde-check.ts +++ b/packages/api/src/tools/demarches/tde-check.ts @@ -1,6 +1,6 @@ import { EtapesTypes } from 'camino-common/src/static/etapesTypes.js' import { isTDEExist } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/index.js' -import { demarcheDefinitionFind, isDemarcheDefinitionMachine } from '../../business/rules-demarches/definitions.js' +import { demarcheDefinitionFind } from '../../business/rules-demarches/definitions.js' import { titresDemarchesGet } from '../../database/queries/titres-demarches.js' import { userSuper } from '../../database/user-super.js' @@ -26,7 +26,7 @@ export const titreTypeDemarcheTypeEtapeTypeCheck = async () => { demarches.forEach(d => { const demarcheDefinition = demarcheDefinitionFind(d.titre!.typeId, d.typeId, d.etapes, d.id) - if (!isDemarcheDefinitionMachine(demarcheDefinition)) { + if (!demarcheDefinition) { 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 ce87bf955..7db76b5b7 100644 --- a/packages/api/src/tools/demarches/tests-creation.ts +++ b/packages/api/src/tools/demarches/tests-creation.ts @@ -4,15 +4,14 @@ import { titresDemarchesGet } from '../../database/queries/titres-demarches.js' import { userSuper } from '../../database/user-super.js' import { titreDemarcheDepotDemandeDateFind } from '../../business/rules/titre-demarche-depot-demande-date-find.js' import { writeFileSync } from 'fs' -import { Etape, toMachineEtapes } from '../../business/rules-demarches/machine-common.js' -import { demarchesDefinitions, isDemarcheDefinitionMachine } from '../../business/rules-demarches/definitions.js' +import { Etape, titreEtapeForMachineValidator, toMachineEtapes } from '../../business/rules-demarches/machine-common.js' +import { demarchesDefinitions } from '../../business/rules-demarches/definitions.js' import { dateAddDays, daysBetween, setDayInMonth } from 'camino-common/src/date.js' import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes.js' +import { toCommuneId } from 'camino-common/src/static/communes.js' const writeEtapesForTest = async () => { - const demarcheDefinitionMachines = demarchesDefinitions.filter(isDemarcheDefinitionMachine) - - for (const demarcheDefinition of demarcheDefinitionMachines) { + for (const demarcheDefinition of demarchesDefinitions) { const demarches = await titresDemarchesGet( { titresTypesIds: [demarcheDefinition.titreTypeId.slice(0, 2)], @@ -22,7 +21,7 @@ const writeEtapesForTest = async () => { { fields: { titre: { id: {}, demarches: { etapes: { id: {} } } }, - etapes: { id: {} }, + etapes: { communes: { id: {} } }, type: { etapesTypes: { id: {} } }, }, }, @@ -36,39 +35,25 @@ const writeEtapesForTest = async () => { return (date ?? '') > demarcheDefinition.dateDebut && !demarcheDefinition.demarcheIdExceptions?.includes(demarche.id) }) - .filter(({ titreId }) => { - if ( - [ - // décision du propriétaire du sol avant le dépôt de la demande - 'EI4lAxLbhdFOoHb6LWL0y9pO', - 'e8ZYqaA9HB3bXuOeRlXz5g76', - // visibilité publique - 'z0DZo6TKEvP28D6oQyAuTvwA', - 'RGOrc6hTOErMD8SBkUChbTyg', - '8KsDiNBHR9lAHv229GIqA7fw', - '8pY4eoUKtuR3is8l3Vy0vmJC', - ].includes(titreId) - ) { - console.info('On ignore le titre ' + titreId) - - return false - } - - return true - }) .map((demarche, index) => { const etapes: Etape[] = toMachineEtapes( - demarche?.etapes - ?.sort((a, b) => (a.ordre ?? 0) - (b.ordre ?? 0)) - ?.map(etape => { - if (etape?.contenu?.arm) { - etape.contenu = { arm: etape.contenu?.arm } - } else { - delete etape.contenu - } + ( + demarche?.etapes + ?.sort((a, b) => (a.ordre ?? 0) - (b.ordre ?? 0)) + ?.map(etape => { + if (etape?.contenu?.arm) { + etape.contenu = { arm: etape.contenu?.arm } + } else { + delete etape.contenu + } + + if (etape.communes?.length) { + etape.communes = etape.communes.map(({ id }) => ({ nom: '', id: toCommuneId(`${id.startsWith('97') ? `${id.substring(0, 3)}00` : `${id.substring(0, 2)}000`}}`) })) + } - return etape - }) ?? [] + return etape + }) ?? [] + ).map(etape => titreEtapeForMachineValidator.parse(etape)) ) // Pour anonymiser la date en gardant les délai en mois entre la saisine et l'apd, // on trouve la date de saisine et on calcule un delta random pour tomber dans le même mois diff --git a/packages/api/src/tools/documents/files-document-check.ts b/packages/api/src/tools/documents/files-document-check.ts index 085834ba4..b773eb6ab 100644 --- a/packages/api/src/tools/documents/files-document-check.ts +++ b/packages/api/src/tools/documents/files-document-check.ts @@ -5,6 +5,7 @@ import { titreEtapeGet } from '../../database/queries/titres-etapes.js' import { userSuper } from '../../database/user-super.js' import { contenuFilesGet } from '../../business/utils/contenu-element-file-process.js' import { getSections } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' +import { newEtapeId } from '../../database/models/_format/id-create.js' const etapeGet = (str: string) => str.split('-').slice(0, -1).join('-') @@ -14,7 +15,7 @@ const contenuFilesCheck = async (filePath: string) => { const split = filePath.split('/') const repertoire = split[0] - const etapeId = split[1] + const etapeId = newEtapeId(split[1]) const fileName = split[2] if (repertoire !== 'demarches') { diff --git a/packages/api/src/tools/geojson.ts b/packages/api/src/tools/geojson.ts index 8e58d904d..31e35ceee 100644 --- a/packages/api/src/tools/geojson.ts +++ b/packages/api/src/tools/geojson.ts @@ -7,6 +7,7 @@ import { knex } from '../knex.js' import { SDOMZoneId } from 'camino-common/src/static/sdom.js' import { SecteursMaritimesIds } from 'camino-common/src/static/facades.js' import { Feature } from 'geojson' +import { CommuneId } from 'camino-common/src/static/communes.js' // convertit des points // en un geojson de type 'MultiPolygon' @@ -155,8 +156,8 @@ export const geojsonIntersectsSecteursMaritime = async (geojson: Feature<any>): return { fallback, data: result.rows.map(({ id }) => id) } } -export const geojsonIntersectsCommunes = async (geojson: Feature<any>): Promise<GeoJsonResult<{ id: string; surface: number }[]>> => { - let result: { rows: { id: string; surface: string }[] } +export const geojsonIntersectsCommunes = async (geojson: Feature<any>): Promise<GeoJsonResult<{ id: CommuneId; surface: number }[]>> => { + let result: { rows: { id: CommuneId; surface: string }[] } let fallback = false try { result = await knex.raw( diff --git a/packages/api/src/tools/phases/tests-creation.ts b/packages/api/src/tools/phases/tests-creation.ts index 900fdd230..77ccb9319 100644 --- a/packages/api/src/tools/phases/tests-creation.ts +++ b/packages/api/src/tools/phases/tests-creation.ts @@ -11,7 +11,7 @@ import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts.js' import { EtapeTypeId } from 'camino-common/src/static/etapesTypes.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { DemarcheId } from 'camino-common/src/demarche.js' -import { idGenerate, newDemarcheId } from '../../database/models/_format/id-create.js' +import { newDemarcheId, newTitreId } from '../../database/models/_format/id-create.js' import { TitreDemarchePhaseFind, TitreEtapePhaseFind } from '../../business/rules/titre-phases-find.js' const writePhasesForTest = async () => { @@ -62,7 +62,7 @@ const writePhasesForTest = async () => { } const fakeDemarcheId = newDemarcheId() - const fakeTitreId = idGenerate() + const fakeTitreId = newTitreId() const etapes: TitreEtapePhaseFind[] = etapesDb.rows .filter(({ titre_demarche_id }) => titre_demarche_id === row.id) diff --git a/packages/api/src/types.ts b/packages/api/src/types.ts index 03047efcc..16baa5d57 100644 --- a/packages/api/src/types.ts +++ b/packages/api/src/types.ts @@ -30,6 +30,8 @@ import { Section, SectionsElement } from 'camino-common/src/static/titresTypes_d import { ActivitesTypesId } from 'camino-common/src/static/activitesTypes.js' import { CommuneId } from 'camino-common/src/static/communes.js' import { ForetId } from 'camino-common/src/static/forets.js' +import { TitreId } from 'camino-common/src/titres.js' +import { EtapeId } from 'camino-common/src/etape' enum TitreEtapesTravauxTypes { DemandeAutorisationOuverture = 'wfa', @@ -347,12 +349,12 @@ interface IAdministrationActiviteTypeEmail { } export interface ITitreTitre { - titreFromId: string - titreToId: string + titreFromId: TitreId + titreToId: TitreId } interface ITitre { - id: string + id: TitreId slug?: string nom: string typeId: TitreTypeId @@ -394,7 +396,7 @@ interface ITitre { interface ITitreActivite { id: string slug?: string - titreId: string + titreId: TitreId titre?: ITitre | null date: CaminoDate typeId: string @@ -422,7 +424,7 @@ interface ITitreDemarche { id: DemarcheId description?: string slug?: string - titreId: string + titreId: TitreId titre?: ITitre | null typeId: DemarcheTypeId statutId?: DemarcheStatutId | null @@ -457,7 +459,7 @@ interface IDocument { nor?: string | null publicLecture?: boolean | null entreprisesLecture?: boolean | null - titreEtapeId?: string | null + titreEtapeId?: EtapeId | null etape?: ITitreEtape | null titreActiviteId?: string | null activite?: ITitreActivite | null @@ -466,7 +468,7 @@ interface IDocument { suppression?: boolean | null } interface ITitreEtape { - id: string + id: EtapeId slug?: string typeId: EtapeTypeId type?: IEtapeType | null diff --git a/packages/api/tests/_utils/administrations-permissions.ts b/packages/api/tests/_utils/administrations-permissions.ts index 869fd0bb3..61d754c83 100644 --- a/packages/api/tests/_utils/administrations-permissions.ts +++ b/packages/api/tests/_utils/administrations-permissions.ts @@ -7,7 +7,7 @@ import DemarchesTypes from '../../src/database/models/demarches-types.js' import options from '../../src/database/queries/_options.js' import { etapeTypeGet } from '../../src/database/queries/metas.js' import { titreEtapePropsIds } from '../../src/business/utils/titre-etape-heritage-props-find.js' -import { newDemarcheId, newDocumentId } from '../../src/database/models/_format/id-create.js' +import { newDemarcheId, newDocumentId, newTitreId, newEtapeId } from '../../src/database/models/_format/id-create.js' import { TitreTypeId } from 'camino-common/src/static/titresTypes.js' import { getDocuments } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/documents.js' import { documentCreate } from '../../src/database/queries/documents.js' @@ -19,6 +19,7 @@ import { AdministrationId, sortedAdministrations } from 'camino-common/src/stati import { TestUser } from 'camino-common/src/tests-utils.js' import type { Pool } from 'pg' import { getSections } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections.js' +import { TitreId } from 'camino-common/src/titres.js' export const visibleCheck = async ( pool: Pool, administrationId: AdministrationId, @@ -36,7 +37,7 @@ export const visibleCheck = async ( const titre = titreBuild( { - titreId: `${titreTypeId}${locale ? '-local' : ''}-${cible}-admin-${administrationId}`, + titreId: newTitreId(`${titreTypeId}${locale ? '-local' : ''}-${cible}-admin-${administrationId}`), titreTypeId, }, gestionnaire ? administrationId : undefined, @@ -272,7 +273,7 @@ export const modificationCheck = async ( const titre = titreBuild( { - titreId: `${titreTypeId}${locale ? '-local' : ''}${etapeTypeId}-${cible}-modification-admin-${administrationId}`, + titreId: newTitreId(`${titreTypeId}${locale ? '-local' : ''}${etapeTypeId}-${cible}-modification-admin-${administrationId}`), titreTypeId, }, gestionnaire ? administrationId : undefined, @@ -348,7 +349,7 @@ const titreBuild = ( titreId, titreTypeId, }: { - titreId: string + titreId: TitreId titreTypeId: TitreTypeId }, administrationIdGestionnaire?: AdministrationId, @@ -368,7 +369,7 @@ const titreBuild = ( typeId: 'oct', etapes: [ { - id: `${titreId}-demarche-id-etape-id`, + id: newEtapeId(`${titreId}-demarche-id-etape-id`), typeId: etapeTypeId || 'mcr', ordre: 0, titreDemarcheId: newDemarcheId(`${titreId}-demarche-id`), diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 6e25e5c97..2e93e11d8 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "allowJs": true, + "allowJs": false, "allowSyntheticDefaultImports": true, "alwaysStrict": true, "esModuleInterop": true, diff --git a/packages/common/src/demarche.ts b/packages/common/src/demarche.ts index 4c919083f..554e7d55e 100644 --- a/packages/common/src/demarche.ts +++ b/packages/common/src/demarche.ts @@ -1,12 +1,13 @@ import { z } from 'zod' import { demarcheTypeIdValidator } from './static/demarchesTypes.js' +import { titreIdValidator } from './titres.js' export const demarcheIdValidator = z.string().brand<'DemarcheId'>() export type DemarcheId = z.infer<typeof demarcheIdValidator> export const commonDemarcheValidator = z.object({ id: z.string(), - titre_id: z.string(), + titre_id: titreIdValidator, type_id: demarcheTypeIdValidator, }) export type CommonDemarche = z.infer<typeof commonDemarcheValidator> diff --git a/packages/common/src/etape.ts b/packages/common/src/etape.ts index 81b9a1cfa..7c7e81cd6 100644 --- a/packages/common/src/etape.ts +++ b/packages/common/src/etape.ts @@ -9,6 +9,9 @@ import { EtapeTypeId, etapeTypeIdValidator } from './static/etapesTypes.js' import { SubstanceLegaleId } from './static/substancesLegales.js' import { z } from 'zod' +export const etapeIdValidator = z.string().brand<'EtapeId'>() +export type EtapeId = z.infer<typeof etapeIdValidator> + export type HeritageProp<T> = | { actif: true @@ -26,7 +29,7 @@ export interface CaminoDocument { } type EtapeBase = { - id: string + id: EtapeId contenu: { [key: string]: unknown } date: CaminoDate type: { id: EtapeTypeId; nom: string } diff --git a/packages/common/src/rest.ts b/packages/common/src/rest.ts index 6933bfc0e..6e7762537 100644 --- a/packages/common/src/rest.ts +++ b/packages/common/src/rest.ts @@ -16,6 +16,7 @@ import { sectionValidator, titreDrealValidator, titreGetValidator, + titreIdValidator, titreLinksValidator, titreOnfValidator, titrePtmgValidator, @@ -23,7 +24,7 @@ import { } from './titres.js' import { userValidator } from './roles.js' import { caminoAnneeValidator, caminoDateValidator } from './date.js' -import { etapeTypeEtapeStatutWithMainStepValidator } from './etape.js' +import { etapeIdValidator, etapeTypeEtapeStatutWithMainStepValidator } from './etape.js' import { statistiquesDGTMValidator, statistiquesGranulatsMarinsValidator, statistiquesGuyaneDataValidator, statistiquesMinerauxMetauxMetropoleValidator } from './statistiques.js' import { fiscaliteValidator } from './fiscalite.js' import { caminoConfigValidator } from './static/config.js' @@ -94,16 +95,16 @@ export const CaminoRestRoutes = { '/rest/statistiques/minerauxMetauxMetropole': { get: { output: statistiquesMinerauxMetauxMetropoleValidator } }, '/rest/statistiques/guyane': { get: { output: statistiquesGuyaneDataValidator } }, '/rest/statistiques/granulatsMarins': { get: { output: statistiquesGranulatsMarinsValidator } }, - '/rest/titreSections/:titreId': { params: { titreId: z.string() }, get: { output: z.array(sectionValidator) } }, + '/rest/titreSections/:titreId': { params: { titreId: titreIdValidator }, get: { output: z.array(sectionValidator) } }, '/rest/demarches/:demarcheId': { params: { demarcheId: demarcheIdValidator }, get: { output: demarcheGetValidator } }, - '/rest/titres/:titreId': { params: { titreId: z.string() }, get: { output: titreGetValidator }, delete: true, post: { output: z.void(), input: editableTitreValidator } }, - '/rest/titres/:titreId/abonne': { params: { titreId: z.string() }, post: { input: utilisateurTitreAbonneValidator, output: z.void() } }, - '/rest/titres/:titreId/date': { params: { titreId: z.string() }, get: { output: caminoDateValidator.nullable() } }, + '/rest/titres/:titreId': { params: { titreId: titreIdValidator }, get: { output: titreGetValidator }, delete: true, post: { output: z.void(), input: editableTitreValidator } }, + '/rest/titres/:titreId/abonne': { params: { titreId: titreIdValidator }, post: { input: utilisateurTitreAbonneValidator, output: z.void() } }, + '/rest/titres/:titreId/date': { params: { titreId: titreIdValidator }, get: { output: caminoDateValidator.nullable() } }, '/rest/titresONF': { get: { output: z.array(titreOnfValidator) } }, '/rest/titresPTMG': { get: { output: z.array(titrePtmgValidator) } }, '/rest/titresDREAL': { get: { output: z.array(titreDrealValidator) } }, - '/rest/titres/:id/titreLiaisons': { params: { id: z.string() }, get: { output: titreLinksValidator }, post: { input: z.array(z.string()), output: titreLinksValidator } }, - '/rest/titres/:id/communes': { params: { id: z.string() }, get: { output: z.array(communeValidator) } }, + '/rest/titres/:id/titreLiaisons': { params: { id: titreIdValidator }, get: { output: titreLinksValidator }, post: { input: z.array(z.string()), output: titreLinksValidator } }, + '/rest/titres/:id/communes': { params: { id: titreIdValidator }, get: { output: z.array(communeValidator) } }, '/rest/statistiques/dgtm': { get: { output: statistiquesDGTMValidator } }, '/rest/entreprises/:entrepriseId/fiscalite/:annee': { params: { entrepriseId: entrepriseIdValidator, annee: caminoAnneeValidator }, get: { output: fiscaliteValidator } }, @@ -126,14 +127,14 @@ export const CaminoRestRoutes = { '/changerMotDePasse': { get: { output: z.string() } }, '/download/fichiers/:documentId': { params: { documentId: documentIdValidator }, download: true }, '/fichiers/:documentId': { params: { documentId: documentIdValidator }, download: true }, - '/titres/:id': { params: { id: z.string() }, download: true }, + '/titres/:id': { params: { id: titreIdValidator }, download: true }, '/titres': { download: true }, '/titres_qgis': { download: true }, '/demarches': { download: true }, '/activites': { download: true }, '/utilisateurs': { download: true }, - '/etape/zip/:etapeId': { params: { etapeId: z.string() }, download: true }, - '/etape/:etapeId/:fichierNom': { params: { etapeId: z.string(), fichierNom: z.string() }, download: true }, + '/etape/zip/:etapeId': { params: { etapeId: etapeIdValidator }, download: true }, + '/etape/:etapeId/:fichierNom': { params: { etapeId: etapeIdValidator, fichierNom: z.string() }, download: true }, '/entreprises': { download: true }, } as const satisfies { [k in CaminoRestRoute]: CaminoRoute<k> } diff --git a/packages/common/src/static/demarchesStatuts.ts b/packages/common/src/static/demarchesStatuts.ts index 44dda458c..6cca05f41 100644 --- a/packages/common/src/static/demarchesStatuts.ts +++ b/packages/common/src/static/demarchesStatuts.ts @@ -1,6 +1,8 @@ import { Definition } from '../definition.js' import { Couleur } from './couleurs.js' +import { z } from 'zod' +const IDS = ['acc', 'cls', 'dep', 'des', 'eco', 'fpm', 'ind', 'ini', 'ins', 'rej', 'ter'] as const export const DemarchesStatutsIds = { Accepte: 'acc', ClasseSansSuite: 'cls', @@ -13,9 +15,10 @@ export const DemarchesStatutsIds = { EnInstruction: 'ins', Rejete: 'rej', Termine: 'ter', -} as const +} as const satisfies Record<string, (typeof IDS)[number]> -export type DemarcheStatutId = (typeof DemarchesStatutsIds)[keyof typeof DemarchesStatutsIds] +export const demarcheStatutIdValidator = z.enum(IDS) +export type DemarcheStatutId = z.infer<typeof demarcheStatutIdValidator> export type DemarcheStatut<T = DemarcheStatutId> = Definition<T> & { couleur: Couleur } diff --git a/packages/common/src/static/pays.test.ts b/packages/common/src/static/pays.test.ts index 6192e44e0..57383aea6 100644 --- a/packages/common/src/static/pays.test.ts +++ b/packages/common/src/static/pays.test.ts @@ -1,4 +1,4 @@ -import { isPaysId, PAYS_IDS } from './pays.js' +import { isGuyane, isMetropole, isOutreMer, isPaysId, PAYS_IDS } from './pays.js' import { test, expect } from 'vitest' test('isPaysId', () => { @@ -11,3 +11,24 @@ test('isPaysId', () => { expect(isPaysId(paysId.toLowerCase())).toBe(false) }) }) + +test('isOutreMer', () => { + expect(isOutreMer('FR')).toBe(false) + expect(isOutreMer(null)).toBe(false) + expect(isOutreMer('GF')).toBe(true) + expect(isOutreMer('XX')).toBe(true) +}) + +test('isGuyane', () => { + expect(isGuyane('FR')).toBe(false) + expect(isGuyane(null)).toBe(false) + expect(isGuyane('GF')).toBe(true) + expect(isGuyane('XX')).toBe(false) +}) + +test('isMetropole', () => { + expect(isMetropole('FR')).toBe(true) + expect(isMetropole(null)).toBe(false) + expect(isMetropole('GF')).toBe(false) + expect(isMetropole('XX')).toBe(false) +}) diff --git a/packages/common/src/static/pays.ts b/packages/common/src/static/pays.ts index 9e15c200d..6a8985113 100644 --- a/packages/common/src/static/pays.ts +++ b/packages/common/src/static/pays.ts @@ -46,3 +46,7 @@ export const PaysList: { [key in PaysId]: Pays<key> } = { } export const isPaysId = (value: string): value is PaysId => paysIdValidator.safeParse(value).success + +export const isGuyane = (pays: PaysId | null): boolean => pays === 'GF' +export const isMetropole = (pays: PaysId | null): boolean => pays === 'FR' +export const isOutreMer = (pays: PaysId | null): boolean => pays !== null && !isMetropole(pays) diff --git a/packages/common/src/titres.ts b/packages/common/src/titres.ts index 44e4d63cd..5c9149ed5 100644 --- a/packages/common/src/titres.ts +++ b/packages/common/src/titres.ts @@ -19,8 +19,11 @@ import { deviseIdValidator } from './static/devise.js' import { z } from 'zod' import { administrationIdValidator } from './static/administrations.js' +export const titreIdValidator = z.string().brand<'TitreId'>() +export type TitreId = z.infer<typeof titreIdValidator> + export const commonTitreValidator = z.object({ - id: z.string(), + id: titreIdValidator, nom: z.string(), slug: z.string(), type_id: titreTypeIdValidator, @@ -36,7 +39,7 @@ export const commonTitreValidator = z.object({ /** @deprecated use CommonRestTitre */ export interface CommonTitre { - id: string + id: TitreId nom: string slug: string typeId: TitreTypeId diff --git a/packages/ui/src/components/_common/perimetre.stories.tsx b/packages/ui/src/components/_common/perimetre.stories.tsx index c4ec5c227..98d50fc75 100644 --- a/packages/ui/src/components/_common/perimetre.stories.tsx +++ b/packages/ui/src/components/_common/perimetre.stories.tsx @@ -4,6 +4,7 @@ import { MapPattern } from '../_map/pattern' import { Perimetre } from './perimetre' import { MultiPolygon, Feature } from 'geojson' import { Point } from '@/utils/titre-etape-edit' +import { titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Common/Perimetre', @@ -112,13 +113,13 @@ const tabUpdate = action('tabUpdate') export const DefaultNoSnapshot: StoryFn = () => ( <> <MapPattern /> - <Perimetre titreTypeId="axm" points={points} geojsonMultiPolygon={geojsonMultiPolygon} titreId="id" tabUpdate={tabUpdate} /> + <Perimetre titreTypeId="axm" points={points} geojsonMultiPolygon={geojsonMultiPolygon} titreId={titreIdValidator.parse('id')} tabUpdate={tabUpdate} /> </> ) export const NoMap: StoryFn = () => ( <> <MapPattern /> - <Perimetre titreTypeId="axm" geojsonMultiPolygon={geojsonMultiPolygon} titreId="id" tabUpdate={tabUpdate} /> + <Perimetre titreTypeId="axm" geojsonMultiPolygon={geojsonMultiPolygon} titreId={titreIdValidator.parse('id')} tabUpdate={tabUpdate} /> </> ) diff --git a/packages/ui/src/components/_common/perimetre.tsx b/packages/ui/src/components/_common/perimetre.tsx index 4874f3ff6..fea7ac083 100644 --- a/packages/ui/src/components/_common/perimetre.tsx +++ b/packages/ui/src/components/_common/perimetre.tsx @@ -6,13 +6,14 @@ import { Icon as IconSprite } from '../_ui/iconSpriteType' import { Download } from './download' import { CamionCommonMap, Props as CaminoCommonMapProps } from './map' import { Points } from './points' +import { TitreId } from 'camino-common/src/titres' export type TabId = 'carte' | 'points' export interface Props { points?: Point[] geojsonMultiPolygon: CaminoCommonMapProps['geojson'] titreTypeId: TitreTypeId - titreId?: string + titreId?: TitreId isMain?: boolean tabId?: TabId tabUpdate: (tabId: TabId) => void diff --git a/packages/ui/src/components/dashboard/pure-onf-dashboard.stories.tsx b/packages/ui/src/components/dashboard/pure-onf-dashboard.stories.tsx index ddaa29459..305949394 100644 --- a/packages/ui/src/components/dashboard/pure-onf-dashboard.stories.tsx +++ b/packages/ui/src/components/dashboard/pure-onf-dashboard.stories.tsx @@ -1,6 +1,6 @@ import { PureONFDashboard } from './pure-onf-dashboard' import { Meta, StoryFn } from '@storybook/vue3' -import { CommonTitreONF } from 'camino-common/src/titres' +import { CommonTitreONF, titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Dashboard/ONF', @@ -13,7 +13,7 @@ export default meta const onfs: CommonTitreONF[] = [ { - id: 'firstId', + id: titreIdValidator.parse('firstId'), slug: 'first-id-slug', nom: 'first-name', titre_statut_id: 'dmi', @@ -30,7 +30,7 @@ const onfs: CommonTitreONF[] = [ enAttenteDeONF: true, }, { - id: 'secondId', + id: titreIdValidator.parse('secondId'), slug: 'second-slug', nom: 'Second Nom de titre', titre_statut_id: 'dmi', @@ -53,7 +53,7 @@ const onfs: CommonTitreONF[] = [ enAttenteDeONF: true, }, { - id: 'thirdId', + id: titreIdValidator.parse('thirdId'), slug: 'third-id-slug', nom: 'third-name', titre_statut_id: 'dmi', @@ -70,7 +70,7 @@ const onfs: CommonTitreONF[] = [ enAttenteDeONF: false, }, { - id: 'fourthId', + id: titreIdValidator.parse('fourthId'), slug: 'fourth-slug', nom: 'Quatrième Nom de titre', titre_statut_id: 'dmi', diff --git a/packages/ui/src/components/dashboard/pure-ptmg-dashboard.stories.tsx b/packages/ui/src/components/dashboard/pure-ptmg-dashboard.stories.tsx index f522e1d36..114411362 100644 --- a/packages/ui/src/components/dashboard/pure-ptmg-dashboard.stories.tsx +++ b/packages/ui/src/components/dashboard/pure-ptmg-dashboard.stories.tsx @@ -1,6 +1,6 @@ import { PurePTMGDashboard } from './pure-ptmg-dashboard' import { Meta, StoryFn } from '@storybook/vue3' -import { CommonTitrePTMG } from 'camino-common/src/titres' +import { CommonTitrePTMG, titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Dashboard/PTMG', @@ -10,7 +10,7 @@ export default meta const titres: CommonTitrePTMG[] = [ { - id: 'firstId', + id: titreIdValidator.parse('firstId'), slug: 'first-id-slug', nom: 'first-name', titre_statut_id: 'dmi', @@ -24,7 +24,7 @@ const titres: CommonTitrePTMG[] = [ enAttenteDePTMG: true, }, { - id: 'secondId', + id: titreIdValidator.parse('secondId'), slug: 'second-slug', nom: 'Second Nom de titre', titre_statut_id: 'dmi', @@ -44,7 +44,7 @@ const titres: CommonTitrePTMG[] = [ enAttenteDePTMG: true, }, { - id: 'thirdId', + id: titreIdValidator.parse('thirdId'), slug: 'third-id-slug', nom: 'third-name', titre_statut_id: 'dmi', @@ -58,7 +58,7 @@ const titres: CommonTitrePTMG[] = [ enAttenteDePTMG: false, }, { - id: 'fourthId', + id: titreIdValidator.parse('fourthId'), slug: 'fourth-slug', nom: 'Quatrième Nom de titre', titre_statut_id: 'dmi', diff --git a/packages/ui/src/components/dashboard/testData.ts b/packages/ui/src/components/dashboard/testData.ts index 2da21bb1e..79bc6675a 100644 --- a/packages/ui/src/components/dashboard/testData.ts +++ b/packages/ui/src/components/dashboard/testData.ts @@ -1,11 +1,11 @@ import { toCaminoDate, toCaminoAnnee } from 'camino-common/src/date' import { ETAPES_TYPES } from 'camino-common/src/static/etapesTypes' import { StatistiquesDGTM } from 'camino-common/src/statistiques' -import { CommonTitreDREAL } from 'camino-common/src/titres' +import { CommonTitreDREAL, titreIdValidator } from 'camino-common/src/titres' export const titresDreal: CommonTitreDREAL[] = [ { - id: 'firstId', + id: titreIdValidator.parse('firstId'), slug: 'first-id-slug', nom: 'first-name', type_id: 'prm', @@ -23,7 +23,7 @@ export const titresDreal: CommonTitreDREAL[] = [ derniereEtape: { date: toCaminoDate('2022-01-01'), etapeTypeId: 'mcr' }, }, { - id: 'secondId', + id: titreIdValidator.parse('secondId'), slug: 'second-slug', nom: 'Second Nom de titre', type_id: 'prm', @@ -47,7 +47,7 @@ export const titresDreal: CommonTitreDREAL[] = [ derniereEtape: { date: toCaminoDate('2022-01-01'), etapeTypeId: 'mcr' }, }, { - id: 'thirdId', + id: titreIdValidator.parse('thirdId'), slug: 'third-id-slug', nom: 'third-name', type_id: 'prm', @@ -65,7 +65,7 @@ export const titresDreal: CommonTitreDREAL[] = [ derniereEtape: { date: toCaminoDate('2022-01-01'), etapeTypeId: 'mcr' }, }, { - id: 'fourthId', + id: titreIdValidator.parse('fourthId'), slug: 'fourth-slug', nom: 'Quatrième Nom de titre', type_id: 'arc', diff --git a/packages/ui/src/components/etape/fondamentales-edit.stories.ts b/packages/ui/src/components/etape/fondamentales-edit.stories.ts index 622c8a66f..d51aa86e8 100644 --- a/packages/ui/src/components/etape/fondamentales-edit.stories.ts +++ b/packages/ui/src/components/etape/fondamentales-edit.stories.ts @@ -1,6 +1,6 @@ import { FondamentalesEdit, Props } from './fondamentales-edit' import { Meta, StoryFn } from '@storybook/vue3' -import { EtapeFondamentale } from 'camino-common/src/etape' +import { EtapeFondamentale, etapeIdValidator } from 'camino-common/src/etape' import { newEntrepriseId } from 'camino-common/src/entreprise' import { toCaminoDate } from 'camino-common/src/date' import { testBlankUser } from 'camino-common/src/tests-utils' @@ -13,7 +13,7 @@ const meta: Meta = { export default meta const etape: EtapeFondamentale = { - id: 'id', + id: etapeIdValidator.parse('id'), type: { id: 'mfr', nom: 'demande', diff --git a/packages/ui/src/components/titre/edit-popup.stories.tsx b/packages/ui/src/components/titre/edit-popup.stories.tsx index e4ecaa01b..ce42f643a 100644 --- a/packages/ui/src/components/titre/edit-popup.stories.tsx +++ b/packages/ui/src/components/titre/edit-popup.stories.tsx @@ -1,6 +1,7 @@ import { EditPopup } from './edit-popup' import { Meta, StoryFn } from '@storybook/vue3' import { action } from '@storybook/addon-actions' +import { titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Titre/EditPopup', @@ -15,7 +16,7 @@ const close = action('close') export const DefaultNoReference: StoryFn = () => ( <EditPopup titre={{ - id: 'id', + id: titreIdValidator.parse('id'), nom: 'Nom du titre', references: [], }} @@ -30,7 +31,7 @@ export const DefaultNoReference: StoryFn = () => ( export const OneReference: StoryFn = () => ( <EditPopup titre={{ - id: 'id', + id: titreIdValidator.parse('id'), nom: 'Nom du titre', references: [{ nom: 'RefValue', referenceTypeId: 'brg' }], }} diff --git a/packages/ui/src/components/titre/header.stories.tsx b/packages/ui/src/components/titre/header.stories.tsx index bbfeed6e1..4abe98f37 100644 --- a/packages/ui/src/components/titre/header.stories.tsx +++ b/packages/ui/src/components/titre/header.stories.tsx @@ -4,6 +4,7 @@ import { action } from '@storybook/addon-actions' import { testBlankUser } from 'camino-common/src/tests-utils' import { TitreApiClient } from './titre-api-client' import { toCaminoDate } from 'camino-common/src/date' +import { titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Titre/Header', @@ -39,7 +40,7 @@ const apiClientMock: Pick<TitreApiClient, 'titreUtilisateurAbonne' | 'editTitre' export const Default: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [], abonnement: false, modification: false, @@ -55,7 +56,7 @@ export const Default: StoryFn = () => ( export const AbonneAuTitre: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [], abonnement: true, modification: false, @@ -71,7 +72,7 @@ export const AbonneAuTitre: StoryFn = () => ( export const CanDeleteTitre: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [], abonnement: false, modification: false, @@ -87,7 +88,7 @@ export const CanDeleteTitre: StoryFn = () => ( export const CanEditTitre: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [{ nom: 'cette-ref', referenceTypeId: 'brg' }], abonnement: false, modification: true, @@ -103,7 +104,7 @@ export const CanEditTitre: StoryFn = () => ( export const Loading: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [{ nom: 'cette-ref', referenceTypeId: 'brg' }], abonnement: false, modification: true, @@ -124,7 +125,7 @@ export const Loading: StoryFn = () => ( export const WithError: StoryFn = () => ( <PureHeader titre={{ - id: 'id', + id: titreIdValidator.parse('id'), references: [{ nom: 'cette-ref', referenceTypeId: 'brg' }], abonnement: false, modification: true, diff --git a/packages/ui/src/components/titre/header.tsx b/packages/ui/src/components/titre/header.tsx index 2b22b16f0..ad916135b 100644 --- a/packages/ui/src/components/titre/header.tsx +++ b/packages/ui/src/components/titre/header.tsx @@ -3,7 +3,7 @@ import { canDeleteTitre } from 'camino-common/src/permissions/titres' import { User } from 'camino-common/src/roles' import { ReferenceTypeId } from 'camino-common/src/static/referencesTypes' import { TitreTypeId } from 'camino-common/src/static/titresTypes' -import { EditableTitre } from 'camino-common/src/titres' +import { EditableTitre, TitreId } from 'camino-common/src/titres' import { computed, ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useStore } from 'vuex' @@ -17,7 +17,7 @@ import { LoadingElement } from '../_ui/functional-loader' interface Props { titre: { - id: string + id: TitreId nom: string typeId: TitreTypeId abonnement: boolean @@ -73,7 +73,7 @@ export const Header = caminoDefineComponent<Props>(['titre', 'titreEventTrack'], store.dispatch('messageAdd', { value: 'le titre a été mis à jour', type: 'success' }, { root: true }) } - const abonne = async (titreId: string, abonner: boolean) => { + const abonne = async (titreId: TitreId, abonner: boolean) => { await titreApiClient.titreUtilisateurAbonne(titreId, abonner) store.commit('titre/set', { ...props.titre, abonnement: abonner }) diff --git a/packages/ui/src/components/titre/infos.stories.tsx b/packages/ui/src/components/titre/infos.stories.tsx index 8f36107cf..601e5af2d 100644 --- a/packages/ui/src/components/titre/infos.stories.tsx +++ b/packages/ui/src/components/titre/infos.stories.tsx @@ -1,8 +1,10 @@ import { Meta, StoryFn } from '@storybook/vue3' import { Infos, Props } from './infos' -import { Section, TitreLink, TitreLinks } from 'camino-common/src/titres' +import { Section, TitreId, TitreLink, TitreLinks, titreIdValidator } from 'camino-common/src/titres' import { testBlankUser } from 'camino-common/src/tests-utils' import { toCaminoDate } from 'camino-common/src/date' +import { demarcheIdValidator } from 'camino-common/src/demarche' +import { entrepriseIdValidator } from 'camino-common/src/entreprise' const meta: Meta = { title: 'Components/Titre/Infos', @@ -10,14 +12,14 @@ const meta: Meta = { } export default meta -const titresTo: TitreLink[] = [{ id: 'id10', nom: 'Titre fils' }] -const titresFrom: TitreLink[] = [{ id: 'id11', nom: 'Titre père' }] +const titresTo: TitreLink[] = [{ id: titreIdValidator.parse('id10'), nom: 'Titre fils' }] +const titresFrom: TitreLink[] = [{ id: titreIdValidator.parse('id11'), nom: 'Titre père' }] const apiClient: Props['apiClient'] = { loadLinkableTitres: () => () => Promise.resolve([]), loadTitreLinks: () => Promise.resolve({ aval: titresTo, amont: titresFrom }), linkTitres: () => new Promise<TitreLinks>(resolve => resolve({ aval: titresTo, amont: titresFrom })), - loadTitreSections: (_titreId: string) => + loadTitreSections: (_titreId: TitreId) => new Promise<Section[]>(resolve => resolve([ { @@ -42,19 +44,19 @@ export const Default: StoryFn = () => ( <Infos currentDay={toCaminoDate('2023-04-06')} titre={{ - id: 'fakeId', + id: titreIdValidator.parse('fakeId'), typeId: 'arm', contenu: { arm: { mecanisation: true } }, titreStatutId: 'val', demarches: [ { - id: 'oct', + id: demarcheIdValidator.parse('oct'), demarcheDateDebut: toCaminoDate('2020-01-01'), demarcheDateFin: toCaminoDate('2022-01-01'), typeId: 'oct', }, { - id: 'pro', + id: demarcheIdValidator.parse('pro'), demarcheDateDebut: toCaminoDate('2022-01-01'), demarcheDateFin: toCaminoDate('2025-01-01'), typeId: 'pro', @@ -63,13 +65,13 @@ export const Default: StoryFn = () => ( administrations: ['ope-onf-973-01'], titulaires: [ { - id: 'entreprise1', + id: entrepriseIdValidator.parse('entreprise1'), nom: 'Entreprise 1', legalSiren: 'Entreprise 1 Siren', operateur: true, }, { - id: 'entreprise2', + id: entrepriseIdValidator.parse('entreprise2'), nom: 'Entreprise 2', legalSiren: 'Entreprise 2 Siren', operateur: false, @@ -77,7 +79,7 @@ export const Default: StoryFn = () => ( ], amodiataires: [ { - id: 'entreprise3', + id: entrepriseIdValidator.parse('entreprise3'), nom: 'Entreprise 3', legalSiren: 'Entreprise 3 Siren', operateur: false, @@ -95,7 +97,7 @@ export const Empty: StoryFn = () => ( <Infos currentDay={toCaminoDate('2023-04-06')} titre={{ - id: 'fakeId', + id: titreIdValidator.parse('fakeId'), typeId: 'arm', contenu: {}, titreStatutId: 'dmi', diff --git a/packages/ui/src/components/titre/infos.tsx b/packages/ui/src/components/titre/infos.tsx index c2df47383..c6cbb9a55 100644 --- a/packages/ui/src/components/titre/infos.tsx +++ b/packages/ui/src/components/titre/infos.tsx @@ -20,20 +20,22 @@ import { LoadingElement } from '@/components/_ui/functional-loader' import { Sections } from '../_common/new-section' import { FunctionalComponent, onMounted, ref } from 'vue' import { AsyncData } from '../../api/client-rest' -import { Section } from 'camino-common/src/titres' +import { Section, TitreId } from 'camino-common/src/titres' import { caminoDefineComponent } from '@/utils/vue-tsx-utils' import { CaminoDate, getCurrent } from 'camino-common/src/date' import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools' +import { DemarcheId } from 'camino-common/src/demarche' +import { EntrepriseId } from 'camino-common/src/entreprise' export interface Entreprise { - id: string + id: EntrepriseId nom: string legalSiren?: string operateur: boolean } interface Demarche { - id: string + id: DemarcheId typeId: DemarcheTypeId demarcheDateDebut: CaminoDate | null demarcheDateFin: CaminoDate | null @@ -42,7 +44,7 @@ interface Demarche { export interface Props { currentDay?: CaminoDate titre: { - id: string + id: TitreId typeId: TitreTypeId titreStatutId: TitreStatutId demarches: Demarche[] diff --git a/packages/ui/src/components/titre/territoires.stories.tsx b/packages/ui/src/components/titre/territoires.stories.tsx index 608d01d9b..ab5714324 100644 --- a/packages/ui/src/components/titre/territoires.stories.tsx +++ b/packages/ui/src/components/titre/territoires.stories.tsx @@ -3,6 +3,7 @@ import { Territoires } from './territoires' import { Meta, StoryFn } from '@storybook/vue3' import { toCommuneId } from 'camino-common/src/static/communes' import { TitreApiClient } from './titre-api-client' +import { titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Titre/Territoires', @@ -27,19 +28,35 @@ const apiClient: Pick<TitreApiClient, 'getTitreCommunes'> = { }, } -export const OnlyCommunes: StoryFn = () => <Territoires surface={0} forets={[]} titreId="titreId" secteursMaritimes={[]} apiClient={apiClient} /> -export const OnlySurface: StoryFn = () => <Territoires surface={4} forets={[]} titreId="pasDeCommunes" secteursMaritimes={[]} apiClient={apiClient} /> -export const OnlyForets: StoryFn = () => <Territoires surface={0} forets={['3PI', 'BEL']} titreId="pasDeCommunes" secteursMaritimes={[]} apiClient={apiClient} /> -export const OnlySdomZones: StoryFn = () => <Territoires surface={0} forets={[]} titreId="pasDeCommunes" secteursMaritimes={[]} sdomZones={['1', '2']} apiClient={apiClient} /> +export const OnlyCommunes: StoryFn = () => <Territoires surface={0} forets={[]} titreId={titreIdValidator.parse('titreId')} secteursMaritimes={[]} apiClient={apiClient} /> +export const OnlySurface: StoryFn = () => <Territoires surface={4} forets={[]} titreId={titreIdValidator.parse('pasDeCommunes')} secteursMaritimes={[]} apiClient={apiClient} /> +export const OnlyForets: StoryFn = () => <Territoires surface={0} forets={['3PI', 'BEL']} titreId={titreIdValidator.parse('pasDeCommunes')} secteursMaritimes={[]} apiClient={apiClient} /> +export const OnlySdomZones: StoryFn = () => ( + <Territoires surface={0} forets={[]} titreId={titreIdValidator.parse('pasDeCommunes')} secteursMaritimes={[]} sdomZones={['1', '2']} apiClient={apiClient} /> +) export const OnlySecteursMaritimes: StoryFn = () => ( - <Territoires surface={0} forets={[]} titreId="pasDeCommunes" secteursMaritimes={['Balagne', 'Bretagne nord', 'Bretagne sud']} sdomZones={[]} apiClient={apiClient} /> + <Territoires surface={0} forets={[]} titreId={titreIdValidator.parse('pasDeCommunes')} secteursMaritimes={['Balagne', 'Bretagne nord', 'Bretagne sud']} sdomZones={[]} apiClient={apiClient} /> ) export const All: StoryFn = () => ( - <Territoires surface={4} forets={['BEL', 'AMO']} secteursMaritimes={['Balagne', 'Bretagne nord', 'Bretagne sud']} sdomZones={['1', '0']} titreId="titreId" apiClient={apiClient} /> + <Territoires + surface={4} + forets={['BEL', 'AMO']} + secteursMaritimes={['Balagne', 'Bretagne nord', 'Bretagne sud']} + sdomZones={['1', '0']} + titreId={titreIdValidator.parse('titreId')} + apiClient={apiClient} + /> ) -export const Empty: StoryFn = () => <Territoires apiClient={apiClient} forets={[]} titreId="pasDeCommunes" secteursMaritimes={[]} /> -export const Loading: StoryFn = () => <Territoires apiClient={{ getTitreCommunes: () => new Promise(() => ({})) }} forets={['BEL', 'AMO']} titreId="titreId" secteursMaritimes={[]} /> +export const Empty: StoryFn = () => <Territoires apiClient={apiClient} forets={[]} titreId={titreIdValidator.parse('pasDeCommunes')} secteursMaritimes={[]} /> +export const Loading: StoryFn = () => ( + <Territoires apiClient={{ getTitreCommunes: () => new Promise(() => ({})) }} forets={['BEL', 'AMO']} titreId={titreIdValidator.parse('titreId')} secteursMaritimes={[]} /> +) export const WithError: StoryFn = () => ( - <Territoires apiClient={{ getTitreCommunes: () => Promise.reject(new Error('Chargement impossible des communes')) }} forets={['BEL', 'AMO']} titreId="titreId" secteursMaritimes={[]} /> + <Territoires + apiClient={{ getTitreCommunes: () => Promise.reject(new Error('Chargement impossible des communes')) }} + forets={['BEL', 'AMO']} + titreId={titreIdValidator.parse('titreId')} + secteursMaritimes={[]} + /> ) diff --git a/packages/ui/src/components/titre/territoires.tsx b/packages/ui/src/components/titre/territoires.tsx index ef94f5284..6d6c292b6 100644 --- a/packages/ui/src/components/titre/territoires.tsx +++ b/packages/ui/src/components/titre/territoires.tsx @@ -1,4 +1,4 @@ -import { DepartementId, Departements, toDepartementId } from 'camino-common/src/static/departement' +import { DepartementId, DepartementLabel, Departements, toDepartementId } from 'camino-common/src/static/departement' import { getFacadesComputed, SecteursMaritimes, FacadeComputed } from 'camino-common/src/static/facades' import { PaysId, PAYS_IDS } from 'camino-common/src/static/pays' import { Regions } from 'camino-common/src/static/region' @@ -12,6 +12,7 @@ import { LoadingElement } from '../_ui/functional-loader' import { caminoDefineComponent } from '../../utils/vue-tsx-utils' import { AsyncData } from '../../api/client-rest' import { TitreApiClient } from './titre-api-client' +import { TitreId } from 'camino-common/src/titres' export interface TerritoiresCommune { id: CommuneId @@ -22,7 +23,7 @@ export interface TerritoiresProps { surface?: number forets: ForetId[] sdomZones?: SDOMZoneId[] - titreId: string + titreId: TitreId secteursMaritimes: SecteursMaritimes[] } @@ -30,7 +31,7 @@ type RegionsComputed = { id: string nom: string paysId: PaysId - departements: { id: DepartementId; nom: string; communes: string[] }[] + departements: { id: DepartementId; nom: DepartementLabel; communes: string[] }[] }[] function CommunesEtRegions({ communes }: { communes: Commune[] }) { diff --git a/packages/ui/src/components/titre/titre-api-client.ts b/packages/ui/src/components/titre/titre-api-client.ts index 66f1dd565..e28a40fd3 100644 --- a/packages/ui/src/components/titre/titre-api-client.ts +++ b/packages/ui/src/components/titre/titre-api-client.ts @@ -1,38 +1,38 @@ -import { EditableTitre, Section, TitreGet } from 'camino-common/src/titres' +import { EditableTitre, Section, TitreGet, TitreId } from 'camino-common/src/titres' import { deleteWithJson, getWithJson, postWithJson } from '../../api/client-rest' import { CaminoDate } from 'camino-common/src/date' import { Commune } from 'camino-common/src/static/communes' export interface TitreApiClient { - loadTitreSections: (titreId: string) => Promise<Section[]> - removeTitre: (titreId: string) => Promise<void> - titreUtilisateurAbonne: (titreId: string, abonne: boolean) => Promise<void> + loadTitreSections: (titreId: TitreId) => Promise<Section[]> + removeTitre: (titreId: TitreId) => Promise<void> + titreUtilisateurAbonne: (titreId: TitreId, abonne: boolean) => Promise<void> editTitre: (titre: EditableTitre) => Promise<void> - getTitreById: (titreId: string) => Promise<TitreGet> - getLastModifiedDate: (titreId: string) => Promise<CaminoDate | null> - getTitreCommunes: (titreId: string) => Promise<Commune[]> + getTitreById: (titreId: TitreId) => Promise<TitreGet> + getLastModifiedDate: (titreId: TitreId) => Promise<CaminoDate | null> + getTitreCommunes: (titreId: TitreId) => Promise<Commune[]> } export const titreApiClient: TitreApiClient = { - loadTitreSections: async (titreId: string): Promise<Section[]> => { + loadTitreSections: async (titreId: TitreId): Promise<Section[]> => { return getWithJson('/rest/titreSections/:titreId', { titreId }) }, - removeTitre: async (titreId: string): Promise<void> => { + removeTitre: async (titreId: TitreId): Promise<void> => { return deleteWithJson('/rest/titres/:titreId', { titreId }) }, - titreUtilisateurAbonne: async (titreId: string, abonne: boolean): Promise<void> => { + titreUtilisateurAbonne: async (titreId: TitreId, abonne: boolean): Promise<void> => { return postWithJson('/rest/titres/:titreId/abonne', { titreId }, { abonne }) }, editTitre: (titre: EditableTitre): Promise<void> => { return postWithJson('/rest/titres/:titreId', { titreId: titre.id }, titre) }, - getTitreById: (titreId: string): Promise<TitreGet> => { + getTitreById: (titreId: TitreId): Promise<TitreGet> => { return getWithJson('/rest/titres/:titreId', { titreId }) }, - getLastModifiedDate: (titreId: string): Promise<CaminoDate | null> => { + getLastModifiedDate: (titreId: TitreId): Promise<CaminoDate | null> => { return getWithJson('/rest/titres/:titreId/date', { titreId }) }, - getTitreCommunes: (id: string): Promise<Commune[]> => { + getTitreCommunes: (id: TitreId): Promise<Commune[]> => { return getWithJson('/rest/titres/:id/communes', { id }) }, } diff --git a/packages/ui/src/components/titre/titres-link-form-api-client.ts b/packages/ui/src/components/titre/titres-link-form-api-client.ts index 975b06977..0326042d8 100644 --- a/packages/ui/src/components/titre/titres-link-form-api-client.ts +++ b/packages/ui/src/components/titre/titres-link-form-api-client.ts @@ -4,7 +4,7 @@ import { getLinkConfig } from 'camino-common/src/permissions/titres' import { apiGraphQLFetch } from '@/api/_client' import gql from 'graphql-tag' -import { TitreLink, TitreLinks } from 'camino-common/src/titres' +import { TitreId, TitreLink, TitreLinks } from 'camino-common/src/titres' import { TitreStatutId } from 'camino-common/src/static/titresStatuts' import { getWithJson, postWithJson } from '@/api/client-rest' import { CaminoDate } from 'camino-common/src/date' @@ -12,11 +12,11 @@ import { CaminoDate } from 'camino-common/src/date' export type TitresLinkConfig = | { type: 'single' - selectedTitreId: string | null + selectedTitreId: TitreId | null } | { type: 'multiple' - selectedTitreIds: string[] + selectedTitreIds: TitreId[] } type TitreLinkDemarche = { demarcheDateDebut: CaminoDate | null; demarcheDateFin: CaminoDate | null } @@ -26,17 +26,17 @@ export type LinkableTitre = TitreLink & { } export interface TitresLinkFormApiClient { - linkTitres: (titreId: string, titreFromIds: string[]) => Promise<TitreLinks> - loadTitreLinks: (titreId: string) => Promise<TitreLinks> + linkTitres: (titreId: TitreId, titreFromIds: TitreId[]) => Promise<TitreLinks> + loadTitreLinks: (titreId: TitreId) => Promise<TitreLinks> loadLinkableTitres: (titreTypeId: TitreTypeId, demarches: { typeId: DemarcheTypeId }[]) => () => Promise<LinkableTitre[]> } export const titresLinkFormApiClient: TitresLinkFormApiClient = { - linkTitres: async (titreId: string, titreFromIds: string[]): Promise<TitreLinks> => { + linkTitres: async (titreId: TitreId, titreFromIds: TitreId[]): Promise<TitreLinks> => { return await postWithJson('/rest/titres/:id/titreLiaisons', { id: titreId }, titreFromIds) }, - loadTitreLinks: async (titreId: string) => { + loadTitreLinks: async (titreId: TitreId) => { return await getWithJson('/rest/titres/:id/titreLiaisons', { id: titreId }) }, diff --git a/packages/ui/src/components/titre/titres-link-form.stories.tsx b/packages/ui/src/components/titre/titres-link-form.stories.tsx index 31f7a74f7..273f403a4 100644 --- a/packages/ui/src/components/titre/titres-link-form.stories.tsx +++ b/packages/ui/src/components/titre/titres-link-form.stories.tsx @@ -1,6 +1,6 @@ import { TitresLinkForm, Props } from './titres-link-form' import { Meta, StoryFn } from '@storybook/vue3' -import { TitreLink, TitreLinks } from 'camino-common/src/titres' +import { TitreLink, TitreLinks, titreIdValidator } from 'camino-common/src/titres' import { LinkableTitre } from '@/components/titre/titres-link-form-api-client' import { testBlankUser } from 'camino-common/src/tests-utils' import { toCaminoDate } from 'camino-common/src/date' @@ -14,7 +14,7 @@ export default meta const linkableTitres: LinkableTitre[] = [ { - id: 'id1', + id: titreIdValidator.parse('id1'), nom: 'Abttis Coucou', titreStatutId: 'ech', demarches: [ @@ -25,7 +25,7 @@ const linkableTitres: LinkableTitre[] = [ ], }, { - id: 'id2', + id: titreIdValidator.parse('id2'), nom: 'Affluent Crique Saint Bernard', titreStatutId: 'ech', demarches: [ @@ -36,7 +36,7 @@ const linkableTitres: LinkableTitre[] = [ ], }, { - id: 'id3', + id: titreIdValidator.parse('id3'), nom: 'Nouveau titre', titreStatutId: 'ech', demarches: [ @@ -48,7 +48,7 @@ const linkableTitres: LinkableTitre[] = [ }, ] -const titresTo: TitreLink[] = [{ id: 'id10', nom: 'Titre fils' }] +const titresTo: TitreLink[] = [{ id: titreIdValidator.parse('id10'), nom: 'Titre fils' }] const titresFrom: TitreLink[] = [linkableTitres[0]] const apiClient: Props['apiClient'] = { @@ -58,7 +58,7 @@ const apiClient: Props['apiClient'] = { } export const AxmWithAlreadySelectedTitre: StoryFn = () => ( - <TitresLinkForm user={{ role: 'super', ...testBlankUser }} titre={{ typeId: 'axm', administrations: [], id: 'titreId', demarches: [] }} apiClient={apiClient} /> + <TitresLinkForm user={{ role: 'super', ...testBlankUser }} titre={{ typeId: 'axm', administrations: [], id: titreIdValidator.parse('titreId'), demarches: [] }} apiClient={apiClient} /> ) export const FusionWithAlreadySelectedTitre: StoryFn = () => ( @@ -67,7 +67,7 @@ export const FusionWithAlreadySelectedTitre: StoryFn = () => ( titre={{ typeId: 'cxm', administrations: [], - id: 'titreId', + id: titreIdValidator.parse('titreId'), demarches: [{ typeId: 'fus' }], }} apiClient={apiClient} @@ -77,7 +77,7 @@ export const FusionWithAlreadySelectedTitre: StoryFn = () => ( export const TitreWithTitreLinksLoading: StoryFn = () => ( <TitresLinkForm user={{ role: 'super', ...testBlankUser }} - titre={{ typeId: 'axm', administrations: [], id: 'titreId', demarches: [] }} + titre={{ typeId: 'axm', administrations: [], id: titreIdValidator.parse('titreId'), demarches: [] }} apiClient={{ ...apiClient, loadTitreLinks: () => new Promise<TitreLinks>(() => ({})), @@ -86,5 +86,5 @@ export const TitreWithTitreLinksLoading: StoryFn = () => ( ) export const DefautCantUpdateLinks: StoryFn = () => ( - <TitresLinkForm user={{ role: 'defaut', ...testBlankUser }} titre={{ typeId: 'axm', administrations: [], id: 'titreId', demarches: [] }} apiClient={apiClient} /> + <TitresLinkForm user={{ role: 'defaut', ...testBlankUser }} titre={{ typeId: 'axm', administrations: [], id: titreIdValidator.parse('titreId'), demarches: [] }} apiClient={apiClient} /> ) diff --git a/packages/ui/src/components/titre/titres-link-form.tsx b/packages/ui/src/components/titre/titres-link-form.tsx index bafe16b0c..0c70080ce 100644 --- a/packages/ui/src/components/titre/titres-link-form.tsx +++ b/packages/ui/src/components/titre/titres-link-form.tsx @@ -9,14 +9,14 @@ import { AsyncData } from '@/api/client-rest' import { LoadingElement } from '@/components/_ui/functional-loader' import { Icon } from '@/components/_ui/icon' import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes' -import { TitreLink, TitreLinks } from 'camino-common/src/titres' +import { TitreId, TitreLink, TitreLinks } from 'camino-common/src/titres' import { ApiClient } from '@/api/api-client' import { TitresLinkConfig } from '@/components/titre/titres-link-form-api-client' export interface Props { user: User titre: { - id: string + id: TitreId typeId: TitreTypeId administrations: AdministrationId[] demarches: { typeId: DemarcheTypeId }[] diff --git a/packages/ui/src/components/titre/titres-link.stories.tsx b/packages/ui/src/components/titre/titres-link.stories.tsx index 2b05573f3..b3c623f13 100644 --- a/packages/ui/src/components/titre/titres-link.stories.tsx +++ b/packages/ui/src/components/titre/titres-link.stories.tsx @@ -3,6 +3,7 @@ import { Meta, StoryFn } from '@storybook/vue3' import { LinkableTitre } from '@/components/titre/titres-link-form-api-client' import { action } from '@storybook/addon-actions' import { toCaminoDate } from 'camino-common/src/date' +import { titreIdValidator } from 'camino-common/src/titres' const meta: Meta = { title: 'Components/Titre/TitresLink', @@ -13,7 +14,7 @@ export default meta const titres: LinkableTitre[] = [ { - id: 'id1', + id: titreIdValidator.parse('id1'), nom: 'Abttis Coucou', titreStatutId: 'ech', demarches: [ @@ -24,7 +25,7 @@ const titres: LinkableTitre[] = [ ], }, { - id: 'id2', + id: titreIdValidator.parse('id2'), nom: 'Affluent Crique Saint Bernard', titreStatutId: 'ech', demarches: [ @@ -35,7 +36,7 @@ const titres: LinkableTitre[] = [ ], }, { - id: 'id3', + id: titreIdValidator.parse('id3'), nom: 'Nouveau titre', titreStatutId: 'ech', demarches: [ @@ -53,7 +54,12 @@ export const AXM: StoryFn = () => ( ) export const AXMWithAlreadySelectedTitre: StoryFn = () => ( - <TitresLink config={{ type: 'single', selectedTitreId: 'id1' }} loadLinkableTitres={() => Promise.resolve(titres)} onSelectTitre={onSelectTitre} onSelectTitres={onSelectTitres} /> + <TitresLink + config={{ type: 'single', selectedTitreId: titreIdValidator.parse('id1') }} + loadLinkableTitres={() => Promise.resolve(titres)} + onSelectTitre={onSelectTitre} + onSelectTitres={onSelectTitres} + /> ) export const DemarcheFusion: StoryFn = () => ( @@ -61,14 +67,19 @@ export const DemarcheFusion: StoryFn = () => ( ) export const DemarcheFusionWithAlreadySelectedTitre: StoryFn = () => ( - <TitresLink config={{ type: 'multiple', selectedTitreIds: ['id1', 'id2'] }} loadLinkableTitres={() => Promise.resolve(titres)} onSelectTitre={onSelectTitre} onSelectTitres={onSelectTitres} /> + <TitresLink + config={{ type: 'multiple', selectedTitreIds: [titreIdValidator.parse('id1'), titreIdValidator.parse('id2')] }} + loadLinkableTitres={() => Promise.resolve(titres)} + onSelectTitre={onSelectTitre} + onSelectTitres={onSelectTitres} + /> ) export const Loading: StoryFn = () => ( <TitresLink config={{ type: 'multiple', - selectedTitreIds: ['id1'], + selectedTitreIds: [titreIdValidator.parse('id1')], }} loadLinkableTitres={() => new Promise<LinkableTitre[]>(resolve => {})} onSelectTitre={onSelectTitre} @@ -80,7 +91,7 @@ export const WithError: StoryFn = () => ( <TitresLink config={{ type: 'multiple', - selectedTitreIds: ['id1'], + selectedTitreIds: [titreIdValidator.parse('id1')], }} loadLinkableTitres={() => Promise.reject(new Error('because reasons'))} onSelectTitre={onSelectTitre} diff --git a/packages/ui/src/utils/titre-etape-edit.test.ts b/packages/ui/src/utils/titre-etape-edit.test.ts index 5a9147958..c023150d0 100644 --- a/packages/ui/src/utils/titre-etape-edit.test.ts +++ b/packages/ui/src/utils/titre-etape-edit.test.ts @@ -2,6 +2,7 @@ import { etapeEditFormat } from './titre-etape-edit' import { GEO_SYSTEME_IDS } from 'camino-common/src/static/geoSystemes' import { describe, expect, test } from 'vitest' import { newEntrepriseId } from 'camino-common/src/entreprise' +import { etapeIdValidator } from 'camino-common/src/etape' // dateFormat describe('etapeEditFormat', () => { @@ -9,7 +10,7 @@ describe('etapeEditFormat', () => { expect( // @ts-ignore etapeEditFormat({ - id: 'etape-id', + id: etapeIdValidator.parse('etape-id'), }) ).toEqual({ id: 'etape-id', @@ -38,7 +39,7 @@ describe('etapeEditFormat', () => { expect( // @ts-ignore etapeEditFormat({ - id: 'etape-id', + id: etapeIdValidator.parse('etape-id'), points: [ { id: 'point-id-111', @@ -98,7 +99,7 @@ describe('etapeEditFormat', () => { expect( etapeEditFormat({ - id: 'etape-id', + id: etapeIdValidator.parse('etape-id'), type: { id: 'aac', nom: 'plop' }, // @ts-ignore statutId: 'etape-statut-id', -- GitLab