Merge pull request #8659 from colinux/fix-titres-numeros-conditional

Titres de section: la numérotation automatique tient compte du conditionnel
This commit is contained in:
Colin Darie 2023-02-27 16:37:27 +00:00 committed by GitHub
commit 905d868390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 167 additions and 31 deletions

View file

@ -89,7 +89,8 @@
color: $light-grey; color: $light-grey;
} }
.conditionnel { .conditionnel,
p {
color: $white; color: $white;
} }
} }

View file

@ -0,0 +1,11 @@
.counter-start-header-section {
counter-reset: headerSectionCounter;
}
.header-section {
counter-increment: headerSectionCounter;
&.header-section-counter::before {
content: counter(headerSectionCounter) ". ";
}
}

View file

@ -1,2 +1,2 @@
%h2.header-section %h2.header-section{ class: @champ.dossier.auto_numbering_section_headers_for?(@champ) ? "header-section-counter" : nil }
= @champ.libelle_with_section_index = @champ.libelle

View file

@ -29,6 +29,10 @@
= form.check_box :mandatory, class: 'small-margin small', id: dom_id(type_de_champ, :mandatory) = form.check_box :mandatory, class: 'small-margin small', id: dom_id(type_de_champ, :mandatory)
= form.label :mandatory, "Champ obligatoire", for: dom_id(type_de_champ, :mandatory) = form.label :mandatory, "Champ obligatoire", for: dom_id(type_de_champ, :mandatory)
= form.text_field :libelle, class: 'small-margin small width-100', id: dom_id(type_de_champ, :libelle), data: input_autofocus = form.text_field :libelle, class: 'small-margin small width-100', id: dom_id(type_de_champ, :libelle), data: input_autofocus
- if type_de_champ.header_section?
%p
%small Nous numérotons automatiquement les titres lorsquaucun de vos titres ne commence par un chiffre.
- if !type_de_champ.header_section? && !type_de_champ.titre_identite? - if !type_de_champ.header_section? && !type_de_champ.titre_identite?
.cell.mt-1 .cell.mt-1
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description) = form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)

View file

@ -25,14 +25,6 @@ class Champs::HeaderSectionChamp < Champ
# The user cannot enter any information here so it doesnt make much sense to search # The user cannot enter any information here so it doesnt make much sense to search
end end
def libelle_with_section_index
if sections&.none?(&:libelle_with_section_index?)
"#{section_index}. #{libelle}"
else
libelle
end
end
def libelle_with_section_index? def libelle_with_section_index?
libelle =~ /^\d/ libelle =~ /^\d/
end end

View file

@ -0,0 +1,35 @@
module DossierSectionsConcern
extend ActiveSupport::Concern
included do
def sections_for(champ)
@sections = Hash.new do |hash, parent|
case parent
when :public
hash[parent] = champs_public.filter(&:header_section?)
when :private
hash[parent] = champs_private.filter(&:header_section?)
else
hash[parent] = parent.champs.filter(&:header_section?)
end
end
@sections[champ.parent || (champ.public? ? :public : :private)]
end
def auto_numbering_section_headers_for?(champ)
sections_for(champ)&.none?(&:libelle_with_section_index?)
end
def index_for_section_header(champ)
champs = champ.private? ? champs_private : champs_public
index = 1
champs.each do |c|
return index if c.stable_id == champ.stable_id
next unless c.visible?
index += 1 if c.type_de_champ.header_section?
end
end
end
end

View file

@ -48,8 +48,9 @@
class Dossier < ApplicationRecord class Dossier < ApplicationRecord
self.ignored_columns = [:en_construction_conservation_extension] self.ignored_columns = [:en_construction_conservation_extension]
include DossierFilteringConcern include DossierFilteringConcern
include DossierRebaseConcern
include DossierPrefillableConcern include DossierPrefillableConcern
include DossierRebaseConcern
include DossierSectionsConcern
enum state: { enum state: {
brouillon: 'brouillon', brouillon: 'brouillon',
@ -1237,20 +1238,6 @@ class Dossier < ApplicationRecord
termine_expired_to_delete.find_each(&:purge_discarded) termine_expired_to_delete.find_each(&:purge_discarded)
end end
def sections_for(champ)
@sections = Hash.new do |hash, parent|
case parent
when :public
hash[parent] = champs_public.filter(&:header_section?)
when :private
hash[parent] = champs_private.filter(&:header_section?)
else
hash[parent] = parent.champs.filter(&:header_section?)
end
end
@sections[champ.parent || (champ.public? ? :public : :private)]
end
def clone def clone
dossier_attributes = [:autorisation_donnees, :user_id, :revision_id, :groupe_instructeur_id] dossier_attributes = [:autorisation_donnees, :user_id, :revision_id, :groupe_instructeur_id]
relationships = [:individual, :etablissement] relationships = [:individual, :etablissement]

View file

@ -192,6 +192,7 @@ class TypeDeChamp < ApplicationRecord
validates :type_champ, presence: true, allow_blank: false, allow_nil: false validates :type_champ, presence: true, allow_blank: false, allow_nil: false
before_validation :check_mandatory before_validation :check_mandatory
before_validation :normalize_libelle
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? } before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
before_validation :remove_drop_down_list, if: -> { type_champ_changed? } before_validation :remove_drop_down_list, if: -> { type_champ_changed? }
before_save :remove_block, if: -> { type_champ_changed? } before_save :remove_block, if: -> { type_champ_changed? }
@ -554,4 +555,8 @@ class TypeDeChamp < ApplicationRecord
.remove_children_of(self) .remove_children_of(self)
end end
end end
def normalize_libelle
self.libelle&.strip!
end
end end

View file

@ -141,7 +141,13 @@ def add_single_champ(pdf, champ)
when 'Champs::PieceJustificativeChamp', 'Champs::TitreIdentiteChamp' when 'Champs::PieceJustificativeChamp', 'Champs::TitreIdentiteChamp'
return return
when 'Champs::HeaderSectionChamp' when 'Champs::HeaderSectionChamp'
add_section_title(pdf, tdc.libelle) libelle = if @dossier.auto_numbering_section_headers_for?(champ)
"#{@dossier.index_for_section_header(champ)}. #{champ.libelle}"
else
champ.libelle
end
add_section_title(pdf, libelle)
when 'Champs::ExplicationChamp' when 'Champs::ExplicationChamp'
format_in_2_lines(pdf, tdc.libelle, strip_tags(tdc.description)) format_in_2_lines(pdf, tdc.libelle, strip_tags(tdc.description))
when 'Champs::CarteChamp' when 'Champs::CarteChamp'

View file

@ -10,8 +10,7 @@
- else - else
%tr %tr
- if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section) - if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section)
%th.header-section{ colspan: 3 } %th.header-section{ colspan: 3, class: c.dossier.auto_numbering_section_headers_for?(c) ? "header-section-counter" : nil }= c.libelle
= c.libelle
- else - else
%td.libelle{ class: repetition ? 'padded' : '' } %td.libelle{ class: repetition ? 'padded' : '' }
= "#{c.libelle} :" = "#{c.libelle} :"

View file

@ -1,4 +1,4 @@
%table.table.vertical.dossier-champs{ role: :presentation } %table.table.vertical.dossier-champs.counter-start-header-section{ role: :presentation }
%tbody %tbody
- if dossier.show_groupe_instructeur_details? - if dossier.show_groupe_instructeur_details?
%td.libelle= dossier.procedure.routing_criteria_name %td.libelle= dossier.procedure.routing_criteria_name

View file

@ -2,7 +2,7 @@
- content_for(:notice_info) do - content_for(:notice_info) do
= render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information } = render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information }
.dossier-edit.container .dossier-edit.container.counter-start-header-section
= render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier } = render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier }
- if dossier.brouillon? - if dossier.brouillon?

View file

@ -0,0 +1,22 @@
namespace :after_party do
desc 'Deployment task: strip_type_de_champ_libelle'
task strip_type_de_champ_libelle: :environment do
puts "Running deploy task 'strip_type_de_champ_libelle'"
# ~ 152K records matched
tdcs = TypeDeChamp.where("libelle LIKE ?", ' %').or(TypeDeChamp.where("libelle LIKE ?", '% '))
progress = ProgressReport.new(tdcs.count)
tdcs.find_each do |tdc|
tdc.save!
progress.inc
end
progress.finish
# Update task as completed. If you remove the line below, the task will
# run with every deploy (or every time you call after_party:run).
AfterParty::TaskRecord
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
end
end

View file

@ -0,0 +1,69 @@
describe DossierSectionsConcern do
describe '#auto_numbering_section_headers_for?' do
let(:public_libelle) { "Infos" }
let(:private_libelle) { "Infos Private" }
let(:types_de_champ_public) { [{ type: :header_section, libelle: public_libelle }, { type: :header_section, libelle: "Details" }] }
let(:types_de_champ_private) { [{ type: :header_section, libelle: private_libelle }, { type: :header_section, libelle: "Details Private" }] }
let(:procedure) { create(:procedure, :for_individual, types_de_champ_public:, types_de_champ_private:) }
let(:dossier) { create(:dossier, procedure: procedure) }
context "with no section having number" do
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_public[1])).to eq(true) }
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_private[1])).to eq(true) }
end
context "with public section having number" do
let(:public_libelle) { "1 - infos" }
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_public[1])).to eq(false) }
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_private[1])).to eq(true) }
end
context "with private section having number" do
let(:private_libelle) { "1 - infos private" }
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_public[1])).to eq(true) }
it { expect(dossier.auto_numbering_section_headers_for?(dossier.champs_private[1])).to eq(false) }
end
end
describe '#index_for_section_header' do
include Logic
let(:number_stable_id) { 99 }
let(:types_de_champ) {
[
{ type: :header_section, libelle: "Infos" }, { type: :integer_number, stable_id: number_stable_id },
{ type: :header_section, libelle: "Details", condition: ds_eq(champ_value(99), constant(5)) }, { type: :header_section, libelle: "Conclusion" }
]
}
let(:procedure) { create(:procedure, :for_individual, types_de_champ_public: types_de_champ) }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:headers) { dossier.champs_public.filter(&:header_section?) }
let(:number_value) { nil }
before do
dossier.champs_public.find { _1.stable_id == number_stable_id }.update(value: number_value)
dossier.reload
end
context "when there are invisible sections" do
it "index accordingly header sections" do
expect(dossier.index_for_section_header(headers[0])).to eq(1)
expect(headers[1]).not_to be_visible
expect(dossier.index_for_section_header(headers[2])).to eq(2)
end
end
context "when all headers are visible" do
let(:number_value) { 5 }
it "index accordingly header sections" do
expect(dossier.index_for_section_header(headers[0])).to eq(1)
expect(headers[1]).to be_visible
expect(dossier.index_for_section_header(headers[1])).to eq(2)
expect(dossier.index_for_section_header(headers[2])).to eq(3)
end
end
end
end

View file

@ -273,4 +273,9 @@ describe TypeDeChamp do
it_behaves_like "a non-prefillable type de champ", :type_de_champ_address it_behaves_like "a non-prefillable type de champ", :type_de_champ_address
it_behaves_like "a non-prefillable type de champ", :type_de_champ_annuaire_education it_behaves_like "a non-prefillable type de champ", :type_de_champ_annuaire_education
end end
describe '#normalize_libelle' do
it { expect(create(:type_de_champ, :header_section, libelle: " 2.3 Test").libelle).to eq("2.3 Test") }
it { expect(create(:type_de_champ, libelle: " fix me ").libelle).to eq("fix me") }
end
end end