From 7d540f9703fdac51e821bd4758c21a24f1898586 Mon Sep 17 00:00:00 2001
From: vmaubert <github@vcmb.dev>
Date: Mon, 5 Aug 2024 11:28:24 +0200
Subject: [PATCH] =?UTF-8?q?feat(d=C3=A9marche):=20ajoute=20la=20d=C3=A9cis?=
 =?UTF-8?q?ion=20implicite=20=C3=A0=20la=20proc=C3=A9dure=20simplifi=C3=A9?=
 =?UTF-8?q?e=20(#1411)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* feat(démarche): ajoute la décision implicite à la procédure simplifiée

* fix test
---
 .../procedure-simplifiee/ps.machine.test.ts   | 17 ++++++++++--
 .../procedure-simplifiee/ps.machine.ts        | 27 +++++++++++++++++--
 packages/common/src/static/etapesStatuts.ts   |  9 ++++++-
 .../src/static/etapesTypesEtapesStatuts.ts    |  1 +
 .../etape-statut.stories_snapshots_All.html   |  6 +++++
 .../src/components/_common/etape-statut.tsx   |  1 +
 6 files changed, 56 insertions(+), 5 deletions(-)

diff --git a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts
index 24dd6a13c..ab488b80c 100644
--- a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts
+++ b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.test.ts
@@ -20,6 +20,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'FAIRE_DEMANDE',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
     ])
     expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.EnConstruction)
   })
@@ -29,6 +30,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'FAIRE_DEMANDE',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
       'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE',
       'PUBLIER_DECISION_ACCEPTEE_AU_JORF',
       'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS',
@@ -62,6 +64,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'OUVRIR_PARTICIPATION_DU_PUBLIC',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
     ])
     expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.EnInstruction)
   })
@@ -76,6 +79,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'OUVRIR_PARTICIPATION_DU_PUBLIC',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
     ])
     expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.EnInstruction)
   })
@@ -83,7 +87,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
   test('ne peut pas faire deux dépôts de la demande', () => {
     const etapes = [ETES.demande.FAIT, ETES.depotDeLaDemande.FAIT, ETES.depotDeLaDemande.FAIT]
     expect(() => setDateAndOrderAndInterpretMachine(psMachine, '2022-04-12', etapes)).toThrowErrorMatchingInlineSnapshot(
-      `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2022-04-15"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"DEPOSER_DEMANDE"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_PARTICIPATION_DU_PUBLIC,RECEVOIR_INFORMATION,RENDRE_DECISION_ADMINISTRATION_ACCEPTEE,RENDRE_DECISION_ADMINISTRATION_REJETEE']`
+      `[Error: Error: cannot execute step: '{"etapeTypeId":"mdp","etapeStatutId":"fai","date":"2022-04-15"}' after '["mfr_fai","mdp_fai"]'. The event {"type":"DEPOSER_DEMANDE"} should be one of 'CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_PARTICIPATION_DU_PUBLIC,RECEVOIR_INFORMATION,RENDRE_DECISION_ADMINISTRATION_ACCEPTEE,RENDRE_DECISION_ADMINISTRATION_REJETEE,RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE']`
     )
   })
 
@@ -169,6 +173,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'RECEVOIR_INFORMATION',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
     ])
   })
   test("peut faire deux demandes d'information consécutives", () => {
@@ -188,6 +193,7 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
       'DESISTER_PAR_LE_DEMANDEUR',
       'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE',
       'RENDRE_DECISION_ADMINISTRATION_REJETEE',
+      'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE',
     ])
   })
 
@@ -222,12 +228,19 @@ describe('vérifie l’arbre des procédures historiques et simplifiées', () =>
     expect(service.getSnapshot().context.visibilite).toBe('confidentielle')
   })
 
-  test("peut rejeter immédiatement un décision de l'administration", () => {
+  test("peut rejeter immédiatement une décision de l'administration", () => {
     const { service, dateFin } = setDateAndOrderAndInterpretMachine(psMachine, '2022-04-08', [ETES.decisionDeLadministration.REJETE])
     expect(service).canOnlyTransitionTo({ machine: psMachine, date: dateFin }, ['PUBLIER_DECISION_ACCEPTEE_AU_JORF'])
     expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.Rejete)
     expect(service.getSnapshot().context.visibilite).toBe('confidentielle')
   })
+
+  test("peut rejeter par décision implicite une décision de l'administration", () => {
+    const { service, dateFin } = setDateAndOrderAndInterpretMachine(psMachine, '2022-04-08', [ETES.decisionDeLadministration.REJETE_DECISION_IMPLICITE])
+    expect(service).canOnlyTransitionTo({ machine: psMachine, date: dateFin }, [])
+    expect(service.getSnapshot().context.demarcheStatut).toBe(DemarchesStatutsIds.Rejete)
+    expect(service.getSnapshot().context.visibilite).toBe('publique')
+  })
   // pour regénérer le oct.cas.json: `npm run test:generate-data -w packages/api`
   test.each(etapesProdProceduresHistoriques as any[])('cas réel N°$id', demarche => {
     // ici les étapes sont déjà ordonnées
diff --git a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts
index 3683ee0fd..9e95e63e4 100644
--- a/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts
+++ b/packages/api/src/business/rules-demarches/procedure-simplifiee/ps.machine.ts
@@ -18,7 +18,10 @@ type RendreDecisionAdministrationRejetee = {
   date: CaminoDate
   type: 'RENDRE_DECISION_ADMINISTRATION_REJETEE'
 }
-
+type RendreDecisionAdministrationRejeteeDecisionImplicite = {
+  date: CaminoDate
+  type: 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE'
+}
 type PublierDecisionAccepteeAuJORF = {
   date: CaminoDate
   type: 'PUBLIER_DECISION_ACCEPTEE_AU_JORF'
@@ -39,6 +42,7 @@ type ProcedureSimplifieeXStateEvent =
   | ParticipationDuPublic
   | RendreDecisionAdministrationAcceptee
   | RendreDecisionAdministrationRejetee
+  | RendreDecisionAdministrationRejeteeDecisionImplicite
   | SaisirInformationHistoriqueIncomplete
   | PublierDecisionAccepteeAuJORF
   | PublierDecisionAuRecueilDesActesAdministratifs
@@ -56,6 +60,7 @@ const trad: { [key in Event]: { db: DBEtat; mainStep: boolean } } = {
   OUVRIR_PARTICIPATION_DU_PUBLIC: { db: ETES.participationDuPublic, mainStep: true },
   RENDRE_DECISION_ADMINISTRATION_ACCEPTEE: { db: { ACCEPTE: ETES.decisionDeLadministration.ACCEPTE }, mainStep: true },
   RENDRE_DECISION_ADMINISTRATION_REJETEE: { db: { REJETE: ETES.decisionDeLadministration.REJETE }, mainStep: true },
+  RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE: { db: { REJETE_DECISION_IMPLICITE: ETES.decisionDeLadministration.REJETE_DECISION_IMPLICITE }, mainStep: true },
   PUBLIER_DECISION_ACCEPTEE_AU_JORF: { db: { FAIT: ETES.publicationDeDecisionAuJORF.FAIT }, mainStep: true },
   PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS: { db: ETES.publicationDeDecisionAuRecueilDesActesAdministratifs, mainStep: true },
   CLASSER_SANS_SUITE: { db: ETES.classementSansSuite, mainStep: false },
@@ -79,6 +84,7 @@ export class ProcedureSimplifieeMachine extends CaminoMachine<ProcedureSimplifie
     switch (event) {
       case 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE':
       case 'RENDRE_DECISION_ADMINISTRATION_REJETEE':
+      case 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE':
       case 'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE':
       case 'PUBLIER_DECISION_ACCEPTEE_AU_JORF':
       case 'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS':
@@ -108,7 +114,8 @@ export class ProcedureSimplifieeMachine extends CaminoMachine<ProcedureSimplifie
         case 'PUBLIER_DECISION_AU_RECUEIL_DES_ACTES_ADMINISTRATIFS':
         case 'SAISIR_INFORMATION_HISTORIQUE_INCOMPLETE':
         case 'RENDRE_DECISION_ADMINISTRATION_ACCEPTEE':
-        case 'RENDRE_DECISION_ADMINISTRATION_REJETEE': {
+        case 'RENDRE_DECISION_ADMINISTRATION_REJETEE':
+        case 'RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE': {
           return { type: eventFromEntry, date: etape.date }
         }
         case 'OUVRIR_PARTICIPATION_DU_PUBLIC': {
@@ -181,6 +188,14 @@ const procedureSimplifieeMachine = createMachine({
         demarcheStatut: DemarchesStatutsIds.Rejete,
       }),
     },
+    RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE: {
+      guard: ({ context, event }) => isBefore(event.date, procedureHistoriqueDateMax) && context.demarcheStatut === defaultDemarcheStatut,
+      target: '.finDeMachine',
+      actions: assign({
+        visibilite: 'publique',
+        demarcheStatut: DemarchesStatutsIds.Rejete,
+      }),
+    },
     CLASSER_SANS_SUITE: {
       guard: ({ context }) => context.demarcheStatut === DemarchesStatutsIds.EnInstruction,
       target: '.finDeMachine',
@@ -248,6 +263,14 @@ const procedureSimplifieeMachine = createMachine({
           }),
           target: 'finDeMachine',
         },
+        RENDRE_DECISION_ADMINISTRATION_REJETEE_DECISION_IMPLICITE: {
+          guard: ({ context }) => isNullOrUndefined(context.ouverturePublicStatut) || context.ouverturePublicStatut === ETAPES_STATUTS.TERMINE,
+          actions: assign({
+            visibilite: 'publique',
+            demarcheStatut: DemarchesStatutsIds.Rejete,
+          }),
+          target: 'finDeMachine',
+        },
       },
     },
     publicationAuRecueilDesActesAdministratifsOupublicationAuJORFAFaire: {
diff --git a/packages/common/src/static/etapesStatuts.ts b/packages/common/src/static/etapesStatuts.ts
index cd05e049d..5525ebf99 100644
--- a/packages/common/src/static/etapesStatuts.ts
+++ b/packages/common/src/static/etapesStatuts.ts
@@ -1,7 +1,7 @@
 import { Couleur } from './couleurs'
 import { z } from 'zod'
 
-const IDS = ['acc', 'dre', 'enc', 'fai', 'dep', 'exe', 'req', 'com', 'inc', 'fav', 'def', 'fre', 'ajo', 'rej', 'ter', 'nul', 'pro'] as const
+const IDS = ['acc', 'dre', 'enc', 'fai', 'dep', 'exe', 'req', 'com', 'inc', 'fav', 'def', 'fre', 'ajo', 'rej', 'rei', 'ter', 'nul', 'pro'] as const
 export const ETAPES_STATUTS = {
   ACCEPTE: 'acc',
   DEFAVORABLE_AVEC_RESERVES: 'dre',
@@ -17,6 +17,7 @@ export const ETAPES_STATUTS = {
   FAVORABLE_AVEC_RESERVE: 'fre',
   AJOURNE: 'ajo',
   REJETE: 'rej',
+  REJETE_DECISION_IMPLICITE: 'rei',
   TERMINE: 'ter',
   NON_APPLICABLE: 'nul',
   PROGRAMME: 'pro',
@@ -57,6 +58,12 @@ export const EtapesStatuts: { [key in EtapeStatutId]: EtapeStatut<key> } = {
     description:
       "La demande a fait l’objet d’une décision défavorable de l'administration. Les textes d’applications du code minier prévoient que les décisions de rejet ne font pas l’objet d’une publication. En conséquence, les démarches qui passent au statut “rejeté” dans Camino sont dé-publiées et rendues inaccessibles aux tiers.\n",
   },
+  rei: {
+    id: 'rei',
+    nom: 'rejeté - décision implicite',
+    couleur: 'error',
+    description: '',
+  },
   req: { id: 'req', nom: 'requis', couleur: 'neutral' },
   ter: {
     id: 'ter',
diff --git a/packages/common/src/static/etapesTypesEtapesStatuts.ts b/packages/common/src/static/etapesTypesEtapesStatuts.ts
index 001daad0a..a86615c06 100644
--- a/packages/common/src/static/etapesTypesEtapesStatuts.ts
+++ b/packages/common/src/static/etapesTypesEtapesStatuts.ts
@@ -109,6 +109,7 @@ export const EtapesTypesEtapesStatuts = {
   decisionDeLadministration: {
     ACCEPTE: { etapeTypeId: 'dex', etapeStatutId: 'acc' },
     REJETE: { etapeTypeId: 'dex', etapeStatutId: 'rej' },
+    REJETE_DECISION_IMPLICITE: { etapeTypeId: 'dex', etapeStatutId: 'rei' },
   },
   decisionImplicite: {
     ACCEPTE: { etapeTypeId: 'dim', etapeStatutId: 'acc' },
diff --git a/packages/ui/src/components/_common/etape-statut.stories_snapshots_All.html b/packages/ui/src/components/_common/etape-statut.stories_snapshots_All.html
index 639491f2d..091550deb 100644
--- a/packages/ui/src/components/_common/etape-statut.stories_snapshots_All.html
+++ b/packages/ui/src/components/_common/etape-statut.stories_snapshots_All.html
@@ -94,6 +94,12 @@
         <p style="z-index: unset; margin-bottom: 0px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;" class="fr-badge fr-badge--md fr-badge--purple-glycine" title="rejeté" aria-label="rejeté">rejeté</p>
       </td>
     </tr>
+    <tr>
+      <td>rejeté - décision implicite</td>
+      <td>
+        <p style="z-index: unset; margin-bottom: 0px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;" class="fr-badge fr-badge--md fr-badge--purple-glycine" title="rejeté - décision implicite" aria-label="rejeté - décision implicite">rejeté - décision implicite</p>
+      </td>
+    </tr>
     <tr>
       <td>requis</td>
       <td>
diff --git a/packages/ui/src/components/_common/etape-statut.tsx b/packages/ui/src/components/_common/etape-statut.tsx
index 4b42f62c9..c21d9dfcb 100644
--- a/packages/ui/src/components/_common/etape-statut.tsx
+++ b/packages/ui/src/components/_common/etape-statut.tsx
@@ -23,6 +23,7 @@ const couleurParStatut = {
   [ETAPES_STATUTS.FAVORABLE_AVEC_RESERVE]: 'green-bourgeon',
   [ETAPES_STATUTS.AJOURNE]: 'orange-terre-battue',
   [ETAPES_STATUTS.REJETE]: 'purple-glycine',
+  [ETAPES_STATUTS.REJETE_DECISION_IMPLICITE]: 'purple-glycine',
   [ETAPES_STATUTS.TERMINE]: 'green-bourgeon',
   [ETAPES_STATUTS.NON_APPLICABLE]: 'beige-gris-galet',
   [ETAPES_STATUTS.PROGRAMME]: 'orange-terre-battue',
-- 
GitLab