Merge pull request #5305 from betagouv/dev

2020-06-26-01
This commit is contained in:
Keirua 2020-06-26 10:54:48 +02:00 committed by GitHub
commit cf01fcdf18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 341 additions and 193 deletions

View file

@ -21,7 +21,7 @@ class ApplicationController < ActionController::Base
before_action :setup_tracking before_action :setup_tracking
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur, helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur,
:administrateur_signed_in?, :current_administrateur :administrateur_signed_in?, :current_administrateur, :current_account
def staging_authenticate def staging_authenticate
if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) } if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) }
@ -49,14 +49,6 @@ class ApplicationController < ActionController::Base
user_signed_in? && administrateur_signed_in? user_signed_in? && administrateur_signed_in?
end end
def pundit_user
{
administrateur: current_administrateur,
instructeur: current_instructeur,
user: current_user
}.compact
end
def current_instructeur def current_instructeur
current_user&.instructeur current_user&.instructeur
end end
@ -73,6 +65,16 @@ class ApplicationController < ActionController::Base
current_administrateur.present? current_administrateur.present?
end end
def current_account
{
administrateur: current_administrateur,
instructeur: current_instructeur,
user: current_user
}.compact
end
alias_method :pundit_user, :current_account
protected protected
def feature_enabled?(feature_name) def feature_enabled?(feature_name)

View file

@ -1,8 +1,8 @@
class ApiEntreprise::EffectifsJob < ApiEntreprise::Job class ApiEntreprise::EffectifsJob < ApiEntreprise::Job
def perform(etablissement_id, procedure_id) def perform(etablissement_id, procedure_id)
etablissement = Etablissement.find(etablissement_id) etablissement = Etablissement.find(etablissement_id)
# april 2020 is at the moment the most actual info for effectifs endpoint # may 2020 is at the moment the most actual info for effectifs endpoint
etablissement_params = ApiEntreprise::EffectifsAdapter.new(etablissement.siret, procedure_id, "2020", "04").to_params etablissement_params = ApiEntreprise::EffectifsAdapter.new(etablissement.siret, procedure_id, "2020", "05").to_params
etablissement.update!(etablissement_params) etablissement.update!(etablissement_params)
end end

View file

@ -11,7 +11,22 @@ class Champ < ApplicationRecord
belongs_to :etablissement, dependent: :destroy belongs_to :etablissement, dependent: :destroy
has_many :champs, -> { ordered }, foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy has_many :champs, -> { ordered }, foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy
delegate :libelle, :type_champ, :procedure, :order_place, :mandatory?, :description, :drop_down_list, :exclude_from_export?, :exclude_from_view?, :repetition?, :dossier_link?, to: :type_de_champ delegate :libelle,
:type_champ,
:procedure,
:order_place,
:mandatory?,
:description,
:drop_down_list,
:drop_down_list_options,
:drop_down_list_options?,
:drop_down_list_disabled_options,
:drop_down_list_enabled_non_empty_options,
:exclude_from_export?,
:exclude_from_view?,
:repetition?,
:dossier_link?,
to: :type_de_champ
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) }

View file

@ -1,2 +1,23 @@
class Champs::DropDownListChamp < Champ class Champs::DropDownListChamp < Champ
THRESHOLD_NB_OPTIONS_AS_RADIO = 5
def render_as_radios?
enabled_non_empty_options.size <= THRESHOLD_NB_OPTIONS_AS_RADIO
end
def options?
drop_down_list_options?
end
def options
drop_down_list_options
end
def disabled_options
drop_down_list_disabled_options
end
def enabled_non_empty_options
drop_down_list_enabled_non_empty_options
end
end end

View file

@ -1,6 +1,10 @@
class Champs::LinkedDropDownListChamp < Champ class Champs::LinkedDropDownListChamp < Champ
delegate :primary_options, :secondary_options, to: 'type_de_champ.dynamic_type' delegate :primary_options, :secondary_options, to: 'type_de_champ.dynamic_type'
def options?
drop_down_list_options?
end
def primary_value def primary_value
if value.present? if value.present?
JSON.parse(value)[0] JSON.parse(value)[0]

View file

@ -1,6 +1,24 @@
class Champs::MultipleDropDownListChamp < Champ class Champs::MultipleDropDownListChamp < Champ
before_save :format_before_save before_save :format_before_save
def options?
drop_down_list_options?
end
def options
drop_down_list_options
end
def disabled_options
drop_down_list_disabled_options
end
def enabled_non_empty_options
drop_down_list_enabled_non_empty_options
end
THRESHOLD_NB_OPTIONS_AS_CHECKBOX = 5
def search_terms def search_terms
selected_options selected_options
end end
@ -21,6 +39,10 @@ class Champs::MultipleDropDownListChamp < Champ
value.present? ? selected_options.join(', ') : nil value.present? ? selected_options.join(', ') : nil
end end
def render_as_checkboxes?
enabled_non_empty_options.size <= THRESHOLD_NB_OPTIONS_AS_CHECKBOX
end
private private
def format_before_save def format_before_save

View file

@ -701,7 +701,8 @@ class Dossier < ApplicationRecord
end end
def attachments_downloadable? def attachments_downloadable?
!PiecesJustificativesService.liste_pieces_justificatives(self).empty? && PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP PiecesJustificativesService.liste_pieces_justificatives(self).present? \
&& PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
end end
def linked_dossiers_for(instructeur) def linked_dossiers_for(instructeur)

View file

@ -1,26 +1,8 @@
class DropDownList < ApplicationRecord class DropDownList < ApplicationRecord
belongs_to :type_de_champ belongs_to :type_de_champ
before_validation :clean_value
def options def options
result = value.split(/[\r\n]|[\r]|[\n]|[\n\r]/).reject(&:empty?) result = value.split(/[\r\n]|[\r]|[\n]|[\n\r]/).reject(&:empty?)
result.blank? ? [] : [''] + result result.blank? ? [] : [''] + result
end end
def disabled_options
options.filter { |v| (v =~ /^--.*--$/).present? }
end
def multiple
type_de_champ.type_champ == TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
end
private
def clean_value
value = read_attribute(:value)
value = value ? value.split("\r\n").map(&:strip).join("\r\n") : ''
write_attribute(:value, value)
end
end end

View file

@ -35,7 +35,7 @@ class TypeDeChamp < ApplicationRecord
belongs_to :parent, class_name: 'TypeDeChamp' belongs_to :parent, class_name: 'TypeDeChamp'
has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy
store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj, :drop_down_options
delegate :tags_for_template, to: :dynamic_type delegate :tags_for_template, to: :dynamic_type
class WithIndifferentAccess class WithIndifferentAccess
@ -53,7 +53,6 @@ class TypeDeChamp < ApplicationRecord
after_initialize :set_dynamic_type after_initialize :set_dynamic_type
after_create :populate_stable_id after_create :populate_stable_id
before_save :setup_procedure before_save :setup_procedure
before_validation :set_default_drop_down_list
attr_reader :dynamic_type attr_reader :dynamic_type
@ -83,6 +82,7 @@ class TypeDeChamp < ApplicationRecord
before_validation :check_mandatory before_validation :check_mandatory
before_save :remove_piece_justificative_template, if: -> { type_champ_changed? } before_save :remove_piece_justificative_template, if: -> { type_champ_changed? }
before_validation :remove_drop_down_list, if: -> { type_champ_changed? }
def valid?(context = nil) def valid?(context = nil)
super super
@ -146,6 +146,10 @@ class TypeDeChamp < ApplicationRecord
]) ])
end end
def linked_drop_down_list?
type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
end
def exclude_from_view? def exclude_from_view?
type_champ == TypeDeChamp.type_champs.fetch(:explication) type_champ == TypeDeChamp.type_champs.fetch(:explication)
end end
@ -158,6 +162,10 @@ class TypeDeChamp < ApplicationRecord
type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) type_champ == TypeDeChamp.type_champs.fetch(:dossier_link)
end end
def piece_justificative?
type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative)
end
def legacy_number? def legacy_number?
type_champ == TypeDeChamp.type_champs.fetch(:number) type_champ == TypeDeChamp.type_champs.fetch(:number)
end end
@ -183,11 +191,31 @@ class TypeDeChamp < ApplicationRecord
end end
def drop_down_list_value def drop_down_list_value
drop_down_list&.value if drop_down_list_options.present?
drop_down_list_options.reject(&:empty?).join("\r\n")
else
''
end
end end
def drop_down_list_value=(value) def drop_down_list_value=(value)
self.drop_down_list_attributes = { value: value } self.drop_down_options = parse_drop_down_list_value(value)
end
def drop_down_list_options?
drop_down_list_options.any?
end
def drop_down_list_options
drop_down_options.presence || drop_down_list&.options || []
end
def drop_down_list_disabled_options
drop_down_list_options.filter { |v| (v =~ /^--.*--$/).present? }
end
def drop_down_list_enabled_non_empty_options
(drop_down_list_options - drop_down_list_disabled_options).reject(&:empty?)
end end
def to_typed_id def to_typed_id
@ -244,10 +272,10 @@ class TypeDeChamp < ApplicationRecord
private private
def set_default_drop_down_list def parse_drop_down_list_value(value)
if drop_down_list? && !drop_down_list value = value ? value.split("\r\n").map(&:strip).join("\r\n") : ''
self.drop_down_list_attributes = { value: '' } result = value.split(/[\r\n]|[\r]|[\n]|[\n\r]/).reject(&:empty?)
end result.blank? ? [] : [''] + result
end end
def setup_procedure def setup_procedure
@ -263,8 +291,15 @@ class TypeDeChamp < ApplicationRecord
end end
def remove_piece_justificative_template def remove_piece_justificative_template
if type_champ != TypeDeChamp.type_champs.fetch(:piece_justificative) && piece_justificative_template.attached? if !piece_justificative? && piece_justificative_template.attached?
piece_justificative_template.purge_later piece_justificative_template.purge_later
end end
end end
def remove_drop_down_list
if !drop_down_list?
self.drop_down_list = nil
self.drop_down_options = nil
end
end
end end

View file

@ -1,26 +1,9 @@
class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
PRIMARY_PATTERN = /^--(.*)--$/ PRIMARY_PATTERN = /^--(.*)--$/
delegate :drop_down_list, to: :@type_de_champ delegate :drop_down_list_options, to: :@type_de_champ
validate :check_presence_of_primary_options validate :check_presence_of_primary_options
def primary_options
primary_options = unpack_options.map(&:first)
if primary_options.present?
primary_options.unshift('')
end
primary_options
end
def secondary_options
secondary_options = unpack_options.to_h
if secondary_options.present?
secondary_options[''] = []
end
secondary_options
end
def tags_for_template def tags_for_template
tags = super tags = super
tdc = @type_de_champ tdc = @type_de_champ
@ -49,16 +32,26 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
tags tags
end end
def primary_options
primary_options = unpack_options.map(&:first)
if primary_options.present?
primary_options.unshift('')
end
primary_options
end
def secondary_options
secondary_options = unpack_options.to_h
if secondary_options.present?
secondary_options[''] = []
end
secondary_options
end
private private
def check_presence_of_primary_options
if !PRIMARY_PATTERN.match?(drop_down_list.options.second)
errors.add(libelle.presence || "La liste", "doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>")
end
end
def unpack_options def unpack_options
_, *options = drop_down_list.options _, *options = drop_down_list_options
chunked = options.slice_before(PRIMARY_PATTERN) chunked = options.slice_before(PRIMARY_PATTERN)
chunked.map do |chunk| chunked.map do |chunk|
primary, *secondary = chunk primary, *secondary = chunk
@ -66,4 +59,10 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
[PRIMARY_PATTERN.match(primary)&.[](1), secondary] [PRIMARY_PATTERN.match(primary)&.[](1), secondary]
end end
end end
def check_presence_of_primary_options
if !PRIMARY_PATTERN.match?(drop_down_list_options.second)
errors.add(libelle.presence || "La liste", "doit commencer par une entrée de menu primaire de la forme <code style='white-space: pre-wrap;'>--texte--</code>")
end
end
end end

View file

@ -1,4 +1,8 @@
class ChampPolicy < ApplicationPolicy class ChampPolicy < ApplicationPolicy
# Scope for WRITING to a champ.
#
# (If the need for a scope to READ a champ emerges, we can implement another scope
# in this file, following this example: https://github.com/varvet/pundit/issues/368#issuecomment-196111115)
class Scope < ApplicationScope class Scope < ApplicationScope
def resolve def resolve
if user.blank? if user.blank?

View file

@ -1,16 +1,10 @@
class PiecesJustificativesService class PiecesJustificativesService
def self.liste_pieces_justificatives(dossier) def self.liste_pieces_justificatives(dossier)
pjs_commentaires = dossier.commentaires pjs_champs = pjs_for_champs(dossier)
.map(&:piece_jointe) pjs_commentaires = pjs_for_commentaires(dossier)
(pjs_champs + pjs_commentaires)
.filter(&:attached?) .filter(&:attached?)
champs_blocs_repetables = dossier.champs
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) }
.flat_map(&:champs)
pjs_commentaires + champs_pieces_justificatives_with_attachments(
champs_blocs_repetables + dossier.champs
)
end end
def self.pieces_justificatives_total_size(dossier) def self.pieces_justificatives_total_size(dossier)
@ -48,10 +42,21 @@ class PiecesJustificativesService
private private
def self.champs_pieces_justificatives_with_attachments(champs) def self.pjs_for_champs(dossier)
champs allowed_champs = dossier.champs + dossier.champs_private
allowed_child_champs = allowed_champs
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) }
.flat_map(&:champs)
(allowed_champs + allowed_child_champs)
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) } .filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) }
.filter { |pj| pj.piece_justificative_file.attached? }
.map(&:piece_justificative_file) .map(&:piece_justificative_file)
end end
def self.pjs_for_commentaires(dossier)
dossier
.commentaires
.map(&:piece_jointe)
end
end end

View file

@ -28,8 +28,8 @@ logo = @attestation[:logo]
signature = @attestation[:signature] signature = @attestation[:signature]
prawn_document(margin: [top_margin, right_margin, bottom_margin, left_margin], page_size: page_size) do |pdf| prawn_document(margin: [top_margin, right_margin, bottom_margin, left_margin], page_size: page_size) do |pdf|
pdf.font_families.update( 'liberation serif' => { normal: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Regular.ttf' )}) pdf.font_families.update( 'marianne' => { normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' )})
pdf.font 'liberation serif' pdf.font 'marianne'
grey = '555555' grey = '555555'
black = '333333' black = '333333'
@ -47,13 +47,13 @@ prawn_document(margin: [top_margin, right_margin, bottom_margin, left_margin], p
end end
pdf.fill_color grey pdf.fill_color grey
pdf.pad_top(40) { pdf.text "le #{l(created_at, format: '%e %B %Y')}", size: 10, align: :right, character_spacing: -0.5 } pdf.pad_top(40) { pdf.text "le #{l(created_at, format: '%e %B %Y')}", size: 9, align: :right, character_spacing: -0.5 }
pdf.fill_color black pdf.fill_color black
pdf.pad_top(40) { pdf.text title, size: 18, character_spacing: -0.2 } pdf.pad_top(40) { pdf.text title, size: 14, character_spacing: -0.2 }
pdf.fill_color grey pdf.fill_color grey
pdf.pad_top(30) { pdf.text body, size: 10, character_spacing: -0.2, align: :justify } pdf.pad_top(30) { pdf.text body, size: 9, character_spacing: -0.2, align: :justify }
if signature.present? if signature.present?
pdf.pad_top(40) do pdf.pad_top(40) do

View file

@ -8,7 +8,7 @@ def render_in_2_columns(pdf, label, text)
end end
def format_in_2_lines(pdf, champ, nb_lines = 1) def format_in_2_lines(pdf, champ, nb_lines = 1)
add_single_line(pdf, champ.libelle, 12, :bold) add_single_line(pdf, champ.libelle, 9, :bold)
add_optionnal_description(pdf, champ) add_optionnal_description(pdf, champ)
height = 10 * (nb_lines+1) height = 10 * (nb_lines+1)
pdf.bounding_box([0, pdf.cursor],:width => 460,:height => height) do pdf.bounding_box([0, pdf.cursor],:width => 460,:height => height) do
@ -27,7 +27,7 @@ def format_in_2_columns(pdf, label)
end end
def format_with_checkbox(pdf, label, offset = 0) def format_with_checkbox(pdf, label, offset = 0)
pdf.font 'liberation serif', size: 12 do pdf.font 'marianne', size: 9 do
pdf.stroke_rectangle [0 + offset, pdf.cursor], 10, 10 pdf.stroke_rectangle [0 + offset, pdf.cursor], 10, 10
pdf.text_box label, at: [15 + offset, pdf.cursor] pdf.text_box label, at: [15 + offset, pdf.cursor]
end end
@ -63,7 +63,7 @@ def add_identite_individual(pdf, dossier)
end end
def add_identite_etablissement(pdf, libelle) def add_identite_etablissement(pdf, libelle)
add_single_line(pdf, libelle, 12, :bold) add_single_line(pdf, libelle, 9, :bold)
format_in_2_columns(pdf, "SIRET") format_in_2_columns(pdf, "SIRET")
format_in_2_columns(pdf, "Dénomination") format_in_2_columns(pdf, "Dénomination")
@ -71,18 +71,18 @@ def add_identite_etablissement(pdf, libelle)
end end
def add_single_line(pdf, libelle, size, style) def add_single_line(pdf, libelle, size, style)
pdf.font 'liberation serif', style: style, size: size do pdf.font 'marianne', style: style, size: size do
pdf.text libelle pdf.text libelle
end end
end end
def add_title(pdf, title) def add_title(pdf, title)
add_single_line(pdf, title, 24, :bold) add_single_line(pdf, title, 20, :bold)
pdf.text "\n" pdf.text "\n"
end end
def add_libelle(pdf, champ) def add_libelle(pdf, champ)
add_single_line(pdf, champ.libelle, 12, :bold) add_single_line(pdf, champ.libelle, 9, :bold)
end end
def add_explanation(pdf, explanation) def add_explanation(pdf, explanation)
@ -98,7 +98,7 @@ def render_single_champ(pdf, champ)
when 'Champs::RepetitionChamp' when 'Champs::RepetitionChamp'
raise 'There should not be a RepetitionChamp here !' raise 'There should not be a RepetitionChamp here !'
when 'Champs::PieceJustificativeChamp' when 'Champs::PieceJustificativeChamp'
add_single_line(pdf, 'Pièce justificative à joindre en complément du dossier', 12, :bold) add_single_line(pdf, 'Pièce justificative à joindre en complément du dossier', 9, :bold)
format_with_checkbox(pdf, champ.libelle) format_with_checkbox(pdf, champ.libelle)
add_optionnal_description(pdf, champ) add_optionnal_description(pdf, champ)
pdf.text "\n" pdf.text "\n"
@ -116,7 +116,7 @@ def render_single_champ(pdf, champ)
format_with_checkbox(pdf, Individual::GENDER_MALE) format_with_checkbox(pdf, Individual::GENDER_MALE)
pdf.text "\n" pdf.text "\n"
when 'Champs::HeaderSectionChamp' when 'Champs::HeaderSectionChamp'
add_single_line(pdf, champ.libelle, 18, :bold) add_single_line(pdf, champ.libelle, 14, :bold)
add_optionnal_description(pdf, champ) add_optionnal_description(pdf, champ)
pdf.text "\n" pdf.text "\n"
when 'Champs::ExplicationChamp' when 'Champs::ExplicationChamp'
@ -129,7 +129,7 @@ def render_single_champ(pdf, champ)
add_libelle(pdf, champ) add_libelle(pdf, champ)
add_optionnal_description(pdf, champ) add_optionnal_description(pdf, champ)
add_explanation(pdf, 'Cochez la mention applicable, une seule valeur possible') add_explanation(pdf, 'Cochez la mention applicable, une seule valeur possible')
champ.drop_down_list.options.reject(&:blank?).each do |option| champ.options.reject(&:blank?).each do |option|
format_with_checkbox(pdf, option) format_with_checkbox(pdf, option)
end end
pdf.text "\n" pdf.text "\n"
@ -137,7 +137,7 @@ def render_single_champ(pdf, champ)
add_libelle(pdf, champ) add_libelle(pdf, champ)
add_optionnal_description(pdf, champ) add_optionnal_description(pdf, champ)
add_explanation(pdf, 'Cochez la mention applicable, plusieurs valeurs possibles') add_explanation(pdf, 'Cochez la mention applicable, plusieurs valeurs possibles')
champ.drop_down_list.options.reject(&:blank?).each do |option| champ.options.reject(&:blank?).each do |option|
format_with_checkbox(pdf, option) format_with_checkbox(pdf, option)
end end
pdf.text "\n" pdf.text "\n"
@ -175,12 +175,12 @@ def add_champs(pdf, champs)
end end
prawn_document(page_size: "A4") do |pdf| prawn_document(page_size: "A4") do |pdf|
pdf.font_families.update( 'liberation serif' => { pdf.font_families.update( 'marianne' => {
normal: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Regular.ttf' ), normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' ),
bold: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Bold.ttf' ), bold: Rails.root.join('lib/prawn/fonts/marianne/marianne-bold.ttf' ),
italic: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Italic.ttf' ), italic: Rails.root.join('lib/prawn/fonts/marianne/marianne-thin.ttf' ),
}) })
pdf.font 'liberation serif' pdf.font 'marianne'
pdf.svg IO.read("app/assets/images/header/logo-ds-wide.svg"), width: 300, position: :center pdf.svg IO.read("app/assets/images/header/logo-ds-wide.svg"), width: 300, position: :center
pdf.move_down(40) pdf.move_down(40)
@ -199,7 +199,7 @@ prawn_document(page_size: "A4") do |pdf|
pdf.text "\n" pdf.text "\n"
add_title(pdf, 'Formulaire') add_title(pdf, 'Formulaire')
add_single_line(pdf, @procedure.description + "\n", 12, :italic) if @procedure.description.present? add_single_line(pdf, @procedure.description + "\n", 9, :italic) if @procedure.description.present?
add_champs(pdf, @dossier.champs) add_champs(pdf, @dossier.champs)
add_page_numbering(pdf) add_page_numbering(pdf)
add_procedure(pdf, @dossier) add_procedure(pdf, @dossier)

View file

@ -1,11 +1,11 @@
require 'prawn/measurement_extensions' require 'prawn/measurement_extensions'
def format_in_2_lines(pdf, label, text) def format_in_2_lines(pdf, label, text)
pdf.font 'liberation serif', style: :bold, size: 12 do pdf.font 'marianne', style: :bold, size: 10 do
pdf.text label pdf.text label
end end
pdf.text text pdf.text text, size: 9
pdf.text "\n" pdf.text "\n", size: 9
end end
def format_in_2_columns(pdf, label, text) def format_in_2_columns(pdf, label, text)
@ -16,8 +16,8 @@ def format_in_2_columns(pdf, label, text)
end end
def add_title(pdf, title) def add_title(pdf, title)
title_style = {style: :bold, size: 24} title_style = {style: :bold, size: 20}
pdf.font 'liberation serif', title_style do pdf.font 'marianne', title_style do
pdf.text title pdf.text title
end end
pdf.text "\n" pdf.text "\n"
@ -83,7 +83,7 @@ def render_single_champ(pdf, champ)
when 'Champs::PieceJustificativeChamp' when 'Champs::PieceJustificativeChamp'
return return
when 'Champs::HeaderSectionChamp' when 'Champs::HeaderSectionChamp'
pdf.font 'liberation serif', style: :bold, size: 18 do pdf.font 'marianne', style: :bold, size: 14 do
pdf.text champ.libelle pdf.text champ.libelle
end end
pdf.text "\n" pdf.text "\n"
@ -92,7 +92,7 @@ def render_single_champ(pdf, champ)
when 'Champs::CarteChamp' when 'Champs::CarteChamp'
format_in_2_lines(pdf, champ.libelle, champ.to_feature_collection.to_json) format_in_2_lines(pdf, champ.libelle, champ.to_feature_collection.to_json)
when 'Champs::SiretChamp' when 'Champs::SiretChamp'
pdf.font 'liberation serif', style: :bold, size: 12 do pdf.font 'marianne', style: :bold, size: 9 do
pdf.text champ.libelle pdf.text champ.libelle
end end
pdf.text " - SIRET: #{champ.to_s}" pdf.text " - SIRET: #{champ.to_s}"
@ -130,8 +130,8 @@ def add_message(pdf, message)
end end
pdf.text "#{sender}, #{format_date(message.created_at)}", style: :bold pdf.text "#{sender}, #{format_date(message.created_at)}", style: :bold
pdf.text ActionView::Base.full_sanitizer.sanitize(message.body) pdf.text ActionView::Base.full_sanitizer.sanitize(message.body), size: 9
pdf.text "\n" pdf.text "\n", size: 9
end end
def add_avis(pdf, avis) def add_avis(pdf, avis)
@ -159,11 +159,11 @@ def add_etats_dossier(pdf, dossier)
end end
prawn_document(page_size: "A4") do |pdf| prawn_document(page_size: "A4") do |pdf|
pdf.font_families.update( 'liberation serif' => { pdf.font_families.update( 'marianne' => {
normal: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Regular.ttf' ), normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf' ),
bold: Rails.root.join('lib/prawn/fonts/liberation_serif/LiberationSerif-Bold.ttf' ), bold: Rails.root.join('lib/prawn/fonts/marianne/marianne-bold.ttf' ),
}) })
pdf.font 'liberation serif' pdf.font 'marianne'
pdf.svg IO.read("app/assets/images/header/logo-ds-wide.svg"), width: 300, position: :center pdf.svg IO.read("app/assets/images/header/logo-ds-wide.svg"), width: 300, position: :center
pdf.move_down(40) pdf.move_down(40)

View file

@ -12,7 +12,7 @@
%li %li
= link_to "Export GeoJSON", geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link" = link_to "Export GeoJSON", geo_data_instructeur_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
- if !PiecesJustificativesService.liste_pieces_justificatives(dossier).empty? - if PiecesJustificativesService.liste_pieces_justificatives(dossier).present?
%span.dropdown.print-menu-opener %span.dropdown.print-menu-opener
%button.button.dropdown-button.icon-only %button.button.dropdown-button.icon-only
%span.icon.attached %span.icon.attached

View file

@ -1,5 +1,14 @@
- if champ.drop_down_list && champ.drop_down_list.options.any? - if champ.options?
- if champ.render_as_radios?
%fieldset.radios
%legend.mandatory-explanation
Sélectionnez une des valeurs
- champ.enabled_non_empty_options.each do |option|
%label
= form.radio_button :value, option
= option
- else
= form.select :value, = form.select :value,
champ.drop_down_list.options, champ.options,
disabled: champ.drop_down_list.disabled_options, disabled: champ.disabled_options,
required: champ.mandatory? required: champ.mandatory?

View file

@ -1,4 +1,4 @@
- if champ.drop_down_list && champ.drop_down_list.options.any? - if champ.options?
= form.select :primary_value, = form.select :primary_value,
champ.primary_options, champ.primary_options,
{ required: champ.mandatory? }, { required: champ.mandatory? },

View file

@ -1,7 +1,15 @@
- if champ.drop_down_list && champ.drop_down_list.options.any? - if champ.options?
- if champ.render_as_checkboxes?
- champ.enabled_non_empty_options.each do |option|
.editable-champ.editable-champ-checkbox
%label
= form.check_box :value, { multiple: true, checked: champ&.value&.include?(option) }, option, nil
= option
- else
= form.select :value, = form.select :value,
champ.drop_down_list.options, champ.options,
{ selected: champ.selected_options, { selected: champ.selected_options,
disabled: champ.drop_down_list.disabled_options }, disabled: champ.disabled_options },
multiple: true, multiple: true,
class: 'select2' class: 'select2'

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,25 @@
namespace :after_party do
desc 'Deployment task: drop_down_list_options_to_json'
task drop_down_list_options_to_json: :environment do
puts "Running deploy task 'drop_down_list_options_to_json'"
types_de_champ = TypeDeChamp.joins(:drop_down_list).where(type_champ: [
TypeDeChamp.type_champs.fetch(:drop_down_list),
TypeDeChamp.type_champs.fetch(:multiple_drop_down_list),
TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
])
progress = ProgressReport.new(types_de_champ.count)
types_de_champ.find_each do |type_de_champ|
type_de_champ.drop_down_list_value = type_de_champ.drop_down_list_value
if type_de_champ.save
type_de_champ.drop_down_list.destroy
end
progress.inc
end
progress.finish
# Update task as completed. If you remove the line below, the task will
# run with every deploy (or every time you call after_party:run).
AfterParty::TaskRecord.create version: '20200618121241'
end
end

View file

@ -1,5 +0,0 @@
FactoryBot.define do
factory :drop_down_list do
value { "val1\r\nval2\r\n--separateur--\r\nval3" }
end
end

View file

@ -233,6 +233,8 @@ FactoryBot.define do
end end
build(:"type_de_champ_#{type_champ}", mandatory: true, libelle: libelle, order_place: index) build(:"type_de_champ_#{type_champ}", mandatory: true, libelle: libelle, order_place: index)
end end
procedure.types_de_champ << build(:type_de_champ_drop_down_list, :long, mandatory: true, libelle: 'simple_choice_drop_down_list_long')
procedure.types_de_champ << build(:type_de_champ_multiple_drop_down_list, :long, mandatory: true, libelle: 'multiple_choice_drop_down_list_long')
end end
end end

View file

@ -52,15 +52,21 @@ FactoryBot.define do
factory :type_de_champ_drop_down_list do factory :type_de_champ_drop_down_list do
libelle { 'Menu déroulant' } libelle { 'Menu déroulant' }
type_champ { TypeDeChamp.type_champs.fetch(:drop_down_list) } type_champ { TypeDeChamp.type_champs.fetch(:drop_down_list) }
drop_down_list { create(:drop_down_list) } drop_down_list_value { "val1\r\nval2\r\n--separateur--\r\nval3" }
trait :long do
drop_down_list_value { "alpha\r\nbravo\r\n--separateur--\r\ncharly\r\ndelta\r\necho\r\nfox-trot\r\ngolf" }
end
end end
factory :type_de_champ_multiple_drop_down_list do factory :type_de_champ_multiple_drop_down_list do
type_champ { TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) } type_champ { TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) }
drop_down_list { create(:drop_down_list) } drop_down_list_value { "val1\r\nval2\r\n--separateur--\r\nval3" }
trait :long do
drop_down_list_value { "alpha\r\nbravo\r\n--separateur--\r\ncharly\r\ndelta\r\necho\r\nfox-trot\r\ngolf" }
end
end end
factory :type_de_champ_linked_drop_down_list do factory :type_de_champ_linked_drop_down_list do
type_champ { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) } type_champ { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
drop_down_list { create(:drop_down_list, value: "--primary--\nsecondary\n") } drop_down_list_value { "--primary--\nsecondary\n" }
end end
factory :type_de_champ_pays do factory :type_de_champ_pays do
type_champ { TypeDeChamp.type_champs.fetch(:pays) } type_champ { TypeDeChamp.type_champs.fetch(:pays) }

View file

@ -139,7 +139,7 @@ feature 'As an administrateur I can edit types de champ', js: true do
fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace }
fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace } fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace }
wait_until { procedure.types_de_champ.first.drop_down_list&.value == 'Un menu' } wait_until { procedure.types_de_champ.first.drop_down_list_options == ['', 'Un menu'] }
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
page.refresh page.refresh

View file

@ -21,9 +21,12 @@ feature 'The user' do
fill_in('email', with: 'loulou@yopmail.com') fill_in('email', with: 'loulou@yopmail.com')
fill_in('phone', with: '1234567890') fill_in('phone', with: '1234567890')
choose('Non') choose('Non')
select('val2', from: form_id_for('simple_drop_down_list')) choose('val2')
select('val1', from: form_id_for('multiple_drop_down_list')) check('val1')
select('val3', from: form_id_for('multiple_drop_down_list')) check('val3')
select('bravo', from: form_id_for('simple_choice_drop_down_list_long'))
select('alpha', from: form_id_for('multiple_choice_drop_down_list_long'))
select('charly', from: form_id_for('multiple_choice_drop_down_list_long'))
select('AUSTRALIE', from: 'pays') select('AUSTRALIE', from: 'pays')
select_champ_geo('regions', 'Ma', 'Martinique') select_champ_geo('regions', 'Ma', 'Martinique')
@ -55,6 +58,8 @@ feature 'The user' do
expect(champ_value_for('phone')).to eq('1234567890') expect(champ_value_for('phone')).to eq('1234567890')
expect(champ_value_for('yes_no')).to eq('false') expect(champ_value_for('yes_no')).to eq('false')
expect(champ_value_for('simple_drop_down_list')).to eq('val2') expect(champ_value_for('simple_drop_down_list')).to eq('val2')
expect(champ_value_for('simple_choice_drop_down_list_long')).to eq('bravo')
expect(JSON.parse(champ_value_for('multiple_choice_drop_down_list_long'))).to match(['alpha', 'charly'])
expect(JSON.parse(champ_value_for('multiple_drop_down_list'))).to match(['val1', 'val3']) expect(JSON.parse(champ_value_for('multiple_drop_down_list'))).to match(['val1', 'val3'])
expect(champ_value_for('pays')).to eq('AUSTRALIE') expect(champ_value_for('pays')).to eq('AUSTRALIE')
expect(champ_value_for('regions')).to eq('Martinique') expect(champ_value_for('regions')).to eq('Martinique')
@ -76,8 +81,11 @@ feature 'The user' do
expect(page).to have_field('email', with: 'loulou@yopmail.com') expect(page).to have_field('email', with: 'loulou@yopmail.com')
expect(page).to have_field('phone', with: '1234567890') expect(page).to have_field('phone', with: '1234567890')
expect(page).to have_checked_field('Non') expect(page).to have_checked_field('Non')
expect(page).to have_selected_value('simple_drop_down_list', selected: 'val2') expect(page).to have_checked_field('val2')
expect(page).to have_selected_value('multiple_drop_down_list', selected: ['val1', 'val3']) expect(page).to have_checked_field('val1')
expect(page).to have_checked_field('val3')
expect(page).to have_selected_value('simple_choice_drop_down_list_long', selected: 'bravo')
expect(page).to have_selected_value('multiple_choice_drop_down_list_long', selected: ['alpha', 'charly'])
expect(page).to have_selected_value('pays', selected: 'AUSTRALIE') expect(page).to have_selected_value('pays', selected: 'AUSTRALIE')
expect(page).to have_selected_value('regions', selected: 'Martinique') expect(page).to have_selected_value('regions', selected: 'Martinique')
expect(page).to have_selected_value('departements', selected: '02 - Aisne') expect(page).to have_selected_value('departements', selected: '02 - Aisne')

View file

@ -13,8 +13,7 @@ feature 'linked dropdown lists' do
Secondary 2.3 Secondary 2.3
END_OF_LIST END_OF_LIST
end end
let(:drop_down_list) { create(:drop_down_list, value: list_items) } let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list_value: list_items) }
let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list: drop_down_list) }
let!(:procedure) do let!(:procedure) do
p = create(:procedure, :published, :for_individual) p = create(:procedure, :published, :for_individual)

View file

@ -6,7 +6,7 @@ RSpec.describe ApiEntreprise::EffectifsJob, type: :job do
let(:procedure_id) { procedure.id } let(:procedure_id) { procedure.id }
let(:now) { Time.zone.local(2020, 3, 12) } let(:now) { Time.zone.local(2020, 3, 12) }
let(:annee) { "2020" } let(:annee) { "2020" }
let(:mois) { "04" } let(:mois) { "05" }
let(:body) { File.read('spec/fixtures/files/api_entreprise/effectifs.json') } let(:body) { File.read('spec/fixtures/files/api_entreprise/effectifs.json') }
let(:status) { 200 } let(:status) { 200 }

View file

@ -13,7 +13,15 @@ describe ActiveStorage::DownloadableFile do
dossier.champs << create(:champ, :piece_justificative, :with_piece_justificative_file) dossier.champs << create(:champ, :piece_justificative, :with_piece_justificative_file)
end end
it { expect(list.length).to be 1 } it { expect(list.length).to eq 1 }
end
context 'when there is a private piece_justificative' do
before do
dossier.champs_private << create(:champ, :piece_justificative, :with_piece_justificative_file, private: true)
end
it { expect(list.length).to eq 1 }
end end
context 'when there is a repetition bloc' do context 'when there is a repetition bloc' do
@ -21,7 +29,7 @@ describe ActiveStorage::DownloadableFile do
let(:dossier) { create(:dossier, :en_construction, champs: [champ]) } let(:dossier) { create(:dossier, :en_construction, champs: [champ]) }
it 'should have 4 piece_justificatives' do it 'should have 4 piece_justificatives' do
expect(list.size).to eq(4) expect(list.size).to eq 4
end end
end end
@ -29,14 +37,14 @@ describe ActiveStorage::DownloadableFile do
let(:commentaire) { create(:commentaire) } let(:commentaire) { create(:commentaire) }
let(:dossier) { commentaire.dossier } let(:dossier) { commentaire.dossier }
it { expect(list.length).to be 0 } it { expect(list.length).to eq 0 }
end end
context 'when there is a message with an attachment' do context 'when there is a message with an attachment' do
let(:commentaire) { create(:commentaire, :with_file) } let(:commentaire) { create(:commentaire, :with_file) }
let(:dossier) { commentaire.dossier } let(:dossier) { commentaire.dossier }
it { expect(list.length).to be 1 } it { expect(list.length).to eq 1 }
end end
end end
end end

View file

@ -62,12 +62,12 @@ describe Champs::LinkedDropDownListChamp do
end end
describe '#mandatory_and_blank' do describe '#mandatory_and_blank' do
let(:drop_down_list) { build(:drop_down_list, value: "--Primary--\nSecondary") } let(:value) { "--Primary--\nSecondary" }
subject { described_class.new(type_de_champ: type_de_champ) } subject { described_class.new(type_de_champ: type_de_champ) }
context 'when the champ is not mandatory' do context 'when the champ is not mandatory' do
let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list_value: value) }
it 'blank is fine' do it 'blank is fine' do
is_expected.not_to be_mandatory_and_blank is_expected.not_to be_mandatory_and_blank
@ -75,7 +75,7 @@ describe Champs::LinkedDropDownListChamp do
end end
context 'when the champ is mandatory' do context 'when the champ is mandatory' do
let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, mandatory: true, drop_down_list: drop_down_list) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, mandatory: true, drop_down_list_value: value) }
context 'when there is no value' do context 'when there is no value' do
it { is_expected.to be_mandatory_and_blank } it { is_expected.to be_mandatory_and_blank }
@ -95,7 +95,7 @@ describe Champs::LinkedDropDownListChamp do
end end
context 'when there is nothing to select for the secondary value' do context 'when there is nothing to select for the secondary value' do
let(:drop_down_list) { build(:drop_down_list, value: "--A--\nAbbott\nAbelard\n--B--\n--C--\nCynthia") } let(:value) { "--A--\nAbbott\nAbelard\n--B--\n--C--\nCynthia" }
before { subject.primary_value = 'B' } before { subject.primary_value = 'B' }
it { is_expected.not_to be_mandatory_and_blank } it { is_expected.not_to be_mandatory_and_blank }

View file

@ -1,41 +0,0 @@
describe DropDownList do
let(:dropdownlist) { create :drop_down_list, value: value }
describe '#options' do
let(:value) do
<<~EOS
Cohésion sociale
Dév.Eco / Emploi
Cadre de vie / Urb.
Pilotage / Ingénierie
EOS
end
it { expect(dropdownlist.options).to eq ['', 'Cohésion sociale', 'Dév.Eco / Emploi', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] }
context 'when one value is empty' do
let(:value) do
<<~EOS
Cohésion sociale
Cadre de vie / Urb.
Pilotage / Ingénierie
EOS
end
it { expect(dropdownlist.options).to eq ['', 'Cohésion sociale', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] }
end
end
describe 'disabled_options' do
let(:value) do
<<~EOS
tip
--top--
--troupt--
ouaich
EOS
end
it { expect(dropdownlist.disabled_options).to match(['--top--', '--troupt--']) }
end
end

View file

@ -187,4 +187,44 @@ shared_examples 'type_de_champ_spec' do
end end
end end
end end
describe '#drop_down_list_options' do
let(:value) do
<<~EOS
Cohésion sociale
Dév.Eco / Emploi
Cadre de vie / Urb.
Pilotage / Ingénierie
EOS
end
let(:type_de_champ) { create(:type_de_champ_drop_down_list, drop_down_list_value: value) }
it { expect(type_de_champ.drop_down_list_options).to eq ['', 'Cohésion sociale', 'Dév.Eco / Emploi', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] }
context 'when one value is empty' do
let(:value) do
<<~EOS
Cohésion sociale
Cadre de vie / Urb.
Pilotage / Ingénierie
EOS
end
it { expect(type_de_champ.drop_down_list_options).to eq ['', 'Cohésion sociale', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] }
end
end
describe 'disabled_options' do
let(:value) do
<<~EOS
tip
--top--
--troupt--
ouaich
EOS
end
let(:type_de_champ) { create(:type_de_champ_drop_down_list, drop_down_list_value: value) }
it { expect(type_de_champ.drop_down_list_disabled_options).to match(['--top--', '--troupt--']) }
end
end end

View file

@ -1,6 +1,5 @@
describe TypesDeChamp::LinkedDropDownListTypeDeChamp do describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
let(:drop_down_list) { build(:drop_down_list, value: menu_options) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list_value: menu_options) }
let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) }
subject { type_de_champ.dynamic_type } subject { type_de_champ.dynamic_type }