+
-
+
-
+
+
+
+
+
+
+
+
diff --git a/app/javascript/new_design/administrateur/DraggableList.js b/app/javascript/new_design/administrateur/DraggableList.js
index b680daa52..f28746ffe 100644
--- a/app/javascript/new_design/administrateur/DraggableList.js
+++ b/app/javascript/new_design/administrateur/DraggableList.js
@@ -5,6 +5,7 @@ export default {
this.state.typesDeChamp.push({
type_champ: 'text',
drop_down_list: {},
+ types_de_champ: [],
options: {}
});
}
diff --git a/app/javascript/new_design/administrateur/DraggableList.vue b/app/javascript/new_design/administrateur/DraggableList.vue
index 7832e565b..361d1b098 100644
--- a/app/javascript/new_design/administrateur/DraggableList.vue
+++ b/app/javascript/new_design/administrateur/DraggableList.vue
@@ -16,7 +16,6 @@
{
+ delegate('click', BUTTON_SELECTOR, evt => {
+ evt.preventDefault();
+
+ const row = evt.target.closest('.row');
+
+ for (let input of row.querySelectorAll(DESTROY_INPUT_SELECTOR)) {
+ input.disabled = false;
+ input.value = true;
+ }
+ for (let champ of row.querySelectorAll(CHAMP_SELECTOR)) {
+ champ.remove();
+ }
+
+ evt.target.remove();
+ row.classList.remove('row');
+ });
+});
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 61ff74ed2..128b7c1b1 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -21,6 +21,7 @@ import '../new_design/select2';
import '../new_design/champs/carte';
import '../new_design/champs/linked-drop-down-list';
+import '../new_design/champs/repetition';
import '../new_design/administrateur/champs-editor';
diff --git a/app/models/champ.rb b/app/models/champ.rb
index 8a7a9b91c..e0d7b35f1 100644
--- a/app/models/champ.rb
+++ b/app/models/champ.rb
@@ -10,7 +10,7 @@ class Champ < ApplicationRecord
has_many :geo_areas, dependent: :destroy
belongs_to :etablissement, dependent: :destroy
- delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, :exclude_from_export?, :exclude_from_view?, to: :type_de_champ
+ delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, :exclude_from_export?, :exclude_from_view?, :repetition?, to: :type_de_champ
scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) }
scope :public_only, -> { where(private: false) }
diff --git a/app/models/champs/repetition_champ.rb b/app/models/champs/repetition_champ.rb
index 8b06ca396..a2f02fa04 100644
--- a/app/models/champs/repetition_champ.rb
+++ b/app/models/champs/repetition_champ.rb
@@ -9,10 +9,22 @@ class Champs::RepetitionChamp < Champ
champs.group_by(&:row).values
end
+ def add_row(row = 0)
+ type_de_champ.types_de_champ.each do |type_de_champ|
+ self.champs << type_de_champ.champ.build(row: row)
+ end
+ end
+
+ def mandatory_and_blank?
+ mandatory? && champs.empty?
+ end
+
def search_terms
# The user cannot enter any information here so it doesn’t make much sense to search
end
+ private
+
def setup_dossier
champs.each do |champ|
champ.dossier = dossier
diff --git a/app/models/dossier.rb b/app/models/dossier.rb
index 97a98442d..2dee58040 100644
--- a/app/models/dossier.rb
+++ b/app/models/dossier.rb
@@ -121,7 +121,13 @@ class Dossier < ApplicationRecord
def build_default_champs
procedure.types_de_champ.each do |type_de_champ|
- champs << type_de_champ.champ.build
+ champ = type_de_champ.champ.build
+
+ if type_de_champ.repetition?
+ champ.add_row
+ end
+
+ champs << champ
end
procedure.types_de_champ_private.each do |type_de_champ|
champs_private << type_de_champ.champ.build
@@ -334,6 +340,14 @@ class Dossier < ApplicationRecord
log_dossier_operation(gestionnaire, :classer_sans_suite)
end
+ def check_mandatory_champs
+ (champs + champs.select(&:repetition?).flat_map(&:champs))
+ .select(&:mandatory_and_blank?)
+ .map do |champ|
+ "Le champ #{champ.libelle.truncate(200)} doit être rempli."
+ end
+ end
+
private
def log_dossier_operation(gestionnaire, operation, automatic_operation: false)
diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb
index c801a4a56..1b167c67a 100644
--- a/app/models/type_de_champ.rb
+++ b/app/models/type_de_champ.rb
@@ -35,7 +35,7 @@ class TypeDeChamp < ApplicationRecord
belongs_to :procedure
belongs_to :parent, class_name: 'TypeDeChamp'
- has_many :types_de_champ, foreign_key: :parent_id, class_name: 'TypeDeChamp', dependent: :destroy
+ has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', dependent: :destroy
store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj
@@ -84,7 +84,7 @@ class TypeDeChamp < ApplicationRecord
has_one_attached :piece_justificative_template
accepts_nested_attributes_for :drop_down_list, update_only: true
- accepts_nested_attributes_for :types_de_champ, allow_destroy: true
+ accepts_nested_attributes_for :types_de_champ, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true
validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :type_champ, presence: true, allow_blank: false, allow_nil: false
@@ -147,10 +147,11 @@ class TypeDeChamp < ApplicationRecord
end
def exclude_from_view?
- type_champ.in?([
- TypeDeChamp.type_champs.fetch(:explication),
- TypeDeChamp.type_champs.fetch(:repetition)
- ])
+ type_champ == TypeDeChamp.type_champs.fetch(:explication)
+ end
+
+ def repetition?
+ type_champ == TypeDeChamp.type_champs.fetch(:repetition)
end
def public?
diff --git a/app/views/champs/repetition/_show.html.haml b/app/views/champs/repetition/_show.html.haml
new file mode 100644
index 000000000..508593712
--- /dev/null
+++ b/app/views/champs/repetition/_show.html.haml
@@ -0,0 +1,10 @@
+- champs = champ.rows.last
+- index = (champ.rows.size - 1) * champs.size
+%div{ class: "row row-#{champs.first.row}" }
+ - champs.each.with_index(index) do |champ, index|
+ = fields_for "#{attribute}[#{index}]", champ do |form|
+ = render partial: "shared/dossiers/editable_champs/editable_champ", locals: { champ: champ, form: form }
+ = form.hidden_field :id
+ = form.hidden_field :_destroy, disabled: true
+ %button.button.danger.remove-row
+ Supprimer
diff --git a/app/views/champs/repetition/show.js.erb b/app/views/champs/repetition/show.js.erb
new file mode 100644
index 000000000..af552c482
--- /dev/null
+++ b/app/views/champs/repetition/show.js.erb
@@ -0,0 +1,3 @@
+<%= append_to_element(".repetition-#{@position}",
+ partial: 'champs/repetition/show',
+ locals: { champ: @champ, attribute: @attribute }) %>
diff --git a/app/views/new_administrateur/procedures/update.js.erb b/app/views/new_administrateur/procedures/update.js.erb
index 4aa3bae04..d8423e18a 100644
--- a/app/views/new_administrateur/procedures/update.js.erb
+++ b/app/views/new_administrateur/procedures/update.js.erb
@@ -1,3 +1,3 @@
<%= render_flash timeout: 6000, fixed: true %>
-<%= fire_event(:ProcedureUpdated, procedure_data(@procedure)) %>
+<%= fire_event(:ProcedureUpdated, procedure_data(@procedure.reload)) %>
diff --git a/app/views/shared/dossiers/_champ_row.html.haml b/app/views/shared/dossiers/_champ_row.html.haml
new file mode 100644
index 000000000..361c6e786
--- /dev/null
+++ b/app/views/shared/dossiers/_champ_row.html.haml
@@ -0,0 +1,40 @@
+- champs.reject(&:exclude_from_view?).each do |c|
+ - if c.type_champ == TypeDeChamp.type_champs.fetch(:repetition)
+ %tr
+ %th.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
+ %th{ colspan: 4 }
+ - else
+ %tr
+ - if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section)
+ %th.header-section{ colspan: 3 }
+ = c.libelle
+ - else
+ %th.libelle{ class: repetition ? 'padded' : '' }
+ = "#{c.libelle} :"
+ %td.rich-text
+ %span{ 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(:siret)
+ = render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile }
+ - when TypeDeChamp.type_champs.fetch(:textarea)
+ = render partial: "shared/champs/textarea/show", locals: { champ: c }
+ - else
+ = sanitize(c.to_s)
+
+ - 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
+ = c.updated_at.strftime("%d/%m/%Y à %H:%M")
diff --git a/app/views/shared/dossiers/_champs.html.haml b/app/views/shared/dossiers/_champs.html.haml
index 08c6a311b..1a511730f 100644
--- a/app/views/shared/dossiers/_champs.html.haml
+++ b/app/views/shared/dossiers/_champs.html.haml
@@ -1,33 +1,3 @@
%table.table.vertical.dossier-champs
%tbody
- - champs.reject(&:exclude_from_view?).each do |c|
- %tr
- - if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section)
- %th.header-section{ colspan: 3 }
- = c.libelle
- - else
- %th.libelle
- = "#{c.libelle} :"
- %td.rich-text
- %span{ 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(:siret)
- = render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile }
- - when TypeDeChamp.type_champs.fetch(:textarea)
- = render partial: "shared/champs/textarea/show", locals: { champ: c }
- - else
- = sanitize(c.to_s)
-
- - 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
- = c.updated_at.strftime("%d/%m/%Y à %H:%M")
+ = render partial: "shared/dossiers/champ_row", locals: { champs: champs, demande_seen_at: demande_seen_at, profile: profile, repetition: false }
diff --git a/app/views/shared/dossiers/editable_champs/_champ_label.html.haml b/app/views/shared/dossiers/editable_champs/_champ_label.html.haml
index 6ba997ae9..43c6d2b11 100644
--- a/app/views/shared/dossiers/editable_champs/_champ_label.html.haml
+++ b/app/views/shared/dossiers/editable_champs/_champ_label.html.haml
@@ -1,4 +1,4 @@
-= form.label champ.main_value_name do
+= form.label champ.main_value_name, { class: champ.repetition? ? 'header-section' : '' } do
#{champ.libelle}
- if champ.mandatory?
%span.mandatory *
diff --git a/app/views/shared/dossiers/editable_champs/_repetition.html.haml b/app/views/shared/dossiers/editable_champs/_repetition.html.haml
index b9fcfa711..d7e8717c7 100644
--- a/app/views/shared/dossiers/editable_champs/_repetition.html.haml
+++ b/app/views/shared/dossiers/editable_champs/_repetition.html.haml
@@ -1 +1,15 @@
-%h2.repetition-libelle= champ.libelle
+%div{ class: "repetition-#{form.index}" }
+ - champ.rows.each do |champs|
+ %div{ class: "row row-#{champs.first.row}" }
+ - champs.each do |champ|
+ = form.fields_for :champs, champ do |form|
+ = render partial: 'shared/dossiers/editable_champs/editable_champ', locals: { champ: form.object, form: form }
+ = form.hidden_field :_destroy, disabled: true
+ %button.button.danger.remove-row
+ Supprimer
+
+- if champ.persisted?
+ = link_to "Ajouter une ligne pour « #{champ.libelle} »", champs_repetition_path(form.index), class: 'button add-row', data: { remote: true, method: 'POST', params: { champ_id: champ&.id }.to_query }
+- else
+ %button.button.add-row{ disabled: true }
+ = "Ajouter une ligne pour « #{champ.libelle} »"
diff --git a/config/features.rb b/config/features.rb
index 2faf85f48..55d02a7bc 100644
--- a/config/features.rb
+++ b/config/features.rb
@@ -10,7 +10,7 @@ Flipflop.configure do
feature :champ_integer_number,
title: "Champ nombre entier"
feature :champ_repetition,
- title: "Bloc répétable (NE MARCHE PAS – NE PAS ACTIVER)"
+ title: "Bloc répétable"
end
feature :web_hook
diff --git a/config/routes.rb b/config/routes.rb
index 570844167..c0b41153f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -127,6 +127,7 @@ Rails.application.routes.draw do
get ':position/siret', to: 'siret#show', as: :siret
get ':position/dossier_link', to: 'dossier_link#show', as: :dossier_link
post ':position/carte', to: 'carte#show', as: :carte
+ post ':position/repetition', to: 'repetition#show', as: :repetition
end
get 'tour-de-france' => 'root#tour_de_france'
diff --git a/spec/features/admin/procedure_creation_spec.rb b/spec/features/admin/procedure_creation_spec.rb
index 646382773..f8fd9a74a 100644
--- a/spec/features/admin/procedure_creation_spec.rb
+++ b/spec/features/admin/procedure_creation_spec.rb
@@ -105,7 +105,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
end
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libelle de champ'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
within '.footer' do
click_on 'Ajouter un champ'
@@ -135,7 +135,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
click_on 'Ajouter un champ'
end
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libelle de champ'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
click_on Procedure.last.libelle
click_on 'onglet-pieces'
diff --git a/spec/features/new_administrateur/procedures_spec.rb b/spec/features/new_administrateur/procedures_spec.rb
index ead5f28da..47ba7e66f 100644
--- a/spec/features/new_administrateur/procedures_spec.rb
+++ b/spec/features/new_administrateur/procedures_spec.rb
@@ -5,6 +5,7 @@ feature 'As an administrateur I edit procedure', js: true do
let(:procedure) { create(:procedure) }
before do
+ Flipflop::FeatureSet.current.test!.switch!(:champ_repetition, true)
login_as administrateur, scope: :administrateur
visit champs_procedure_path(procedure)
end
@@ -15,14 +16,14 @@ feature 'As an administrateur I edit procedure', js: true do
end
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
page.refresh
within '.footer' do
click_on 'Enregistrer'
end
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
end
it "Add multiple champs" do
@@ -34,7 +35,7 @@ feature 'As an administrateur I edit procedure', js: true do
end
expect(page).not_to have_content('Le libellé doit être rempli.')
expect(page).not_to have_content('Modifications non sauvegardées.')
- expect(page).not_to have_content('Champs enregistrés')
+ expect(page).not_to have_content('Formulaire mis à jour')
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ 0'
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
@@ -44,7 +45,7 @@ feature 'As an administrateur I edit procedure', js: true do
expect(page).to have_content('Le libellé doit être rempli.')
expect(page).to have_content('Modifications non sauvegardées.')
- expect(page).not_to have_content('Champs enregistrés')
+ expect(page).not_to have_content('Formulaire mis à jour')
fill_in 'procedure_types_de_champ_attributes_2_libelle', with: 'libellé de champ 2'
within '.draggable-item-3' do
@@ -53,12 +54,12 @@ feature 'As an administrateur I edit procedure', js: true do
expect(page).to have_content('Le libellé doit être rempli.')
expect(page).to have_content('Modifications non sauvegardées.')
- expect(page).not_to have_content('Champs enregistrés')
+ expect(page).not_to have_content('Formulaire mis à jour')
fill_in 'procedure_types_de_champ_attributes_1_libelle', with: 'libellé de champ 1'
expect(page).not_to have_content('Le libellé doit être rempli.')
expect(page).not_to have_content('Modifications non sauvegardées.')
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
page.refresh
expect(page).to have_content('Supprimer', count: 3)
@@ -69,11 +70,11 @@ feature 'As an administrateur I edit procedure', js: true do
click_on 'Ajouter un champ'
end
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
page.refresh
click_on 'Supprimer'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
expect(page).not_to have_content('Supprimer')
page.refresh
@@ -87,9 +88,39 @@ feature 'As an administrateur I edit procedure', js: true do
expect(page).to have_selector('#procedure_types_de_champ_attributes_0_description')
fill_in 'procedure_types_de_champ_attributes_0_description', with: 'déscription du champ'
expect(page).to have_content('Le libellé doit être rempli.')
- expect(page).not_to have_content('Champs enregistrés')
+ expect(page).not_to have_content('Formulaire mis à jour')
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
- expect(page).to have_content('Champs enregistrés')
+ expect(page).to have_content('Formulaire mis à jour')
+ end
+
+ it "Add repetition champ" do
+ within '.footer' do
+ click_on 'Ajouter un champ'
+ end
+ expect(page).to have_selector('#procedure_types_de_champ_attributes_0_libelle')
+ select('Bloc répétable', from: 'procedure_types_de_champ_attributes_0_type_champ')
+ fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libellé de champ'
+
+ expect(page).to have_content('Formulaire mis à jour')
+ page.refresh
+
+ within '.flex-grow' do
+ click_on 'Ajouter un champ'
+ end
+
+ fill_in 'procedure_types_de_champ_attributes_0_types_de_champ_attributes_0_libelle', with: 'libellé de champ 1'
+
+ expect(page).to have_content('Formulaire mis à jour')
+ expect(page).to have_content('Supprimer', count: 2)
+
+ within '.footer' do
+ click_on 'Ajouter un champ'
+ end
+
+ select('Bloc répétable', from: 'procedure_types_de_champ_attributes_1_type_champ')
+ fill_in 'procedure_types_de_champ_attributes_1_libelle', with: 'libellé de champ 2'
+
+ expect(page).to have_content('Supprimer', count: 3)
end
end
diff --git a/spec/features/new_user/brouillon_spec.rb b/spec/features/new_user/brouillon_spec.rb
index 660d084a8..16c2d82ba 100644
--- a/spec/features/new_user/brouillon_spec.rb
+++ b/spec/features/new_user/brouillon_spec.rb
@@ -83,6 +83,41 @@ feature 'The user' do
expect(page).to have_field('dossier_link', with: '123')
end
+ let(:procedure_with_repetition) do
+ tdc = create(:type_de_champ_repetition, libelle: 'repetition')
+ tdc.types_de_champ << create(:type_de_champ_text, libelle: 'text')
+ create(:procedure, :published, :for_individual, types_de_champ: [tdc])
+ end
+
+ scenario 'fill a dossier with repetition', js: true do
+ log_in(user.email, password, procedure_with_repetition)
+
+ fill_individual
+
+ fill_in('text', with: 'super texte')
+ expect(page).to have_field('text', with: 'super texte')
+
+ click_on 'Ajouter une ligne pour'
+
+ within '.row-1' do
+ fill_in('text', with: 'un autre texte')
+ end
+
+ expect(page).to have_content('Supprimer', count: 2)
+
+ click_on 'Enregistrer le brouillon'
+
+ expect(page).to have_content('Supprimer', count: 2)
+
+ within '.row-1' do
+ click_on 'Supprimer'
+ end
+
+ click_on 'Enregistrer le brouillon'
+
+ expect(page).to have_content('Supprimer', count: 1)
+ end
+
let(:simple_procedure) do
tdcs = [create(:type_de_champ, mandatory: true, libelle: 'texte obligatoire')]
create(:procedure, :published, :for_individual, types_de_champ: tdcs)
diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb
index c5a7ee826..451fdffbe 100644
--- a/spec/models/dossier_spec.rb
+++ b/spec/models/dossier_spec.rb
@@ -832,4 +832,63 @@ describe Dossier do
it { expect(dossier.followers_gestionnaires).not_to include(gestionnaire) }
it { expect(dossier.dossier_operation_logs.pluck(:gestionnaire_id, :operation, :automatic_operation)).to match([[nil, 'passer_en_instruction', true]]) }
end
+
+ describe "#check_mandatory_champs" do
+ let(:procedure) { create(:procedure, :with_type_de_champ) }
+ let(:dossier) { create(:dossier, :with_all_champs, procedure: procedure) }
+
+ it 'no mandatory champs' do
+ expect(dossier.check_mandatory_champs).to be_empty
+ end
+
+ context "with mandatory champs" do
+ let(:procedure) { create(:procedure, :with_type_de_champ_mandatory) }
+ let(:champ_with_error) { dossier.champs.first }
+
+ before do
+ champ_with_error.value = nil
+ champ_with_error.save
+ end
+
+ it 'should have errors' do
+ errors = dossier.check_mandatory_champs
+ expect(errors).not_to be_empty
+ expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
+ end
+ end
+
+ context "with champ repetition" do
+ let(:procedure) { create(:procedure) }
+ let(:type_de_champ_repetition) { create(:type_de_champ_repetition, mandatory: true) }
+
+ before do
+ procedure.types_de_champ << type_de_champ_repetition
+ type_de_champ_repetition.types_de_champ << create(:type_de_champ_text, mandatory: true)
+ end
+
+ context "when no champs" do
+ let(:champ_with_error) { dossier.champs.first }
+
+ it 'should have errors' do
+ errors = dossier.check_mandatory_champs
+ expect(errors).not_to be_empty
+ expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
+ end
+ end
+
+ context "when mandatory champ inside repetition" do
+ let(:champ_with_error) { dossier.champs.first.champs.first }
+
+ before do
+ dossier.champs.first.add_row
+ end
+
+ it 'should have errors' do
+ errors = dossier.check_mandatory_champs
+ expect(errors).not_to be_empty
+ expect(errors.first).to eq("Le champ #{champ_with_error.libelle} doit être rempli.")
+ end
+ end
+ end
+ end
end
diff --git a/spec/views/shared/dossiers/_champs.html.haml_spec.rb b/spec/views/shared/dossiers/_champs.html.haml_spec.rb
index d8a80ab50..58d6c5690 100644
--- a/spec/views/shared/dossiers/_champs.html.haml_spec.rb
+++ b/spec/views/shared/dossiers/_champs.html.haml_spec.rb
@@ -8,7 +8,7 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
allow(view).to receive(:current_gestionnaire).and_return(gestionnaire)
end
- subject { render 'shared/dossiers/champs.html.haml', champs: champs, demande_seen_at: demande_seen_at }
+ subject { render 'shared/dossiers/champs.html.haml', champs: champs, demande_seen_at: demande_seen_at, profile: nil }
context "there are some champs" do
let(:dossier) { create(:dossier) }