Merge pull request #9695 from tchak/use-types-de-champ-as-source-of-truth
refactor(dossier): use revision as source of truth to diplay champs
This commit is contained in:
commit
a247ec6c12
47 changed files with 374 additions and 351 deletions
|
@ -1,10 +1,11 @@
|
||||||
- each_champ do |champ|
|
- each_champ do |champ|
|
||||||
- if champ.repetition?
|
- if champ.repetition?
|
||||||
- champ.rows.each.with_index do |row, i|
|
- types_de_champ = champ.dossier.revision.children_of(champ.type_de_champ)
|
||||||
|
- champs_by_stable_id_with_row = champ.dossier.champs_by_stable_id_with_row
|
||||||
|
- champ.row_ids.each.with_index do |row_id, i|
|
||||||
.fr-background-alt--grey.fr-p-2w.fr-my-3w.fr-ml-2w.champ-repetition
|
.fr-background-alt--grey.fr-p-2w.fr-my-3w.fr-ml-2w.champ-repetition
|
||||||
%p.font-weight-bold= "#{champ.libelle} #{i + 1} :"
|
%p.font-weight-bold= "#{champ.libelle} #{i + 1} :"
|
||||||
|
= render ViewableChamp::SectionComponent.new(types_de_champ:, champs_by_stable_id_with_row:, row_id:, demande_seen_at: seen_at, profile:)
|
||||||
= render Dossiers::ChampsRowsShowComponent.new(champs: row, seen_at:, profile:)
|
|
||||||
|
|
||||||
- else
|
- else
|
||||||
= render Dossiers::RowShowComponent.new(label: champ.libelle, seen_at:, profile:, content_class: champ.type_champ, updated_at: updated_after_deposer?(champ) ? champ.updated_at : nil) do |c|
|
= render Dossiers::RowShowComponent.new(label: champ.libelle, seen_at:, profile:, content_class: champ.type_champ, updated_at: updated_after_deposer?(champ) ? champ.updated_at : nil) do |c|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
|
|
||||||
.repetition{ id: dom_id(@champ, :rows) }
|
.repetition{ id: dom_id(@champ, :rows) }
|
||||||
- @champ.rows.each do |champs|
|
- @champ.row_ids.each do |row_id|
|
||||||
= render EditableChamp::RepetitionRowComponent.new(form: @form, champ: @champ, row: champs, seen_at: @seen_at)
|
= render EditableChamp::RepetitionRowComponent.new(form: @form, champ: @champ, row_id:, seen_at: @seen_at)
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= render NestedForms::OwnedButtonComponent.new(formaction: champs_repetition_path(@champ.id), http_method: :create, opt: { class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-circle-line fr-mb-3w", title: t(".add_title", libelle: @champ.libelle), id: dom_id(@champ, :create_repetition)}) do
|
= render NestedForms::OwnedButtonComponent.new(formaction: champs_repetition_path(@champ.id), http_method: :create, opt: { class: "fr-btn fr-btn--secondary fr-btn--icon-left fr-icon-add-circle-line fr-mb-3w", title: t(".add_title", libelle: @champ.libelle), id: dom_id(@champ, :create_repetition)}) do
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
class EditableChamp::RepetitionRowComponent < ApplicationComponent
|
class EditableChamp::RepetitionRowComponent < ApplicationComponent
|
||||||
def initialize(form:, champ:, row:, seen_at: nil)
|
def initialize(form:, champ:, row_id:, seen_at: nil)
|
||||||
@form, @champ, @row, @seen_at = form, champ, row, seen_at
|
@form, @champ, @row_id, @seen_at = form, champ, row_id, seen_at
|
||||||
|
|
||||||
|
@types_de_champ = champ.dossier.revision.children_of(champ.type_de_champ)
|
||||||
|
@champs_by_stable_id_with_row = champ.dossier.champs_by_stable_id_with_row
|
||||||
|
@row_number = champ.row_ids.find_index(row_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :row_id, :row_number
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def section_component
|
||||||
|
EditableChamp::SectionComponent.new(types_de_champ: @types_de_champ, champs_by_stable_id_with_row: @champs_by_stable_id_with_row, row_id:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
- row_id = "safe-row-selector-#{@row.first.row_id}"
|
.row{ id: "safe-row-selector-#{row_id}" }
|
||||||
.row{ id: row_id }
|
- if @types_de_champ.size > 1
|
||||||
- if @row.size > 1
|
|
||||||
%fieldset
|
%fieldset
|
||||||
%legend.block-id= "#{@champ.libelle} "
|
%legend.block-id= "#{@champ.libelle} "
|
||||||
= render EditableChamp::SectionComponent.new(champs: @row)
|
= render section_component
|
||||||
- else
|
- else
|
||||||
= render EditableChamp::SectionComponent.new(champs: @row)
|
= render section_component
|
||||||
|
|
||||||
.flex.row-reverse
|
.flex.row-reverse
|
||||||
= render NestedForms::OwnedButtonComponent.new(formaction: champs_repetition_path(@champ.id, row_id: @row.first.row_id), http_method: :delete, opt: { class: "fr-btn fr-btn--sm fr-btn--tertiary fr-text-action-high--red-marianne", title: t(".delete_title", row_number: @champ.rows.find_index(@row))}) do
|
= render NestedForms::OwnedButtonComponent.new(formaction: champs_repetition_path(@champ.id, row_id:), http_method: :delete, opt: { class: "fr-btn fr-btn--sm fr-btn--tertiary fr-text-action-high--red-marianne", title: t(".delete_title", row_number:)}) do
|
||||||
= t(".delete")
|
= t(".delete")
|
||||||
|
|
|
@ -2,8 +2,10 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include TreeableConcern
|
include TreeableConcern
|
||||||
|
|
||||||
def initialize(nodes: nil, champs: nil)
|
def initialize(nodes: nil, types_de_champ: nil, row_id: nil, champs_by_stable_id_with_row:)
|
||||||
nodes ||= to_tree(champs:)
|
nodes ||= to_tree(types_de_champ:)
|
||||||
|
@champs_by_stable_id_with_row = champs_by_stable_id_with_row
|
||||||
|
@row_id = row_id
|
||||||
@nodes = to_fieldset(nodes:)
|
@nodes = to_fieldset(nodes:)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -12,7 +14,8 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def header_section
|
def header_section
|
||||||
@nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
node = @nodes.first
|
||||||
|
champ_for_type_de_champ(node) if node.is_a?(TypeDeChamp) && node.header_section?
|
||||||
end
|
end
|
||||||
|
|
||||||
def splitted_tail
|
def splitted_tail
|
||||||
|
@ -35,17 +38,21 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
when EditableChamp::SectionComponent
|
when EditableChamp::SectionComponent
|
||||||
[node, nil]
|
[node, nil]
|
||||||
else
|
else
|
||||||
[nil, node]
|
[nil, champ_for_type_de_champ(node)]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def to_fieldset(nodes:)
|
def to_fieldset(nodes:)
|
||||||
nodes.map { _1.is_a?(Array) ? EditableChamp::SectionComponent.new(nodes: _1) : _1 }
|
nodes.map { _1.is_a?(Array) ? EditableChamp::SectionComponent.new(nodes: _1, row_id: @row_id, champs_by_stable_id_with_row: @champs_by_stable_id_with_row) : _1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
def first_champ_is_an_header_section?
|
def first_champ_is_an_header_section?
|
||||||
header_section.present?
|
header_section.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def champ_for_type_de_champ(type_de_champ)
|
||||||
|
@champs_by_stable_id_with_row[[@row_id, type_de_champ.stable_id].compact]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,9 +2,9 @@ class ViewableChamp::SectionComponent < ApplicationComponent
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include TreeableConcern
|
include TreeableConcern
|
||||||
|
|
||||||
def initialize(champs: nil, nodes: nil, demande_seen_at:, profile:)
|
def initialize(nodes: nil, types_de_champ: nil, row_id: nil, demande_seen_at:, profile:, champs_by_stable_id_with_row:)
|
||||||
@demande_seen_at, @profile, @repetition = demande_seen_at, profile
|
@demande_seen_at, @profile, @row_id, @champs_by_stable_id_with_row = demande_seen_at, profile, row_id, champs_by_stable_id_with_row
|
||||||
nodes ||= to_tree(champs:)
|
nodes ||= to_tree(types_de_champ:)
|
||||||
@nodes = to_sections(nodes:)
|
@nodes = to_sections(nodes:)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,17 +13,18 @@ class ViewableChamp::SectionComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def header_section
|
def header_section
|
||||||
if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
maybe_header_section = @nodes.first
|
||||||
@nodes.first
|
if maybe_header_section.is_a?(TypeDeChamp) && maybe_header_section.header_section?
|
||||||
|
champ_for_type_de_champ(maybe_header_section)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def champs
|
def champs
|
||||||
tail.filter { _1.is_a?(Champ) }
|
tail.filter_map { _1.is_a?(TypeDeChamp) ? champ_for_type_de_champ(_1) : nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
def sections
|
def sections
|
||||||
tail.filter { !_1.is_a?(Champ) }
|
tail.filter { _1.is_a?(ViewableChamp::SectionComponent) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def tail
|
def tail
|
||||||
|
@ -48,6 +49,10 @@ class ViewableChamp::SectionComponent < ApplicationComponent
|
||||||
private
|
private
|
||||||
|
|
||||||
def to_sections(nodes:)
|
def to_sections(nodes:)
|
||||||
nodes.map { _1.is_a?(Array) ? ViewableChamp::SectionComponent.new(nodes: _1, demande_seen_at: @demande_seen_at, profile: @profile) : _1 }
|
nodes.map { _1.is_a?(Array) ? ViewableChamp::SectionComponent.new(nodes: _1, demande_seen_at: @demande_seen_at, profile: @profile, champs_by_stable_id_with_row: @champs_by_stable_id_with_row) : _1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
def champ_for_type_de_champ(type_de_champ)
|
||||||
|
@champs_by_stable_id_with_row[[@row_id, type_de_champ.stable_id].compact]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,9 @@ class Champs::RepetitionController < ApplicationController
|
||||||
|
|
||||||
def add
|
def add
|
||||||
@champ = policy_scope(Champ).includes(:champs).find(params[:champ_id])
|
@champ = policy_scope(Champ).includes(:champs).find(params[:champ_id])
|
||||||
@champs = @champ.add_row(@champ.dossier.revision)
|
row = @champ.add_row(@champ.dossier.revision)
|
||||||
|
@first_champ_id = row.map(&:focusable_input_id).compact.first
|
||||||
|
@row_id = row.first&.row_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove
|
def remove
|
||||||
|
|
|
@ -26,7 +26,7 @@ class RootController < ApplicationController
|
||||||
description = "Allez voir le super site : #{APPLICATION_BASE_URL}"
|
description = "Allez voir le super site : #{APPLICATION_BASE_URL}"
|
||||||
|
|
||||||
all_champs = TypeDeChamp.type_champs
|
all_champs = TypeDeChamp.type_champs
|
||||||
.map { |name, _| TypeDeChamp.new(type_champ: name, private: false, libelle: name.humanize, description: description, mandatory: true) }
|
.map.with_index { |(name, _), i| TypeDeChamp.new(type_champ: name, private: false, libelle: name.humanize, description:, mandatory: true, stable_id: i) }
|
||||||
.map.with_index { |type_de_champ, i| type_de_champ.champ.build(id: i) }
|
.map.with_index { |type_de_champ, i| type_de_champ.champ.build(id: i) }
|
||||||
|
|
||||||
all_champs
|
all_champs
|
||||||
|
@ -76,7 +76,7 @@ class RootController < ApplicationController
|
||||||
.each { |champ| champ.value = value }
|
.each { |champ| champ.value = value }
|
||||||
end
|
end
|
||||||
|
|
||||||
@dossier = Dossier.new(champs_public: all_champs)
|
@dossier = Dossier.new(champs: all_champs)
|
||||||
@dossier.association(:procedure).target = Procedure.new
|
@dossier.association(:procedure).target = Procedure.new
|
||||||
all_champs.each do |champ|
|
all_champs.each do |champ|
|
||||||
champ.association(:dossier).target = @dossier
|
champ.association(:dossier).target = @dossier
|
||||||
|
@ -85,7 +85,7 @@ class RootController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
draft_revision = @dossier.procedure.build_draft_revision(types_de_champ_public: all_champs.map(&:type_de_champ))
|
draft_revision = @dossier.procedure.build_draft_revision(types_de_champ: all_champs.map(&:type_de_champ))
|
||||||
@dossier.association(:revision).target = draft_revision
|
@dossier.association(:revision).target = draft_revision
|
||||||
@dossier.champs_public.map(&:type_de_champ).map do |tdc|
|
@dossier.champs_public.map(&:type_de_champ).map do |tdc|
|
||||||
tdc.association(:revision_type_de_champ).target = tdc.build_revision_type_de_champ(revision: draft_revision)
|
tdc.association(:revision_type_de_champ).target = tdc.build_revision_type_de_champ(revision: draft_revision)
|
||||||
|
|
|
@ -11,15 +11,17 @@ module Types::Champs
|
||||||
field :rows, [Row], null: false
|
field :rows, [Row], null: false
|
||||||
|
|
||||||
def champs
|
def champs
|
||||||
Loaders::Association.for(object.class, champs: :type_de_champ).load(object).then do |champs|
|
object.rows.flat_map { _1.filter(&:visible?) }
|
||||||
champs.filter(&:visible?)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def rows
|
def rows
|
||||||
Loaders::Association.for(object.class, champs: :type_de_champ).load(object).then do |champs|
|
object
|
||||||
object.association(:champs).target = champs.filter(&:visible?)
|
.rows
|
||||||
object.rows.map { { champs: _1, id: GraphQL::Schema::UniqueWithinType.encode('Row', _1.first.row_id) } }
|
.map do
|
||||||
|
{
|
||||||
|
id: GraphQL::Schema::UniqueWithinType.encode('Row', _1.first.row_id),
|
||||||
|
champs: _1.filter(&:visible?)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -157,10 +157,7 @@ module Types
|
||||||
.for(object, private: false)
|
.for(object, private: false)
|
||||||
.load(ApplicationRecord.id_from_typed_id(id))
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
else
|
else
|
||||||
Loaders::Association
|
object.champs_for_revision(scope: :public, root: true).filter(&:visible?)
|
||||||
.for(object.class, champs_public: :type_de_champ)
|
|
||||||
.load(object)
|
|
||||||
.then { |champs| champs.filter(&:visible?) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -170,7 +167,7 @@ module Types
|
||||||
.for(object, private: true)
|
.for(object, private: true)
|
||||||
.load(ApplicationRecord.id_from_typed_id(id))
|
.load(ApplicationRecord.id_from_typed_id(id))
|
||||||
else
|
else
|
||||||
Loaders::Association.for(object.class, champs_private: :type_de_champ).load(object)
|
object.champs_for_revision(scope: :private, root: true).filter(&:visible?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -79,10 +79,10 @@ class AttestationTemplate < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def unspecified_champs_for_dossier(dossier)
|
def unspecified_champs_for_dossier(dossier)
|
||||||
all_champs_with_libelle_index = (dossier.champs_public + dossier.champs_private).index_by { |champ| "tdc#{champ.stable_id}" }
|
champs_by_stable_id = dossier.champs_for_revision(root: true).index_by { "tdc#{_1.stable_id}" }
|
||||||
|
|
||||||
used_tags.filter_map do |used_tag|
|
used_tags.filter_map do |used_tag|
|
||||||
corresponding_champ = all_champs_with_libelle_index[used_tag]
|
corresponding_champ = champs_by_stable_id[used_tag]
|
||||||
|
|
||||||
if corresponding_champ && corresponding_champ.blank?
|
if corresponding_champ && corresponding_champ.blank?
|
||||||
corresponding_champ
|
corresponding_champ
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Champ < ApplicationRecord
|
||||||
# here because otherwise we can't easily use includes in our queries.
|
# here because otherwise we can't easily use includes in our queries.
|
||||||
has_many :geo_areas, -> { order(:created_at) }, dependent: :destroy, inverse_of: :champ
|
has_many :geo_areas, -> { order(:created_at) }, dependent: :destroy, inverse_of: :champ
|
||||||
belongs_to :etablissement, optional: true, dependent: :destroy
|
belongs_to :etablissement, optional: true, dependent: :destroy
|
||||||
has_many :champs, -> { ordered }, foreign_key: :parent_id, inverse_of: :parent
|
has_many :champs, foreign_key: :parent_id, inverse_of: :parent
|
||||||
|
|
||||||
delegate :procedure, to: :dossier
|
delegate :procedure, to: :dossier
|
||||||
|
|
||||||
|
@ -70,14 +70,6 @@ class Champ < ApplicationRecord
|
||||||
scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) }
|
scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) }
|
||||||
scope :public_only, -> { where(private: false) }
|
scope :public_only, -> { where(private: false) }
|
||||||
scope :private_only, -> { where(private: true) }
|
scope :private_only, -> { where(private: true) }
|
||||||
scope :ordered, -> do
|
|
||||||
includes(:type_de_champ)
|
|
||||||
.joins(dossier: { revision: :revision_types_de_champ })
|
|
||||||
.where('procedure_revision_types_de_champ.type_de_champ_id = champs.type_de_champ_id')
|
|
||||||
.order(:row_id, :position)
|
|
||||||
end
|
|
||||||
scope :public_ordered, -> { public_only.ordered }
|
|
||||||
scope :private_ordered, -> { private_only.ordered }
|
|
||||||
scope :root, -> { where(parent_id: nil) }
|
scope :root, -> { where(parent_id: nil) }
|
||||||
scope :prefilled, -> { where(prefilled: true) }
|
scope :prefilled, -> { where(prefilled: true) }
|
||||||
|
|
||||||
|
@ -99,10 +91,6 @@ class Champ < ApplicationRecord
|
||||||
[row_id, stable_id].compact
|
[row_id, stable_id].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def sections
|
|
||||||
@sections ||= dossier.sections_for(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# used for the `required` html attribute
|
# used for the `required` html attribute
|
||||||
# check visibility to avoid hidden required input
|
# check visibility to avoid hidden required input
|
||||||
# which prevent the form from being sent.
|
# which prevent the form from being sent.
|
||||||
|
|
|
@ -16,8 +16,4 @@ class Champs::HeaderSectionChamp < Champ
|
||||||
def libelle_with_section_index?
|
def libelle_with_section_index?
|
||||||
libelle =~ /^\d/
|
libelle =~ /^\d/
|
||||||
end
|
end
|
||||||
|
|
||||||
def section_index
|
|
||||||
sections.index(self) + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,13 @@ class Champs::RepetitionChamp < Champ
|
||||||
delegate :libelle_for_export, to: :type_de_champ
|
delegate :libelle_for_export, to: :type_de_champ
|
||||||
|
|
||||||
def rows
|
def rows
|
||||||
champs.group_by(&:row_id).values
|
dossier
|
||||||
|
.champs_for_revision(scope: type_de_champ)
|
||||||
|
.group_by(&:row_id).values
|
||||||
|
end
|
||||||
|
|
||||||
|
def row_ids
|
||||||
|
rows.map { _1.first.row_id }
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_row(revision)
|
def add_row(revision)
|
||||||
|
@ -35,13 +41,15 @@ class Champs::RepetitionChamp < Champ
|
||||||
end
|
end
|
||||||
|
|
||||||
def rows_for_export
|
def rows_for_export
|
||||||
rows.each.with_index(1).map do |champs, index|
|
champs = dossier.champs_by_stable_id_with_row
|
||||||
Champs::RepetitionChamp::Row.new(index: index, dossier_id: dossier_id.to_s, champs: champs)
|
row_ids.each.with_index(1).map do |row_id, index|
|
||||||
|
Champs::RepetitionChamp::Row.new(index: index, row_id:, dossier_id: dossier_id.to_s, champs:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Row < Hashie::Dash
|
class Row < Hashie::Dash
|
||||||
property :index
|
property :index
|
||||||
|
property :row_id
|
||||||
property :dossier_id
|
property :dossier_id
|
||||||
property :champs
|
property :champs
|
||||||
|
|
||||||
|
@ -53,7 +61,7 @@ class Champs::RepetitionChamp < Champ
|
||||||
[
|
[
|
||||||
['Dossier ID', :dossier_id],
|
['Dossier ID', :dossier_id],
|
||||||
['Ligne', :index]
|
['Ligne', :index]
|
||||||
] + Dossier.champs_for_export(champs, types_de_champ)
|
] + Dossier.champs_for_export(types_de_champ, champs, row_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,10 +42,10 @@ module DossierCloneConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_diff(editing_fork)
|
def make_diff(editing_fork)
|
||||||
origin_champs_index = champs_public_all.index_by(&:stable_id_with_row)
|
origin_champs_index = champs_for_revision(scope: :public).index_by(&:stable_id_with_row)
|
||||||
forked_champs_index = editing_fork.champs_public_all.index_by(&:stable_id_with_row)
|
forked_champs_index = editing_fork.champs_for_revision(scope: :public).index_by(&:stable_id_with_row)
|
||||||
updated_champs_index = editing_fork
|
updated_champs_index = editing_fork
|
||||||
.champs_public_all
|
.champs_for_revision(scope: :public)
|
||||||
.filter { _1.updated_at > editing_fork.created_at }
|
.filter { _1.updated_at > editing_fork.created_at }
|
||||||
.index_by(&:stable_id_with_row)
|
.index_by(&:stable_id_with_row)
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ module DossierCloneConcern
|
||||||
dossier_attributes += [:groupe_instructeur_id] if fork
|
dossier_attributes += [:groupe_instructeur_id] if fork
|
||||||
relationships = [:individual, :etablissement]
|
relationships = [:individual, :etablissement]
|
||||||
|
|
||||||
cloned_champs = champs
|
cloned_champs = champs_for_revision
|
||||||
.index_by(&:id)
|
.index_by(&:id)
|
||||||
.transform_values { [_1, _1.clone(fork)] }
|
.transform_values { [_1, _1.clone(fork)] }
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ module DossierCloneConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_diff(diff)
|
def apply_diff(diff)
|
||||||
champs_index = (champs_public_all + diff[:added]).index_by(&:stable_id_with_row)
|
champs_index = (champs_for_revision(scope: :public) + diff[:added]).index_by(&:stable_id_with_row)
|
||||||
|
|
||||||
diff[:added].each do |champ|
|
diff[:added].each do |champ|
|
||||||
if champ.child?
|
if champ.child?
|
||||||
|
|
|
@ -6,11 +6,11 @@ module DossierSectionsConcern
|
||||||
@sections = Hash.new do |hash, parent|
|
@sections = Hash.new do |hash, parent|
|
||||||
case parent
|
case parent
|
||||||
when :public
|
when :public
|
||||||
hash[parent] = champs_public.filter(&:header_section?)
|
hash[parent] = champs_for_revision(scope: :public, root: true).filter(&:header_section?)
|
||||||
when :private
|
when :private
|
||||||
hash[parent] = champs_private.filter(&:header_section?)
|
hash[parent] = champs_for_revision(scope: :private, root: true).filter(&:header_section?)
|
||||||
else
|
else
|
||||||
hash[parent] = parent.champs.filter(&:header_section?)
|
hash[parent] = champs_for_revision(scope: parent.type_de_champ).filter(&:header_section?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@sections[champ.parent || (champ.public? ? :public : :private)]
|
@sections[champ.parent || (champ.public? ? :public : :private)]
|
||||||
|
@ -23,7 +23,7 @@ module DossierSectionsConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def index_for_section_header(champ)
|
def index_for_section_header(champ)
|
||||||
champs = champ.private? ? champs_private : champs_public
|
champs = champ.private? ? champs_for_revision(scope: :private, root: true) : champs_for_revision(scope: :public, root: true)
|
||||||
index = 1
|
index = 1
|
||||||
champs.each do |c|
|
champs.each do |c|
|
||||||
if c.repetition?
|
if c.repetition?
|
||||||
|
|
|
@ -5,30 +5,30 @@ module TreeableConcern
|
||||||
# but a repetition can be nested an header_section, so 3+3=6=MAX_DEPTH
|
# but a repetition can be nested an header_section, so 3+3=6=MAX_DEPTH
|
||||||
|
|
||||||
included do
|
included do
|
||||||
# as we progress in the list of ordered champs
|
# as we progress in the list of ordered types_de_champ
|
||||||
# we keep a reference to each level of nesting (walk)
|
# we keep a reference to each level of nesting (walk)
|
||||||
# when we encounter an header_section, it depends of its own depth of nesting minus 1, ie:
|
# when we encounter an header_section, it depends of its own depth of nesting minus 1, ie:
|
||||||
# h1 belongs to prior (rooted_tree)
|
# h1 belongs to prior (rooted_tree)
|
||||||
# h2 belongs to prior h1
|
# h2 belongs to prior h1
|
||||||
# h3 belongs to prior h2
|
# h3 belongs to prior h2
|
||||||
# h1 belongs to prior (rooted_tree)
|
# h1 belongs to prior (rooted_tree)
|
||||||
# then, each and every champs which are not an header_section
|
# then, each and every types_de_champ which are not an header_section
|
||||||
# are added to the current_tree
|
# are added to the current_tree
|
||||||
# given a root_depth at 0, we build a full tree
|
# given a root_depth at 0, we build a full tree
|
||||||
# given a root_depth > 0, we build a partial tree (aka, a repetition)
|
# given a root_depth > 0, we build a partial tree (aka, a repetition)
|
||||||
def to_tree(champs:)
|
def to_tree(types_de_champ:)
|
||||||
rooted_tree = []
|
rooted_tree = []
|
||||||
walk = Array.new(MAX_DEPTH)
|
walk = Array.new(MAX_DEPTH)
|
||||||
walk[0] = rooted_tree
|
walk[0] = rooted_tree
|
||||||
current_tree = rooted_tree
|
current_tree = rooted_tree
|
||||||
|
|
||||||
champs.each do |champ|
|
types_de_champ.each do |type_de_champ|
|
||||||
if champ.header_section?
|
if type_de_champ.header_section?
|
||||||
new_tree = [champ]
|
new_tree = [type_de_champ]
|
||||||
walk[champ.header_section_level_value - 1].push(new_tree)
|
walk[type_de_champ.header_section_level_value - 1].push(new_tree)
|
||||||
current_tree = walk[champ.header_section_level_value] = new_tree
|
current_tree = walk[type_de_champ.header_section_level_value] = new_tree
|
||||||
else
|
else
|
||||||
current_tree.push(champ)
|
current_tree.push(type_de_champ)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rooted_tree
|
rooted_tree
|
||||||
|
|
|
@ -45,8 +45,8 @@ class Dossier < ApplicationRecord
|
||||||
# We have to remove champs in a particular order - champs with a reference to a parent have to be
|
# We have to remove champs in a particular order - champs with a reference to a parent have to be
|
||||||
# removed first, otherwise we get a foreign key constraint error.
|
# removed first, otherwise we get a foreign key constraint error.
|
||||||
has_many :champs_to_destroy, -> { order(:parent_id) }, class_name: 'Champ', inverse_of: false, dependent: :destroy
|
has_many :champs_to_destroy, -> { order(:parent_id) }, class_name: 'Champ', inverse_of: false, dependent: :destroy
|
||||||
has_many :champs_public, -> { root.public_ordered }, class_name: 'Champ', inverse_of: false
|
has_many :champs_public, -> { root.public_only }, class_name: 'Champ', inverse_of: false
|
||||||
has_many :champs_private, -> { root.private_ordered }, class_name: 'Champ', inverse_of: false
|
has_many :champs_private, -> { root.private_only }, class_name: 'Champ', inverse_of: false
|
||||||
has_many :champs_public_all, -> { public_only }, class_name: 'Champ', inverse_of: false
|
has_many :champs_public_all, -> { public_only }, class_name: 'Champ', inverse_of: false
|
||||||
has_many :champs_private_all, -> { private_only }, class_name: 'Champ', inverse_of: false
|
has_many :champs_private_all, -> { private_only }, class_name: 'Champ', inverse_of: false
|
||||||
has_many :prefilled_champs_public, -> { root.public_only.prefilled }, class_name: 'Champ', inverse_of: false
|
has_many :prefilled_champs_public, -> { root.public_only.prefilled }, class_name: 'Champ', inverse_of: false
|
||||||
|
@ -610,7 +610,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
def any_etablissement_as_degraded_mode?
|
def any_etablissement_as_degraded_mode?
|
||||||
return true if etablissement&.as_degraded_mode?
|
return true if etablissement&.as_degraded_mode?
|
||||||
return true if champs_public_all.any? { _1.etablissement&.as_degraded_mode? }
|
return true if champs_for_revision(scope: :public).any? { _1.etablissement&.as_degraded_mode? }
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
@ -1165,7 +1165,8 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_mandatory_and_visible_champs
|
def check_mandatory_and_visible_champs
|
||||||
(champs_public + champs_public.filter(&:block?).filter(&:visible?).flat_map(&:champs))
|
champs_for_revision(scope: :public)
|
||||||
|
.filter { _1.child? ? _1.parent.visible? : true }
|
||||||
.filter(&:visible?)
|
.filter(&:visible?)
|
||||||
.filter(&:mandatory_blank?)
|
.filter(&:mandatory_blank?)
|
||||||
.map do |champ|
|
.map do |champ|
|
||||||
|
@ -1268,15 +1269,15 @@ class Dossier < ApplicationRecord
|
||||||
if procedure.routing_enabled?
|
if procedure.routing_enabled?
|
||||||
columns << ['Groupe instructeur', groupe_instructeur.label]
|
columns << ['Groupe instructeur', groupe_instructeur.label]
|
||||||
end
|
end
|
||||||
columns + self.class.champs_for_export(champs_public + champs_private, types_de_champ)
|
columns + self.class.champs_for_export(types_de_champ, champs_by_stable_id_with_row)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get all the champs values for the types de champ in the final list.
|
# Get all the champs values for the types de champ in the final list.
|
||||||
# Dossier might not have corresponding champ – display nil.
|
# Dossier might not have corresponding champ – display nil.
|
||||||
# To do so, we build a virtual champ when there is no value so we can call for_export with all indexes
|
# To do so, we build a virtual champ when there is no value so we can call for_export with all indexes
|
||||||
def self.champs_for_export(champs, types_de_champ)
|
def self.champs_for_export(types_de_champ, champs, row_id = nil)
|
||||||
types_de_champ.flat_map do |type_de_champ|
|
types_de_champ.flat_map do |type_de_champ|
|
||||||
champ = champs.find { |champ| champ.stable_id == type_de_champ.stable_id }
|
champ = champs[[row_id, type_de_champ.stable_id].compact]
|
||||||
|
|
||||||
exported_values = if champ.nil? || !champ.visible?
|
exported_values = if champ.nil? || !champ.visible?
|
||||||
# some champs export multiple columns
|
# some champs export multiple columns
|
||||||
|
@ -1299,7 +1300,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def linked_dossiers_for(instructeur_or_expert)
|
def linked_dossiers_for(instructeur_or_expert)
|
||||||
dossier_ids = champs_public.filter(&:dossier_link?).filter_map(&:value)
|
dossier_ids = champs_for_revision.filter(&:dossier_link?).filter_map(&:value)
|
||||||
instructeur_or_expert.dossiers.where(id: dossier_ids)
|
instructeur_or_expert.dossiers.where(id: dossier_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1308,7 +1309,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def geo_data?
|
def geo_data?
|
||||||
GeoArea.exists?(champ_id: champs_public.ids + champs_private.ids)
|
GeoArea.exists?(champ_id: champs_for_revision)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_feature_collection
|
def to_feature_collection
|
||||||
|
@ -1391,6 +1392,24 @@ class Dossier < ApplicationRecord
|
||||||
user.france_connect_information.present?
|
user.france_connect_information.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def champs_by_stable_id_with_row
|
||||||
|
champs_for_revision.index_by(&:stable_id_with_row)
|
||||||
|
end
|
||||||
|
|
||||||
|
def champs_for_revision(scope: nil, root: false)
|
||||||
|
champs_index = champs.group_by(&:stable_id)
|
||||||
|
|
||||||
|
if scope.is_a?(TypeDeChamp)
|
||||||
|
revision.children_of(scope)
|
||||||
|
else
|
||||||
|
revision.types_de_champ_for(scope:, root:)
|
||||||
|
end.flat_map { champs_index[_1.stable_id] || [] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_annotations?
|
||||||
|
revision.revision_types_de_champ_private.present?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_missing_traitemets
|
def create_missing_traitemets
|
||||||
|
@ -1412,7 +1431,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def geo_areas
|
def geo_areas
|
||||||
champs_public.flat_map(&:geo_areas) + champs_private.flat_map(&:geo_areas)
|
champs_for_revision.flat_map(&:geo_areas)
|
||||||
end
|
end
|
||||||
|
|
||||||
def bounding_box
|
def bounding_box
|
||||||
|
|
|
@ -118,9 +118,9 @@ class DossierPreloader
|
||||||
dossier.association(:champs_private_all).target += champs
|
dossier.association(:champs_private_all).target += champs
|
||||||
end
|
end
|
||||||
|
|
||||||
parent.association(name).target = champs.sort_by do |champ|
|
parent.association(name).target = champs
|
||||||
[champ.row_id, positions[dossier.revision_id][champ.type_de_champ_id]]
|
.filter { positions[dossier.revision_id][_1.type_de_champ_id].present? }
|
||||||
end
|
.sort_by { [_1.row_id, positions[dossier.revision_id][_1.type_de_champ_id]] }
|
||||||
|
|
||||||
# Load children champs
|
# Load children champs
|
||||||
champs.filter(&:block?).each do |parent_champ|
|
champs.filter(&:block?).each do |parent_champ|
|
||||||
|
|
|
@ -155,6 +155,22 @@ class ProcedureRevision < ApplicationRecord
|
||||||
dossier
|
dossier
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def types_de_champ_for(scope: nil, root: false)
|
||||||
|
# We return an unordered collection
|
||||||
|
return types_de_champ if !root && scope.nil?
|
||||||
|
return types_de_champ.filter { scope == :public ? _1.public? : _1.private? } if !root
|
||||||
|
|
||||||
|
# We return an ordered collection
|
||||||
|
case scope
|
||||||
|
when :public
|
||||||
|
types_de_champ_public
|
||||||
|
when :private
|
||||||
|
types_de_champ_private
|
||||||
|
else
|
||||||
|
types_de_champ_public + types_de_champ_private
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def children_of(tdc)
|
def children_of(tdc)
|
||||||
if revision_types_de_champ.loaded?
|
if revision_types_de_champ.loaded?
|
||||||
parent_coordinate_id = revision_types_de_champ
|
parent_coordinate_id = revision_types_de_champ
|
||||||
|
|
|
@ -357,6 +357,10 @@ class TypeDeChamp < ApplicationRecord
|
||||||
type_champ == TypeDeChamp.type_champs.fetch(:drop_down_list)
|
type_champ == TypeDeChamp.type_champs.fetch(:drop_down_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def multiple_drop_down_list?
|
||||||
|
type_champ == TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||||
|
end
|
||||||
|
|
||||||
def linked_drop_down_list?
|
def linked_drop_down_list?
|
||||||
type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,8 +36,21 @@ class ChampSerializer < ActiveModel::Serializer
|
||||||
object.etablissement&.entreprise
|
object.etablissement&.entreprise
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Row < Hashie::Dash
|
||||||
|
property :index
|
||||||
|
property :champs
|
||||||
|
|
||||||
|
def read_attribute_for_serialization(attribute)
|
||||||
|
self[attribute]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def rows
|
def rows
|
||||||
object.rows_for_export
|
object.dossier
|
||||||
|
.champs_for_revision(scope: object.type_de_champ)
|
||||||
|
.group_by(&:row_id)
|
||||||
|
.values
|
||||||
|
.map.with_index(1) { |champs, index| Row.new(index:, champs:) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def include_etablissement?
|
def include_etablissement?
|
||||||
|
|
|
@ -23,16 +23,6 @@ class ProcedureArchiveService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.procedure_files_size(procedure)
|
|
||||||
dossiers_files_size(procedure.dossiers)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.dossiers_files_size(dossiers)
|
|
||||||
dossiers.map do |dossier|
|
|
||||||
liste_pieces_justificatives_for_archive(dossier).sum(&:byte_size)
|
|
||||||
end.sum
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def zip_root_folder(archive)
|
def zip_root_folder(archive)
|
||||||
|
@ -43,19 +33,4 @@ class ProcedureArchiveService
|
||||||
archive.id
|
archive.id
|
||||||
].join("-")
|
].join("-")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.attachments_from_champs_piece_justificative(champs)
|
|
||||||
champs
|
|
||||||
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) }
|
|
||||||
.map(&:piece_justificative_file)
|
|
||||||
.filter(&:attached?)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.liste_pieces_justificatives_for_archive(dossier)
|
|
||||||
champs_blocs_repetables = dossier.champs_public
|
|
||||||
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) }
|
|
||||||
.flat_map(&:champs)
|
|
||||||
|
|
||||||
attachments_from_champs_piece_justificative(champs_blocs_repetables + dossier.champs_public)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,9 +90,7 @@ class ProcedureExportService
|
||||||
|
|
||||||
def etablissements
|
def etablissements
|
||||||
@etablissements ||= dossiers.flat_map do |dossier|
|
@etablissements ||= dossiers.flat_map do |dossier|
|
||||||
[dossier.champs_public, dossier.champs_private]
|
dossier.champs.filter { _1.is_a?(Champs::SiretChamp) }
|
||||||
.flatten
|
|
||||||
.filter { |champ| champ.is_a?(Champs::SiretChamp) }
|
|
||||||
end.filter_map(&:etablissement) + dossiers.filter_map(&:etablissement)
|
end.filter_map(&:etablissement) + dossiers.filter_map(&:etablissement)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -102,7 +100,7 @@ class ProcedureExportService
|
||||||
|
|
||||||
def champs_repetables_options
|
def champs_repetables_options
|
||||||
champs_by_stable_id = dossiers
|
champs_by_stable_id = dossiers
|
||||||
.flat_map { |dossier| (dossier.champs_public + dossier.champs_private).filter(&:repetition?) }
|
.flat_map { _1.champs.filter(&:repetition?) }
|
||||||
.group_by(&:stable_id)
|
.group_by(&:stable_id)
|
||||||
|
|
||||||
procedure
|
procedure
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
= tab_item('le dossier',
|
= tab_item('le dossier',
|
||||||
apercu_admin_procedure_path(@dossier.procedure, tab: 'dossier'),
|
apercu_admin_procedure_path(@dossier.procedure, tab: 'dossier'),
|
||||||
active: @tab == 'dossier')
|
active: @tab == 'dossier')
|
||||||
- if @dossier.champs_private.size > 0
|
- if @dossier.has_annotations?
|
||||||
= tab_item('les annotations privées',
|
= tab_item('les annotations privées',
|
||||||
apercu_admin_procedure_path(@dossier.procedure, tab: 'annotations-privees'),
|
apercu_admin_procedure_path(@dossier.procedure, tab: 'annotations-privees'),
|
||||||
active: @tab == 'annotations-privees')
|
active: @tab == 'annotations-privees')
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
- if @champs.present?
|
- if @row_id.present?
|
||||||
= fields_for @champ.input_name, @champ do |form|
|
= fields_for @champ.input_name, @champ do |form|
|
||||||
= turbo_stream.append dom_id(@champ, :rows), render(EditableChamp::RepetitionRowComponent.new(form: form, champ: @champ, row: @champs))
|
= turbo_stream.append dom_id(@champ, :rows), render(EditableChamp::RepetitionRowComponent.new(form: form, champ: @champ, row_id: @row_id))
|
||||||
- first_champ_id = @champs.map(&:focusable_input_id).compact.first
|
- if @first_champ_id
|
||||||
- if first_champ_id
|
= turbo_stream.focus(@first_champ_id)
|
||||||
= turbo_stream.focus(first_champ_id)
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ prawn_document(page_size: "A4") do |pdf|
|
||||||
add_title(pdf, 'Formulaire')
|
add_title(pdf, 'Formulaire')
|
||||||
add_champs(pdf, @dossier.champs_public)
|
add_champs(pdf, @dossier.champs_public)
|
||||||
|
|
||||||
if @acls[:include_infos_administration] && @dossier.champs_private.present?
|
if @acls[:include_infos_administration] && @dossier.has_annotations?
|
||||||
add_title(pdf, "Annotations privées")
|
add_title(pdf, "Annotations privées")
|
||||||
add_champs(pdf, @dossier.champs_private)
|
add_champs(pdf, @dossier.champs_private)
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
|
|
||||||
%h2 Formulaire
|
%h2 Formulaire
|
||||||
|
|
||||||
- champs = @dossier.champs_public
|
- types_de_champ_public = @dossier.revision.types_de_champ_public
|
||||||
- if champs.any? || @dossier.procedure.routing_enabled?
|
- if types_de_champ_public.any? || @dossier.procedure.routing_enabled?
|
||||||
= render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
|
= render partial: "shared/dossiers/champs", locals: { types_de_champ: types_de_champ_public, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
|
||||||
|
|
||||||
%h2 Annotations privées
|
%h2 Annotations privées
|
||||||
|
|
||||||
- champs_annotations_privees = @dossier.champs_private
|
- types_de_champ_private = @dossier.revision.types_de_champ_private
|
||||||
- if champs_annotations_privees.any?
|
- if types_de_champ_private.any?
|
||||||
= render partial: "shared/dossiers/champs", locals: { champs: champs_annotations_privees, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
|
= render partial: "shared/dossiers/champs", locals: { types_de_champ: types_de_champ_private, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
|
||||||
- else
|
- else
|
||||||
Aucune annotation privée
|
Aucune annotation privée
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
%form.form
|
%form.form
|
||||||
= form_for @dossier, url: '', html: { class: 'form' } do |f|
|
= form_for @dossier, url: '', html: { class: 'form' } do |f|
|
||||||
= render EditableChamp::SectionComponent.new(champs: @dossier.champs_public)
|
= render EditableChamp::SectionComponent.new(types_de_champ: @dossier.revision.types_de_champ_public, champs_by_stable_id_with_row: @dossier.champs_by_stable_id_with_row)
|
||||||
|
|
||||||
.editable-champ.editable-champ-text
|
.editable-champ.editable-champ-text
|
||||||
%label Mot de passe
|
%label Mot de passe
|
||||||
|
@ -331,7 +331,7 @@
|
||||||
%h1.fr-mt-4w Attachment::EditComponent
|
%h1.fr-mt-4w Attachment::EditComponent
|
||||||
%span.fr-hint-text Note: direct upload, suppression ne marchent pas comme attendu ici.
|
%span.fr-hint-text Note: direct upload, suppression ne marchent pas comme attendu ici.
|
||||||
|
|
||||||
- champ = @dossier.champs_public.find { _1.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) }
|
- champ = @dossier.champs.find { _1.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) }
|
||||||
- tdc = champ.type_de_champ
|
- tdc = champ.type_de_champ
|
||||||
- avis = Avis.new
|
- avis = Avis.new
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
= render ViewableChamp::SectionComponent.new(champs: champs, demande_seen_at: demande_seen_at, profile: profile)
|
= render ViewableChamp::SectionComponent.new(types_de_champ:, champs_by_stable_id_with_row: dossier.champs_by_stable_id_with_row, demande_seen_at:, profile:)
|
||||||
|
|
|
@ -51,6 +51,6 @@
|
||||||
%h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex
|
%h2.fr-h6.fr-background-alt--grey.fr-mb-0.flex
|
||||||
.flex-grow.fr-py-3v.fr-px-2w= t('views.shared.dossiers.demande.form')
|
.flex-grow.fr-py-3v.fr-px-2w= t('views.shared.dossiers.demande.form')
|
||||||
|
|
||||||
- champs = dossier.champs_public
|
- types_de_champ = dossier.revision.types_de_champ_public
|
||||||
- if champs.any? || dossier.procedure.routing_enabled?
|
- if types_de_champ.any? || dossier.procedure.routing_enabled?
|
||||||
= render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile }
|
= render partial: "shared/dossiers/champs", locals: { types_de_champ:, dossier:, demande_seen_at:, profile: }
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
= render Procedure::NoticeComponent.new(procedure: dossier.procedure)
|
= render Procedure::NoticeComponent.new(procedure: dossier.procedure)
|
||||||
|
|
||||||
= render EditableChamp::SectionComponent.new(champs: dossier_for_editing.champs_public)
|
= render EditableChamp::SectionComponent.new(types_de_champ: dossier_for_editing.revision.types_de_champ_public, champs_by_stable_id_with_row: dossier_for_editing.champs_by_stable_id_with_row)
|
||||||
|
|
||||||
= render Dossiers::PendingCorrectionCheckboxComponent.new(dossier: dossier)
|
= render Dossiers::PendingCorrectionCheckboxComponent.new(dossier: dossier)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
.container.dossier-edit
|
.container.dossier-edit
|
||||||
- if dossier.champs_private.present?
|
- if dossier.has_annotations?
|
||||||
%section.counter-start-header-section
|
%section.counter-start-header-section
|
||||||
= render NestedForms::FormOwnerComponent.new
|
= render NestedForms::FormOwnerComponent.new
|
||||||
= form_for dossier, url: annotations_instructeur_dossier_path(dossier.procedure, dossier), html: { class: 'form', multipart: true } do |f|
|
= form_for dossier, url: annotations_instructeur_dossier_path(dossier.procedure, dossier), html: { class: 'form', multipart: true } do |f|
|
||||||
= render EditableChamp::SectionComponent.new(champs: dossier.champs_private)
|
= render EditableChamp::SectionComponent.new(types_de_champ: dossier.revision.types_de_champ_private, champs_by_stable_id_with_row: dossier.champs_by_stable_id_with_row)
|
||||||
|
|
||||||
= render Dossiers::EditFooterComponent.new(dossier: dossier, annotation: true)
|
= render Dossiers::EditFooterComponent.new(dossier: dossier, annotation: true)
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
describe EditableChamp::SectionComponent, type: :component do
|
describe EditableChamp::SectionComponent, type: :component do
|
||||||
include TreeableConcern
|
include TreeableConcern
|
||||||
let(:component) { described_class.new(champs: champs) }
|
let(:types_de_champ) { champs.map(&:type_de_champ) }
|
||||||
|
let(:champs_by_stable_id_with_row) { champs.index_by(&:stable_id_with_row) }
|
||||||
|
let(:component) { described_class.new(types_de_champ:, champs_by_stable_id_with_row:) }
|
||||||
before { render_inline(component).to_html }
|
before { render_inline(component).to_html }
|
||||||
|
|
||||||
context 'list of champs without an header_section' do
|
context 'list of champs without an header_section' do
|
||||||
|
@ -98,6 +100,7 @@ describe EditableChamp::SectionComponent, type: :component do
|
||||||
end
|
end
|
||||||
let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) }
|
let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) }
|
||||||
let(:champs) { dossier.champs_public }
|
let(:champs) { dossier.champs_public }
|
||||||
|
let(:champs_by_stable_id_with_row) { dossier.champs_by_stable_id_with_row }
|
||||||
|
|
||||||
it 'render nested fieldsets, increase heading level for repetition header_section' do
|
it 'render nested fieldsets, increase heading level for repetition header_section' do
|
||||||
expect(page).to have_selector("fieldset")
|
expect(page).to have_selector("fieldset")
|
||||||
|
|
|
@ -280,8 +280,14 @@ FactoryBot.define do
|
||||||
after(:create) do |dossier, _evaluator|
|
after(:create) do |dossier, _evaluator|
|
||||||
dossier.champs_to_destroy.where(private: false).destroy_all
|
dossier.champs_to_destroy.where(private: false).destroy_all
|
||||||
dossier.types_de_champ.each do |type_de_champ|
|
dossier.types_de_champ.each do |type_de_champ|
|
||||||
|
if type_de_champ.simple_drop_down_list?
|
||||||
|
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first)
|
||||||
|
elsif type_de_champ.multiple_drop_down_list?
|
||||||
|
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json)
|
||||||
|
else
|
||||||
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:)
|
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -290,8 +296,14 @@ FactoryBot.define do
|
||||||
after(:create) do |dossier, _evaluator|
|
after(:create) do |dossier, _evaluator|
|
||||||
dossier.champs_to_destroy.where(private: true).destroy_all
|
dossier.champs_to_destroy.where(private: true).destroy_all
|
||||||
dossier.types_de_champ_private.each do |type_de_champ|
|
dossier.types_de_champ_private.each do |type_de_champ|
|
||||||
|
if type_de_champ.simple_drop_down_list?
|
||||||
|
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first)
|
||||||
|
elsif type_de_champ.multiple_drop_down_list?
|
||||||
|
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json)
|
||||||
|
else
|
||||||
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:)
|
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
dossier.reload
|
dossier.reload
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -300,9 +300,15 @@ def build_types_de_champ(types_de_champ, revision:, scope: :public, parent: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
if type.in?([:drop_down_list, :multiple_drop_down_list, :linked_drop_down_list])
|
if type.in?([:drop_down_list, :multiple_drop_down_list, :linked_drop_down_list])
|
||||||
|
if options.delete(:short).present?
|
||||||
|
type_de_champ_attributes[:drop_down_list_value] = "val1\r\nval2\r\n--separateur--\r\nval3"
|
||||||
|
elsif options.delete(:long).present?
|
||||||
|
type_de_champ_attributes[:drop_down_list_value] = "alpha\r\nbravo\r\n--separateur--\r\ncharly\r\ndelta\r\necho\r\nfox-trot\r\ngolf"
|
||||||
|
else
|
||||||
type_de_champ_attributes[:drop_down_list_value] = options.join("\r\n")
|
type_de_champ_attributes[:drop_down_list_value] = options.join("\r\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if type == :linked_drop_down_list
|
if type == :linked_drop_down_list
|
||||||
type_de_champ_attributes[:drop_down_secondary_libelle] = type_de_champ_attributes.delete(:secondary_libelle)
|
type_de_champ_attributes[:drop_down_secondary_libelle] = type_de_champ_attributes.delete(:secondary_libelle)
|
||||||
|
|
|
@ -25,8 +25,8 @@ describe Recovery::AlignChampWithDossierRevision do
|
||||||
expect(procedure.revisions.size).to eq(3)
|
expect(procedure.revisions.size).to eq(3)
|
||||||
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
||||||
expect(bad_dossier.champs.size).to eq(2)
|
expect(bad_dossier.champs.size).to eq(2)
|
||||||
expect(bad_dossier.champs_public.size).to eq(1)
|
expect(bad_dossier.champs_public.size).to eq(2)
|
||||||
expect { DossierPreloader.load_one(bad_dossier) }.to raise_error(ArgumentError)
|
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
|
||||||
|
|
||||||
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
||||||
fixer.run
|
fixer.run
|
||||||
|
@ -53,7 +53,7 @@ describe Recovery::AlignChampWithDossierRevision do
|
||||||
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
||||||
expect(bad_dossier.champs.size).to eq(2)
|
expect(bad_dossier.champs.size).to eq(2)
|
||||||
expect(bad_dossier.champs_public.size).to eq(2)
|
expect(bad_dossier.champs_public.size).to eq(2)
|
||||||
expect { DossierPreloader.load_one(bad_dossier) }.to raise_error(ArgumentError)
|
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
|
||||||
|
|
||||||
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
||||||
fixer.run(destroy_extra_champs: true)
|
fixer.run(destroy_extra_champs: true)
|
||||||
|
|
|
@ -26,11 +26,11 @@ describe 'Recovery::Revision::LifeCycle' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect { DossierPreloader.load_one(dossier) }.to raise_error(ArgumentError)
|
expect { DossierPreloader.load_one(dossier) }.not_to raise_error(ArgumentError)
|
||||||
expect(dossier.champs_public.size).to eq(1)
|
expect(dossier.champs_public.size).to eq(1)
|
||||||
expect(dossier.champs.size).to eq(2)
|
expect(dossier.champs.size).to eq(2)
|
||||||
importer.load
|
importer.load
|
||||||
expect { DossierPreloader.load_one(dossier) }.not_to raise_error
|
expect { DossierPreloader.load_one(dossier) }.not_to raise_error(ArgumentError)
|
||||||
expect(dossier.champs_public.size).to eq(2)
|
expect(dossier.champs_public.size).to eq(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,11 +83,6 @@ describe Champ do
|
||||||
expect(public_sections).not_to be_empty
|
expect(public_sections).not_to be_empty
|
||||||
expect(private_sections).not_to be_empty
|
expect(private_sections).not_to be_empty
|
||||||
expect(sections_in_repetition).not_to be_empty
|
expect(sections_in_repetition).not_to be_empty
|
||||||
|
|
||||||
expect(public_champ.sections).to eq(public_sections)
|
|
||||||
expect(private_champ.sections).to eq(private_sections)
|
|
||||||
expect(champ_in_repetition.sections).to eq(sections_in_repetition)
|
|
||||||
expect(standalone_champ.sections).to eq([])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
describe Champs::HeaderSectionChamp do
|
|
||||||
describe '#section_index' do
|
|
||||||
let(:types_de_champ) do
|
|
||||||
[
|
|
||||||
{ type: :header_section },
|
|
||||||
{ type: :civilite },
|
|
||||||
{ type: :text },
|
|
||||||
{ type: :header_section },
|
|
||||||
{ type: :email }
|
|
||||||
]
|
|
||||||
end
|
|
||||||
let(:types_de_champ_public) { types_de_champ }
|
|
||||||
let(:procedure) { create(:procedure, types_de_champ_public: types_de_champ_public) }
|
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
|
||||||
|
|
||||||
context 'for root-level champs' do
|
|
||||||
let(:first_header) { dossier.champs_public.first }
|
|
||||||
let(:second_header) { dossier.champs_public.fourth }
|
|
||||||
|
|
||||||
it 'returns the index of the section (starting from 1)' do
|
|
||||||
expect(first_header.section_index).to eq 1
|
|
||||||
expect(second_header.section_index).to eq 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'for repetition champs' do
|
|
||||||
let(:types_de_champ_public) { [{ type: :repetition, mandatory: true, children: types_de_champ }] }
|
|
||||||
|
|
||||||
let(:first_header) { dossier.champs_public.first.champs.first }
|
|
||||||
let(:second_header) { dossier.champs_public.first.champs.fourth }
|
|
||||||
|
|
||||||
it 'returns the index of the section in the repetition (starting from 1)' do
|
|
||||||
expect(first_header.section_index).to eq 1
|
|
||||||
expect(second_header.section_index).to eq 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,20 +1,23 @@
|
||||||
RSpec.describe DossierCloneConcern do
|
RSpec.describe DossierCloneConcern do
|
||||||
let(:procedure) do
|
let(:procedure) do
|
||||||
create(:procedure, types_de_champ_public: [
|
create(:procedure, types_de_champ_public:, types_de_champ_private:).tap(&:publish!)
|
||||||
|
end
|
||||||
|
let(:types_de_champ_public) do
|
||||||
|
[
|
||||||
{ type: :text, libelle: "Un champ text", stable_id: 99 },
|
{ type: :text, libelle: "Un champ text", stable_id: 99 },
|
||||||
{ type: :text, libelle: "Un autre champ text", stable_id: 991 },
|
{ type: :text, libelle: "Un autre champ text", stable_id: 991 },
|
||||||
{ type: :yes_no, libelle: "Un champ yes no", stable_id: 992 },
|
{ type: :yes_no, libelle: "Un champ yes no", stable_id: 992 },
|
||||||
{ type: :repetition, libelle: "Un champ répétable", stable_id: 993, mandatory: true, children: [{ type: :text, libelle: 'Nom', stable_id: 994 }] }
|
{ type: :repetition, libelle: "Un champ répétable", stable_id: 993, mandatory: true, children: [{ type: :text, libelle: 'Nom', stable_id: 994 }] }
|
||||||
])
|
]
|
||||||
end
|
end
|
||||||
|
let(:types_de_champ_private) { [] }
|
||||||
let(:dossier) { create(:dossier, :en_construction, procedure:) }
|
let(:dossier) { create(:dossier, :en_construction, procedure:) }
|
||||||
let(:forked_dossier) { dossier.find_or_create_editing_fork(dossier.user) }
|
let(:forked_dossier) { dossier.find_or_create_editing_fork(dossier.user) }
|
||||||
|
|
||||||
before { procedure.publish! }
|
|
||||||
|
|
||||||
describe '#clone' do
|
describe '#clone' do
|
||||||
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) }
|
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
let(:types_de_champ_public) { [{}] }
|
||||||
|
let(:types_de_champ_private) { [{}] }
|
||||||
let(:fork) { false }
|
let(:fork) { false }
|
||||||
let(:new_dossier) { dossier.clone(fork:) }
|
let(:new_dossier) { dossier.clone(fork:) }
|
||||||
|
|
||||||
|
@ -137,9 +140,9 @@ RSpec.describe DossierCloneConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do
|
context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :piece_justificative }] }
|
||||||
let(:champ_piece_justificative) { create(:champ_piece_justificative, dossier_id: dossier.id) }
|
let(:champ_piece_justificative) { dossier.champs_public.first }
|
||||||
before { dossier.champs_public << champ_piece_justificative }
|
|
||||||
it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) }
|
it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -181,8 +184,8 @@ RSpec.describe DossierCloneConcern do
|
||||||
it { expect(new_dossier.champs_public[0].updated_at).to eq(dossier.champs_public[0].updated_at) }
|
it { expect(new_dossier.champs_public[0].updated_at).to eq(dossier.champs_public[0].updated_at) }
|
||||||
|
|
||||||
context "piece justificative champ" do
|
context "piece justificative champ" do
|
||||||
let(:champ_pj) { create(:champ_piece_justificative, dossier_id: dossier.id) }
|
let(:types_de_champ_public) { [{ type: :piece_justificative }] }
|
||||||
before { dossier.champs_public << champ_pj.reload }
|
let(:champ_pj) { dossier.champs_public.first }
|
||||||
|
|
||||||
it {
|
it {
|
||||||
champ_pj_fork = Champs::PieceJustificativeChamp.where(dossier: new_dossier).first
|
champ_pj_fork = Champs::PieceJustificativeChamp.where(dossier: new_dossier).first
|
||||||
|
|
|
@ -577,7 +577,7 @@ describe DossierRebaseConcern do
|
||||||
end
|
end
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure) }
|
let!(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
|
||||||
def champ_libelles = dossier.champs_public.map(&:libelle)
|
def champ_libelles = dossier.revision.types_de_champ_public.map(&:libelle)
|
||||||
|
|
||||||
context 'when a tdc is added in the middle' do
|
context 'when a tdc is added in the middle' do
|
||||||
before do
|
before do
|
||||||
|
@ -639,7 +639,7 @@ describe DossierRebaseConcern do
|
||||||
tdc_to_update.update(type_champ: :integer_number)
|
tdc_to_update.update(type_champ: :integer_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect { subject }.to change { dossier.champs_public.map(&:type_champ) }.from(['text', 'text']).to(['integer_number', 'text']) }
|
it { expect { subject }.to change { dossier.revision.types_de_champ_public.map(&:type_champ) }.from(['text', 'text']).to(['integer_number', 'text']) }
|
||||||
it { expect { subject }.to change { first_champ.class }.from(Champs::TextChamp).to(Champs::IntegerNumberChamp) }
|
it { expect { subject }.to change { first_champ.class }.from(Champs::TextChamp).to(Champs::IntegerNumberChamp) }
|
||||||
it { expect { subject }.to change { first_champ.value }.from('v1').to(nil) }
|
it { expect { subject }.to change { first_champ.value }.from('v1').to(nil) }
|
||||||
it { expect { subject }.to change { first_champ.external_id }.from('123').to(nil) }
|
it { expect { subject }.to change { first_champ.external_id }.from('123').to(nil) }
|
||||||
|
@ -667,7 +667,8 @@ describe DossierRebaseConcern do
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure) }
|
let!(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
let(:repetition) { procedure.draft_revision.types_de_champ.find(&:repetition?) }
|
let(:repetition) { procedure.draft_revision.types_de_champ.find(&:repetition?) }
|
||||||
|
|
||||||
def child_libelles = dossier.champs_public.first.champs.map(&:libelle)
|
def child_libelles = dossier.revision.revision_types_de_champ_public.first.revision_types_de_champ.map(&:libelle)
|
||||||
|
def child_types_champ = dossier.revision.revision_types_de_champ_public.first.revision_types_de_champ.map(&:type_champ)
|
||||||
|
|
||||||
context 'when a child tdc is added in the middle' do
|
context 'when a child tdc is added in the middle' do
|
||||||
before do
|
before do
|
||||||
|
@ -708,7 +709,7 @@ describe DossierRebaseConcern do
|
||||||
tdc_to_update.update(type_champ: :integer_number)
|
tdc_to_update.update(type_champ: :integer_number)
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect { subject }.to change { dossier.champs_public.first.champs.map(&:type_champ) }.from(['text', 'text']).to(['integer_number', 'text']) }
|
it { expect { subject }.to change { child_types_champ }.from(['text', 'text']).to(['integer_number', 'text']) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the parents type is changed' do
|
context 'when the parents type is changed' do
|
||||||
|
|
|
@ -3,35 +3,35 @@ describe TreeableConcern do
|
||||||
include TreeableConcern
|
include TreeableConcern
|
||||||
|
|
||||||
attr_reader :root
|
attr_reader :root
|
||||||
def initialize(champs:)
|
def initialize(types_de_champ:)
|
||||||
@root = to_tree(champs:)
|
@root = to_tree(types_de_champ:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subject { ChampsToTree.new(champs: champs).root }
|
subject { ChampsToTree.new(types_de_champ:).root }
|
||||||
describe "to_tree" do
|
describe "to_tree" do
|
||||||
let(:header_1) { build(:champ_header_section_level_1) }
|
let(:header_1) { build(:champ_header_section_level_1).type_de_champ }
|
||||||
let(:header_1_2) { build(:champ_header_section_level_2) }
|
let(:header_1_2) { build(:champ_header_section_level_2).type_de_champ }
|
||||||
let(:header_2) { build(:champ_header_section_level_1) }
|
let(:header_2) { build(:champ_header_section_level_1).type_de_champ }
|
||||||
let(:champ_text) { build(:champ_text) }
|
let(:champ_text) { build(:champ_text).type_de_champ }
|
||||||
let(:champ_textarea) { build(:champ_textarea) }
|
let(:champ_textarea) { build(:champ_textarea).type_de_champ }
|
||||||
let(:champ_explication) { build(:champ_explication) }
|
let(:champ_explication) { build(:champ_explication).type_de_champ }
|
||||||
let(:champ_communes) { build(:champ_communes) }
|
let(:champ_communes) { build(:champ_communes).type_de_champ }
|
||||||
|
|
||||||
context 'without section' do
|
context 'without section' do
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
champ_text, champ_textarea
|
champ_text, champ_textarea
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
it 'inlines champs at root level' do
|
it 'inlines champs at root level' do
|
||||||
expect(subject.size).to eq(champs.size)
|
expect(subject.size).to eq(types_de_champ.size)
|
||||||
expect(subject).to eq(champs)
|
expect(subject).to eq(types_de_champ)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with header_section and champs' do
|
context 'with header_section and champs' do
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
header_1,
|
header_1,
|
||||||
champ_explication,
|
champ_explication,
|
||||||
|
@ -51,7 +51,7 @@ describe TreeableConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'leading champs, and in between sections only' do
|
context 'leading champs, and in between sections only' do
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
champ_text,
|
champ_text,
|
||||||
champ_textarea,
|
champ_textarea,
|
||||||
|
@ -74,7 +74,7 @@ describe TreeableConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with one sub sections' do
|
context 'with one sub sections' do
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
header_1,
|
header_1,
|
||||||
champ_explication,
|
champ_explication,
|
||||||
|
@ -94,11 +94,11 @@ describe TreeableConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with consecutive subsection' do
|
context 'with consecutive subsection' do
|
||||||
let(:header_1) { build(:champ_header_section_level_1) }
|
let(:header_1) { build(:champ_header_section_level_1).type_de_champ }
|
||||||
let(:header_1_2_1) { build(:champ_header_section_level_2) }
|
let(:header_1_2_1) { build(:champ_header_section_level_2).type_de_champ }
|
||||||
let(:header_1_2_2) { build(:champ_header_section_level_2) }
|
let(:header_1_2_2) { build(:champ_header_section_level_2).type_de_champ }
|
||||||
let(:header_1_2_3) { build(:champ_header_section_level_2) }
|
let(:header_1_2_3) { build(:champ_header_section_level_2).type_de_champ }
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
header_1,
|
header_1,
|
||||||
header_1_2_1,
|
header_1_2_1,
|
||||||
|
@ -123,9 +123,9 @@ describe TreeableConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with one sub sections and one subsub section' do
|
context 'with one sub sections and one subsub section' do
|
||||||
let(:header_1_2_3) { build(:champ_header_section_level_3) }
|
let(:header_1_2_3) { build(:champ_header_section_level_3).type_de_champ }
|
||||||
|
|
||||||
let(:champs) do
|
let(:types_de_champ) do
|
||||||
[
|
[
|
||||||
header_1,
|
header_1,
|
||||||
champ_explication,
|
champ_explication,
|
||||||
|
|
|
@ -357,26 +357,6 @@ describe Dossier, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#champs' do
|
|
||||||
let(:procedure) { create(:procedure) }
|
|
||||||
let!(:tdc_1) { create(:type_de_champ, libelle: 'l1', position: 1, procedure: procedure) }
|
|
||||||
let!(:tdc_3) { create(:type_de_champ, libelle: 'l3', position: 3, procedure: procedure) }
|
|
||||||
let!(:tdc_2) { create(:type_de_champ, libelle: 'l2', position: 2, procedure: procedure) }
|
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
|
||||||
|
|
||||||
it { expect(dossier.champs_public.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#champs_private' do
|
|
||||||
let(:procedure) { create(:procedure) }
|
|
||||||
let!(:tdc_1) { create(:type_de_champ, :private, libelle: 'l1', position: 1, procedure: procedure) }
|
|
||||||
let!(:tdc_3) { create(:type_de_champ, :private, libelle: 'l3', position: 3, procedure: procedure) }
|
|
||||||
let!(:tdc_2) { create(:type_de_champ, :private, libelle: 'l2', position: 2, procedure: procedure) }
|
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
|
||||||
|
|
||||||
it { expect(dossier.champs_private.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#text_summary" do
|
describe "#text_summary" do
|
||||||
let(:service) { create(:service, nom: 'nom du service') }
|
let(:service) { create(:service, nom: 'nom du service') }
|
||||||
let(:procedure) { create(:procedure, libelle: "Démarche", organisation: "Organisme", service: service) }
|
let(:procedure) { create(:procedure, libelle: "Démarche", organisation: "Organisme", service: service) }
|
||||||
|
@ -1540,10 +1520,10 @@ describe Dossier, type: :model do
|
||||||
|
|
||||||
context "with mandatory SIRET champ" do
|
context "with mandatory SIRET champ" do
|
||||||
let(:type_de_champ) { { type: :siret, mandatory: true } }
|
let(:type_de_champ) { { type: :siret, mandatory: true } }
|
||||||
let(:champ_siret) { dossier.champs_public.first }
|
let(:champ_siret) { dossier.champs.first }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
champ_siret.value = '44011762001530'
|
champ_siret.update(value: '44011762001530')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not have errors' do
|
it 'should not have errors' do
|
||||||
|
@ -1776,6 +1756,7 @@ describe Dossier, type: :model do
|
||||||
|
|
||||||
it "should solve N+1 problem" do
|
it "should solve N+1 problem" do
|
||||||
dossier.champs_public << create_list(:champ_carte, 3, type_de_champ: type_de_champ_carte, geo_areas: [create(:geo_area)])
|
dossier.champs_public << create_list(:champ_carte, 3, type_de_champ: type_de_champ_carte, geo_areas: [create(:geo_area)])
|
||||||
|
dossier.champs_for_revision
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
@ -1928,9 +1909,9 @@ describe Dossier, type: :model do
|
||||||
let(:repetition_second_revision_champ) { dossier_second_revision.champs_public.find(&:repetition?) }
|
let(:repetition_second_revision_champ) { dossier_second_revision.champs_public.find(&:repetition?) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
let(:dossier_second_revision) { create(:dossier, procedure: procedure) }
|
let(:dossier_second_revision) { create(:dossier, procedure: procedure) }
|
||||||
let(:dossier_champs_for_export) { Dossier.champs_for_export(dossier.champs_public, procedure.types_de_champ_for_procedure_presentation.not_repetition) }
|
let(:dossier_champs_for_export) { Dossier.champs_for_export(procedure.types_de_champ_for_procedure_presentation.not_repetition, dossier.champs_by_stable_id_with_row) }
|
||||||
let(:dossier_second_revision_champs_for_export) { Dossier.champs_for_export(dossier_second_revision.champs_public, procedure.types_de_champ_for_procedure_presentation.not_repetition) }
|
let(:dossier_second_revision_champs_for_export) { Dossier.champs_for_export(procedure.types_de_champ_for_procedure_presentation.not_repetition, dossier_second_revision.champs_by_stable_id_with_row) }
|
||||||
let(:repetition_second_revision_champs_for_export) { Dossier.champs_for_export(repetition_second_revision_champ.champs, procedure.types_de_champ_for_procedure_presentation.repetition) }
|
let(:repetition_second_revision_champs_for_export) { Dossier.champs_for_export(procedure.types_de_champ_for_procedure_presentation.repetition, dossier.champs_by_stable_id_with_row) }
|
||||||
|
|
||||||
context "when procedure published" do
|
context "when procedure published" do
|
||||||
before do
|
before do
|
||||||
|
@ -1968,7 +1949,7 @@ describe Dossier, type: :model do
|
||||||
repetition = proc_test.types_de_champ_for_procedure_presentation.repetition.first
|
repetition = proc_test.types_de_champ_for_procedure_presentation.repetition.first
|
||||||
type_champs = proc_test.types_de_champ_for_procedure_presentation(repetition).to_a
|
type_champs = proc_test.types_de_champ_for_procedure_presentation(repetition).to_a
|
||||||
expect(type_champs.size).to eq(1)
|
expect(type_champs.size).to eq(1)
|
||||||
expect(Dossier.champs_for_export(dossier.champs_public, type_champs).size).to eq(3)
|
expect(Dossier.champs_for_export(type_champs, dossier.champs_by_stable_id_with_row).size).to eq(3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1991,7 +1972,7 @@ describe Dossier, type: :model do
|
||||||
let(:text_tdc) { procedure.active_revision.types_de_champ_public.second }
|
let(:text_tdc) { procedure.active_revision.types_de_champ_public.second }
|
||||||
let(:tdcs) { dossier.champs_public.map(&:type_de_champ) }
|
let(:tdcs) { dossier.champs_public.map(&:type_de_champ) }
|
||||||
|
|
||||||
subject { Dossier.champs_for_export(dossier.champs_public, tdcs) }
|
subject { Dossier.champs_for_export(tdcs, dossier.champs_by_stable_id_with_row) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
text_tdc.update(condition: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true)))
|
text_tdc.update(condition: ds_eq(champ_value(yes_no_tdc.stable_id), constant(true)))
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
RSpec.describe TypesDeChamp::PrefillRepetitionTypeDeChamp, type: :model do
|
RSpec.describe TypesDeChamp::PrefillRepetitionTypeDeChamp, type: :model do
|
||||||
let(:procedure) { create(:procedure) }
|
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{}, { type: :integer_number }, { type: :regions }] }]) }
|
||||||
let(:type_de_champ) { build(:type_de_champ_repetition, :with_types_de_champ, :with_region_types_de_champ, procedure: procedure) }
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
let(:champ) { create(:champ_repetition, type_de_champ: type_de_champ) }
|
let(:type_de_champ) { champ.type_de_champ }
|
||||||
|
let(:champ) { dossier.champs.first }
|
||||||
let(:prefillable_subchamps) { TypesDeChamp::PrefillRepetitionTypeDeChamp.new(type_de_champ, procedure.active_revision).send(:prefillable_subchamps) }
|
let(:prefillable_subchamps) { TypesDeChamp::PrefillRepetitionTypeDeChamp.new(type_de_champ, procedure.active_revision).send(:prefillable_subchamps) }
|
||||||
let(:text_repetition) { prefillable_subchamps.first }
|
let(:text_repetition) { prefillable_subchamps.first }
|
||||||
let(:integer_repetition) { prefillable_subchamps.second }
|
let(:integer_repetition) { prefillable_subchamps.second }
|
||||||
|
|
|
@ -2,6 +2,9 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
let(:instructeur) { create(:instructeur) }
|
let(:instructeur) { create(:instructeur) }
|
||||||
let(:demande_seen_at) { nil }
|
let(:demande_seen_at) { nil }
|
||||||
let(:profile) { "instructeur" }
|
let(:profile) { "instructeur" }
|
||||||
|
let(:procedure) { create(:procedure, types_de_champ_public:) }
|
||||||
|
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
|
||||||
|
let(:types_de_champ) { dossier.revision.types_de_champ_public }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
view.extend DossierHelper
|
view.extend DossierHelper
|
||||||
|
@ -12,17 +15,23 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subject { render 'shared/dossiers/champs', champs:, dossier:, demande_seen_at:, profile: }
|
subject { render 'shared/dossiers/champs', types_de_champ:, dossier:, demande_seen_at:, profile: }
|
||||||
|
|
||||||
context "there are some champs" do
|
context "there are some champs" do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :checkbox }, { type: :header_section }, { type: :explication }, { type: :dossier_link }, { type: :textarea }, { type: :rna }] }
|
||||||
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: 'true') }
|
let(:champ1) { dossier.champs[0] }
|
||||||
let(:champ2) { create(:champ_header_section, dossier: dossier, value: "Section") }
|
let(:champ2) { dossier.champs[1] }
|
||||||
let(:champ3) { create(:champ_explication, dossier: dossier, value: "mazette") }
|
let(:champ3) { dossier.champs[2] }
|
||||||
let(:champ4) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
|
let(:champ4) { dossier.champs[3] }
|
||||||
let(:champ5) { create(:champ_textarea, dossier: dossier, value: "Some long text in a textarea.") }
|
let(:champ5) { dossier.champs[4] }
|
||||||
let(:champ6) { create(:champ_rna, value: "W173847273") }
|
let(:champ6) { dossier.champs[5] }
|
||||||
let(:champs) { [champ1, champ2, champ3, champ4, champ5, champ6] }
|
|
||||||
|
before do
|
||||||
|
champ1.update(value: 'true')
|
||||||
|
champ4.update(value: dossier.id)
|
||||||
|
champ5.update(value: "Some long text in a textarea.")
|
||||||
|
champ6.update(value: "W173847273")
|
||||||
|
end
|
||||||
|
|
||||||
it "renders titles and values of champs" do
|
it "renders titles and values of champs" do
|
||||||
expect(subject).to include(champ1.libelle)
|
expect(subject).to include(champ1.libelle)
|
||||||
|
@ -41,12 +50,19 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
|
|
||||||
it "doesn't render explication champs" do
|
it "doesn't render explication champs" do
|
||||||
expect(subject).not_to include(champ3.libelle)
|
expect(subject).not_to include(champ3.libelle)
|
||||||
expect(subject).not_to include(champ3.value)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with auto-link" do
|
context "with auto-link" do
|
||||||
let(:champ1) { create(:champ_text, value: "https://github.com/tchak") }
|
let(:types_de_champ_public) { [{ type: :text }, { type: :textarea }] }
|
||||||
let(:champ2) { create(:champ_textarea, value: "https://github.com/LeSim") }
|
let(:champ1) { dossier.champs[0] }
|
||||||
|
let(:champ2) { dossier.champs[1] }
|
||||||
|
|
||||||
|
before do
|
||||||
|
champ1.update(value: 'https://github.com/tchak')
|
||||||
|
champ2.update(value: "https://github.com/LeSim")
|
||||||
|
end
|
||||||
|
|
||||||
let(:link1) { '<a href="https://github.com/tchak" target="_blank" rel="noopener">https://github.com/tchak</a>' }
|
let(:link1) { '<a href="https://github.com/tchak" target="_blank" rel="noopener">https://github.com/tchak</a>' }
|
||||||
let(:link2) { '<a href="https://github.com/LeSim" target="_blank" rel="noopener">https://github.com/LeSim</a>' }
|
let(:link2) { '<a href="https://github.com/LeSim" target="_blank" rel="noopener">https://github.com/LeSim</a>' }
|
||||||
|
|
||||||
|
@ -55,12 +71,13 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
expect(subject).to include(link2)
|
expect(subject).to include(link2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context "with a dossier champ, but we are not authorized to acces the dossier" do
|
context "with a dossier champ, but we are not authorized to acces the dossier" do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :dossier_link }] }
|
||||||
let(:champ) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
|
|
||||||
let(:champs) { [champ] }
|
before do
|
||||||
|
dossier.champs.first.update(value: dossier.id)
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.not_to have_link("Dossier nº #{dossier.id}") }
|
it { is_expected.not_to have_link("Dossier nº #{dossier.id}") }
|
||||||
it { is_expected.to include("Dossier nº #{dossier.id}") }
|
it { is_expected.to include("Dossier nº #{dossier.id}") }
|
||||||
|
@ -68,9 +85,11 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a dossier_link champ but without value" do
|
context "with a dossier_link champ but without value" do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :dossier_link }] }
|
||||||
let(:champ) { create(:champ_dossier_link, dossier: dossier, value: nil) }
|
|
||||||
let(:champs) { [champ] }
|
before do
|
||||||
|
dossier.champs.first.update(value: nil)
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.not_to include("non saisi") }
|
it { is_expected.not_to include("non saisi") }
|
||||||
|
|
||||||
|
@ -81,9 +100,11 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a piece justificative without value" do
|
context "with a piece justificative without value" do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :piece_justificative }] }
|
||||||
let(:champ) { create(:champ_without_piece_justificative, dossier:) }
|
|
||||||
let(:champs) { [champ] }
|
before do
|
||||||
|
dossier.champs.first.piece_justificative_file.purge
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.not_to include("pièce justificative non saisie") }
|
it { is_expected.not_to include("pièce justificative non saisie") }
|
||||||
|
|
||||||
|
@ -94,9 +115,9 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with seen_at" do
|
context "with seen_at" do
|
||||||
let(:dossier) { create(:dossier, :en_construction, depose_at: 1.day.ago) }
|
let(:types_de_champ_public) { [{ type: :checkbox }] }
|
||||||
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: 'true') }
|
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:, depose_at: 1.day.ago) }
|
||||||
let(:champs) { [champ1] }
|
let(:champ1) { dossier.champs[0] }
|
||||||
|
|
||||||
context "with a demande_seen_at after champ updated_at" do
|
context "with a demande_seen_at after champ updated_at" do
|
||||||
let(:demande_seen_at) { champ1.updated_at + 1.hour }
|
let(:demande_seen_at) { champ1.updated_at + 1.hour }
|
||||||
|
@ -105,9 +126,13 @@ describe 'shared/dossiers/champs', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with champ updated_at at depose_at" do
|
context "with champ updated_at at depose_at" do
|
||||||
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: 'true', updated_at: dossier.depose_at) }
|
let(:champ1) { dossier.champs[0] }
|
||||||
let(:demande_seen_at) { champ1.updated_at - 1.hour }
|
let(:demande_seen_at) { champ1.updated_at - 1.hour }
|
||||||
|
|
||||||
|
before do
|
||||||
|
champ1.update(value: 'false', updated_at: dossier.depose_at)
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.not_to have_css(".fr-badge--new") }
|
it { is_expected.not_to have_css(".fr-badge--new") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,29 +6,34 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
|
|
||||||
subject { render 'shared/dossiers/edit', dossier: dossier, apercu: false }
|
subject { render 'shared/dossiers/edit', dossier: dossier, apercu: false }
|
||||||
|
|
||||||
context 'when there are some champs' do
|
let(:procedure) { create(:procedure, types_de_champ_public:) }
|
||||||
let(:dossier) { create(:dossier) }
|
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
|
||||||
let(:champ_checkbox) { create(:champ_checkbox, dossier: dossier, value: 'true') }
|
|
||||||
let(:champ_header_section) { create(:champ_header_section, dossier: dossier, value: 'Section') }
|
|
||||||
let(:champ_explication) { create(:champ_explication, dossier: dossier, value: 'mazette') }
|
|
||||||
let(:champ_dossier_link) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
|
|
||||||
let(:champ_textarea) { create(:champ_textarea, dossier: dossier, value: 'Some long text in a textarea.') }
|
|
||||||
let(:champs) { [champ_checkbox, champ_header_section, champ_explication, champ_dossier_link, champ_textarea] }
|
|
||||||
|
|
||||||
before { dossier.champs_public << champs }
|
context 'when there are some champs' do
|
||||||
|
let(:champs_by_stable_id_with_row) { dossier.champs_by_stable_id_with_row }
|
||||||
|
|
||||||
|
let(:type_de_champ_header_section) { procedure.draft_types_de_champ_public.find(&:header_section?) }
|
||||||
|
let(:type_de_champ_explication) { procedure.draft_types_de_champ_public.find(&:explication?) }
|
||||||
|
let(:type_de_champ_dossier_link) { procedure.draft_types_de_champ_public.find(&:dossier_link?) }
|
||||||
|
let(:type_de_champ_checkbox) { procedure.draft_types_de_champ_public.find(&:checkbox?) }
|
||||||
|
let(:type_de_champ_textarea) { procedure.draft_types_de_champ_public.find(&:textarea?) }
|
||||||
|
|
||||||
|
let(:champ_checkbox) { champs_by_stable_id_with_row[[type_de_champ_checkbox.stable_id]] }
|
||||||
|
let(:champ_dossier_link) { champs_by_stable_id_with_row[[type_de_champ_dossier_link.stable_id]] }
|
||||||
|
let(:champ_textarea) { champs_by_stable_id_with_row[[type_de_champ_textarea.stable_id]] }
|
||||||
|
|
||||||
|
let(:types_de_champ_public) { [{ type: :checkbox }, { type: :header_section }, { type: :explication }, { type: :dossier_link }, { type: :textarea }] }
|
||||||
|
|
||||||
it 'renders labels and editable values of champs' do
|
it 'renders labels and editable values of champs' do
|
||||||
expect(subject).to have_field(champ_checkbox.libelle, checked: true)
|
expect(subject).to have_field(champ_checkbox.libelle, checked: true)
|
||||||
expect(subject).to have_css(".header-section", text: champ_header_section.libelle)
|
expect(subject).to have_css(".header-section", text: type_de_champ_header_section.libelle)
|
||||||
expect(subject).to have_text(champ_explication.libelle)
|
expect(subject).to have_text(type_de_champ_explication.libelle)
|
||||||
expect(subject).to have_field(champ_dossier_link.libelle, with: champ_dossier_link.value)
|
expect(subject).to have_field(type_de_champ_dossier_link.libelle, with: champ_dossier_link.value)
|
||||||
expect(subject).to have_field(champ_textarea.libelle, with: champ_textarea.value)
|
expect(subject).to have_field(champ_textarea.libelle, with: champ_textarea.value)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with standard champs" do
|
context "with standard champs" do
|
||||||
let(:champ_email) { create(:champ_email, dossier: dossier) }
|
let(:types_de_champ_public) { [{ type: :email }, { type: :phone }] }
|
||||||
let(:champ_phone) { create(:champ_phone, dossier: dossier) }
|
|
||||||
let(:champs) { [champ_email, champ_phone] }
|
|
||||||
|
|
||||||
it "does not render basic placeholders" do
|
it "does not render basic placeholders" do
|
||||||
expect(subject).not_to have_css('input[type="email"][placeholder$="exemple.fr"]')
|
expect(subject).not_to have_css('input[type="email"][placeholder$="exemple.fr"]')
|
||||||
|
@ -38,17 +43,18 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a single-value list' do
|
context 'with a single-value list' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :drop_down_list, options:, mandatory: }] }
|
||||||
let(:type_de_champ) { create(:type_de_champ_drop_down_list, mandatory: mandatory, procedure: dossier.procedure) }
|
let(:champ) { dossier.champs_public.first }
|
||||||
let(:champ) { create(:champ_drop_down_list, dossier: dossier, type_de_champ: type_de_champ, value: value) }
|
let(:type_de_champ) { champ.type_de_champ }
|
||||||
let(:enabled_options) { type_de_champ.drop_down_list_enabled_non_empty_options }
|
let(:enabled_options) { type_de_champ.drop_down_list_enabled_non_empty_options }
|
||||||
let(:mandatory) { true }
|
let(:mandatory) { true }
|
||||||
|
let(:options) { nil }
|
||||||
before { dossier.champs_public << champ }
|
|
||||||
|
|
||||||
context 'when the list is short' do
|
context 'when the list is short' do
|
||||||
let(:value) { 'val1' }
|
let(:value) { 'val1' }
|
||||||
|
|
||||||
|
before { champ.update(value:) }
|
||||||
|
|
||||||
it 'renders the list as radio buttons' do
|
it 'renders the list as radio buttons' do
|
||||||
expect(subject).to have_selector('input[type=radio]', count: enabled_options.count)
|
expect(subject).to have_selector('input[type=radio]', count: enabled_options.count)
|
||||||
end
|
end
|
||||||
|
@ -65,7 +71,9 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
|
|
||||||
context 'when the list is long' do
|
context 'when the list is long' do
|
||||||
let(:value) { 'alpha' }
|
let(:value) { 'alpha' }
|
||||||
let(:type_de_champ) { create(:type_de_champ_drop_down_list, :long, procedure: dossier.procedure) }
|
let(:options) { [:long] }
|
||||||
|
|
||||||
|
before { champ.update(value:) }
|
||||||
|
|
||||||
it 'renders the list as a dropdown' do
|
it 'renders the list as a dropdown' do
|
||||||
expect(subject).to have_select(type_de_champ.libelle, options: enabled_options + [''])
|
expect(subject).to have_select(type_de_champ.libelle, options: enabled_options + [''])
|
||||||
|
@ -74,21 +82,18 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a multiple-values list' do
|
context 'with a multiple-values list' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :multiple_drop_down_list, options: }] }
|
||||||
let(:type_de_champ) { create(:type_de_champ_multiple_drop_down_list, procedure: dossier.procedure, drop_down_list_value: drop_down_list_value) }
|
let(:champ) { dossier.champs.first }
|
||||||
let(:champ) { create(:champ_multiple_drop_down_list, dossier: dossier, type_de_champ: type_de_champ, value: champ_value) }
|
let(:type_de_champ) { champ.type_de_champ }
|
||||||
let(:options) { type_de_champ.drop_down_list_options }
|
let(:options) { type_de_champ.drop_down_list_options }
|
||||||
let(:enabled_options) { type_de_champ.drop_down_list_enabled_non_empty_options }
|
let(:enabled_options) { type_de_champ.drop_down_list_enabled_non_empty_options }
|
||||||
|
|
||||||
before { dossier.champs_public << champ }
|
|
||||||
|
|
||||||
context 'when the list is short' do
|
context 'when the list is short' do
|
||||||
let(:drop_down_list_value) { ['valid', 'invalid', 'not sure yet'].join("\r\n") }
|
let(:options) { ['valid', 'invalid', 'not sure yet'] }
|
||||||
let(:champ_value) { ['invalid'].to_json }
|
|
||||||
|
|
||||||
it 'renders the list as checkboxes' do
|
it 'renders the list as checkboxes' do
|
||||||
expect(subject).to have_selector('input[type=checkbox]', count: enabled_options.count)
|
expect(subject).to have_selector('input[type=checkbox]', count: enabled_options.count)
|
||||||
expect(subject).to have_selector('input[type=checkbox][checked=checked]', count: 1)
|
expect(subject).to have_selector('input[type=checkbox][checked=checked]', count: 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds an extra hidden input, to send a blank value even when all checkboxes are unchecked' do
|
it 'adds an extra hidden input, to send a blank value even when all checkboxes are unchecked' do
|
||||||
|
@ -97,8 +102,7 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the list is long' do
|
context 'when the list is long' do
|
||||||
let(:drop_down_list_value) { ['peach', 'banana', 'pear', 'apricot', 'apple', 'grapefruit'].join("\r\n") }
|
let(:options) { ['peach', 'banana', 'pear', 'apricot', 'apple', 'grapefruit'] }
|
||||||
let(:champ_value) { ['banana', 'grapefruit'].to_json }
|
|
||||||
|
|
||||||
it 'renders the list as a multiple-selection dropdown' do
|
it 'renders the list as a multiple-selection dropdown' do
|
||||||
expect(subject).to have_selector('select')
|
expect(subject).to have_selector('select')
|
||||||
|
@ -107,13 +111,11 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a mandatory piece justificative' do
|
context 'with a mandatory piece justificative' do
|
||||||
let(:dossier) { create(:dossier) }
|
let(:types_de_champ_public) { [{ type: :piece_justificative, mandatory: true }] }
|
||||||
let(:type_de_champ) { create(:type_de_champ_piece_justificative, procedure: dossier.procedure, mandatory: true) }
|
let(:champ) { dossier.champs.first }
|
||||||
let(:champ) { create(:champ_piece_justificative, dossier: dossier, type_de_champ: type_de_champ) }
|
|
||||||
|
|
||||||
context 'when dossier is en construction' do
|
context 'when dossier is en construction' do
|
||||||
let(:dossier) { create(:dossier, :en_construction) }
|
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
|
||||||
before { dossier.champs_public << champ }
|
|
||||||
|
|
||||||
it 'can delete a piece justificative' do
|
it 'can delete a piece justificative' do
|
||||||
expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
||||||
|
@ -121,10 +123,6 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when dossier is brouillon' do
|
context 'when dossier is brouillon' do
|
||||||
before do
|
|
||||||
dossier.champs_public << champ
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'can delete a piece justificative' do
|
it 'can delete a piece justificative' do
|
||||||
expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
|
||||||
end
|
end
|
||||||
|
@ -132,16 +130,11 @@ describe 'shared/dossiers/edit', type: :view do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a routed procedure' do
|
context 'with a routed procedure' do
|
||||||
let(:procedure_routee) do
|
let(:groupe_instructeur) { create(:groupe_instructeur) }
|
||||||
create(:procedure, :routee)
|
let(:procedure) { create(:procedure, :routee, groupe_instructeurs: [groupe_instructeur], types_de_champ_public: [{ type: :drop_down_list, options: }]) }
|
||||||
end
|
let(:options) { [groupe_instructeur.label] }
|
||||||
let!(:drop_down_tdc) { create(:type_de_champ_drop_down_list, procedure: procedure_routee, drop_down_options: options) }
|
let(:dossier) { create(:dossier, procedure:) }
|
||||||
let(:options) { procedure_routee.groupe_instructeurs.pluck(:label) }
|
let(:champ_drop_down) { dossier.champs.first }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure_routee) }
|
|
||||||
let(:champs) { [champ_drop_down] }
|
|
||||||
let(:champ_drop_down) { create(:champ_drop_down_list, dossier: dossier, type_de_champ: drop_down_tdc, value: options.first) }
|
|
||||||
|
|
||||||
before { dossier.champs_public << champs }
|
|
||||||
|
|
||||||
it 'renders the libelle of the type de champ used for routing' do
|
it 'renders the libelle of the type de champ used for routing' do
|
||||||
expect(subject).to include(champ_drop_down.libelle)
|
expect(subject).to include(champ_drop_down.libelle)
|
||||||
|
|
Loading…
Add table
Reference in a new issue