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:
Paul Chavard 2024-03-04 15:03:02 +00:00 committed by GitHub
commit a247ec6c12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 374 additions and 351 deletions

View file

@ -1,10 +1,11 @@
- each_champ do |champ|
- 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
%p.font-weight-bold= "#{champ.libelle} #{i + 1} :"
= render Dossiers::ChampsRowsShowComponent.new(champs: row, seen_at:, profile:)
%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:)
- 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|

View file

@ -5,8 +5,8 @@
.repetition{ id: dom_id(@champ, :rows) }
- @champ.rows.each do |champs|
= render EditableChamp::RepetitionRowComponent.new(form: @form, champ: @champ, row: champs, seen_at: @seen_at)
- @champ.row_ids.each do |row_id|
= render EditableChamp::RepetitionRowComponent.new(form: @form, champ: @champ, row_id:, seen_at: @seen_at)
.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

View file

@ -1,5 +1,17 @@
class EditableChamp::RepetitionRowComponent < ApplicationComponent
def initialize(form:, champ:, row:, seen_at: nil)
@form, @champ, @row, @seen_at = form, champ, row, seen_at
def initialize(form:, champ:, row_id:, seen_at: nil)
@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

View file

@ -1,12 +1,11 @@
- row_id = "safe-row-selector-#{@row.first.row_id}"
.row{ id: row_id }
- if @row.size > 1
.row{ id: "safe-row-selector-#{row_id}" }
- if @types_de_champ.size > 1
%fieldset
%legend.block-id= "#{@champ.libelle} "
= render EditableChamp::SectionComponent.new(champs: @row)
= render section_component
- else
= render EditableChamp::SectionComponent.new(champs: @row)
= render section_component
.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")

View file

@ -2,8 +2,10 @@ class EditableChamp::SectionComponent < ApplicationComponent
include ApplicationHelper
include TreeableConcern
def initialize(nodes: nil, champs: nil)
nodes ||= to_tree(champs:)
def initialize(nodes: nil, types_de_champ: nil, row_id: nil, champs_by_stable_id_with_row:)
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:)
end
@ -12,7 +14,8 @@ class EditableChamp::SectionComponent < ApplicationComponent
end
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
def splitted_tail
@ -35,17 +38,21 @@ class EditableChamp::SectionComponent < ApplicationComponent
when EditableChamp::SectionComponent
[node, nil]
else
[nil, node]
[nil, champ_for_type_de_champ(node)]
end
end
private
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
def first_champ_is_an_header_section?
header_section.present?
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

View file

@ -2,9 +2,9 @@ class ViewableChamp::SectionComponent < ApplicationComponent
include ApplicationHelper
include TreeableConcern
def initialize(champs: nil, nodes: nil, demande_seen_at:, profile:)
@demande_seen_at, @profile, @repetition = demande_seen_at, profile
nodes ||= to_tree(champs:)
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, @row_id, @champs_by_stable_id_with_row = demande_seen_at, profile, row_id, champs_by_stable_id_with_row
nodes ||= to_tree(types_de_champ:)
@nodes = to_sections(nodes:)
end
@ -13,17 +13,18 @@ class ViewableChamp::SectionComponent < ApplicationComponent
end
def header_section
if @nodes.first.is_a?(Champs::HeaderSectionChamp)
@nodes.first
maybe_header_section = @nodes.first
if maybe_header_section.is_a?(TypeDeChamp) && maybe_header_section.header_section?
champ_for_type_de_champ(maybe_header_section)
end
end
def champs
tail.filter { _1.is_a?(Champ) }
tail.filter_map { _1.is_a?(TypeDeChamp) ? champ_for_type_de_champ(_1) : nil }
end
def sections
tail.filter { !_1.is_a?(Champ) }
tail.filter { _1.is_a?(ViewableChamp::SectionComponent) }
end
def tail
@ -48,6 +49,10 @@ class ViewableChamp::SectionComponent < ApplicationComponent
private
def to_sections(nodes:)
nodes.map { _1.is_a?(Array) ? ViewableChamp::SectionComponent.new(nodes: _1, demande_seen_at: @demande_seen_at, profile: @profile) : _1 }
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

View file

@ -3,7 +3,9 @@ class Champs::RepetitionController < ApplicationController
def add
@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
def remove

View file

@ -26,7 +26,7 @@ class RootController < ApplicationController
description = "Allez voir le super site : #{APPLICATION_BASE_URL}"
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) }
all_champs
@ -76,7 +76,7 @@ class RootController < ApplicationController
.each { |champ| champ.value = value }
end
@dossier = Dossier.new(champs_public: all_champs)
@dossier = Dossier.new(champs: all_champs)
@dossier.association(:procedure).target = Procedure.new
all_champs.each do |champ|
champ.association(:dossier).target = @dossier
@ -85,7 +85,7 @@ class RootController < ApplicationController
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.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)

View file

@ -11,16 +11,18 @@ module Types::Champs
field :rows, [Row], null: false
def champs
Loaders::Association.for(object.class, champs: :type_de_champ).load(object).then do |champs|
champs.filter(&:visible?)
end
object.rows.flat_map { _1.filter(&:visible?) }
end
def rows
Loaders::Association.for(object.class, champs: :type_de_champ).load(object).then do |champs|
object.association(:champs).target = champs.filter(&:visible?)
object.rows.map { { champs: _1, id: GraphQL::Schema::UniqueWithinType.encode('Row', _1.first.row_id) } }
end
object
.rows
.map do
{
id: GraphQL::Schema::UniqueWithinType.encode('Row', _1.first.row_id),
champs: _1.filter(&:visible?)
}
end
end
end
end

View file

@ -157,10 +157,7 @@ module Types
.for(object, private: false)
.load(ApplicationRecord.id_from_typed_id(id))
else
Loaders::Association
.for(object.class, champs_public: :type_de_champ)
.load(object)
.then { |champs| champs.filter(&:visible?) }
object.champs_for_revision(scope: :public, root: true).filter(&:visible?)
end
end
@ -170,7 +167,7 @@ module Types
.for(object, private: true)
.load(ApplicationRecord.id_from_typed_id(id))
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

View file

@ -79,10 +79,10 @@ class AttestationTemplate < ApplicationRecord
end
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|
corresponding_champ = all_champs_with_libelle_index[used_tag]
corresponding_champ = champs_by_stable_id[used_tag]
if corresponding_champ && corresponding_champ.blank?
corresponding_champ

View file

@ -10,7 +10,7 @@ class Champ < ApplicationRecord
# here because otherwise we can't easily use includes in our queries.
has_many :geo_areas, -> { order(:created_at) }, dependent: :destroy, inverse_of: :champ
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
@ -70,14 +70,6 @@ class Champ < ApplicationRecord
scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) }
scope :public_only, -> { where(private: false) }
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 :prefilled, -> { where(prefilled: true) }
@ -99,10 +91,6 @@ class Champ < ApplicationRecord
[row_id, stable_id].compact
end
def sections
@sections ||= dossier.sections_for(self)
end
# used for the `required` html attribute
# check visibility to avoid hidden required input
# which prevent the form from being sent.

View file

@ -16,8 +16,4 @@ class Champs::HeaderSectionChamp < Champ
def libelle_with_section_index?
libelle =~ /^\d/
end
def section_index
sections.index(self) + 1
end
end

View file

@ -3,7 +3,13 @@ class Champs::RepetitionChamp < Champ
delegate :libelle_for_export, to: :type_de_champ
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
def add_row(revision)
@ -35,13 +41,15 @@ class Champs::RepetitionChamp < Champ
end
def rows_for_export
rows.each.with_index(1).map do |champs, index|
Champs::RepetitionChamp::Row.new(index: index, dossier_id: dossier_id.to_s, champs: champs)
champs = dossier.champs_by_stable_id_with_row
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
class Row < Hashie::Dash
property :index
property :row_id
property :dossier_id
property :champs
@ -53,7 +61,7 @@ class Champs::RepetitionChamp < Champ
[
['Dossier ID', :dossier_id],
['Ligne', :index]
] + Dossier.champs_for_export(champs, types_de_champ)
] + Dossier.champs_for_export(types_de_champ, champs, row_id)
end
end
end

View file

@ -42,10 +42,10 @@ module DossierCloneConcern
end
def make_diff(editing_fork)
origin_champs_index = champs_public_all.index_by(&:stable_id_with_row)
forked_champs_index = editing_fork.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_for_revision(scope: :public).index_by(&:stable_id_with_row)
updated_champs_index = editing_fork
.champs_public_all
.champs_for_revision(scope: :public)
.filter { _1.updated_at > editing_fork.created_at }
.index_by(&:stable_id_with_row)
@ -80,7 +80,7 @@ module DossierCloneConcern
dossier_attributes += [:groupe_instructeur_id] if fork
relationships = [:individual, :etablissement]
cloned_champs = champs
cloned_champs = champs_for_revision
.index_by(&:id)
.transform_values { [_1, _1.clone(fork)] }
@ -142,7 +142,7 @@ module DossierCloneConcern
end
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|
if champ.child?

View file

@ -6,11 +6,11 @@ module DossierSectionsConcern
@sections = Hash.new do |hash, parent|
case parent
when :public
hash[parent] = champs_public.filter(&:header_section?)
hash[parent] = champs_for_revision(scope: :public, root: true).filter(&:header_section?)
when :private
hash[parent] = champs_private.filter(&:header_section?)
hash[parent] = champs_for_revision(scope: :private, root: true).filter(&:header_section?)
else
hash[parent] = parent.champs.filter(&:header_section?)
hash[parent] = champs_for_revision(scope: parent.type_de_champ).filter(&:header_section?)
end
end
@sections[champ.parent || (champ.public? ? :public : :private)]
@ -23,7 +23,7 @@ module DossierSectionsConcern
end
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
champs.each do |c|
if c.repetition?

View file

@ -5,30 +5,30 @@ module TreeableConcern
# but a repetition can be nested an header_section, so 3+3=6=MAX_DEPTH
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)
# when we encounter an header_section, it depends of its own depth of nesting minus 1, ie:
# h1 belongs to prior (rooted_tree)
# h2 belongs to prior h1
# h3 belongs to prior h2
# 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
# given a root_depth at 0, we build a full tree
# 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 = []
walk = Array.new(MAX_DEPTH)
walk[0] = rooted_tree
current_tree = rooted_tree
champs.each do |champ|
if champ.header_section?
new_tree = [champ]
walk[champ.header_section_level_value - 1].push(new_tree)
current_tree = walk[champ.header_section_level_value] = new_tree
types_de_champ.each do |type_de_champ|
if type_de_champ.header_section?
new_tree = [type_de_champ]
walk[type_de_champ.header_section_level_value - 1].push(new_tree)
current_tree = walk[type_de_champ.header_section_level_value] = new_tree
else
current_tree.push(champ)
current_tree.push(type_de_champ)
end
end
rooted_tree

View file

@ -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
# 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_public, -> { root.public_ordered }, class_name: 'Champ', inverse_of: false
has_many :champs_private, -> { root.private_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_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 :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?
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
end
@ -1165,7 +1165,8 @@ class Dossier < ApplicationRecord
end
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(&:mandatory_blank?)
.map do |champ|
@ -1268,15 +1269,15 @@ class Dossier < ApplicationRecord
if procedure.routing_enabled?
columns << ['Groupe instructeur', groupe_instructeur.label]
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
# Get all the champs values for the types de champ in the final list.
# 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
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|
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?
# some champs export multiple columns
@ -1299,7 +1300,7 @@ class Dossier < ApplicationRecord
end
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)
end
@ -1308,7 +1309,7 @@ class Dossier < ApplicationRecord
end
def geo_data?
GeoArea.exists?(champ_id: champs_public.ids + champs_private.ids)
GeoArea.exists?(champ_id: champs_for_revision)
end
def to_feature_collection
@ -1391,6 +1392,24 @@ class Dossier < ApplicationRecord
user.france_connect_information.present?
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
def create_missing_traitemets
@ -1412,7 +1431,7 @@ class Dossier < ApplicationRecord
end
def geo_areas
champs_public.flat_map(&:geo_areas) + champs_private.flat_map(&:geo_areas)
champs_for_revision.flat_map(&:geo_areas)
end
def bounding_box

View file

@ -118,9 +118,9 @@ class DossierPreloader
dossier.association(:champs_private_all).target += champs
end
parent.association(name).target = champs.sort_by do |champ|
[champ.row_id, positions[dossier.revision_id][champ.type_de_champ_id]]
end
parent.association(name).target = champs
.filter { positions[dossier.revision_id][_1.type_de_champ_id].present? }
.sort_by { [_1.row_id, positions[dossier.revision_id][_1.type_de_champ_id]] }
# Load children champs
champs.filter(&:block?).each do |parent_champ|

View file

@ -155,6 +155,22 @@ class ProcedureRevision < ApplicationRecord
dossier
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)
if revision_types_de_champ.loaded?
parent_coordinate_id = revision_types_de_champ

View file

@ -357,6 +357,10 @@ class TypeDeChamp < ApplicationRecord
type_champ == TypeDeChamp.type_champs.fetch(:drop_down_list)
end
def multiple_drop_down_list?
type_champ == TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
end
def linked_drop_down_list?
type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
end

View file

@ -36,8 +36,21 @@ class ChampSerializer < ActiveModel::Serializer
object.etablissement&.entreprise
end
class Row < Hashie::Dash
property :index
property :champs
def read_attribute_for_serialization(attribute)
self[attribute]
end
end
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
def include_etablissement?

View file

@ -23,16 +23,6 @@ class ProcedureArchiveService
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
def zip_root_folder(archive)
@ -43,19 +33,4 @@ class ProcedureArchiveService
archive.id
].join("-")
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

View file

@ -90,9 +90,7 @@ class ProcedureExportService
def etablissements
@etablissements ||= dossiers.flat_map do |dossier|
[dossier.champs_public, dossier.champs_private]
.flatten
.filter { |champ| champ.is_a?(Champs::SiretChamp) }
dossier.champs.filter { _1.is_a?(Champs::SiretChamp) }
end.filter_map(&:etablissement) + dossiers.filter_map(&:etablissement)
end
@ -102,7 +100,7 @@ class ProcedureExportService
def champs_repetables_options
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)
procedure

View file

@ -7,7 +7,7 @@
= tab_item('le dossier',
apercu_admin_procedure_path(@dossier.procedure, tab: 'dossier'),
active: @tab == 'dossier')
- if @dossier.champs_private.size > 0
- if @dossier.has_annotations?
= tab_item('les annotations privées',
apercu_admin_procedure_path(@dossier.procedure, tab: 'annotations-privees'),
active: @tab == 'annotations-privees')

View file

@ -1,6 +1,5 @@
- if @champs.present?
- if @row_id.present?
= 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))
- first_champ_id = @champs.map(&:focusable_input_id).compact.first
- if first_champ_id
= turbo_stream.focus(first_champ_id)
= turbo_stream.append dom_id(@champ, :rows), render(EditableChamp::RepetitionRowComponent.new(form: form, champ: @champ, row_id: @row_id))
- if @first_champ_id
= turbo_stream.focus(@first_champ_id)

View file

@ -349,7 +349,7 @@ prawn_document(page_size: "A4") do |pdf|
add_title(pdf, 'Formulaire')
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_champs(pdf, @dossier.champs_private)
end

View file

@ -13,15 +13,15 @@
%h2 Formulaire
- champs = @dossier.champs_public
- if champs.any? || @dossier.procedure.routing_enabled?
= render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
- types_de_champ_public = @dossier.revision.types_de_champ_public
- if types_de_champ_public.any? || @dossier.procedure.routing_enabled?
= 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
- champs_annotations_privees = @dossier.champs_private
- if champs_annotations_privees.any?
= render partial: "shared/dossiers/champs", locals: { champs: champs_annotations_privees, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
- types_de_champ_private = @dossier.revision.types_de_champ_private
- if types_de_champ_private.any?
= render partial: "shared/dossiers/champs", locals: { types_de_champ: types_de_champ_private, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
- else
Aucune annotation privée

View file

@ -33,7 +33,7 @@
%form.form
= 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
%label Mot de passe
@ -331,7 +331,7 @@
%h1.fr-mt-4w Attachment::EditComponent
%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
- avis = Avis.new

View file

@ -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:)

View file

@ -51,6 +51,6 @@
%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')
- champs = dossier.champs_public
- if champs.any? || dossier.procedure.routing_enabled?
= render partial: "shared/dossiers/champs", locals: { champs: champs, dossier: dossier, demande_seen_at: demande_seen_at, profile: profile }
- types_de_champ = dossier.revision.types_de_champ_public
- if types_de_champ.any? || dossier.procedure.routing_enabled?
= render partial: "shared/dossiers/champs", locals: { types_de_champ:, dossier:, demande_seen_at:, profile: }

View file

@ -21,7 +21,7 @@
= 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)

View file

@ -1,9 +1,9 @@
.container.dossier-edit
- if dossier.champs_private.present?
- if dossier.has_annotations?
%section.counter-start-header-section
= render NestedForms::FormOwnerComponent.new
= 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)
- else