From b2f3a7af4c8e7e6dc3a2a39f09fc0d7e03de143e Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Mon, 20 Feb 2023 17:00:10 +0100 Subject: [PATCH 01/33] feat(GroupeInstructeurSupprimerInstructeurs): enable emailing for unrouted procedures --- .../mutations/groupe_instructeur_supprimer_instructeurs.rb | 7 +++++++ .../api/v2/graphql_controller_stored_queries_spec.rb | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb index 0c14d16cc00..e6746cc7c66 100644 --- a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb +++ b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb @@ -14,6 +14,13 @@ def resolve(groupe_instructeur:, instructeurs:) instructeurs.each { groupe_instructeur.remove(_1) } groupe_instructeur.reload + + if instructeurs.present? + GroupeInstructeurMailer + .notify_group_when_instructeurs_removed(groupe_instructeur, instructeurs, current_administrateur.email) + .deliver_later + end + { groupe_instructeur: } end end diff --git a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb index ae6749376c7..56d209864da 100644 --- a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb @@ -379,6 +379,8 @@ let(:operation_name) { 'groupeInstructeurSupprimerInstructeurs' } before do + allow(GroupeInstructeurMailer).to receive(:notify_group_when_instructeurs_removed) + .and_return(double(deliver_later: true)) existing_instructeur groupe_instructeur.add(new_instructeur) end @@ -390,6 +392,11 @@ expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:id]).to eq(groupe_instructeur.to_typed_id) expect(groupe_instructeur.instructeurs.count).to eq(1) expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }]) + expect(GroupeInstructeurMailer).to have_received(:notify_group_when_instructeurs_removed).with( + groupe_instructeur, + [new_instructeur], + admin.email + ) } end From ac0d7a67a120ea35426020a1fdc40f4900741141 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Mon, 20 Feb 2023 17:28:23 +0100 Subject: [PATCH 02/33] feat(GroupeInstructeurAjouterInstructeurs): add notification for added instructeurs via API --- .../groupe_instructeur_ajouter_instructeurs.rb | 7 ++++++- .../api/v2/graphql_controller_stored_queries_spec.rb | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/graphql/mutations/groupe_instructeur_ajouter_instructeurs.rb b/app/graphql/mutations/groupe_instructeur_ajouter_instructeurs.rb index a6e6a6c1f66..22f9a552d69 100644 --- a/app/graphql/mutations/groupe_instructeur_ajouter_instructeurs.rb +++ b/app/graphql/mutations/groupe_instructeur_ajouter_instructeurs.rb @@ -13,7 +13,12 @@ def resolve(groupe_instructeur:, instructeurs:) ids, emails = partition_instructeurs_by(instructeurs) _, invalid_emails = groupe_instructeur.add_instructeurs(ids:, emails:) - groupe_instructeur.reload + if instructeurs.present? + groupe_instructeur.reload + GroupeInstructeurMailer + .notify_added_instructeurs(groupe_instructeur, instructeurs, current_administrateur.email) + .deliver_later + end result = { groupe_instructeur: } diff --git a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb index 56d209864da..051b26a74b3 100644 --- a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb @@ -360,6 +360,11 @@ let(:variables) { { input: { groupeInstructeurId: groupe_instructeur.to_typed_id, instructeurs: [{ email: }, { email: 'yolo' }, { id: existing_instructeur.to_typed_id }] }, includeInstructeurs: true } } let(:operation_name) { 'groupeInstructeurAjouterInstructeurs' } + before do + allow(GroupeInstructeurMailer).to receive(:notify_added_instructeurs) + .and_return(double(deliver_later: true)) + end + it { expect(gql_errors).to be_nil expect(gql_data[:groupeInstructeurAjouterInstructeurs][:errors]).to be_nil @@ -367,6 +372,11 @@ expect(gql_data[:groupeInstructeurAjouterInstructeurs][:groupeInstructeur][:id]).to eq(groupe_instructeur.to_typed_id) expect(groupe_instructeur.instructeurs.count).to eq(2) expect(gql_data[:groupeInstructeurAjouterInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }, { id: Instructeur.last.to_typed_id, email: }]) + expect(GroupeInstructeurMailer).to have_received(:notify_added_instructeurs).with( + groupe_instructeur, + [Instructeur.last], + admin.email + ) } end From a150aa33ef441dcee259da27fb0940d5d4daa879 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Mon, 20 Feb 2023 17:48:56 +0100 Subject: [PATCH 03/33] feat(GroupeInstructeurSupprimerInstructeurs): add notification for removed instructeurs via API --- .../groupe_instructeur_supprimer_instructeurs.rb | 6 ++++++ .../v2/graphql_controller_stored_queries_spec.rb | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb index e6746cc7c66..8a45f4719a9 100644 --- a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb +++ b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb @@ -19,6 +19,12 @@ def resolve(groupe_instructeur:, instructeurs:) GroupeInstructeurMailer .notify_group_when_instructeurs_removed(groupe_instructeur, instructeurs, current_administrateur.email) .deliver_later + + instructeurs.each do |instructeur| + GroupeInstructeurMailer + .notify_removed_instructeur(groupe_instructeur, instructeur, current_administrateur.email) + .deliver_later + end end { groupe_instructeur: } diff --git a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb index 051b26a74b3..ebb8a2bf598 100644 --- a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb @@ -384,19 +384,23 @@ let(:email) { 'test@test.com' } let(:groupe_instructeur) { procedure.groupe_instructeurs.first } let(:existing_instructeur) { groupe_instructeur.instructeurs.first } - let(:new_instructeur) { create(:instructeur) } - let(:variables) { { input: { groupeInstructeurId: groupe_instructeur.to_typed_id, instructeurs: [{ email: }, { id: new_instructeur.to_typed_id }] }, includeInstructeurs: true } } + let(:instructeur_2) { create(:instructeur) } + let(:instructeur_3) { create(:instructeur) } + let(:variables) { { input: { groupeInstructeurId: groupe_instructeur.to_typed_id, instructeurs: [{ email: }, { id: instructeur_2.to_typed_id }, { id: instructeur_3.to_typed_id }] }, includeInstructeurs: true } } let(:operation_name) { 'groupeInstructeurSupprimerInstructeurs' } before do allow(GroupeInstructeurMailer).to receive(:notify_group_when_instructeurs_removed) .and_return(double(deliver_later: true)) + allow(GroupeInstructeurMailer).to receive(:notify_removed_instructeur) + .and_return(double(deliver_later: true)) existing_instructeur - groupe_instructeur.add(new_instructeur) + groupe_instructeur.add(instructeur_2) + groupe_instructeur.add(instructeur_3) end it { - expect(groupe_instructeur.reload.instructeurs.count).to eq(2) + expect(groupe_instructeur.reload.instructeurs.count).to eq(3) expect(gql_errors).to be_nil expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:errors]).to be_nil expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:id]).to eq(groupe_instructeur.to_typed_id) @@ -404,9 +408,10 @@ expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }]) expect(GroupeInstructeurMailer).to have_received(:notify_group_when_instructeurs_removed).with( groupe_instructeur, - [new_instructeur], + [instructeur_2, instructeur_3], admin.email ) + expect(GroupeInstructeurMailer).to have_received(:notify_removed_instructeur).twice } end From 6c277e867815db89311f0cebcab69bc4c56a7b94 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Tue, 21 Feb 2023 09:51:14 +0100 Subject: [PATCH 04/33] fix(groupe instructeur API): move condition to catch error --- .../mutations/groupe_instructeur_supprimer_instructeurs.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb index 8a45f4719a9..3dc02a7390f 100644 --- a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb +++ b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb @@ -12,10 +12,10 @@ def resolve(groupe_instructeur:, instructeurs:) ids, emails = partition_instructeurs_by(instructeurs) instructeurs = groupe_instructeur.instructeurs.find_all_by_identifier(ids:, emails:) - instructeurs.each { groupe_instructeur.remove(_1) } - groupe_instructeur.reload - if instructeurs.present? + instructeurs.each { groupe_instructeur.remove(_1) } + groupe_instructeur.reload + GroupeInstructeurMailer .notify_group_when_instructeurs_removed(groupe_instructeur, instructeurs, current_administrateur.email) .deliver_later From 72b6dacfbd4a0a7084dfa61302b30475f6f4b348 Mon Sep 17 00:00:00 2001 From: Eric Leroy-Terquem Date: Thu, 2 Mar 2023 10:17:31 +0100 Subject: [PATCH 05/33] fix(API): remove notification to group when instructeurs removed --- .../groupe_instructeur_supprimer_instructeurs.rb | 5 +---- .../api/v2/graphql_controller_stored_queries_spec.rb | 12 ------------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb index 3dc02a7390f..50358115e33 100644 --- a/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb +++ b/app/graphql/mutations/groupe_instructeur_supprimer_instructeurs.rb @@ -14,11 +14,8 @@ def resolve(groupe_instructeur:, instructeurs:) if instructeurs.present? instructeurs.each { groupe_instructeur.remove(_1) } - groupe_instructeur.reload - GroupeInstructeurMailer - .notify_group_when_instructeurs_removed(groupe_instructeur, instructeurs, current_administrateur.email) - .deliver_later + groupe_instructeur.reload instructeurs.each do |instructeur| GroupeInstructeurMailer diff --git a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb index ebb8a2bf598..4c6a44e9643 100644 --- a/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_stored_queries_spec.rb @@ -372,11 +372,6 @@ expect(gql_data[:groupeInstructeurAjouterInstructeurs][:groupeInstructeur][:id]).to eq(groupe_instructeur.to_typed_id) expect(groupe_instructeur.instructeurs.count).to eq(2) expect(gql_data[:groupeInstructeurAjouterInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }, { id: Instructeur.last.to_typed_id, email: }]) - expect(GroupeInstructeurMailer).to have_received(:notify_added_instructeurs).with( - groupe_instructeur, - [Instructeur.last], - admin.email - ) } end @@ -390,8 +385,6 @@ let(:operation_name) { 'groupeInstructeurSupprimerInstructeurs' } before do - allow(GroupeInstructeurMailer).to receive(:notify_group_when_instructeurs_removed) - .and_return(double(deliver_later: true)) allow(GroupeInstructeurMailer).to receive(:notify_removed_instructeur) .and_return(double(deliver_later: true)) existing_instructeur @@ -406,11 +399,6 @@ expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:id]).to eq(groupe_instructeur.to_typed_id) expect(groupe_instructeur.instructeurs.count).to eq(1) expect(gql_data[:groupeInstructeurSupprimerInstructeurs][:groupeInstructeur][:instructeurs]).to eq([{ id: existing_instructeur.to_typed_id, email: existing_instructeur.email }]) - expect(GroupeInstructeurMailer).to have_received(:notify_group_when_instructeurs_removed).with( - groupe_instructeur, - [instructeur_2, instructeur_3], - admin.email - ) expect(GroupeInstructeurMailer).to have_received(:notify_removed_instructeur).twice } end From 7ee62a170d39afb34c3176a30f2952bd5f338314 Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Mon, 19 Jun 2023 15:19:58 +0200 Subject: [PATCH 06/33] harmonize admin header for dashboard view --- .../administrateurs/_breadcrumbs.html.haml | 23 +++++++++++++------ .../locales/views/layouts/_breadcrumb.en.yml | 2 +- .../locales/views/layouts/_breadcrumb.fr.yml | 6 ++--- .../procedures/show.html.haml_spec.rb | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/views/administrateurs/_breadcrumbs.html.haml b/app/views/administrateurs/_breadcrumbs.html.haml index e0f96e56e17..0b3c69c0b04 100644 --- a/app/views/administrateurs/_breadcrumbs.html.haml +++ b/app/views/administrateurs/_breadcrumbs.html.haml @@ -22,12 +22,21 @@ - if defined?(metadatas) .metadatas.pb-3 - %h1.fr-h6.fr-mb-0= t('created_at', scope: [:layouts, :breadcrumb], number: @procedure.id, date: @procedure.created_at.strftime('%d/%m/%Y')) + %h1.fr-h6.fr-mb-1w + = @procedure.libelle + %span.fr-text--sm + = t('created_at', scope: [:layouts, :breadcrumb], number: @procedure.id, date: @procedure.created_at.strftime('%d/%m/%Y')) + - if @procedure.close? - %p.fr-h2= t('closed_at', scope: [:layouts, :breadcrumb], date: @procedure.closed_at.strftime('%d/%m/%Y')) - %p - - if @procedure.locked? - = t('published', scope: [:layouts, :breadcrumb]) - = link_to commencer_url(@procedure.path), commencer_url(@procedure.path) - - else + %span.fr-badge.fr-badge--warning + = t('closed_at', scope: [:layouts, :breadcrumb], date: @procedure.closed_at.strftime('%d/%m/%Y')) + + - elsif @procedure.locked? + .flex + %span.fr-badge.fr-badge--success.fr-mr-1w + = t('published', scope: [:layouts, :breadcrumb]) + = link_to commencer_url(@procedure.path), commencer_url(@procedure.path), class: "fr-link" + + - else + %span.fr-badge.fr-badge--info = t('draft', scope: [:layouts, :breadcrumb]) diff --git a/config/locales/views/layouts/_breadcrumb.en.yml b/config/locales/views/layouts/_breadcrumb.en.yml index 61c5e67460c..7c9037d2c31 100644 --- a/config/locales/views/layouts/_breadcrumb.en.yml +++ b/config/locales/views/layouts/_breadcrumb.en.yml @@ -7,7 +7,7 @@ en: preview: "Preview the form" continue: "Continue" continue_title: "You can comeback using this link" - created_at: "Procedure n° %{number} created at %{date}" + created_at: "- n° %{number} created at %{date}" closed_at: "Closed at %{date}" published: "Published" draft: "Draft" diff --git a/config/locales/views/layouts/_breadcrumb.fr.yml b/config/locales/views/layouts/_breadcrumb.fr.yml index 605fae51a35..87da3c3613f 100644 --- a/config/locales/views/layouts/_breadcrumb.fr.yml +++ b/config/locales/views/layouts/_breadcrumb.fr.yml @@ -7,7 +7,7 @@ fr: preview: "Prévisualiser le formulaire" continue: "Continuer" continue_title: "Vous pourrez revenir ici par la suite" - created_at: "Démarche n° %{number}, créée le %{date}" + created_at: "- n° %{number}, créée le %{date}" closed_at: "Close le %{date}" - published: "Publiée – " - draft: "Brouillon" + published: "Publiée" + draft: "En test" diff --git a/spec/views/administrateurs/procedures/show.html.haml_spec.rb b/spec/views/administrateurs/procedures/show.html.haml_spec.rb index f1059f15852..57224b13bbb 100644 --- a/spec/views/administrateurs/procedures/show.html.haml_spec.rb +++ b/spec/views/administrateurs/procedures/show.html.haml_spec.rb @@ -22,7 +22,7 @@ end describe 'procedure path is not customized' do - it { expect(rendered).to have_content('Brouillon') } + it { expect(rendered).to have_content('En test') } end describe 'archive button' do From 87347d34c63ad8e6f0bf17190acf30e10aa4b19c Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Thu, 22 Jun 2023 15:38:49 +0200 Subject: [PATCH 07/33] change date with status + add a title on the page regarding to Olivier Figma --- .../administrateurs/_breadcrumbs.html.haml | 19 +++++++++++-------- .../administrateurs/procedures/show.html.haml | 9 +++++---- .../locales/views/layouts/_breadcrumb.en.yml | 4 ++-- .../locales/views/layouts/_breadcrumb.fr.yml | 4 ++-- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/app/views/administrateurs/_breadcrumbs.html.haml b/app/views/administrateurs/_breadcrumbs.html.haml index 0b3c69c0b04..3907e6022c5 100644 --- a/app/views/administrateurs/_breadcrumbs.html.haml +++ b/app/views/administrateurs/_breadcrumbs.html.haml @@ -24,19 +24,22 @@ .metadatas.pb-3 %h1.fr-h6.fr-mb-1w = @procedure.libelle - %span.fr-text--sm - = t('created_at', scope: [:layouts, :breadcrumb], number: @procedure.id, date: @procedure.created_at.strftime('%d/%m/%Y')) - if @procedure.close? - %span.fr-badge.fr-badge--warning - = t('closed_at', scope: [:layouts, :breadcrumb], date: @procedure.closed_at.strftime('%d/%m/%Y')) + .flex + %span.fr-badge.fr-badge--warning.fr-mr-1w + = t('closed', scope: [:layouts, :breadcrumb]) + = t('since', scope: [:layouts, :breadcrumb], date: l(@procedure.closed_at.to_date)) - elsif @procedure.locked? - .flex + = link_to commencer_url(@procedure.path), commencer_url(@procedure.path), class: "fr-link" + .flex.fr-mt-1w %span.fr-badge.fr-badge--success.fr-mr-1w = t('published', scope: [:layouts, :breadcrumb]) - = link_to commencer_url(@procedure.path), commencer_url(@procedure.path), class: "fr-link" + = t('since', scope: [:layouts, :breadcrumb], number: @procedure.id, date: l(@procedure.published_at.to_date)) - else - %span.fr-badge.fr-badge--info - = t('draft', scope: [:layouts, :breadcrumb]) + .flex + %span.fr-badge.fr-badge--new.fr-mr-1w + = t('draft', scope: [:layouts, :breadcrumb]) + = t('since', scope: [:layouts, :breadcrumb], number: @procedure.id, date: l(@procedure.created_at.to_date)) diff --git a/app/views/administrateurs/procedures/show.html.haml b/app/views/administrateurs/procedures/show.html.haml index 1929d1e6321..04732db1778 100644 --- a/app/views/administrateurs/procedures/show.html.haml +++ b/app/views/administrateurs/procedures/show.html.haml @@ -43,8 +43,9 @@ - if !@procedure.procedure_expires_when_termine_enabled? = render partial: 'administrateurs/procedures/suggest_expires_when_termine', locals: { procedure: @procedure } .fr-container - %h2.fr-mt-5w.fr-mb-3w.fr-h1 Indispensable avant publication - .fr-grid-row.fr-grid-row--gutters + %h2= "Gestion de la démarche № #{@procedure.id}" + %h3.fr-h6 Indispensable avant publication + .fr-grid-row.fr-grid-row--gutters.fr-mb-5w = render Procedure::Card::PresentationComponent.new(procedure: @procedure) = render Procedure::Card::ZonesComponent.new(procedure: @procedure) if Rails.application.config.ds_zonage_enabled = render Procedure::Card::ChampsComponent.new(procedure: @procedure) @@ -53,8 +54,8 @@ = render Procedure::Card::InstructeursComponent.new(procedure: @procedure) = render Procedure::Card::ModificationsComponent.new(procedure: @procedure) - %h2.fr-mt-5w.fr-mb-3w.fr-h1 Pour aller plus loin - .fr-grid-row.fr-grid-row--gutters + %h3.fr-h6 Pour aller plus loin + .fr-grid-row.fr-grid-row--gutters.fr-mb-5w = render Procedure::Card::AttestationComponent.new(procedure: @procedure) = render Procedure::Card::ExpertsComponent.new(procedure: @procedure) = render Procedure::Card::EmailsComponent.new(procedure: @procedure) diff --git a/config/locales/views/layouts/_breadcrumb.en.yml b/config/locales/views/layouts/_breadcrumb.en.yml index 7c9037d2c31..91de48e102d 100644 --- a/config/locales/views/layouts/_breadcrumb.en.yml +++ b/config/locales/views/layouts/_breadcrumb.en.yml @@ -7,7 +7,7 @@ en: preview: "Preview the form" continue: "Continue" continue_title: "You can comeback using this link" - created_at: "- n° %{number} created at %{date}" - closed_at: "Closed at %{date}" + since: "since %{date}" + closed: "Closed" published: "Published" draft: "Draft" diff --git a/config/locales/views/layouts/_breadcrumb.fr.yml b/config/locales/views/layouts/_breadcrumb.fr.yml index 87da3c3613f..d38f9727160 100644 --- a/config/locales/views/layouts/_breadcrumb.fr.yml +++ b/config/locales/views/layouts/_breadcrumb.fr.yml @@ -7,7 +7,7 @@ fr: preview: "Prévisualiser le formulaire" continue: "Continuer" continue_title: "Vous pourrez revenir ici par la suite" - created_at: "- n° %{number}, créée le %{date}" - closed_at: "Close le %{date}" + since: "depuis le %{date}" + closed: "Close" published: "Publiée" draft: "En test" From 9c89719a51f535dfe9b97051d297dc2eed345e71 Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Thu, 22 Jun 2023 15:52:21 +0200 Subject: [PATCH 08/33] fix specs --- spec/system/administrateurs/procedure_archive_and_export_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/system/administrateurs/procedure_archive_and_export_spec.rb b/spec/system/administrateurs/procedure_archive_and_export_spec.rb index 7ff0d437af2..be511183e6c 100644 --- a/spec/system/administrateurs/procedure_archive_and_export_spec.rb +++ b/spec/system/administrateurs/procedure_archive_and_export_spec.rb @@ -7,6 +7,7 @@ let(:procedure) do create(:procedure, :with_service, :with_instructeur, aasm_state: :publiee, + published_at: Date.today, administrateurs: [administrateur], libelle: 'libellé de la procédure', path: 'libelle-de-la-procedure') From 5022018cff449c5cb19a4822bca389aab60a3c74 Mon Sep 17 00:00:00 2001 From: Julie Salha Date: Thu, 13 Apr 2023 16:25:45 +0200 Subject: [PATCH 09/33] additional content visible by default --- app/assets/stylesheets/dossier_champs.scss | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/assets/stylesheets/dossier_champs.scss b/app/assets/stylesheets/dossier_champs.scss index 86808d340c9..5b7271f7525 100644 --- a/app/assets/stylesheets/dossier_champs.scss +++ b/app/assets/stylesheets/dossier_champs.scss @@ -16,17 +16,5 @@ color: $dark-grey; text-align: right; width: 190px; - - > span { - opacity: 0; - - &.highlighted { - opacity: 1; - } - } - } - - tr:hover .updated-at > span { - opacity: 1; } } From e399aaf55d8d387b30bb7ca8093dd8e15968c43a Mon Sep 17 00:00:00 2001 From: Julie Salha Date: Thu, 13 Apr 2023 17:12:49 +0200 Subject: [PATCH 10/33] update structure and styles card dossier-champs --- app/assets/stylesheets/dossier_champs.scss | 7 +++++-- .../shared/dossiers/_champ_row.html.haml | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/dossier_champs.scss b/app/assets/stylesheets/dossier_champs.scss index 5b7271f7525..85aa2a94faf 100644 --- a/app/assets/stylesheets/dossier_champs.scss +++ b/app/assets/stylesheets/dossier_champs.scss @@ -11,10 +11,13 @@ width: 325px; } + td.libelle, td.updated-at { + width: 50%; + } + td.updated-at { font-size: 13px; color: $dark-grey; - text-align: right; - width: 190px; + text-align: left; } } diff --git a/app/views/shared/dossiers/_champ_row.html.haml b/app/views/shared/dossiers/_champ_row.html.haml index ea12edae6e5..a3b416e7718 100644 --- a/app/views/shared/dossiers/_champ_row.html.haml +++ b/app/views/shared/dossiers/_champ_row.html.haml @@ -13,9 +13,16 @@ %th.header-section{ colspan: 3, class: c.dossier.auto_numbering_section_headers_for?(c) ? "header-section-counter" : nil }= c.libelle - else %td.libelle{ class: repetition ? 'padded' : '' } - = "#{c.libelle} :" - %td.rich-text{ class: c.type_champ } - %div{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } + = "#{c.libelle} :" + - if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section) + %td.updated-at + %span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } + modifié le + = try_format_datetime(c.updated_at) + + %tr + %td.rich-text{ class: c.type_champ } + %div{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } - case c.type_champ - when TypeDeChamp.type_champs.fetch(:carte) = render partial: "shared/champs/carte/show", locals: { champ: c } @@ -62,8 +69,4 @@ - else = format_text_value(c.to_s) unless c.blank? - - if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section) - %td.updated-at - %span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } - modifié le - = try_format_datetime(c.updated_at) + From ddaacf1268392d1838f1fb8feefd8979db8f1ec7 Mon Sep 17 00:00:00 2001 From: Julie Salha Date: Thu, 13 Apr 2023 17:19:08 +0200 Subject: [PATCH 11/33] fix PR: each selector in one line --- app/assets/stylesheets/dossier_champs.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/dossier_champs.scss b/app/assets/stylesheets/dossier_champs.scss index 85aa2a94faf..bc272051373 100644 --- a/app/assets/stylesheets/dossier_champs.scss +++ b/app/assets/stylesheets/dossier_champs.scss @@ -11,7 +11,8 @@ width: 325px; } - td.libelle, td.updated-at { + td.libelle, + td.updated-at { width: 50%; } From dc0eaed2f081fa811f5511ef4300dce368351b89 Mon Sep 17 00:00:00 2001 From: Julie Salha Date: Thu, 13 Apr 2023 17:22:53 +0200 Subject: [PATCH 12/33] fix PR : remove trailing whitespace --- app/assets/stylesheets/dossier_champs.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/dossier_champs.scss b/app/assets/stylesheets/dossier_champs.scss index bc272051373..48755c339e0 100644 --- a/app/assets/stylesheets/dossier_champs.scss +++ b/app/assets/stylesheets/dossier_champs.scss @@ -11,7 +11,7 @@ width: 325px; } - td.libelle, + td.libelle, td.updated-at { width: 50%; } From 43c6f03d10ce4ab77044d93b9103f8ccb784aeb0 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 28 Apr 2023 10:33:01 +0200 Subject: [PATCH 13/33] amelioration(users/dossiers#demande): passage a la nouvelle ui/ux wip --- app/assets/stylesheets/02_utils.scss | 1 + app/assets/stylesheets/demande.scss | 34 +- app/assets/stylesheets/dossier_champs.scss | 20 +- app/assets/stylesheets/sections.scss | 12 +- .../dossiers/champ_row_show_component.rb | 21 ++ .../champ_row_show_component.en.yml | 3 + .../champ_row_show_component.fr.yml | 3 + .../champ_row_show_component.html.haml | 64 ++++ .../header_section_component.rb | 15 +- .../viewable_champ/section_component.rb | 45 +++ .../section_component.en.yml | 3 + .../section_component.fr.yml | 3 + .../section_component.html.haml | 14 + .../controllers/expand_controller.ts | 7 + app/javascript/shared/utils.test.ts | 10 +- app/javascript/shared/utils.ts | 4 +- .../shared/champs/address/_show.html.haml | 8 +- .../shared/champs/communes/_show.html.haml | 12 +- .../champs/dossier_link/_show.html.haml | 8 +- .../shared/dossiers/_champ_row.html.haml | 72 ---- app/views/shared/dossiers/_champs.html.haml | 26 +- app/views/shared/dossiers/_demande.html.haml | 32 +- .../dossiers/_identite_entreprise.html.haml | 350 +++++++++--------- .../dossiers/_identite_individual.html.haml | 37 +- .../dossiers/_infos_generales.html.haml | 28 +- .../shared/dossiers/_user_infos.html.haml | 9 +- app/views/users/dossiers/demande.html.haml | 1 + .../users/dossiers/show/_header.html.haml | 2 +- config/locales/en.yml | 2 + config/locales/fr.yml | 4 +- .../shared/dossiers/_champs.html.haml_spec.rb | 2 +- 31 files changed, 495 insertions(+), 357 deletions(-) create mode 100644 app/components/dossiers/champ_row_show_component.rb create mode 100644 app/components/dossiers/champ_row_show_component/champ_row_show_component.en.yml create mode 100644 app/components/dossiers/champ_row_show_component/champ_row_show_component.fr.yml create mode 100644 app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml create mode 100644 app/components/viewable_champ/section_component.rb create mode 100644 app/components/viewable_champ/section_component/section_component.en.yml create mode 100644 app/components/viewable_champ/section_component/section_component.fr.yml create mode 100644 app/components/viewable_champ/section_component/section_component.html.haml delete mode 100644 app/views/shared/dossiers/_champ_row.html.haml diff --git a/app/assets/stylesheets/02_utils.scss b/app/assets/stylesheets/02_utils.scss index 6e1a39bf1b1..0870552ae38 100644 --- a/app/assets/stylesheets/02_utils.scss +++ b/app/assets/stylesheets/02_utils.scss @@ -133,6 +133,7 @@ } } + // who known .highlighted { background: $orange-bg; diff --git a/app/assets/stylesheets/demande.scss b/app/assets/stylesheets/demande.scss index df4fd10c434..52dd1ef0796 100644 --- a/app/assets/stylesheets/demande.scss +++ b/app/assets/stylesheets/demande.scss @@ -1,27 +1,25 @@ @import "colors"; @import "constants"; -.demande { - padding-top: 3 * $default-padding; - padding-bottom: 3 * $default-padding; - - h1 { - margin-bottom: $default-padding; +.container { + @media (max-width: 48em) { + .d-block-sm { + display: block; + } } +} - .intro { - margin: $default-padding 0; - } +.champ-content { + padding: 0 0 ,5rem; - b { - font-weight: bold; + p { + padding: 0; + margin: 0; } +} - hr { - border: none; - height: 1px; - background-color: $grey; - margin-top: 2 * $default-padding; - margin-bottom: 2 * $default-padding; - } +.top-bordered { + border-top: 1px solid var(--border-default-grey); } + + diff --git a/app/assets/stylesheets/dossier_champs.scss b/app/assets/stylesheets/dossier_champs.scss index 48755c339e0..86808d340c9 100644 --- a/app/assets/stylesheets/dossier_champs.scss +++ b/app/assets/stylesheets/dossier_champs.scss @@ -11,14 +11,22 @@ width: 325px; } - td.libelle, - td.updated-at { - width: 50%; - } - td.updated-at { font-size: 13px; color: $dark-grey; - text-align: left; + text-align: right; + width: 190px; + + > span { + opacity: 0; + + &.highlighted { + opacity: 1; + } + } + } + + tr:hover .updated-at > span { + opacity: 1; } } diff --git a/app/assets/stylesheets/sections.scss b/app/assets/stylesheets/sections.scss index ef729ff35d9..7b08a1c26bd 100644 --- a/app/assets/stylesheets/sections.scss +++ b/app/assets/stylesheets/sections.scss @@ -29,32 +29,32 @@ counter-reset: h7; } - .header-section.fr-h2::before { + .header-section.section-2::before { counter-increment: h2; content: counter(h2) ". "; } - .header-section.fr-h3::before { + .header-section.section-3::before { counter-increment: h3; content: counter(h2) "." counter(h3) ". "; } - .header-section.fr-h4::before { + .header-section.section-4::before { counter-increment: h4; content: counter(h2) "." counter(h3) "." counter(h4) ". "; } - .header-section.fr-h5::before { + .header-section.section-5::before { counter-increment: h5; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". "; } - .header-section.fr-h6::before { + .header-section.section-6::before { counter-increment: h6; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "; } - .header-section.fr-h7::before { + .header-section.section-7::before { counter-increment: h7; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) "." counter(h7) ". "; } diff --git a/app/components/dossiers/champ_row_show_component.rb b/app/components/dossiers/champ_row_show_component.rb new file mode 100644 index 00000000000..07c844cd987 --- /dev/null +++ b/app/components/dossiers/champ_row_show_component.rb @@ -0,0 +1,21 @@ +class Dossiers::ChampRowShowComponent < ApplicationComponent + include ChampHelper + include DossierHelper + include ApplicationHelper + def initialize(champs:, demande_seen_at:, profile:, repetition:) + @repetition = repetition + @champs = champs + @demande_seen_at = demande_seen_at + @profile = profile + end + + def updated_after_deposer?(champ) + return false if champ.dossier.depose_at.blank? + champ.updated_at > champ.dossier.depose_at + end + + def number_with_html_delimiter(num) + # we are using the span delimiter that doesn't insert spaces when copying and pasting the number + number_with_delimiter(num, delimiter: tag.span(class: 'numbers-delimiter')) + end +end diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.en.yml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.en.yml new file mode 100644 index 00000000000..06715466672 --- /dev/null +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.en.yml @@ -0,0 +1,3 @@ +--- +en: + blank: "blank (optional)" diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.fr.yml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.fr.yml new file mode 100644 index 00000000000..a4af6d922e8 --- /dev/null +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.fr.yml @@ -0,0 +1,3 @@ +--- +fr: + blank: "non saisi (facultatif)" diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml new file mode 100644 index 00000000000..529b69470bb --- /dev/null +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -0,0 +1,64 @@ +- @champs.each do |champ| + .fr-px-4v.fr-my-2v + - if champ.repetition? + = champ.libelle + - champ.rows.each do |row| + = render Dossiers::ChampRowShowComponent.new(champs: row, demande_seen_at: @demande_seen_at, profile: @profile, repetition: true) + + - else + .flex.d-block-sm + %p.flex-grow.fr-text-action-high--grey.fr-mb-0= "#{champ.libelle} :" + %p.champ-updated-at.fr-mb-0.fr-text--sm + - if updated_after_deposer?(champ) + %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } + modifié le + = try_format_datetime(champ.updated_at) + + - if champ.blank? + .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } + %p= t('.blank') + - else + .champ-content.fr-text-action-high--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } + - case champ.type_champ + - when TypeDeChamp.type_champs.fetch(:carte) + = render partial: "shared/champs/carte/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:dossier_link) + = render partial: "shared/champs/dossier_link/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) + = render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:piece_justificative), TypeDeChamp.type_champs.fetch(:titre_identite) + = render partial: "shared/champs/piece_justificative/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:siret) + = render partial: "shared/champs/siret/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:iban) + = render partial: "shared/champs/iban/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:textarea) + = render partial: "shared/champs/textarea/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:annuaire_education) + = render partial: "shared/champs/annuaire_education/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:cnaf) + = render partial: "shared/champs/cnaf/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:dgfip) + = render partial: "shared/champs/dgfip/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:pole_emploi) + = render partial: "shared/champs/pole_emploi/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:mesri) + = render partial: "shared/champs/mesri/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:address) + = render partial: "shared/champs/address/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:communes) + = render partial: "shared/champs/communes/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:regions) + = render partial: "shared/champs/regions/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:rna) + = render partial: "shared/champs/rna/show", locals: { champ: champ, profile: @profile } + - when TypeDeChamp.type_champs.fetch(:epci) + = render partial: "shared/champs/epci/show", locals: { champ: champ } + - when TypeDeChamp.type_champs.fetch(:date) + %p= champ.to_s + - when TypeDeChamp.type_champs.fetch(:datetime) + %p= champ.to_s + - when TypeDeChamp.type_champs.fetch(:number) + %p= number_with_html_delimiter(champ.to_s) + - else + %p= format_text_value(champ.to_s.strip) unless champ.blank? diff --git a/app/components/editable_champ/header_section_component.rb b/app/components/editable_champ/header_section_component.rb index 31a10e7f5f8..e8ccadfc0d9 100644 --- a/app/components/editable_champ/header_section_component.rb +++ b/app/components/editable_champ/header_section_component.rb @@ -1,21 +1,28 @@ class EditableChamp::HeaderSectionComponent < ApplicationComponent - def initialize(form: nil, champ:, seen_at: nil) + def initialize(form: nil, champ:, seen_at: nil, html_class: {}) @champ = champ + @html_class = html_class end def level @champ.level + 1 # skip one heading level end + def collapsible? + @champ.level == 1 + end + def libelle @champ.libelle end def header_section_classnames class_names( - "fr-h#{level}": true, - 'header-section': @champ.dossier.auto_numbering_section_headers_for?(@champ), - 'hidden': !@champ.visible? + { + "section-#{level}": true, + 'header-section': @champ.dossier.auto_numbering_section_headers_for?(@champ), + 'hidden': !@champ.visible? + }.merge(@html_class) ) end diff --git a/app/components/viewable_champ/section_component.rb b/app/components/viewable_champ/section_component.rb new file mode 100644 index 00000000000..e35999a02c9 --- /dev/null +++ b/app/components/viewable_champ/section_component.rb @@ -0,0 +1,45 @@ +class ViewableChamp::SectionComponent < ApplicationComponent + include ApplicationHelper + include TreeableConcern + + def initialize(champs: nil, nodes: nil, demande_seen_at:, profile:) + @demande_seen_at, @profile, @repetition = demande_seen_at, profile + if nodes.nil? + nodes = to_tree(champs:) + end + @nodes = to_sections(nodes:) + end + + def section_id + @section_id ||= header_section ? dom_id(header_section, :content) : SecureRandom.uuid + end + + def header_section + return @nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp) + end + + def champs + tail.filter { _1.is_a?(Champ) && _1.visible? && !_1.exclude_from_view? } + end + + def sections + tail.filter { !_1.is_a?(Champ) } + end + + def tail + return @nodes if header_section.blank? + _, *rest_of_champ = @nodes + + rest_of_champ + end + + def tag_for_depth + "h#{header_section.level + 1}" if header_section + end + + private + + def to_sections(nodes:) + nodes.map { _1.is_a?(Array) ? ViewableChamp::SectionComponent.new(nodes: _1, demande_seen_at: @demande_seen_at, profile: @profile) : _1 } + end +end diff --git a/app/components/viewable_champ/section_component/section_component.en.yml b/app/components/viewable_champ/section_component/section_component.en.yml new file mode 100644 index 00000000000..2f33e8cc388 --- /dev/null +++ b/app/components/viewable_champ/section_component/section_component.en.yml @@ -0,0 +1,3 @@ +--- +en: + toggle_section: "Show/hide fields of « %{section} »" diff --git a/app/components/viewable_champ/section_component/section_component.fr.yml b/app/components/viewable_champ/section_component/section_component.fr.yml new file mode 100644 index 00000000000..57463791ca3 --- /dev/null +++ b/app/components/viewable_champ/section_component/section_component.fr.yml @@ -0,0 +1,3 @@ +--- +fr: + toggle_section: "Afficher/Cacher les champs de la section « %{section} »" diff --git a/app/components/viewable_champ/section_component/section_component.html.haml b/app/components/viewable_champ/section_component/section_component.html.haml new file mode 100644 index 00000000000..35995dec4b1 --- /dev/null +++ b/app/components/viewable_champ/section_component/section_component.html.haml @@ -0,0 +1,14 @@ += tag.div(class: "reset-#{tag_for_depth} fr-mt-4v", 'data-controller': 'expand') do + - if header_section + %div{ class: class_names(flex: true, "top-bordered" => header_section.level == 1) } + = render EditableChamp::HeaderSectionComponent.new(champ: header_section, html_class: {' fr-m-0 fr-text--md fr-px-4v flex-grow' => true, "fr-text-action-high--blue-france" => header_section.level == 1, 'fr-py-3v' => header_section.level == 1, 'fr-pt-3v' => header_section.level == 1}) + - if ![champs, sections].map(&:empty?).all? && header_section.level == 1 + %button{ type: "button", aria: { controls: section_id, "expanded": "true", label: t('.toggle_section', section: header_section.libelle) }, href: section_id, 'data-action': 'click->expand#toggle', class: "fr-btn fr-btn--tertiary-no-outline" } + %i.fr-icon-arrow-up-s-line{ 'aria-hidden': 'true', 'data-expand-target': 'icon' } + + %div{ id: section_id, 'data-expand-target': 'content' } + - if !champs.empty? + = render Dossiers::ChampRowShowComponent.new(champs: champs, demande_seen_at: @demande_seen_at, profile: @profile, repetition: false) + + - sections.each do |section| + = render section diff --git a/app/javascript/controllers/expand_controller.ts b/app/javascript/controllers/expand_controller.ts index 48352c08d87..79a84703819 100644 --- a/app/javascript/controllers/expand_controller.ts +++ b/app/javascript/controllers/expand_controller.ts @@ -8,8 +8,15 @@ export class ExpandController extends ApplicationController { declare readonly iconTarget: HTMLElement; toggle(event: Event) { + const target = event.currentTarget as HTMLButtonElement; + event.preventDefault(); toggle(this.contentTarget); toggleExpandIcon(this.iconTarget); + if (this.contentTarget.classList.contains('hidden')) { + target.setAttribute('aria-expanded', 'false'); + } else { + target.setAttribute('aria-expanded', 'true'); + } } } diff --git a/app/javascript/shared/utils.test.ts b/app/javascript/shared/utils.test.ts index 8bfec1edba7..8597cb61e9d 100644 --- a/app/javascript/shared/utils.test.ts +++ b/app/javascript/shared/utils.test.ts @@ -37,14 +37,14 @@ suite('@utils', () => { test('toggleExpandIcon', () => { const icon = document.createElement('icon'); - icon.classList.add('fr-icon-add-line'); + icon.classList.add('fr-icon-arrow-down-s-line'); toggleExpandIcon(icon); - expect(icon.classList.contains('fr-icon-subtract-line')).toBeTruthy(); - expect(icon.classList.contains('fr-icon-add-line')).toBeFalsy(); + expect(icon.classList.contains('fr-icon-arrow-up-s-line')).toBeTruthy(); + expect(icon.classList.contains('fr-icon-arrow-down-s-line')).toBeFalsy(); toggleExpandIcon(icon); - expect(icon.classList.contains('fr-icon-add-line')).toBeTruthy(); - expect(icon.classList.contains('fr-icon-subtract-line')).toBeFalsy(); + expect(icon.classList.contains('fr-icon-arrow-down-s-line')).toBeTruthy(); + expect(icon.classList.contains('fr-icon-arrow-up-s-line')).toBeFalsy(); }); test('isSelectElement', () => { diff --git a/app/javascript/shared/utils.ts b/app/javascript/shared/utils.ts index 77093a2125f..3d3d8d44e1e 100644 --- a/app/javascript/shared/utils.ts +++ b/app/javascript/shared/utils.ts @@ -88,8 +88,8 @@ export function toggle(el: Element | null, force?: boolean) { } export function toggleExpandIcon(icon: Element | null) { - icon?.classList.toggle('fr-icon-add-line'); - icon?.classList?.toggle('fr-icon-subtract-line'); + icon?.classList.toggle('fr-icon-arrow-down-s-line'); + icon?.classList?.toggle('fr-icon-arrow-up-s-line'); } export function enable( diff --git a/app/views/shared/champs/address/_show.html.haml b/app/views/shared/champs/address/_show.html.haml index aeafc0864ec..2febbf37aaa 100644 --- a/app/views/shared/champs/address/_show.html.haml +++ b/app/views/shared/champs/address/_show.html.haml @@ -1,4 +1,6 @@ -= format_text_value(champ.to_s) +- if champ.to_s.present? + %p= format_text_value(champ.to_s) - if champ.data.present? - Code INSEE : - = champ.data['city_code'] + %p + Code INSEE : + = champ.data['city_code'] diff --git a/app/views/shared/champs/communes/_show.html.haml b/app/views/shared/champs/communes/_show.html.haml index 10c7563d796..8bf86290d18 100644 --- a/app/views/shared/champs/communes/_show.html.haml +++ b/app/views/shared/champs/communes/_show.html.haml @@ -1,9 +1,9 @@ -= champ.to_s +%p= champ.to_s - if champ.code? - %p.text-sm + %p.fr-text--sm Code INSEE : = champ.code - - if champ.departement? - %br - Departement : - = champ.departement_code_and_name +- if champ.departement? + %p.fr-text--sm + Departement : + = champ.departement_code_and_name diff --git a/app/views/shared/champs/dossier_link/_show.html.haml b/app/views/shared/champs/dossier_link/_show.html.haml index 442a6c71c38..7d61a243ec0 100644 --- a/app/views/shared/champs/dossier_link/_show.html.haml +++ b/app/views/shared/champs/dossier_link/_show.html.haml @@ -2,10 +2,10 @@ - if dossier - path = dossier_linked_path(current_instructeur || current_user, dossier) - if path.present? - = link_to("Dossier nº #{dossier.id}", path, target: '_blank', rel: 'noopener') + %p= link_to("Dossier nº #{dossier.id}", path, target: '_blank', rel: 'noopener') - else - Dossier nº #{dossier.id} + %p Dossier nº #{dossier.id} %br - = sanitize(dossier.text_summary) + %p= sanitize(dossier.text_summary) - else - Pas de dossier associé + %p Pas de dossier associé diff --git a/app/views/shared/dossiers/_champ_row.html.haml b/app/views/shared/dossiers/_champ_row.html.haml deleted file mode 100644 index a3b416e7718..00000000000 --- a/app/views/shared/dossiers/_champ_row.html.haml +++ /dev/null @@ -1,72 +0,0 @@ -- champs.reject(&:exclude_from_view?).filter(&:visible?).each do |c| - - if c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) - %tr - %td.libelle.repetition{ colspan: 3 } - = "#{c.libelle} :" - - c.rows.each do |champs| - = render partial: "shared/dossiers/champ_row", locals: { champs: champs, demande_seen_at: demande_seen_at, profile: profile, repetition: true } - %tr - %td.libelle{ colspan: 4 } - - else - %tr - - if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section) - %th.header-section{ colspan: 3, class: c.dossier.auto_numbering_section_headers_for?(c) ? "header-section-counter" : nil }= c.libelle - - else - %td.libelle{ class: repetition ? 'padded' : '' } - = "#{c.libelle} :" - - if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section) - %td.updated-at - %span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } - modifié le - = try_format_datetime(c.updated_at) - - %tr - %td.rich-text{ class: c.type_champ } - %div{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) } - - case c.type_champ - - when TypeDeChamp.type_champs.fetch(:carte) - = render partial: "shared/champs/carte/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:dossier_link) - = render partial: "shared/champs/dossier_link/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) - = render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:piece_justificative) - = render partial: "shared/champs/piece_justificative/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:titre_identite) - = render partial: "shared/champs/piece_justificative/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:siret) - = render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:iban) - = render partial: "shared/champs/iban/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:textarea) - = render partial: "shared/champs/textarea/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:annuaire_education) - = render partial: "shared/champs/annuaire_education/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:cnaf) - = render partial: "shared/champs/cnaf/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:dgfip) - = render partial: "shared/champs/dgfip/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:pole_emploi) - = render partial: "shared/champs/pole_emploi/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:mesri) - = render partial: "shared/champs/mesri/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:address) - = render partial: "shared/champs/address/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:communes) - = render partial: "shared/champs/communes/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:regions) - = render partial: "shared/champs/regions/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:rna) - = render partial: "shared/champs/rna/show", locals: { champ: c, profile: profile } - - when TypeDeChamp.type_champs.fetch(:epci) - = render partial: "shared/champs/epci/show", locals: { champ: c } - - when TypeDeChamp.type_champs.fetch(:date) - = c.to_s - - when TypeDeChamp.type_champs.fetch(:datetime) - = c.to_s - - when TypeDeChamp.type_champs.fetch(:number) - = number_with_html_delimiter(c.to_s) - - else - = format_text_value(c.to_s) unless c.blank? - - diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml index 4eba2463f3f..497fe1cad65 100644 --- a/app/views/shared/dossiers/_champs.html.haml +++ b/app/views/shared/dossiers/_champs.html.haml @@ -1,10 +1,16 @@ -%table.table.vertical.dossier-champs.counter-start-header-section{ role: :presentation } - %tbody - - if dossier.show_groupe_instructeur_details? - %td.libelle= dossier.procedure.routing_criteria_name - %td{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) }= dossier.groupe_instructeur.label - %td.updated-at - %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } - modifié le - = try_format_datetime(dossier.updated_at) - = render partial: "shared/dossiers/champ_row", locals: { champs: champs, demande_seen_at: demande_seen_at, profile: profile, repetition: false } +- if dossier.show_groupe_instructeur_details? + .fr-my-4v.fr-px-4v + .flex + + %p.flex-grow.fr-text-action-high--grey.fr-mb-0= dossier.procedure.routing_criteria_name + %p.champ-updated-at.fr-mb-0.fr-text--sm + - if demande_seen_at&.<(dossier.groupe_instructeur_updated_at) + %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } + modifié le + = try_format_datetime(dossier.updated_at) + + .champ-content.fr-text-action-high--grey{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } + %p= dossier.groupe_instructeur.label + + += render ViewableChamp::SectionComponent.new(champs: champs, demande_seen_at: demande_seen_at, profile: profile) diff --git a/app/views/shared/dossiers/_demande.html.haml b/app/views/shared/dossiers/_demande.html.haml index 3cf1acd66c2..400e7e49a24 100644 --- a/app/views/shared/dossiers/_demande.html.haml +++ b/app/views/shared/dossiers/_demande.html.haml @@ -2,38 +2,40 @@ - content_for(:notice_info) do = render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information } -.container +.container.counter-start-header-section + %h2.fr-h6.fr-background-alt--grey.fr-mb-0 + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.en_construction') + - if dossier.depose_at.present? - .card - = render partial: "shared/dossiers/infos_generales", locals: { dossier: dossier } + = render partial: "shared/dossiers/infos_generales", locals: { dossier: dossier } .tab-title - %h2.fr-h6= t('views.shared.dossiers.demande.requester_identity') + %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.requester_identity') + - if dossier.etablissement.present? && profile == 'usager' && !dossier.read_only? + = link_to t('views.shared.dossiers.demande.edit_siret'), siret_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' + + - if dossier.individual.present? && profile == 'usager' && !dossier.read_only? + = link_to t('views.shared.dossiers.demande.edit_identity'), identite_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' + - if dossier.identity_updated_at.present? && demande_seen_at&.<(dossier.identity_updated_at) %span.highlighted modifié le = try_format_datetime(dossier.identity_updated_at) - .card + .fr-my-4v.fr-px-4v = render partial: "shared/dossiers/user_infos", locals: { user_deleted: dossier.user_deleted?, email: dossier.user_email_for(:display) } - if dossier.etablissement.present? = render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: dossier.etablissement, profile: profile } - - if profile == 'usager' && !dossier.read_only? - .flex.row-reverse - = link_to t('views.shared.dossiers.demande.edit_siret'), siret_dossier_path(dossier), class: 'button' - - if dossier.individual.present? = render partial: "shared/dossiers/identite_individual", locals: { individual: dossier.individual } - - if profile == 'usager' && !dossier.read_only? - .flex.row-reverse - = link_to t('views.shared.dossiers.demande.edit_identity'), identite_dossier_path(dossier), class: 'fr-btn fr-btn--tertiary' + %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.form') - %h2.fr-h6= t('views.shared.dossiers.demande.form') - champs = dossier.champs_public - if champs.any? || dossier.procedure.routing_enabled? - .card - = render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile } + = render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile } diff --git a/app/views/shared/dossiers/_identite_entreprise.html.haml b/app/views/shared/dossiers/_identite_entreprise.html.haml index 914186c3687..cc986b88761 100644 --- a/app/views/shared/dossiers/_identite_entreprise.html.haml +++ b/app/views/shared/dossiers/_identite_entreprise.html.haml @@ -1,173 +1,193 @@ - if etablissement.as_degraded_mode? - %table.table.vertical.dossier-champs{ role: :presentation } - %tbody - %tr - %td{ colspan: 2 } - .fr-alert.fr-alert--warning.fr-alert--sm - %p - LʼINSEE est indisponible, les informations sur lʼentreprise arriveront dʼici quelques heures. - - if profile == "instructeur" - %br - Il nʼest pas possible dʼaccepter ou de refuser un dossier sans cette étape. - - - - %tr - %td.libelle SIRET : - %td= etablissement.siret + .fr-alert.fr-alert--warning.fr-alert--sm + %p + LʼINSEE est indisponible, les informations sur lʼentreprise arriveront dʼici quelques heures. + - if profile == "instructeur" + %p + Il nʼest pas possible dʼaccepter ou de refuser un dossier sans cette étape. + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 SIRET : + .champ-content.fr-text-action-high--grey + %p= etablissement.siret - else - %table.table.vertical.dossier-champs{ role: :presentation } - %tbody - - if etablissement.diffusable_commercialement == false && profile != 'instructeur' - %tr - %td= t('warning_for_private_info', scope: 'views.shared.dossiers.identite_entreprise', siret: pretty_siret(etablissement.siret)) - - else - %tr - %td.libelle Dénomination : - %td= raison_sociale_or_name(etablissement) - %tr - %td.libelle SIRET : - %td #{pretty_siret(etablissement.siret)} #{ render Dsfr::CopyButtonComponent.new(text: etablissement.siret, title: "Copier le siret dans le presse-papier", success: "Le siret a été copié dans le presse-papier") } - - - - unless local_assigns[:short_identity] - - if etablissement.siret != etablissement.entreprise.siret_siege_social - %tr - %td.libelle SIRET du siège social: - %td= etablissement.entreprise.siret_siege_social - %tr - %td.libelle Forme juridique : - %td= sanitize(etablissement.entreprise.forme_juridique) - %tr - %td.libelle Libellé NAF : - %td= etablissement.libelle_naf - %tr - %td.libelle Code NAF : - %td= etablissement.naf - %tr - %td.libelle Date de création : - %td - = try_format_date(etablissement.entreprise.date_creation) - - - if etablissement.entreprise_etat_administratif.present? - %span.label= humanized_entreprise_etat_administratif(etablissement) - + - if etablissement.diffusable_commercialement == false && profile != 'instructeur' + .fr-my-2v + .champ-content.fr-text-action-high--grey + %p= t('warning_for_private_info', scope: 'views.shared.dossiers.identite_entreprise', siret: pretty_siret(etablissement.siret)) + - else + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Dénomination : + .champ-content.fr-text-action-high--grey + %p= raison_sociale_or_name(etablissement) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 SIRET : + .champ-content.fr-text-action-high--grey + %p #{pretty_siret(etablissement.siret)} #{ render Dsfr::CopyButtonComponent.new(text: etablissement.siret, title: "Copier le siret dans le presse-papier", success: "Le siret a été copié dans le presse-papier") } + + + - unless local_assigns[:short_identity] + - if etablissement.siret != etablissement.entreprise.siret_siege_social + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 SIRET du siège social: + .champ-content.fr-text-action-high--grey + %p= etablissement.entreprise.siret_siege_social + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Forme juridique : + .champ-content.fr-text-action-high--grey + %p= sanitize(etablissement.entreprise.forme_juridique) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Libellé NAF : + .champ-content.fr-text-action-high--grey + %p= etablissement.libelle_naf + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Code NAF : + .champ-content.fr-text-action-high--grey + %p= etablissement.naf + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Date de création : + .champ-content.fr-text-action-high--grey + %p + = try_format_date(etablissement.entreprise.date_creation) + + - if etablissement.entreprise_etat_administratif.present? + %span.label= humanized_entreprise_etat_administratif(etablissement) + + - if profile == 'instructeur' + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 + Effectif mensuel + = try_format_mois_effectif(etablissement) + (URSSAF) : + .champ-content.fr-text-action-high--grey + %p= etablissement.entreprise_effectif_mensuel + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 + Effectif moyen annuel + = etablissement.entreprise_effectif_annuel_annee + (URSSAF) : + .champ-content.fr-text-action-high--grey + %p= etablissement.entreprise_effectif_annuel + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Effectif de l'organisation (INSEE) : + .champ-content.fr-text-action-high--grey + %p + = effectif(etablissement) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Numéro de TVA intracommunautaire : + .champ-content.fr-text-action-high--grey + %p= etablissement.entreprise.numero_tva_intracommunautaire + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Adresse : + .champ-content.fr-text-action-high--grey + %p + - etablissement.adresse.split("\n").each do |line| + = line + %br + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Capital social : + .champ-content.fr-text-action-high--grey + %p= pretty_currency(etablissement.entreprise.capital_social) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Chiffre d’affaires : + .champ-content.fr-text-action-high--grey + %p - if profile == 'instructeur' - %tr - %td.libelle - Effectif mensuel - = try_format_mois_effectif(etablissement) - (URSSAF) : - %td= etablissement.entreprise_effectif_mensuel - %tr - %td.libelle - Effectif moyen annuel - = etablissement.entreprise_effectif_annuel_annee - (URSSAF) : - %td= etablissement.entreprise_effectif_annuel - %tr - %td.libelle Effectif de l'organisation (INSEE) : - %td - = effectif(etablissement) - %tr - %td.libelle Numéro de TVA intracommunautaire : - %td= etablissement.entreprise.numero_tva_intracommunautaire - %tr - %td.libelle Adresse : - %td - - etablissement.adresse.split("\n").each do |line| - = line + %details + - etablissement.exercices.each_with_index do |exercice, index| + = "#{exercice.date_fin_exercice.year} : " + = pretty_currency(exercice.ca) %br - %tr - %td.libelle Capital social : - %td= pretty_currency(etablissement.entreprise.capital_social) - %tr - %td.libelle Chiffre d’affaires : - %td - - if profile == 'instructeur' - %details - - etablissement.exercices.each_with_index do |exercice, index| - = "#{exercice.date_fin_exercice.year} : " - = pretty_currency(exercice.ca) - %br - - elsif etablissement.exercices.present? - = t('activemodel.models.exercices_summary', count: etablissement.exercices.count) - - - - if etablissement.entreprise_bilans_bdf.present? - - if profile == 'instructeur' - = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', - locals: { libelle: 'Résultat exercice', key: 'resultat_exercice', etablissement: etablissement } - - = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', - locals: { libelle: "Excédent brut d’exploitation", key: 'excedent_brut_exploitation', etablissement: etablissement } - - = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', - locals: { libelle: 'Fonds de roulement net global', key: 'fonds_roulement_net_global', etablissement: etablissement } - - = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', - locals: { libelle: 'Besoin en fonds de roulement', key: 'besoin_en_fonds_de_roulement', etablissement: etablissement } - %tr - %td.libelle - Chiffres financiers clés (Banque de France) - = "en #{pretty_currency_unit(etablissement.entreprise_bilans_bdf_monnaie)} :" - - - if controller.is_a?(Instructeurs::AvisController) - %td - Les consulter - = link_to "au format csv", bilans_bdf_instructeur_avis_path(@avis, format: 'csv') - , - = link_to "au format xlsx", bilans_bdf_instructeur_avis_path(@avis, format: 'xlsx') - ou - = link_to "au format ods", bilans_bdf_instructeur_avis_path(@avis, format: 'ods') - - else - %td - Les consulter - = link_to "au format csv", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'csv') - , - = link_to "au format xlsx", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'xlsx') - ou - = link_to "au format ods", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'ods') + - elsif etablissement.exercices.present? + = t('activemodel.models.exercices_summary', count: etablissement.exercices.count) + + + - if etablissement.entreprise_bilans_bdf.present? + - if profile == 'instructeur' + = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', + locals: { libelle: 'Résultat exercice', key: 'resultat_exercice', etablissement: etablissement } + + = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', + locals: { libelle: "Excédent brut d’exploitation", key: 'excedent_brut_exploitation', etablissement: etablissement } + + = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', + locals: { libelle: 'Fonds de roulement net global', key: 'fonds_roulement_net_global', etablissement: etablissement } + + = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', + locals: { libelle: 'Besoin en fonds de roulement', key: 'besoin_en_fonds_de_roulement', etablissement: etablissement } + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 + Chiffres financiers clés (Banque de France) + = "en #{pretty_currency_unit(etablissement.entreprise_bilans_bdf_monnaie)} :" + + - if controller.is_a?(Instructeurs::AvisController) + .champ-content.fr-text-action-high--grey + %p + Les consulter + = link_to "au format csv", bilans_bdf_instructeur_avis_path(@avis, format: 'csv') + , + = link_to "au format xlsx", bilans_bdf_instructeur_avis_path(@avis, format: 'xlsx') + ou + = link_to "au format ods", bilans_bdf_instructeur_avis_path(@avis, format: 'ods') - else - %tr - %td.libelle - Bilans Banque de France : - %td Les 3 derniers bilans connus de votre entreprise par la Banque de France ont été joints à votre dossier. - - if etablissement.entreprise_attestation_sociale.attached? - %tr - %td.libelle Attestation sociale : - - if profile == 'instructeur' - %td= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_sociale) - - else - %td Une attestation de vigilance délivrée par l'ACOSS a été jointe à votre dossier. - - - if etablissement.entreprise_attestation_fiscale.attached? - %tr - %td.libelle Attestation fiscale : - - if profile == 'instructeur' - %td= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_fiscale) - - else - %td Une attestation fiscale délivrée par l'URSSAF a été jointe à votre dossier. - - - if etablissement.association? - %tr - %td.libelle Numéro RNA : - %td= etablissement.association_rna - %tr - %td.libelle Titre : - %td= etablissement.association_titre - %tr - %td.libelle Objet : - %td= etablissement.association_objet - %tr - %td.libelle Date de création : - %td= try_format_date(etablissement.association_date_creation) - %tr - %td.libelle Date de publication : - %td= try_format_date(etablissement.association_date_publication) - %tr - %td.libelle Date de déclaration : - %td= try_format_date(etablissement.association_date_declaration) + .champ-content.fr-text-action-high--grey + %p + Les consulter + = link_to "au format csv", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'csv') + , + = link_to "au format xlsx", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'xlsx') + ou + = link_to "au format ods", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'ods') + - else + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 + Bilans Banque de France : + .champ-content.fr-text-action-high--grey + %p Les 3 derniers bilans connus de votre entreprise par la Banque de France ont été joints à votre dossier. + - if etablissement.entreprise_attestation_sociale.attached? + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Attestation sociale : + - if profile == 'instructeur' + .champ-content.fr-text-action-high--grey + %p= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_sociale) + - else + .champ-content.fr-text-action-high--grey + %p Une attestation de vigilance délivrée par l'ACOSS a été jointe à votre dossier. + + - if etablissement.entreprise_attestation_fiscale.attached? + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Attestation fiscale : + - if profile == 'instructeur' + .champ-content.fr-text-action-high--grey + %p= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_fiscale) + - else + .champ-content.fr-text-action-high--grey + %p Une attestation fiscale délivrée par l'URSSAF a été jointe à votre dossier. + + - if etablissement.association? + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Numéro RNA : + .champ-content.fr-text-action-high--grey + %p= etablissement.association_rna + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Titre : + .champ-content.fr-text-action-high--grey + %p= etablissement.association_titre + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Objet : + .champ-content.fr-text-action-high--grey + %p= etablissement.association_objet + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Date de création : + .champ-content.fr-text-action-high--grey + %p= try_format_date(etablissement.association_date_creation) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Date de publication : + .champ-content.fr-text-action-high--grey + %p= try_format_date(etablissement.association_date_publication) + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Date de déclaration : + .champ-content.fr-text-action-high--grey + %p= try_format_date(etablissement.association_date_declaration) - unless local_assigns[:short_identity] %p diff --git a/app/views/shared/dossiers/_identite_individual.html.haml b/app/views/shared/dossiers/_identite_individual.html.haml index d7f0f44731c..8532799d49d 100644 --- a/app/views/shared/dossiers/_identite_individual.html.haml +++ b/app/views/shared/dossiers/_identite_individual.html.haml @@ -1,19 +1,18 @@ -%table.table.vertical.dossier-champs{ role: :presentation } - %tbody - %tr - %td.libelle - = t('views.users.dossiers.identite.civility') - %td= individual.gender - %tr - %td.libelle - = t('views.users.dossiers.identite.first_name') - %td= individual.prenom - %tr - %td.libelle - = t('views.users.dossiers.identite.last_name') - %td= individual.nom - - if individual.birthdate.present? - %tr - %td.libelle - = t('views.users.dossiers.identite.birthdate') - %td= try_format_date(individual.birthdate) + +.fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.civility') + .champ-content.fr-text-action-high--grey + %p= individual.gender +.fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.first_name') + .champ-content.fr-text-action-high--grey + %p= individual.prenom +.fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.last_name') + .champ-content.fr-text-action-high--grey + %p= individual.nom +- if individual.birthdate.present? + .fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.birthdate') + .champ-content.fr-text-action-high--grey + %p= try_format_date(individual.birthdate) diff --git a/app/views/shared/dossiers/_infos_generales.html.haml b/app/views/shared/dossiers/_infos_generales.html.haml index 4eae901faab..752ad175460 100644 --- a/app/views/shared/dossiers/_infos_generales.html.haml +++ b/app/views/shared/dossiers/_infos_generales.html.haml @@ -1,26 +1,26 @@ -%table.table.vertical.dossier-champs{ role: :presentation } - %tbody - %tr - %td.libelle Déposé le : - %td= l(dossier.depose_at, format: '%d %B %Y') +%div + %p.fr-my-4v.fr-px-4v.fr-text-action-high--grey + = l(dossier.depose_at, format: '%d %B %Y %H:%m') + - if dossier.updated_at != dossier.depose_at + = t('views.shared.dossiers.demande.updated_at', updated_at: l(dossier.updated_at, format: '%d %B %y %H:%m')) - if dossier.justificatif_motivation.attached? - %tr - %td.libelle Justificatif : - %td + .fr-my-4v.fr-px-4v + %p.fr-text-action-high--grey.fr-mb-0 Justificatif : + .champ-content.fr-text-action-high--grey .action = render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment) - if dossier.motivation.present? - %tr - %td.libelle Motivation : - %td + .fr-my-4v.fr-px-4v + %p.fr-text-action-high--grey.fr-mb-0 Motivation : + .champ-content.fr-text-action-high--grey .action = dossier.motivation - if dossier.attestation.present? - %tr - %td.libelle Attestation : - %td + .fr-my-4v.fr-px-4v + %p.fr-text-action-high--grey.fr-mb-0 Attestation : + .champ-content.fr-text-action-high--grey .action = link_to('Voir l’attestation', attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener') diff --git a/app/views/shared/dossiers/_user_infos.html.haml b/app/views/shared/dossiers/_user_infos.html.haml index 06fb41b94e2..c52e9367d8b 100644 --- a/app/views/shared/dossiers/_user_infos.html.haml +++ b/app/views/shared/dossiers/_user_infos.html.haml @@ -1,5 +1,4 @@ -%table.table.vertical.dossier-champs{ role: :presentation } - %tbody - %tr - %td.libelle Email : - %td= user_deleted ? "#{email} (l’usager a supprimé son compte)" : email +.fr-my-2v + %p.fr-text-action-high--grey.fr-mb-0 Email : + .champ-content.fr-text-action-high--grey + %p= user_deleted ? "#{email} (l’usager a supprimé son compte)" : email diff --git a/app/views/users/dossiers/demande.html.haml b/app/views/users/dossiers/demande.html.haml index 9f969420b9a..ab42fc52d04 100644 --- a/app/views/users/dossiers/demande.html.haml +++ b/app/views/users/dossiers/demande.html.haml @@ -14,6 +14,7 @@ = render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'usager' } + .container - if !@dossier.read_only? = link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm', 'title'=> "Modifier mon dossier tant qu'il n'est pas passé en instruction" diff --git a/app/views/users/dossiers/show/_header.html.haml b/app/views/users/dossiers/show/_header.html.haml index e5544c01a29..4ec22aa40c7 100644 --- a/app/views/users/dossiers/show/_header.html.haml +++ b/app/views/users/dossiers/show/_header.html.haml @@ -18,7 +18,7 @@ = render partial: 'invites/dropdown', locals: { dossier: dossier, morphing: false } - if dossier.can_be_updated_by_user? && !current_page?(modifier_dossier_path(dossier)) = link_to t('views.users.dossiers.show.header.edit_dossier'), modifier_dossier_path(dossier), class: 'fr-btn fr-btn-sm', - title: { label: t('views.users.dossiers.show.header.edit_dossier_title') } + title: t('views.users.dossiers.show.header.edit_dossier_title') = render(partial: 'users/dossiers/show/print_dossier', locals: { dossier: dossier }) %nav.tabs diff --git a/config/locales/en.yml b/config/locales/en.yml index e23626a0fcb..8daf00e0b4f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -341,6 +341,8 @@ en: write_message_placeholder: "Write your message here" write_message_to_administration_placeholder: "Write your message to the administration here" demande: + en_construction: "File submission date" + updated_at: "updated at %{updated_at}" requester_identity: "Identity of the requester" my_identity: "My identity" form: "Form" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 57a1ee46dc2..c44f09dc27f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -341,9 +341,11 @@ fr: write_message_placeholder: "Écrivez votre message ici" write_message_to_administration_placeholder: "Écrivez votre message à l’administration ici" demande: + en_construction: "Date de dépôt du dossier" + updated_at: "mis à jour le %{updated_at}" requester_identity: "Identité du demandeur" my_identity: "Mon identité" - form: "Formulaire" + form: "Sections du formulaire" edit_siret: "Modifier le SIRET" edit_identity: "Modifier l’identité" instructeurs: diff --git a/spec/views/shared/dossiers/_champs.html.haml_spec.rb b/spec/views/shared/dossiers/_champs.html.haml_spec.rb index bcf3ae71906..1737cd6e9a6 100644 --- a/spec/views/shared/dossiers/_champs.html.haml_spec.rb +++ b/spec/views/shared/dossiers/_champs.html.haml_spec.rb @@ -108,7 +108,7 @@ let(:champ) { create(:champ_dossier_link, dossier: dossier, value: nil) } let(:champs) { [champ] } - it { is_expected.to include("Pas de dossier associé") } + it { is_expected.to include("non saisi (facultatif)") } end context "with seen_at" do From 217f32deca97953b754f1e75333737437f620107 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 22 Jun 2023 17:17:53 +0200 Subject: [PATCH 14/33] review(colin): quelques suggestions de co-linux --- .../champ_row_show_component.html.haml | 4 +- .../editable_champ/section_component.rb | 4 +- .../viewable_champ/section_component.rb | 12 ++-- app/views/shared/dossiers/_champs.html.haml | 3 +- app/views/shared/dossiers/_demande.html.haml | 56 ++++++++++--------- .../dossiers/_infos_generales.html.haml | 3 +- app/views/users/dossiers/demande.html.haml | 10 ++-- config/locales/en.yml | 4 +- config/locales/fr.yml | 7 ++- 9 files changed, 56 insertions(+), 47 deletions(-) diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index 529b69470bb..bfa8796009b 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -11,9 +11,7 @@ %p.champ-updated-at.fr-mb-0.fr-text--sm - if updated_after_deposer?(champ) %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } - modifié le - = try_format_datetime(champ.updated_at) - + = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(champ.updated_at)) - if champ.blank? .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } %p= t('.blank') diff --git a/app/components/editable_champ/section_component.rb b/app/components/editable_champ/section_component.rb index c8ad567a1ef..12a14f01d8c 100644 --- a/app/components/editable_champ/section_component.rb +++ b/app/components/editable_champ/section_component.rb @@ -3,9 +3,7 @@ class EditableChamp::SectionComponent < ApplicationComponent include TreeableConcern def initialize(nodes: nil, champs: nil) - if (nodes.nil?) - nodes = to_tree(champs:) - end + nodes ||= to_tree(champs:) @nodes = to_fieldset(nodes:) end diff --git a/app/components/viewable_champ/section_component.rb b/app/components/viewable_champ/section_component.rb index e35999a02c9..703eb8b0917 100644 --- a/app/components/viewable_champ/section_component.rb +++ b/app/components/viewable_champ/section_component.rb @@ -4,9 +4,7 @@ class ViewableChamp::SectionComponent < ApplicationComponent def initialize(champs: nil, nodes: nil, demande_seen_at:, profile:) @demande_seen_at, @profile, @repetition = demande_seen_at, profile - if nodes.nil? - nodes = to_tree(champs:) - end + nodes ||= to_tree(champs:) @nodes = to_sections(nodes:) end @@ -15,7 +13,9 @@ def section_id end def header_section - return @nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp) + if @nodes.first.is_a?(Champs::HeaderSectionChamp) + @nodes.first + end end def champs @@ -37,6 +37,10 @@ def tag_for_depth "h#{header_section.level + 1}" if header_section end + def first_level? + header_section.level == 1 + end + private def to_sections(nodes:) diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml index 497fe1cad65..8ee1d233661 100644 --- a/app/views/shared/dossiers/_champs.html.haml +++ b/app/views/shared/dossiers/_champs.html.haml @@ -6,8 +6,7 @@ %p.champ-updated-at.fr-mb-0.fr-text--sm - if demande_seen_at&.<(dossier.groupe_instructeur_updated_at) %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } - modifié le - = try_format_datetime(dossier.updated_at) + = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(dossier.updated_at)) .champ-content.fr-text-action-high--grey{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } %p= dossier.groupe_instructeur.label diff --git a/app/views/shared/dossiers/_demande.html.haml b/app/views/shared/dossiers/_demande.html.haml index 400e7e49a24..83f329e21e4 100644 --- a/app/views/shared/dossiers/_demande.html.haml +++ b/app/views/shared/dossiers/_demande.html.haml @@ -2,40 +2,42 @@ - content_for(:notice_info) do = render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information } -.container.counter-start-header-section - %h2.fr-h6.fr-background-alt--grey.fr-mb-0 - .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.en_construction') +.fr-container.counter-start-header-section + .fr-grid-row + .fr-col-12.fr-col-offset-lg-2.fr-col-lg-8 + %h2.fr-h6.fr-background-alt--grey.fr-mb-0 + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.en_construction') - - if dossier.depose_at.present? - = render partial: "shared/dossiers/infos_generales", locals: { dossier: dossier } + - if dossier.depose_at.present? + = render partial: "shared/dossiers/infos_generales", locals: { dossier: dossier } - .tab-title - %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex - .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.requester_identity') - - if dossier.etablissement.present? && profile == 'usager' && !dossier.read_only? - = link_to t('views.shared.dossiers.demande.edit_siret'), siret_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' + .tab-title + %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.requester_identity') + - if dossier.etablissement.present? && profile == 'usager' && !dossier.read_only? + = link_to t('views.shared.dossiers.demande.edit_siret'), siret_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' - - if dossier.individual.present? && profile == 'usager' && !dossier.read_only? - = link_to t('views.shared.dossiers.demande.edit_identity'), identite_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' + - if dossier.individual.present? && profile == 'usager' && !dossier.read_only? + = link_to t('views.shared.dossiers.demande.edit_identity'), identite_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' - - if dossier.identity_updated_at.present? && demande_seen_at&.<(dossier.identity_updated_at) - %span.highlighted - modifié le - = try_format_datetime(dossier.identity_updated_at) + - if dossier.identity_updated_at.present? && demande_seen_at&.<(dossier.identity_updated_at) + %span.highlighted + modifié le + = try_format_datetime(dossier.identity_updated_at) - .fr-my-4v.fr-px-4v - = render partial: "shared/dossiers/user_infos", locals: { user_deleted: dossier.user_deleted?, email: dossier.user_email_for(:display) } + .fr-my-4v.fr-px-4v + = render partial: "shared/dossiers/user_infos", locals: { user_deleted: dossier.user_deleted?, email: dossier.user_email_for(:display) } - - if dossier.etablissement.present? - = render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: dossier.etablissement, profile: profile } + - if dossier.etablissement.present? + = render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: dossier.etablissement, profile: profile } - - if dossier.individual.present? - = render partial: "shared/dossiers/identite_individual", locals: { individual: dossier.individual } + - if dossier.individual.present? + = render partial: "shared/dossiers/identite_individual", locals: { individual: dossier.individual } - %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex - .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.form') + %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex + .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.form') - - champs = dossier.champs_public - - if champs.any? || dossier.procedure.routing_enabled? - = render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile } + - champs = dossier.champs_public + - if champs.any? || dossier.procedure.routing_enabled? + = render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile } diff --git a/app/views/shared/dossiers/_infos_generales.html.haml b/app/views/shared/dossiers/_infos_generales.html.haml index 752ad175460..3f03d963944 100644 --- a/app/views/shared/dossiers/_infos_generales.html.haml +++ b/app/views/shared/dossiers/_infos_generales.html.haml @@ -2,7 +2,8 @@ %p.fr-my-4v.fr-px-4v.fr-text-action-high--grey = l(dossier.depose_at, format: '%d %B %Y %H:%m') - if dossier.updated_at != dossier.depose_at - = t('views.shared.dossiers.demande.updated_at', updated_at: l(dossier.updated_at, format: '%d %B %y %H:%m')) + = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: l(dossier.updated_at, format: :long)) + - if dossier.justificatif_motivation.attached? .fr-my-4v.fr-px-4v diff --git a/app/views/users/dossiers/demande.html.haml b/app/views/users/dossiers/demande.html.haml index ab42fc52d04..f6d81f1bffb 100644 --- a/app/views/users/dossiers/demande.html.haml +++ b/app/views/users/dossiers/demande.html.haml @@ -15,7 +15,9 @@ = render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'usager' } - .container - - if !@dossier.read_only? - = link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm', 'title'=> "Modifier mon dossier tant qu'il n'est pas passé en instruction" - .clearfix + .fr-container + .fr-grid-row + .fr-col-12.fr-col-offset-lg-2.fr-col-lg-8 + - if !@dossier.read_only? + = link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm', 'title'=> "Modifier mon dossier tant qu'il n'est pas passé en instruction" + .clearfix diff --git a/config/locales/en.yml b/config/locales/en.yml index 8daf00e0b4f..540124a7241 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -330,6 +330,8 @@ en: hello: Dear Sir or Madam, best_regards: Best Regards, dossiers: + form: + updated_at: "updated at %{datetime}" edit: autosave: Your file is automatically saved after each modification. You can close the window at any time and pick up where you left off later. notice: "Download the notice of the procedure" @@ -341,8 +343,6 @@ en: write_message_placeholder: "Write your message here" write_message_to_administration_placeholder: "Write your message to the administration here" demande: - en_construction: "File submission date" - updated_at: "updated at %{updated_at}" requester_identity: "Identity of the requester" my_identity: "My identity" form: "Form" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index c44f09dc27f..7779d584b9b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -330,6 +330,8 @@ fr: hello: Bonjour, best_regards: Bonne journée, dossiers: + form: + updated_at: "modifié le %{datetime}" edit: autosave: Votre dossier est enregistré automatiquement après chaque modification. Vous pouvez à tout moment fermer la fenêtre et reprendre plus tard là où vous en étiez. notice: Télécharger le guide de la démarche @@ -342,7 +344,6 @@ fr: write_message_to_administration_placeholder: "Écrivez votre message à l’administration ici" demande: en_construction: "Date de dépôt du dossier" - updated_at: "mis à jour le %{updated_at}" requester_identity: "Identité du demandeur" my_identity: "Mon identité" form: "Sections du formulaire" @@ -692,6 +693,10 @@ fr: time: formats: default: "%d %B %Y %R" + long: "%d %B %y %H:%m" + datetime: + formats: + long: "%d %B %y %H:%m" pluralize: case: one: dossier From 7ce7a3f62c0773296f96fbdde76dd484ee9d8607 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Wed, 21 Jun 2023 15:16:55 +0200 Subject: [PATCH 15/33] feat: change pj token to year/aa/bb/token to spread pjs under namespaces --- config/initializers/active_storage.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb index dfa8c858211..bea706177ab 100644 --- a/config/initializers/active_storage.rb +++ b/config/initializers/active_storage.rb @@ -7,6 +7,11 @@ include BlobTitreIdentiteWatermarkConcern include BlobVirusScannerConcern include BlobSignedIdConcern + + def self.generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) + token = super + "#{Time.current.year}/#{token[0..1]}/#{token[2..3]}/#{token}" + end end ActiveSupport.on_load(:active_storage_attachment) do From 9fa864448ee345272d0eb62cac553bc2caab7c28 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 26 Jun 2023 10:24:52 +0200 Subject: [PATCH 16/33] add tasks / job to migrate pjs under namespace --- app/jobs/pjs_migration_job.rb | 31 +++++++++++++++++++++++++++++++ lib/tasks/pjs.rake | 25 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 app/jobs/pjs_migration_job.rb create mode 100644 lib/tasks/pjs.rake diff --git a/app/jobs/pjs_migration_job.rb b/app/jobs/pjs_migration_job.rb new file mode 100644 index 00000000000..eff8b501457 --- /dev/null +++ b/app/jobs/pjs_migration_job.rb @@ -0,0 +1,31 @@ +class PjsMigrationJob < ApplicationJob + queue_as :pj_migration_jobs + + def perform(blob_id) + blob = Blob.find(blob_id) + + return if already_moved?(blob) + + service = blob.service + client = service.client + container = service.container + old_key = blob.key + new_key = "#{blob.created_at.year}/#{old_key[0..1]}/#{old_key[2..3]}/#{old_key}" + + excon_response = client.copy_object(container, + old_key, + container, + new_key, + { "Content-Type" => blob.content_type }) + + if excon_response.status == 201 + blob.update_columns(key: new_key) + client.delete_object(container, old_key) + end + rescue Fog::OpenStack::Storage::NotFound + end + + def already_moved?(blob) + blob.key.include?('/') + end +end diff --git a/lib/tasks/pjs.rake b/lib/tasks/pjs.rake new file mode 100644 index 00000000000..6b52198fc1a --- /dev/null +++ b/lib/tasks/pjs.rake @@ -0,0 +1,25 @@ +namespace :pjs do + task stats: :environment do + end + + desc <<~EOD + bin/rake 'pjs:migrate['aa']' + bin/rake 'pjs:migrate['aa-ab-ac']' + EOD + task :migrate, [:prefixes] => :environment do |_t, args| + # [a-b] => "key LIKE 'a%' or key LIKE 'b%'" + prefix_like_query = args[:prefixes] + .split('-') + .map { "key LIKE '#{_1}%'" } + .join(' or ') + + blobs = ActiveStorage::Blob + .where(prefix_like_query) + .where.not("key LIKE '%/%'") # do not touch already moved blob + + blobs_count = blobs.count + rake_puts "targeted prefix: #{args[:prefixes]}, #{blobs_count} blobs" + + blobs.in_batches { |batch| batch.ids.each { |id| PjsMigrationJob.perform_later(id) } } + end +end From 61d620c280d96dcaf9074b5cd5431ae4f94ab538 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 23 Jun 2023 14:21:00 +0200 Subject: [PATCH 17/33] amelioration(expiration.dossiers): evite d'envoyer tous les mails d'un coup. Donc supprime les dossiers en brouillon a 22h, les dossiers en construction a 14h, les dossiers termine a 7h. --- app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb | 7 +++++++ app/jobs/cron/expired_dossiers_deletion_job.rb | 9 --------- .../expired_dossiers_en_construction_deletion_job.rb | 7 +++++++ app/jobs/cron/expired_dossiers_termine_deletion_job.rb | 7 +++++++ 4 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb delete mode 100644 app/jobs/cron/expired_dossiers_deletion_job.rb create mode 100644 app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb create mode 100644 app/jobs/cron/expired_dossiers_termine_deletion_job.rb diff --git a/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb b/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb new file mode 100644 index 00000000000..fb3e291686b --- /dev/null +++ b/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb @@ -0,0 +1,7 @@ +class Cron::ExpiredDossiersBrouillonDeletionJob < Cron::CronJob + self.schedule_expression = "every day at 10 pm" + + def perform(*args) + ExpiredDossiersDeletionService.process_expired_dossiers_brouillon + end +end diff --git a/app/jobs/cron/expired_dossiers_deletion_job.rb b/app/jobs/cron/expired_dossiers_deletion_job.rb deleted file mode 100644 index 05ee5363255..00000000000 --- a/app/jobs/cron/expired_dossiers_deletion_job.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Cron::ExpiredDossiersDeletionJob < Cron::CronJob - self.schedule_expression = "every day at 7 am" - - def perform(*args) - ExpiredDossiersDeletionService.process_expired_dossiers_brouillon - ExpiredDossiersDeletionService.process_expired_dossiers_en_construction - ExpiredDossiersDeletionService.process_expired_dossiers_termine - end -end diff --git a/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb b/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb new file mode 100644 index 00000000000..a97db1e9b7b --- /dev/null +++ b/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb @@ -0,0 +1,7 @@ +class Cron::ExpiredDossiersEnConstructionDeletionJob < Cron::CronJob + self.schedule_expression = "every day at 3 pm" + + def perform(*args) + ExpiredDossiersDeletionService.process_expired_dossiers_en_construction + end +end diff --git a/app/jobs/cron/expired_dossiers_termine_deletion_job.rb b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb new file mode 100644 index 00000000000..f8a14c25738 --- /dev/null +++ b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb @@ -0,0 +1,7 @@ +class Cron::ExpiredDossiersTermineDeletionJob < Cron::CronJob + self.schedule_expression = "every day at 7 am" + + def perform(*args) + ExpiredDossiersDeletionService.process_expired_dossiers_termine + end +end From 5f8fce7997714d49830d976770f20b189ebd8808 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 23 Jun 2023 18:14:10 +0200 Subject: [PATCH 18/33] =?UTF-8?q?amelioration(dossier.indexes):=20lors=20d?= =?UTF-8?q?e=20sa=20suppression,=20un=20dossier=20nullifie=20les=20autre?= =?UTF-8?q?=20parent=5Fdossier=5Fid=20ayant=20son=20id.=20=C3=A7a=20fait?= =?UTF-8?q?=20que=20la=20suppression=20des=20dossiers=20[ds=20le=20cas=20d?= =?UTF-8?q?es=20expires]=20est=20LENT=20[3s=20pr=20executer=20la=20requete?= =?UTF-8?q?=20de=20nullification=20en=20dev]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20230623160831_add_index_to_parent_dossier_id.rb | 7 +++++++ db/schema.rb | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20230623160831_add_index_to_parent_dossier_id.rb diff --git a/db/migrate/20230623160831_add_index_to_parent_dossier_id.rb b/db/migrate/20230623160831_add_index_to_parent_dossier_id.rb new file mode 100644 index 00000000000..4610a9461fe --- /dev/null +++ b/db/migrate/20230623160831_add_index_to_parent_dossier_id.rb @@ -0,0 +1,7 @@ +class AddIndexToParentDossierId < ActiveRecord::Migration[7.0] + disable_ddl_transaction! + + def change + add_index :dossiers, :parent_dossier_id, algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index b3d1e30c251..a387e005c25 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_06_21_161733) do +ActiveRecord::Schema[7.0].define(version: 2023_06_23_160831) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -416,6 +416,7 @@ t.index ["editing_fork_origin_id"], name: "index_dossiers_on_editing_fork_origin_id" t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id" t.index ["hidden_at"], name: "index_dossiers_on_hidden_at" + t.index ["parent_dossier_id"], name: "index_dossiers_on_parent_dossier_id" t.index ["prefill_token"], name: "index_dossiers_on_prefill_token", unique: true t.index ["revision_id"], name: "index_dossiers_on_revision_id" t.index ["state"], name: "index_dossiers_on_state" From d45a250075cff8170fe703207ab47121642a5d97 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 26 Jun 2023 10:37:32 +0200 Subject: [PATCH 19/33] amelioration(mail): ajoute d'un simili rate limiter pour envoyer les mails sur des fenetres de temps ayant une limite --- ...expired_dossiers_brouillon_deletion_job.rb | 2 +- ...d_dossiers_en_construction_deletion_job.rb | 2 +- .../expired_dossiers_termine_deletion_job.rb | 2 +- .../expired_dossiers_deletion_service.rb | 60 ++++++++++++------- app/services/mail_rate_limiter.rb | 32 ++++++++++ spec/lib/mail_rate_limiter_spec.rb | 26 ++++++++ .../expired_dossiers_deletion_service_spec.rb | 34 +++++------ 7 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 app/services/mail_rate_limiter.rb create mode 100644 spec/lib/mail_rate_limiter_spec.rb diff --git a/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb b/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb index fb3e291686b..5243db04654 100644 --- a/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb +++ b/app/jobs/cron/expired_dossiers_brouillon_deletion_job.rb @@ -2,6 +2,6 @@ class Cron::ExpiredDossiersBrouillonDeletionJob < Cron::CronJob self.schedule_expression = "every day at 10 pm" def perform(*args) - ExpiredDossiersDeletionService.process_expired_dossiers_brouillon + ExpiredDossiersDeletionService.new.process_expired_dossiers_brouillon end end diff --git a/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb b/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb index a97db1e9b7b..84f5b340686 100644 --- a/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb +++ b/app/jobs/cron/expired_dossiers_en_construction_deletion_job.rb @@ -2,6 +2,6 @@ class Cron::ExpiredDossiersEnConstructionDeletionJob < Cron::CronJob self.schedule_expression = "every day at 3 pm" def perform(*args) - ExpiredDossiersDeletionService.process_expired_dossiers_en_construction + ExpiredDossiersDeletionService.new.process_expired_dossiers_en_construction end end diff --git a/app/jobs/cron/expired_dossiers_termine_deletion_job.rb b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb index f8a14c25738..ce47f3f5a4e 100644 --- a/app/jobs/cron/expired_dossiers_termine_deletion_job.rb +++ b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb @@ -2,6 +2,6 @@ class Cron::ExpiredDossiersTermineDeletionJob < Cron::CronJob self.schedule_expression = "every day at 7 am" def perform(*args) - ExpiredDossiersDeletionService.process_expired_dossiers_termine + ExpiredDossiersDeletionService.new.process_expired_dossiers_termine end end diff --git a/app/services/expired_dossiers_deletion_service.rb b/app/services/expired_dossiers_deletion_service.rb index a046ebd59d8..534a68f8fa1 100644 --- a/app/services/expired_dossiers_deletion_service.rb +++ b/app/services/expired_dossiers_deletion_service.rb @@ -1,20 +1,28 @@ class ExpiredDossiersDeletionService - def self.process_expired_dossiers_brouillon + def initialize(rate_limiter: MailRateLimiter.new(limit: 200, window: 10.minutes)) + @rate_limiter = rate_limiter + end + + def process_expired_dossiers_brouillon send_brouillon_expiration_notices delete_expired_brouillons_and_notify end - def self.process_expired_dossiers_en_construction + def process_expired_dossiers_en_construction send_en_construction_expiration_notices delete_expired_en_construction_and_notify end - def self.process_expired_dossiers_termine + def process_expired_dossiers_termine send_termine_expiration_notices delete_expired_termine_and_notify end - def self.send_brouillon_expiration_notices + def safe_send_email(mail) + @rate_limiter.send_with_delay(mail) + end + + def send_brouillon_expiration_notices dossiers_close_to_expiration = Dossier .brouillon_close_to_expiration .without_brouillon_expiration_notice_sent @@ -24,66 +32,70 @@ def self.send_brouillon_expiration_notices dossiers_close_to_expiration.in_batches.update_all(brouillon_close_to_expiration_notice_sent_at: Time.zone.now) user_notifications.each do |(email, dossiers)| - DossierMailer.notify_brouillon_near_deletion( + mail = DossierMailer.notify_brouillon_near_deletion( dossiers, email - ).deliver_later + ) + safe_send_email(mail) end end - def self.send_en_construction_expiration_notices + def send_en_construction_expiration_notices send_expiration_notices( Dossier.en_construction_close_to_expiration.without_en_construction_expiration_notice_sent, :en_construction_close_to_expiration_notice_sent_at ) end - def self.send_termine_expiration_notices + def send_termine_expiration_notices send_expiration_notices( Dossier.termine_close_to_expiration.without_termine_expiration_notice_sent, :termine_close_to_expiration_notice_sent_at ) end - def self.delete_expired_brouillons_and_notify + def delete_expired_brouillons_and_notify user_notifications = group_by_user_email(Dossier.brouillon_expired) .map { |(email, dossiers)| [email, dossiers.map(&:hash_for_deletion_mail)] } Dossier.brouillon_expired.in_batches.destroy_all user_notifications.each do |(email, dossiers_hash)| - DossierMailer.notify_brouillon_deletion( + mail = DossierMailer.notify_brouillon_deletion( dossiers_hash, email - ).deliver_later + ) + safe_send_email(mail) end end - def self.delete_expired_en_construction_and_notify + def delete_expired_en_construction_and_notify delete_expired_and_notify(Dossier.en_construction_expired) end - def self.delete_expired_termine_and_notify + def delete_expired_termine_and_notify delete_expired_and_notify(Dossier.termine_expired, notify_on_closed_procedures_to_user: true) end private - def self.send_expiration_notices(dossiers_close_to_expiration, close_to_expiration_flag) + def send_expiration_notices(dossiers_close_to_expiration, close_to_expiration_flag) user_notifications = group_by_user_email(dossiers_close_to_expiration) administration_notifications = group_by_fonctionnaire_email(dossiers_close_to_expiration) dossiers_close_to_expiration.in_batches.update_all(close_to_expiration_flag => Time.zone.now) user_notifications.each do |(email, dossiers)| - DossierMailer.notify_near_deletion_to_user(dossiers, email).deliver_later + mail = DossierMailer.notify_near_deletion_to_user(dossiers, email) + safe_send_email(mail) end administration_notifications.each do |(email, dossiers)| - DossierMailer.notify_near_deletion_to_administration(dossiers, email).deliver_later + mail = DossierMailer.notify_near_deletion_to_administration(dossiers, email) + safe_send_email(mail) end end - def self.delete_expired_and_notify(dossiers_to_remove, notify_on_closed_procedures_to_user: false) + def delete_expired_and_notify(dossiers_to_remove, notify_on_closed_procedures_to_user: false) user_notifications = group_by_user_email(dossiers_to_remove, notify_on_closed_procedures_to_user: notify_on_closed_procedures_to_user) .map { |(email, dossiers)| [email, dossiers.map(&:id)] } administration_notifications = group_by_fonctionnaire_email(dossiers_to_remove) @@ -98,24 +110,26 @@ def self.delete_expired_and_notify(dossiers_to_remove, notify_on_closed_procedur user_notifications.each do |(email, dossier_ids)| dossier_ids = dossier_ids.intersection(deleted_dossier_ids) if dossier_ids.present? - DossierMailer.notify_automatic_deletion_to_user( + mail = DossierMailer.notify_automatic_deletion_to_user( DeletedDossier.where(dossier_id: dossier_ids).to_a, email - ).deliver_later + ) + safe_send_email(mail) end end administration_notifications.each do |(email, dossier_ids)| dossier_ids = dossier_ids.intersection(deleted_dossier_ids) if dossier_ids.present? - DossierMailer.notify_automatic_deletion_to_administration( + mail = DossierMailer.notify_automatic_deletion_to_administration( DeletedDossier.where(dossier_id: dossier_ids).to_a, email - ).deliver_later + ) + safe_send_email(mail) end end end - def self.group_by_user_email(dossiers, notify_on_closed_procedures_to_user: false) + def group_by_user_email(dossiers, notify_on_closed_procedures_to_user: false) dossiers .visible_by_user .with_notifiable_procedure(notify_on_closed: notify_on_closed_procedures_to_user) @@ -124,7 +138,7 @@ def self.group_by_user_email(dossiers, notify_on_closed_procedures_to_user: fals .map { |(user, dossiers)| [user.email, dossiers] } end - def self.group_by_fonctionnaire_email(dossiers) + def group_by_fonctionnaire_email(dossiers) dossiers .visible_by_administration .with_notifiable_procedure(notify_on_closed: true) diff --git a/app/services/mail_rate_limiter.rb b/app/services/mail_rate_limiter.rb new file mode 100644 index 00000000000..67cf6d4b104 --- /dev/null +++ b/app/services/mail_rate_limiter.rb @@ -0,0 +1,32 @@ +class MailRateLimiter + attr_reader :delay, :current_window + + def send_with_delay(mail) + if current_window_full? + @delay += @window + end + if current_window_full? || current_window_expired? + @current_window = { started_at: Time.current, sent: 0 } + end + @current_window[:sent] += 1 + + mail.deliver_later(wait: delay) + end + + private + + def initialize(limit:, window:) + @limit = limit + @window = window + @current_window = { started_at: Time.current, sent: 0 } + @delay = 0 + end + + def current_window_expired? + @current_window[:started_at] + @window <= Time.zone.now.utc + end + + def current_window_full? + @current_window[:sent] == @limit + end +end diff --git a/spec/lib/mail_rate_limiter_spec.rb b/spec/lib/mail_rate_limiter_spec.rb new file mode 100644 index 00000000000..b1b4d5e105f --- /dev/null +++ b/spec/lib/mail_rate_limiter_spec.rb @@ -0,0 +1,26 @@ +describe MailRateLimiter do + describe 'hits limits' do + let(:limit) { 10 } + let(:window) { 2.seconds } + let(:rate_limiter) { MailRateLimiter.new(limit:, window:) } + let(:mail) { DossierMailer.notify_automatic_deletion_to_user([], 'tartampion@france.fr') } + + it 'decreases current_window[:limit]' do + expect { rate_limiter.send_with_delay(mail) }.to change { rate_limiter.current_window[:sent] }.by(1) + end + + it 'increases the delay by window when it reaches the max number of call' do + expect do + (limit + 1).times { rate_limiter.send_with_delay(mail) } + end.to change { rate_limiter.delay }.by(window) + end + + it 'renews current_window when it expires' do + rate_limiter.send_with_delay(mail) + Timecop.travel(window + 1.second) do + rate_limiter.send_with_delay(mail) + expect(rate_limiter.current_window[:sent]).to eq(1) + end + end + end +end diff --git a/spec/services/expired_dossiers_deletion_service_spec.rb b/spec/services/expired_dossiers_deletion_service_spec.rb index 653948ee133..767390bc589 100644 --- a/spec/services/expired_dossiers_deletion_service_spec.rb +++ b/spec/services/expired_dossiers_deletion_service_spec.rb @@ -6,7 +6,7 @@ let(:procedure) { create(:procedure, :published, procedure_opts) } let(:procedure_2) { create(:procedure, :published, procedure_opts) } let(:reference_date) { Date.parse("March 8") } - + let(:service) { ExpiredDossiersDeletionService.new } describe '#process_expired_dossiers_brouillon' do before { Timecop.freeze(reference_date) } after { Timecop.return } @@ -26,7 +26,7 @@ allow(DossierMailer).to receive(:notify_brouillon_near_deletion).and_call_original allow(DossierMailer).to receive(:notify_brouillon_deletion).and_call_original - ExpiredDossiersDeletionService.process_expired_dossiers_brouillon + service.process_expired_dossiers_brouillon end it 'emails should be sent' do @@ -58,7 +58,7 @@ context 'with a single dossier' do let!(:dossier) { create(:dossier, procedure: procedure, created_at: created_at) } - before { ExpiredDossiersDeletionService.send_brouillon_expiration_notices } + before { service.send_brouillon_expiration_notices } context 'when the dossier is not close to expiration' do let(:created_at) { (conservation_par_defaut - 2.weeks - 1.day).ago } @@ -80,7 +80,7 @@ let!(:dossier_1) { create(:dossier, procedure: procedure, user: user, created_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } let!(:dossier_2) { create(:dossier, procedure: procedure_2, user: user, created_at: (conservation_par_defaut - 2.weeks + 1.day).ago) } - before { ExpiredDossiersDeletionService.send_brouillon_expiration_notices } + before { service.send_brouillon_expiration_notices } it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).once } it { expect(DossierMailer).to have_received(:notify_brouillon_near_deletion).with(match_array([dossier_1, dossier_2]), user.email) } @@ -98,7 +98,7 @@ context 'with a single dossier' do let!(:dossier) { create(:dossier, procedure: procedure, brouillon_close_to_expiration_notice_sent_at: notice_sent_at) } - before { ExpiredDossiersDeletionService.delete_expired_brouillons_and_notify } + before { service.delete_expired_brouillons_and_notify } context 'when no notice has been sent' do let(:notice_sent_at) { nil } @@ -128,7 +128,7 @@ let!(:dossier_1) { create(:dossier, procedure: procedure, user: user, brouillon_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } let!(:dossier_2) { create(:dossier, procedure: procedure_2, user: user, brouillon_close_to_expiration_notice_sent_at: (warning_period + 1.day).ago) } - before { ExpiredDossiersDeletionService.delete_expired_brouillons_and_notify } + before { service.delete_expired_brouillons_and_notify } it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).once } it { expect(DossierMailer).to have_received(:notify_brouillon_deletion).with(match_array([dossier_1.hash_for_deletion_mail, dossier_2.hash_for_deletion_mail]), user.email) } @@ -147,7 +147,7 @@ context 'with a single dossier' do let!(:dossier) { create(:dossier, :en_construction, :followed, procedure: procedure, en_construction_at: en_construction_at) } - before { ExpiredDossiersDeletionService.send_en_construction_expiration_notices } + before { service.send_en_construction_expiration_notices } context 'when the dossier is not near deletion' do let(:en_construction_at) { (conservation_par_defaut - 2.weeks - 1.day).ago } @@ -178,7 +178,7 @@ before do instructeur.followed_dossiers << dossier_1 << dossier_2 - ExpiredDossiersDeletionService.send_en_construction_expiration_notices + service.send_en_construction_expiration_notices end it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once } @@ -195,7 +195,7 @@ before do administrateur.instructeur.followed_dossiers << dossier - ExpiredDossiersDeletionService.send_en_construction_expiration_notices + service.send_en_construction_expiration_notices end it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once } @@ -219,7 +219,7 @@ let!(:dossier) { create(:dossier, :en_construction, :followed, procedure: procedure, en_construction_close_to_expiration_notice_sent_at: notice_sent_at) } let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) } - before { ExpiredDossiersDeletionService.delete_expired_en_construction_and_notify } + before { service.delete_expired_en_construction_and_notify } context 'when no notice has been sent' do let(:notice_sent_at) { nil } @@ -261,7 +261,7 @@ before do instructeur.followed_dossiers << dossier_1 << dossier_2 - ExpiredDossiersDeletionService.delete_expired_en_construction_and_notify + service.delete_expired_en_construction_and_notify end it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once } @@ -290,7 +290,7 @@ context 'with a single dossier' do let!(:dossier) { create(:dossier, :followed, state: :accepte, procedure: procedure, processed_at: processed_at) } - before { ExpiredDossiersDeletionService.send_termine_expiration_notices } + before { service.send_termine_expiration_notices } context 'when the dossier is not near deletion' do let(:processed_at) { (conservation_par_defaut - 2.weeks - 1.day).ago } @@ -321,7 +321,7 @@ before do instructeur.followed_dossiers << dossier_1 << dossier_2 - ExpiredDossiersDeletionService.send_termine_expiration_notices + service.send_termine_expiration_notices end it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once } @@ -338,7 +338,7 @@ before do administrateur.instructeur.followed_dossiers << dossier - ExpiredDossiersDeletionService.send_termine_expiration_notices + service.send_termine_expiration_notices end it { expect(DossierMailer).to have_received(:notify_near_deletion_to_user).once } @@ -366,7 +366,7 @@ let!(:dossier) { create(:dossier, :followed, :accepte, procedure: procedure, termine_close_to_expiration_notice_sent_at: notice_sent_at) } let(:deleted_dossier) { DeletedDossier.find_by(dossier_id: dossier.id) } - before { ExpiredDossiersDeletionService.delete_expired_termine_and_notify } + before { service.delete_expired_termine_and_notify } context 'when no notice has been sent' do let(:notice_sent_at) { nil } @@ -408,7 +408,7 @@ before do instructeur.followed_dossiers << dossier_1 << dossier_2 - ExpiredDossiersDeletionService.delete_expired_termine_and_notify + service.delete_expired_termine_and_notify end it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once } @@ -430,7 +430,7 @@ before do instructeur.followed_dossiers << dossier_1 << dossier_2 - ExpiredDossiersDeletionService.delete_expired_termine_and_notify + service.delete_expired_termine_and_notify end it { expect(DossierMailer).to have_received(:notify_automatic_deletion_to_user).once } From 18096a709b3ef87da25f98fa50564baa489c2c83 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Mon, 26 Jun 2023 10:14:38 +0200 Subject: [PATCH 20/33] chore(email): tag sentry mailers --- app/mailers/application_mailer.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index be55e4ab406..4577daf46d4 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -7,6 +7,8 @@ class ApplicationMailer < ActionMailer::Base default from: "#{APPLICATION_NAME} <#{CONTACT_EMAIL}>" layout 'mailer' + before_action -> { Sentry.set_tags(mailer: mailer_name, action: action_name) } + # Attach the procedure logo to the email (if any). # Returns the attachment url. def attach_logo(procedure) From a0ceee96bd1f740c45be96c82698807fda0a9545 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 26 Jun 2023 15:23:59 +0200 Subject: [PATCH 21/33] amelioration(email.resume_hebdomadaire): envoie le mail a 4h du matin sur une periode de 3h tech( Co-authored-by: Colin Darie --- app/jobs/cron/weekly_overview_job.rb | 7 ++----- app/services/mail_rate_limiter.rb | 4 ++-- spec/lib/mail_rate_limiter_spec.rb | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/jobs/cron/weekly_overview_job.rb b/app/jobs/cron/weekly_overview_job.rb index f8857d75967..45408c58d14 100644 --- a/app/jobs/cron/weekly_overview_job.rb +++ b/app/jobs/cron/weekly_overview_job.rb @@ -1,16 +1,13 @@ class Cron::WeeklyOverviewJob < Cron::CronJob - self.schedule_expression = "every monday at 7 am" + self.schedule_expression = "every monday at 4 am" def perform # Feature flipped to avoid mails in staging due to unprocessed dossier return unless Rails.application.config.ds_weekly_overview Instructeur.find_each do |instructeur| - # NOTE: it's not exactly accurate because rate limit is not shared between jobs processes - Dolist::API.sleep_until_limit_reset if Dolist::API.near_rate_limit? - # mailer won't send anything if overview if empty - InstructeurMailer.last_week_overview(instructeur)&.deliver_later + InstructeurMailer.last_week_overview(instructeur)&.deliver_later(wait: rand(0..3.hours)) end end end diff --git a/app/services/mail_rate_limiter.rb b/app/services/mail_rate_limiter.rb index 67cf6d4b104..7e5a929b3c2 100644 --- a/app/services/mail_rate_limiter.rb +++ b/app/services/mail_rate_limiter.rb @@ -23,10 +23,10 @@ def initialize(limit:, window:) end def current_window_expired? - @current_window[:started_at] + @window <= Time.zone.now.utc + (@current_window[:started_at] + @window).past? end def current_window_full? - @current_window[:sent] == @limit + @current_window[:sent] >= @limit end end diff --git a/spec/lib/mail_rate_limiter_spec.rb b/spec/lib/mail_rate_limiter_spec.rb index b1b4d5e105f..26418eafd26 100644 --- a/spec/lib/mail_rate_limiter_spec.rb +++ b/spec/lib/mail_rate_limiter_spec.rb @@ -17,7 +17,7 @@ it 'renews current_window when it expires' do rate_limiter.send_with_delay(mail) - Timecop.travel(window + 1.second) do + travel_to(Time.current + window + 1.second) do rate_limiter.send_with_delay(mail) expect(rate_limiter.current_window[:sent]).to eq(1) end From 7ec604ced38fc16d246ee3ce0678a09b0408de07 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 26 Jun 2023 21:32:07 +0200 Subject: [PATCH 22/33] typo --- app/jobs/pjs_migration_job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/pjs_migration_job.rb b/app/jobs/pjs_migration_job.rb index eff8b501457..d964b3f95ee 100644 --- a/app/jobs/pjs_migration_job.rb +++ b/app/jobs/pjs_migration_job.rb @@ -2,7 +2,7 @@ class PjsMigrationJob < ApplicationJob queue_as :pj_migration_jobs def perform(blob_id) - blob = Blob.find(blob_id) + blob = ActiveStorage::Blob.find(blob_id) return if already_moved?(blob) From bc8b2e2c970fe41a60fd17feed216e4661c54e6a Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 27 Jun 2023 09:30:16 +0200 Subject: [PATCH 23/33] =?UTF-8?q?correctif(champ.pj):=20ETQ=20usager=20et?= =?UTF-8?q?=20instructeur,=20l'affichage=20des=20PJs=20etait=20cass=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../champ_row_show_component/champ_row_show_component.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index bfa8796009b..f42cd694d3b 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -12,7 +12,7 @@ - if updated_after_deposer?(champ) %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(champ.updated_at)) - - if champ.blank? + - if champ.blank? && ![TypeDeChamp.type_champs.fetch(:piece_justificative), TypeDeChamp.type_champs.fetch(:titre_identite)].include?(champ.type_champ) .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } %p= t('.blank') - else From d37a8b1c32b562e3b0c984f52149af2812afd2d2 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 10:59:15 +0200 Subject: [PATCH 24/33] style(demande): fix responsive layout --- app/assets/stylesheets/demande.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/demande.scss b/app/assets/stylesheets/demande.scss index 52dd1ef0796..b52aef7b239 100644 --- a/app/assets/stylesheets/demande.scss +++ b/app/assets/stylesheets/demande.scss @@ -1,7 +1,7 @@ @import "colors"; @import "constants"; -.container { +.fr-container { @media (max-width: 48em) { .d-block-sm { display: block; From 2f3b2b296287ee441af61b5f70ca9a731ea29d53 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 10:59:33 +0200 Subject: [PATCH 25/33] style(demande): fix updated at font size --- app/views/shared/dossiers/_champs.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml index 8ee1d233661..25a64686865 100644 --- a/app/views/shared/dossiers/_champs.html.haml +++ b/app/views/shared/dossiers/_champs.html.haml @@ -3,7 +3,7 @@ .flex %p.flex-grow.fr-text-action-high--grey.fr-mb-0= dossier.procedure.routing_criteria_name - %p.champ-updated-at.fr-mb-0.fr-text--sm + %p.champ-updated-at.fr-mb-0.fr-text--xs - if demande_seen_at&.<(dossier.groupe_instructeur_updated_at) %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(dossier.updated_at)) From 8358a1c9e6b6af680578d062d693a718d8d02cad Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 11:04:26 +0200 Subject: [PATCH 26/33] style: remove oboslete class champ-updated-at --- .../champ_row_show_component/champ_row_show_component.html.haml | 2 +- app/views/shared/dossiers/_champs.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index f42cd694d3b..42fc1599195 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -8,7 +8,7 @@ - else .flex.d-block-sm %p.flex-grow.fr-text-action-high--grey.fr-mb-0= "#{champ.libelle} :" - %p.champ-updated-at.fr-mb-0.fr-text--sm + %p.fr-mb-0.fr-text--sm - if updated_after_deposer?(champ) %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(champ.updated_at)) diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml index 25a64686865..b909a90f8be 100644 --- a/app/views/shared/dossiers/_champs.html.haml +++ b/app/views/shared/dossiers/_champs.html.haml @@ -3,7 +3,7 @@ .flex %p.flex-grow.fr-text-action-high--grey.fr-mb-0= dossier.procedure.routing_criteria_name - %p.champ-updated-at.fr-mb-0.fr-text--xs + %p.fr-mb-0.fr-text--xs - if demande_seen_at&.<(dossier.groupe_instructeur_updated_at) %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(dossier.updated_at)) From 899f671aed4f1742725edab71492763ef80a402d Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 12:25:29 +0200 Subject: [PATCH 27/33] style(demande): improve global readability --- app/assets/stylesheets/demande.scss | 28 +++-- .../champ_row_show_component.html.haml | 6 +- app/views/shared/dossiers/_champs.html.haml | 4 +- app/views/shared/dossiers/_demande.html.haml | 6 +- .../dossiers/_identite_entreprise.html.haml | 108 +++++++++--------- .../dossiers/_identite_individual.html.haml | 16 +-- .../shared/dossiers/_user_infos.html.haml | 4 +- app/views/users/dossiers/demande.html.haml | 10 +- 8 files changed, 93 insertions(+), 89 deletions(-) diff --git a/app/assets/stylesheets/demande.scss b/app/assets/stylesheets/demande.scss index b52aef7b239..aaced29114a 100644 --- a/app/assets/stylesheets/demande.scss +++ b/app/assets/stylesheets/demande.scss @@ -1,25 +1,29 @@ @import "colors"; @import "constants"; -.fr-container { +.dossier-show { @media (max-width: 48em) { .d-block-sm { display: block; } } -} - -.champ-content { - padding: 0 0 ,5rem; - p { - padding: 0; - margin: 0; + .champ-label { + font-weight: 600; + margin-bottom: 0; + color: var(--text-action-high-grey); } -} -.top-bordered { - border-top: 1px solid var(--border-default-grey); -} + .champ-content { + padding: 0 0 0.5rem; + p { + padding: 0; + margin: 0; + } + } + .top-bordered { + border-top: 1px solid var(--border-default-grey); + } +} diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index 42fc1599195..60d763bc300 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -1,13 +1,13 @@ - @champs.each do |champ| .fr-px-4v.fr-my-2v - if champ.repetition? - = champ.libelle + %p.champ-label= "#{champ.libelle} :" - champ.rows.each do |row| = render Dossiers::ChampRowShowComponent.new(champs: row, demande_seen_at: @demande_seen_at, profile: @profile, repetition: true) - else .flex.d-block-sm - %p.flex-grow.fr-text-action-high--grey.fr-mb-0= "#{champ.libelle} :" + %p.champ-label.flex-grow= "#{champ.libelle} :" %p.fr-mb-0.fr-text--sm - if updated_after_deposer?(champ) %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } @@ -16,7 +16,7 @@ .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } %p= t('.blank') - else - .champ-content.fr-text-action-high--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } + .champ-content{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } - case champ.type_champ - when TypeDeChamp.type_champs.fetch(:carte) = render partial: "shared/champs/carte/show", locals: { champ: champ } diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml index b909a90f8be..1491b8ed179 100644 --- a/app/views/shared/dossiers/_champs.html.haml +++ b/app/views/shared/dossiers/_champs.html.haml @@ -2,13 +2,13 @@ .fr-my-4v.fr-px-4v .flex - %p.flex-grow.fr-text-action-high--grey.fr-mb-0= dossier.procedure.routing_criteria_name + %p.champ-label.flex-grow= dossier.procedure.routing_criteria_name %p.fr-mb-0.fr-text--xs - if demande_seen_at&.<(dossier.groupe_instructeur_updated_at) %span{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(dossier.updated_at)) - .champ-content.fr-text-action-high--grey{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } + .champ-content{ class: highlight_if_unseen_class(demande_seen_at, dossier.groupe_instructeur_updated_at) } %p= dossier.groupe_instructeur.label diff --git a/app/views/shared/dossiers/_demande.html.haml b/app/views/shared/dossiers/_demande.html.haml index 83f329e21e4..0ecaef389d6 100644 --- a/app/views/shared/dossiers/_demande.html.haml +++ b/app/views/shared/dossiers/_demande.html.haml @@ -2,9 +2,9 @@ - content_for(:notice_info) do = render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information } -.fr-container.counter-start-header-section - .fr-grid-row - .fr-col-12.fr-col-offset-lg-2.fr-col-lg-8 +.fr-container.counter-start-header-section.dossier-show + .fr-grid-row.fr-grid-row--center + .fr-col-12.fr-col-lg-10.fr-col-xl-8 %h2.fr-h6.fr-background-alt--grey.fr-mb-0 .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.en_construction') diff --git a/app/views/shared/dossiers/_identite_entreprise.html.haml b/app/views/shared/dossiers/_identite_entreprise.html.haml index cc986b88761..e94f3a94634 100644 --- a/app/views/shared/dossiers/_identite_entreprise.html.haml +++ b/app/views/shared/dossiers/_identite_entreprise.html.haml @@ -6,46 +6,46 @@ %p Il nʼest pas possible dʼaccepter ou de refuser un dossier sans cette étape. .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 SIRET : - .champ-content.fr-text-action-high--grey + %p.champ-label SIRET : + .champ-content %p= etablissement.siret - else - if etablissement.diffusable_commercialement == false && profile != 'instructeur' .fr-my-2v - .champ-content.fr-text-action-high--grey + .champ-content %p= t('warning_for_private_info', scope: 'views.shared.dossiers.identite_entreprise', siret: pretty_siret(etablissement.siret)) - else .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Dénomination : - .champ-content.fr-text-action-high--grey + %p.champ-label Dénomination : + .champ-content %p= raison_sociale_or_name(etablissement) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 SIRET : - .champ-content.fr-text-action-high--grey + %p.champ-label SIRET : + .champ-content %p #{pretty_siret(etablissement.siret)} #{ render Dsfr::CopyButtonComponent.new(text: etablissement.siret, title: "Copier le siret dans le presse-papier", success: "Le siret a été copié dans le presse-papier") } - unless local_assigns[:short_identity] - if etablissement.siret != etablissement.entreprise.siret_siege_social .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 SIRET du siège social: - .champ-content.fr-text-action-high--grey + %p.champ-label SIRET du siège social: + .champ-content %p= etablissement.entreprise.siret_siege_social .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Forme juridique : - .champ-content.fr-text-action-high--grey + %p.champ-label Forme juridique : + .champ-content %p= sanitize(etablissement.entreprise.forme_juridique) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Libellé NAF : - .champ-content.fr-text-action-high--grey + %p.champ-label Libellé NAF : + .champ-content %p= etablissement.libelle_naf .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Code NAF : - .champ-content.fr-text-action-high--grey + %p.champ-label Code NAF : + .champ-content %p= etablissement.naf .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Date de création : - .champ-content.fr-text-action-high--grey + %p.champ-label Date de création : + .champ-content %p = try_format_date(etablissement.entreprise.date_creation) @@ -54,42 +54,42 @@ - if profile == 'instructeur' .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 + %p.champ-label Effectif mensuel = try_format_mois_effectif(etablissement) (URSSAF) : - .champ-content.fr-text-action-high--grey + .champ-content %p= etablissement.entreprise_effectif_mensuel .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 + %p.champ-label Effectif moyen annuel = etablissement.entreprise_effectif_annuel_annee (URSSAF) : - .champ-content.fr-text-action-high--grey + .champ-content %p= etablissement.entreprise_effectif_annuel .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Effectif de l'organisation (INSEE) : - .champ-content.fr-text-action-high--grey + %p.champ-label Effectif de l'organisation (INSEE) : + .champ-content %p = effectif(etablissement) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Numéro de TVA intracommunautaire : - .champ-content.fr-text-action-high--grey + %p.champ-label Numéro de TVA intracommunautaire : + .champ-content %p= etablissement.entreprise.numero_tva_intracommunautaire .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Adresse : - .champ-content.fr-text-action-high--grey + %p.champ-label Adresse : + .champ-content %p - etablissement.adresse.split("\n").each do |line| = line %br .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Capital social : - .champ-content.fr-text-action-high--grey + %p.champ-label Capital social : + .champ-content %p= pretty_currency(etablissement.entreprise.capital_social) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Chiffre d’affaires : - .champ-content.fr-text-action-high--grey + %p.champ-label Chiffre d’affaires : + .champ-content %p - if profile == 'instructeur' %details @@ -115,12 +115,12 @@ = render partial: 'shared/dossiers/identite_entreprise_bilan_detail', locals: { libelle: 'Besoin en fonds de roulement', key: 'besoin_en_fonds_de_roulement', etablissement: etablissement } .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 + %p.champ-label Chiffres financiers clés (Banque de France) = "en #{pretty_currency_unit(etablissement.entreprise_bilans_bdf_monnaie)} :" - if controller.is_a?(Instructeurs::AvisController) - .champ-content.fr-text-action-high--grey + .champ-content %p Les consulter = link_to "au format csv", bilans_bdf_instructeur_avis_path(@avis, format: 'csv') @@ -129,7 +129,7 @@ ou = link_to "au format ods", bilans_bdf_instructeur_avis_path(@avis, format: 'ods') - else - .champ-content.fr-text-action-high--grey + .champ-content %p Les consulter = link_to "au format csv", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'csv') @@ -139,54 +139,54 @@ = link_to "au format ods", bilans_bdf_instructeur_dossier_path(procedure_id: @dossier.procedure.id, dossier_id: @dossier.id, format: 'ods') - else .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 + %p.champ-label Bilans Banque de France : - .champ-content.fr-text-action-high--grey + .champ-content %p Les 3 derniers bilans connus de votre entreprise par la Banque de France ont été joints à votre dossier. - if etablissement.entreprise_attestation_sociale.attached? .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Attestation sociale : + %p.champ-label Attestation sociale : - if profile == 'instructeur' - .champ-content.fr-text-action-high--grey + .champ-content %p= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_sociale) - else - .champ-content.fr-text-action-high--grey + .champ-content %p Une attestation de vigilance délivrée par l'ACOSS a été jointe à votre dossier. - if etablissement.entreprise_attestation_fiscale.attached? .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Attestation fiscale : + %p.champ-label Attestation fiscale : - if profile == 'instructeur' - .champ-content.fr-text-action-high--grey + .champ-content %p= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_fiscale) - else - .champ-content.fr-text-action-high--grey + .champ-content %p Une attestation fiscale délivrée par l'URSSAF a été jointe à votre dossier. - if etablissement.association? .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Numéro RNA : - .champ-content.fr-text-action-high--grey + %p.champ-label Numéro RNA : + .champ-content %p= etablissement.association_rna .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Titre : - .champ-content.fr-text-action-high--grey + %p.champ-label Titre : + .champ-content %p= etablissement.association_titre .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Objet : - .champ-content.fr-text-action-high--grey + %p.champ-label Objet : + .champ-content %p= etablissement.association_objet .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Date de création : - .champ-content.fr-text-action-high--grey + %p.champ-label Date de création : + .champ-content %p= try_format_date(etablissement.association_date_creation) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Date de publication : - .champ-content.fr-text-action-high--grey + %p.champ-label Date de publication : + .champ-content %p= try_format_date(etablissement.association_date_publication) .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Date de déclaration : - .champ-content.fr-text-action-high--grey + %p.champ-label Date de déclaration : + .champ-content %p= try_format_date(etablissement.association_date_declaration) - unless local_assigns[:short_identity] diff --git a/app/views/shared/dossiers/_identite_individual.html.haml b/app/views/shared/dossiers/_identite_individual.html.haml index 8532799d49d..7a2f0748b0a 100644 --- a/app/views/shared/dossiers/_identite_individual.html.haml +++ b/app/views/shared/dossiers/_identite_individual.html.haml @@ -1,18 +1,18 @@ .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.civility') - .champ-content.fr-text-action-high--grey + %p.champ-label= t('views.users.dossiers.identite.civility') + .champ-content %p= individual.gender .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.first_name') - .champ-content.fr-text-action-high--grey + %p.champ-label= t('views.users.dossiers.identite.first_name') + .champ-content %p= individual.prenom .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.last_name') - .champ-content.fr-text-action-high--grey + %p.champ-label= t('views.users.dossiers.identite.last_name') + .champ-content %p= individual.nom - if individual.birthdate.present? .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0= t('views.users.dossiers.identite.birthdate') - .champ-content.fr-text-action-high--grey + %p.champ-label= t('views.users.dossiers.identite.birthdate') + .champ-content %p= try_format_date(individual.birthdate) diff --git a/app/views/shared/dossiers/_user_infos.html.haml b/app/views/shared/dossiers/_user_infos.html.haml index c52e9367d8b..381a157a7fb 100644 --- a/app/views/shared/dossiers/_user_infos.html.haml +++ b/app/views/shared/dossiers/_user_infos.html.haml @@ -1,4 +1,4 @@ .fr-my-2v - %p.fr-text-action-high--grey.fr-mb-0 Email : - .champ-content.fr-text-action-high--grey + %p.champ-label Email : + .champ-content %p= user_deleted ? "#{email} (l’usager a supprimé son compte)" : email diff --git a/app/views/users/dossiers/demande.html.haml b/app/views/users/dossiers/demande.html.haml index f6d81f1bffb..e300ea4ddd6 100644 --- a/app/views/users/dossiers/demande.html.haml +++ b/app/views/users/dossiers/demande.html.haml @@ -3,21 +3,21 @@ - content_for :footer do = render partial: "users/procedure_footer", locals: { procedure: @dossier.procedure, dossier: @dossier } -.dossier-container.mb-4 +.dossier-container.fr-mb-4w = render partial: 'users/dossiers/show/header', locals: { dossier: @dossier } - if @dossier.en_construction? .fr-container .fr-grid-row.fr-grid-row--center - .fr-col-md-10.fr-col-lg-9 + .fr-col-md-10.fr-col-xl-9 = render Dossiers::EnConstructionNotSubmittedComponent.new(dossier: @dossier, user: current_user) = render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'usager' } - .fr-container - .fr-grid-row - .fr-col-12.fr-col-offset-lg-2.fr-col-lg-8 + .fr-container.fr-mt-2w + .fr-grid-row.fr-grid-row--center + .fr-col-12.fr-col-lg-10.fr-col-xl-8 - if !@dossier.read_only? = link_to t('views.users.dossiers.demande.edit_dossier'), modifier_dossier_path(@dossier), class: 'fr-btn fr-btn-sm', 'title'=> "Modifier mon dossier tant qu'il n'est pas passé en instruction" .clearfix From acd95177d405b2af38d333a56133165665f54a08 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 12:53:12 +0200 Subject: [PATCH 28/33] style(demande): fix identity updated at mention --- app/views/shared/dossiers/_demande.html.haml | 13 +++++++------ config/locales/en.yml | 3 ++- config/locales/fr.yml | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/views/shared/dossiers/_demande.html.haml b/app/views/shared/dossiers/_demande.html.haml index 0ecaef389d6..58f1c07e147 100644 --- a/app/views/shared/dossiers/_demande.html.haml +++ b/app/views/shared/dossiers/_demande.html.haml @@ -13,7 +13,13 @@ .tab-title %h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex - .flex-grow.fr-py-3v.fr-px-4v= t('views.shared.dossiers.demande.requester_identity') + .flex-grow.fr-py-3v.fr-px-4v + = t('views.shared.dossiers.demande.requester_identity') + + - if dossier.identity_updated_at.present? && demande_seen_at&.<(dossier.identity_updated_at) + %span.fr-badge.fr-badge--new.fr-badge--sm + = t('views.shared.dossiers.demande.requester_identity_updated_at', date: try_format_datetime(dossier.identity_updated_at)) + - if dossier.etablissement.present? && profile == 'usager' && !dossier.read_only? = link_to t('views.shared.dossiers.demande.edit_siret'), siret_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' @@ -21,11 +27,6 @@ = link_to t('views.shared.dossiers.demande.edit_identity'), identite_dossier_path(dossier), class: 'fr-py-3v fr-btn fr-btn--tertiary-no-outline' - - if dossier.identity_updated_at.present? && demande_seen_at&.<(dossier.identity_updated_at) - %span.highlighted - modifié le - = try_format_datetime(dossier.identity_updated_at) - .fr-my-4v.fr-px-4v = render partial: "shared/dossiers/user_infos", locals: { user_deleted: dossier.user_deleted?, email: dossier.user_email_for(:display) } diff --git a/config/locales/en.yml b/config/locales/en.yml index 540124a7241..4effa355480 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -331,7 +331,7 @@ en: best_regards: Best Regards, dossiers: form: - updated_at: "updated at %{datetime}" + updated_at: "updated on %{datetime}" edit: autosave: Your file is automatically saved after each modification. You can close the window at any time and pick up where you left off later. notice: "Download the notice of the procedure" @@ -344,6 +344,7 @@ en: write_message_to_administration_placeholder: "Write your message to the administration here" demande: requester_identity: "Identity of the requester" + requester_identity_updated_at: "updated on %{date}" my_identity: "My identity" form: "Form" edit_siret: "Edit SIRET" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 7779d584b9b..f5500627665 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -345,6 +345,7 @@ fr: demande: en_construction: "Date de dépôt du dossier" requester_identity: "Identité du demandeur" + requester_identity_updated_at: "modifiée le %{date}" my_identity: "Mon identité" form: "Sections du formulaire" edit_siret: "Modifier le SIRET" From ea559edb92995e9297d57931c4250af919ddf2a3 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 13:07:19 +0200 Subject: [PATCH 29/33] style(demande): fix highlighted background updated at champ --- app/assets/stylesheets/02_utils.scss | 5 +++-- .../champ_row_show_component.html.haml | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/02_utils.scss b/app/assets/stylesheets/02_utils.scss index 0870552ae38..d4d6f21ce36 100644 --- a/app/assets/stylesheets/02_utils.scss +++ b/app/assets/stylesheets/02_utils.scss @@ -136,8 +136,9 @@ // who known .highlighted { - background: $orange-bg; - color: $black; + background-color: var(--background-contrast-yellow-moutarde); // from fr-badge--new + color: var(--text-action-high-grey); + background-clip: content-box; } .overflow-y-visible { diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index 60d763bc300..85441b5877e 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -8,10 +8,12 @@ - else .flex.d-block-sm %p.champ-label.flex-grow= "#{champ.libelle} :" - %p.fr-mb-0.fr-text--sm - - if updated_after_deposer?(champ) + + - if updated_after_deposer?(champ) + %p.fr-mb-0.fr-text--sm %span{ class: highlight_if_unseen_class(@demande_seen_at, champ.updated_at) } = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: try_format_datetime(champ.updated_at)) + - if champ.blank? && ![TypeDeChamp.type_champs.fetch(:piece_justificative), TypeDeChamp.type_champs.fetch(:titre_identite)].include?(champ.type_champ) .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } %p= t('.blank') @@ -59,4 +61,5 @@ - when TypeDeChamp.type_champs.fetch(:number) %p= number_with_html_delimiter(champ.to_s) - else - %p= format_text_value(champ.to_s.strip) unless champ.blank? + - if champ.present? + = format_text_value(champ.to_s.strip) # format already wrap in p From 8724212d83202b159f6519c1a0d22ca9607238b5 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 13:24:55 +0200 Subject: [PATCH 30/33] style(demande): match general dates with mockup --- .../shared/dossiers/_infos_generales.html.haml | 13 +++++++------ config/locales/en.yml | 3 ++- config/locales/fr.yml | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/views/shared/dossiers/_infos_generales.html.haml b/app/views/shared/dossiers/_infos_generales.html.haml index 3f03d963944..1397a11071e 100644 --- a/app/views/shared/dossiers/_infos_generales.html.haml +++ b/app/views/shared/dossiers/_infos_generales.html.haml @@ -1,27 +1,28 @@ %div - %p.fr-my-4v.fr-px-4v.fr-text-action-high--grey - = l(dossier.depose_at, format: '%d %B %Y %H:%m') + %p.fr-my-2w.fr-px-4v + = t(:submitted_at, scope: [:views, :shared, :dossiers, :form], datetime: l(dossier.depose_at)) + %br - if dossier.updated_at != dossier.depose_at - = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: l(dossier.updated_at, format: :long)) + = t(:updated_at, scope: [:views, :shared, :dossiers, :form], datetime: l(dossier.updated_at)) - if dossier.justificatif_motivation.attached? .fr-my-4v.fr-px-4v - %p.fr-text-action-high--grey.fr-mb-0 Justificatif : + %p.champ-label Justificatif : .champ-content.fr-text-action-high--grey .action = render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment) - if dossier.motivation.present? .fr-my-4v.fr-px-4v - %p.fr-text-action-high--grey.fr-mb-0 Motivation : + %p.champ-label Motivation : .champ-content.fr-text-action-high--grey .action = dossier.motivation - if dossier.attestation.present? .fr-my-4v.fr-px-4v - %p.fr-text-action-high--grey.fr-mb-0 Attestation : + %p.champ-label Attestation : .champ-content.fr-text-action-high--grey .action = link_to('Voir l’attestation', attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener') diff --git a/config/locales/en.yml b/config/locales/en.yml index 4effa355480..ec9dd32bc75 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -331,7 +331,8 @@ en: best_regards: Best Regards, dossiers: form: - updated_at: "updated on %{datetime}" + submitted_at: "Submitted on %{datetime}" + updated_at: "Updated on %{datetime}" edit: autosave: Your file is automatically saved after each modification. You can close the window at any time and pick up where you left off later. notice: "Download the notice of the procedure" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index f5500627665..942a9404d83 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -331,7 +331,8 @@ fr: best_regards: Bonne journée, dossiers: form: - updated_at: "modifié le %{datetime}" + submitted_at: "Déposé le %{datetime}" + updated_at: "Modifié le %{datetime}" edit: autosave: Votre dossier est enregistré automatiquement après chaque modification. Vous pouvez à tout moment fermer la fenêtre et reprendre plus tard là où vous en étiez. notice: Télécharger le guide de la démarche From d7cc5a8091aedfe7aac8c55e6d33a0c579ffaa43 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 27 Jun 2023 14:40:01 +0200 Subject: [PATCH 31/33] style(demande): italic for empty champ value (accordingly to mockup) --- .../champ_row_show_component.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml index 85441b5877e..5c545958cc7 100644 --- a/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml +++ b/app/components/dossiers/champ_row_show_component/champ_row_show_component.html.haml @@ -16,7 +16,8 @@ - if champ.blank? && ![TypeDeChamp.type_champs.fetch(:piece_justificative), TypeDeChamp.type_champs.fetch(:titre_identite)].include?(champ.type_champ) .champ-content.fr-text-mention--grey{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } - %p= t('.blank') + %p + %em= t('.blank') - else .champ-content{ class: [highlight_if_unseen_class(@demande_seen_at, champ.updated_at), champ.type_champ] } - case champ.type_champ From 46b75c7525079eea1d80c0642fd5b5f55db46867 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 27 Jun 2023 14:55:50 +0200 Subject: [PATCH 32/33] tech(active-storage.queues.purge): place les jobs de purge ds low_priority --- config/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/application.rb b/config/application.rb index cf264ec08c8..36183bc483e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -58,6 +58,7 @@ class Application < Rails::Application # Set the queue name for the analysis jobs to 'active_storage_analysis' config.active_storage.queues.analysis = :active_storage_analysis + config.active_storage.queues.purge = :expires config.to_prepare do # Make main application helpers available in administrate From cc4d1240683a65391997d0623983286222320da8 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 27 Jun 2023 15:54:36 +0200 Subject: [PATCH 33/33] tech(expires): pause car on est entrain de trop enqueue de jobs --- app/jobs/cron/expired_dossiers_termine_deletion_job.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/jobs/cron/expired_dossiers_termine_deletion_job.rb b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb index ce47f3f5a4e..0d9e796f162 100644 --- a/app/jobs/cron/expired_dossiers_termine_deletion_job.rb +++ b/app/jobs/cron/expired_dossiers_termine_deletion_job.rb @@ -2,6 +2,7 @@ class Cron::ExpiredDossiersTermineDeletionJob < Cron::CronJob self.schedule_expression = "every day at 7 am" def perform(*args) - ExpiredDossiersDeletionService.new.process_expired_dossiers_termine + # ExpiredDossiersDeletionService.new.process_expired_dossiers_termine + return "until we purge stock" end end