Merge branch 'dev'

This commit is contained in:
gregoirenovel 2018-09-25 16:17:15 +02:00
commit a05a129c76
40 changed files with 332 additions and 181 deletions

View file

@ -424,3 +424,16 @@ $cta-panel-button-border-size: 2px;
text-decoration: none; text-decoration: none;
} }
} }
.tour-de-france-banner {
padding-top: 15px;
padding-bottom: 15px;
background-color: $blue;
color: #FFFFFF;
text-align: center;
a {
color: #FFFFFF;
text-decoration: underline;
}
}

View file

@ -3,22 +3,25 @@ class AutoReceiveDossiersForProcedureJob < ApplicationJob
def perform(procedure_id, state) def perform(procedure_id, state)
procedure = Procedure.find(procedure_id) procedure = Procedure.find(procedure_id)
attrs = case state case state
when Dossier.states.fetch(:en_instruction) when Dossier.states.fetch(:en_instruction)
{ procedure.dossiers.state_en_construction.update_all(
state: Dossier.states.fetch(:en_instruction), state: Dossier.states.fetch(:en_instruction),
en_instruction_at: DateTime.now en_instruction_at: DateTime.now
} )
when Dossier.states.fetch(:accepte) when Dossier.states.fetch(:accepte)
{ procedure.dossiers.state_en_construction.find_each do |dossier|
state: Dossier.states.fetch(:accepte), dossier.update(
en_instruction_at: DateTime.now, state: Dossier.states.fetch(:accepte),
processed_at: DateTime.now en_instruction_at: DateTime.now,
} processed_at: DateTime.now
)
dossier.attestation = dossier.build_attestation
dossier.save
NotificationMailer.send_closed_notification(dossier).deliver_later
end
else else
raise "Receiving Procedure##{procedure_id} in invalid state \"#{state}\"" raise "Receiving Procedure##{procedure_id} in invalid state \"#{state}\""
end end
procedure.dossiers.state_en_construction.update_all(attrs)
end end
end end

View file

@ -1,5 +1,5 @@
class Champs::LinkedDropDownListChamp < Champ class Champs::LinkedDropDownListChamp < Champ
delegate :primary_options, :secondary_options, to: :type_de_champ delegate :primary_options, :secondary_options, to: 'type_de_champ.dynamic_type'
def primary_value def primary_value
if value.present? if value.present?

View file

@ -1,4 +1,7 @@
class TypeDeChamp < ApplicationRecord class TypeDeChamp < ApplicationRecord
# TODO drop next line when `type` column has been dropped from `types_de_champ` table
self.inheritance_column = nil
enum type_champs: { enum type_champs: {
text: 'text', text: 'text',
textarea: 'textarea', textarea: 'textarea',
@ -27,6 +30,10 @@ class TypeDeChamp < ApplicationRecord
belongs_to :procedure belongs_to :procedure
after_initialize :set_dynamic_type
attr_reader :dynamic_type
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, -> { order(order_place: :asc) } scope :ordered, -> { order(order_place: :asc) }
@ -52,6 +59,15 @@ 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? }
def set_dynamic_type
@dynamic_type = type_champ.present? ? self.class.type_champ_to_class_name(type_champ).constantize.new(self) : nil
end
def type_champ=(value)
super(value)
set_dynamic_type
end
def params_for_champ def params_for_champ
{ {
private: private?, private: private?,

View file

@ -1,2 +1,2 @@
class TypesDeChamp::CheckboxTypeDeChamp < TypeDeChamp class TypesDeChamp::CheckboxTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::CiviliteTypeDeChamp < TypeDeChamp class TypesDeChamp::CiviliteTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::DateTypeDeChamp < TypeDeChamp class TypesDeChamp::DateTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::DatetimeTypeDeChamp < TypeDeChamp class TypesDeChamp::DatetimeTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::DossierLinkTypeDeChamp < TypeDeChamp class TypesDeChamp::DossierLinkTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::DropDownListTypeDeChamp < TypeDeChamp class TypesDeChamp::DropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::HeaderSectionTypeDeChamp < TypeDeChamp class TypesDeChamp::HeaderSectionTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,6 +1,8 @@
class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypeDeChamp class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
PRIMARY_PATTERN = /^--(.*)--$/ PRIMARY_PATTERN = /^--(.*)--$/
delegate :drop_down_list, to: :@type_de_champ
def primary_options def primary_options
primary_options = unpack_options.map(&:first) primary_options = unpack_options.map(&:first)
if primary_options.present? if primary_options.present?

View file

@ -1,2 +1,2 @@
class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypeDeChamp class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::NumberTypeDeChamp < TypeDeChamp class TypesDeChamp::NumberTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::PieceJustificativeTypeDeChamp < TypeDeChamp class TypesDeChamp::PieceJustificativeTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::SiretTypeDeChamp < TypeDeChamp class TypesDeChamp::SiretTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -1,2 +1,2 @@
class TypesDeChamp::TextTypeDeChamp < TypeDeChamp class TypesDeChamp::TextTypeDeChamp < TypesDeChamp::TypeDeChampBase
end end

View file

@ -0,0 +1,5 @@
class TypesDeChamp::TypeDeChampBase
def initialize(type_de_champ)
@type_de_champ = type_de_champ
end
end

View file

@ -51,8 +51,6 @@ class DossierFieldService
dossier.user.send(column) dossier.user.send(column)
when 'france_connect_information' when 'france_connect_information'
dossier.user.france_connect_information&.send(column) dossier.user.france_connect_information&.send(column)
when 'entreprise'
dossier.etablissement&.send(:"entreprise_#{column}")
when 'etablissement' when 'etablissement'
dossier.etablissement&.send(column) dossier.etablissement&.send(column)
when 'type_de_champ' when 'type_de_champ'
@ -79,19 +77,19 @@ class DossierFieldService
.includes(relation) .includes(relation)
.where("champs.type_de_champ_id = ?", filter['column'].to_i) .where("champs.type_de_champ_id = ?", filter['column'].to_i)
.where("champs.value ILIKE ?", "%#{filter['value']}%") .where("champs.value ILIKE ?", "%#{filter['value']}%")
when 'entreprise' when 'etablissement'
table = 'etablissement' table = filter['table']
if filter['column'] == 'date_creation' if filter['column'] == 'entreprise_date_creation'
date = filter['value'].to_date rescue nil date = filter['value'].to_date rescue nil
dossiers dossiers
.includes(table) .includes(table)
.where("#{table.pluralize}.entreprise_#{filter['column']} = ?", date) .where("#{table.pluralize}.#{filter['column']} = ?", date)
else else
dossiers dossiers
.includes(table) .includes(table)
.where("#{table.pluralize}.entreprise_#{filter['column']} ILIKE ?", "%#{filter['value']}%") .where("#{table.pluralize}.#{filter['column']} ILIKE ?", "%#{filter['value']}%")
end end
when 'user', 'etablissement' when 'user'
dossiers dossiers
.includes(filter['table']) .includes(filter['table'])
.where("#{filter['table'].pluralize}.#{filter['column']} ILIKE ?", "%#{filter['value']}%") .where("#{filter['table'].pluralize}.#{filter['column']} ILIKE ?", "%#{filter['value']}%")

View file

@ -19,10 +19,6 @@ class TypesDeChampService
parameters[attributes].each do |index, param| parameters[attributes].each do |index, param|
param[:private] = private param[:private] = private
if param[:type_champ]
param[:type] = TypeDeChamp.type_champ_to_class_name(param[:type_champ])
end
if param[:libelle].empty? if param[:libelle].empty?
parameters[attributes].delete(index.to_s) parameters[attributes].delete(index.to_s)
end end

View file

@ -46,7 +46,6 @@
.form-group .form-group
= ff.hidden_field :order_place, value: ff.index = ff.hidden_field :order_place, value: ff.index
= ff.hidden_field :type
= ff.hidden_field :id = ff.hidden_field :id
- if ff.object.id.present? - if ff.object.id.present?

View file

@ -1,6 +1,12 @@
- content_for :footer do - content_for :footer do
= render partial: "root/footer" = render partial: "root/footer"
.tour-de-france-banner
.container
L'équipe demarches-simplifiees.fr vient à votre rencontre cet automne.
= succeed '.' do
= link_to "En savoir plus", tour_de_france_path
.landing .landing
.landing-panel.hero-panel .landing-panel.hero-panel
.container .container

View file

@ -0,0 +1,5 @@
class DropEntreprises < ActiveRecord::Migration[5.2]
def change
drop_table :entreprises
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_09_19_084403) do ActiveRecord::Schema.define(version: 2018_09_24_074121) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -251,25 +251,6 @@ ActiveRecord::Schema.define(version: 2018_09_19_084403) do
t.index ["type_de_champ_id"], name: "index_drop_down_lists_on_type_de_champ_id" t.index ["type_de_champ_id"], name: "index_drop_down_lists_on_type_de_champ_id"
end end
create_table "entreprises", id: :serial, force: :cascade do |t|
t.string "siren"
t.bigint "capital_social"
t.string "numero_tva_intracommunautaire"
t.string "forme_juridique"
t.string "forme_juridique_code"
t.string "nom_commercial"
t.string "raison_sociale"
t.string "siret_siege_social"
t.string "code_effectif_entreprise"
t.datetime "date_creation"
t.string "nom"
t.string "prenom"
t.integer "dossier_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["dossier_id"], name: "index_entreprises_on_dossier_id"
end
create_table "etablissements", id: :serial, force: :cascade do |t| create_table "etablissements", id: :serial, force: :cascade do |t|
t.string "siret" t.string "siret"
t.boolean "siege_social" t.boolean "siege_social"

View file

@ -15,7 +15,7 @@ namespace :'2018_05_14_add_annotation_privee_to_procedure' do
tdc.update_attribute(:order_place, tdc.order_place + 1) tdc.update_attribute(:order_place, tdc.order_place + 1)
end end
new_tdc = TypesDeChamp::TextTypeDeChamp.create( new_tdc = TypeDeChamp.create(
procedure_id: procedure_id, procedure_id: procedure_id,
private: true, private: true,
libelle: 'URL Espace de consultation', libelle: 'URL Espace de consultation',

View file

@ -34,7 +34,7 @@ namespace :'2018_07_31_nutriscore' do
end end
discard_source_champ( discard_source_champ(
TypesDeChamp::TextTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'text', type_champ: 'text',
order_place: siret_order_place, order_place: siret_order_place,
libelle: 'Numéro SIRET' libelle: 'Numéro SIRET'
@ -42,7 +42,7 @@ namespace :'2018_07_31_nutriscore' do
) )
discard_source_champ( discard_source_champ(
TypesDeChamp::TextTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'text', type_champ: 'text',
order_place: fonction_order_place, order_place: fonction_order_place,
libelle: 'Fonction' libelle: 'Fonction'
@ -50,7 +50,7 @@ namespace :'2018_07_31_nutriscore' do
) )
compute_destination_champ( compute_destination_champ(
TypesDeChamp::TextTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'text', type_champ: 'text',
order_place: fonction_order_place, order_place: fonction_order_place,
libelle: 'Fonction', libelle: 'Fonction',
@ -66,7 +66,7 @@ namespace :'2018_07_31_nutriscore' do
end end
compute_destination_champ( compute_destination_champ(
TypesDeChamp::SiretTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'siret', type_champ: 'siret',
order_place: siret_order_place, order_place: siret_order_place,
libelle: 'Numéro SIRET' libelle: 'Numéro SIRET'
@ -80,7 +80,7 @@ namespace :'2018_07_31_nutriscore' do
end end
compute_destination_champ( compute_destination_champ(
TypesDeChamp::HeaderSectionTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'header_section', type_champ: 'header_section',
order_place: 18, order_place: 18,
libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE' libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE'
@ -90,7 +90,7 @@ namespace :'2018_07_31_nutriscore' do
end end
compute_destination_champ( compute_destination_champ(
TypesDeChamp::MultipleDropDownListTypeDeChamp.new( TypeDeChamp.new(
type_champ: 'multiple_drop_down_list', type_champ: 'multiple_drop_down_list',
order_place: 19, order_place: 19,
libelle: 'Pays de commercialisation', libelle: 'Pays de commercialisation',

View file

@ -0,0 +1,51 @@
namespace :'2018_09_20_procedure_presentation_entreprise' do
task run: :environment do
Class.new do
def run
fix_displayed_fields
fix_sort
fix_filters
end
def fix_displayed_fields
ProcedurePresentation.where(%q`displayed_fields @> '[{"table": "entreprise"}]'`).each do |procedure_presentation|
procedure_presentation.displayed_fields.each { |field| entreprise_to_etablissement(field) }
procedure_presentation.save
end
end
def fix_sort
ProcedurePresentation.where(%q`sort @> '{"table": "entreprise"}'`).each do |procedure_presentation|
entreprise_to_etablissement(procedure_presentation['sort'])
procedure_presentation.save
end
end
def fix_filters
ProcedurePresentation.find_by_sql(
<<~SQL
SELECT procedure_presentations.*, array_agg(key) as keys
FROM procedure_presentations, LATERAL jsonb_each(filters)
WHERE value @> '[{"table": "entreprise"}]'
GROUP BY id;
SQL
).each do |procedure_presentation|
procedure_presentation.keys.each do |key|
procedure_presentation.filters[key].each { |filter| entreprise_to_etablissement(filter) }
end
procedure_presentation.save
end
end
def entreprise_to_etablissement(field)
if field['table'] == 'entreprise'
field['table'] = 'etablissement'
field['column'] = "entreprise_#{field['column']}"
end
end
end.new.run
end
end

View file

@ -57,7 +57,7 @@ module Tasks
def type_de_champ_to_expectation(tdc) def type_de_champ_to_expectation(tdc)
if tdc.present? if tdc.present?
expectation = tdc.as_json(only: [:libelle, :type, :type_champ, :mandatory]) expectation = tdc.as_json(only: [:libelle, :type_champ, :mandatory])
expectation['drop_down'] = tdc.drop_down_list.presence&.options&.presence expectation['drop_down'] = tdc.drop_down_list.presence&.options&.presence
expectation expectation
else else
@ -107,9 +107,6 @@ module Tasks
if actual_tdc.libelle != expected_tdc['libelle'] if actual_tdc.libelle != expected_tdc['libelle']
errors.append("incorrect libelle #{actual_tdc.libelle} (expected #{expected_tdc['libelle']})") errors.append("incorrect libelle #{actual_tdc.libelle} (expected #{expected_tdc['libelle']})")
end end
if actual_tdc.type != expected_tdc['type']
errors.append("incorrect type #{actual_tdc.type} (expected #{expected_tdc['type']})")
end
if actual_tdc.type_champ != expected_tdc['type_champ'] if actual_tdc.type_champ != expected_tdc['type_champ']
errors.append("incorrect type champ #{actual_tdc.type_champ} (expected #{expected_tdc['type_champ']})") errors.append("incorrect type champ #{actual_tdc.type_champ} (expected #{expected_tdc['type_champ']})")
end end

View file

@ -22,6 +22,14 @@ FactoryBot.define do
end end
end end
factory :simple_procedure do
after(:build) do |procedure, _evaluator|
procedure.for_individual = true
procedure.types_de_champ << create(:type_de_champ, libelle: 'Texte obligatoire', mandatory: true)
procedure.publish!(generate(:published_path))
end
end
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
if procedure.module_api_carto.nil? if procedure.module_api_carto.nil?
module_api_carto = create(:module_api_carto) module_api_carto = create(:module_api_carto)

View file

@ -1,5 +1,5 @@
FactoryBot.define do FactoryBot.define do
factory :type_de_champ, class: 'TypesDeChamp::TextTypeDeChamp' do factory :type_de_champ do
private { false } private { false }
# Previous line is kept blank so that rubocop does not complain # Previous line is kept blank so that rubocop does not complain
@ -9,79 +9,79 @@ FactoryBot.define do
order_place { 1 } order_place { 1 }
mandatory { false } mandatory { false }
factory :type_de_champ_text, class: 'TypesDeChamp::TextTypeDeChamp' do factory :type_de_champ_text do
type_champ { TypeDeChamp.type_champs.fetch(:text) } type_champ { TypeDeChamp.type_champs.fetch(:text) }
end end
factory :type_de_champ_textarea, class: 'TypesDeChamp::TextareaTypeDeChamp' do factory :type_de_champ_textarea do
type_champ { TypeDeChamp.type_champs.fetch(:textarea) } type_champ { TypeDeChamp.type_champs.fetch(:textarea) }
end end
factory :type_de_champ_number, class: 'TypesDeChamp::NumberTypeDeChamp' do factory :type_de_champ_number do
type_champ { TypeDeChamp.type_champs.fetch(:number) } type_champ { TypeDeChamp.type_champs.fetch(:number) }
end end
factory :type_de_champ_checkbox, class: 'TypesDeChamp::CheckboxTypeDeChamp' do factory :type_de_champ_checkbox do
type_champ { TypeDeChamp.type_champs.fetch(:checkbox) } type_champ { TypeDeChamp.type_champs.fetch(:checkbox) }
end end
factory :type_de_champ_civilite, class: 'TypesDeChamp::CiviliteTypeDeChamp' do factory :type_de_champ_civilite do
type_champ { TypeDeChamp.type_champs.fetch(:civilite) } type_champ { TypeDeChamp.type_champs.fetch(:civilite) }
end end
factory :type_de_champ_email, class: 'TypesDeChamp::EmailTypeDeChamp' do factory :type_de_champ_email do
type_champ { TypeDeChamp.type_champs.fetch(:email) } type_champ { TypeDeChamp.type_champs.fetch(:email) }
end end
factory :type_de_champ_phone, class: 'TypesDeChamp::PhoneTypeDeChamp' do factory :type_de_champ_phone do
type_champ { TypeDeChamp.type_champs.fetch(:phone) } type_champ { TypeDeChamp.type_champs.fetch(:phone) }
end end
factory :type_de_champ_address, class: 'TypesDeChamp::AddressTypeDeChamp' do factory :type_de_champ_address do
type_champ { TypeDeChamp.type_champs.fetch(:address) } type_champ { TypeDeChamp.type_champs.fetch(:address) }
end end
factory :type_de_champ_yes_no, class: 'TypesDeChamp::YesNoTypeDeChamp' do factory :type_de_champ_yes_no do
libelle { 'Yes/no' } libelle { 'Yes/no' }
type_champ { TypeDeChamp.type_champs.fetch(:yes_no) } type_champ { TypeDeChamp.type_champs.fetch(:yes_no) }
end end
factory :type_de_champ_date, class: 'TypesDeChamp::DateTypeDeChamp' do factory :type_de_champ_date do
type_champ { TypeDeChamp.type_champs.fetch(:date) } type_champ { TypeDeChamp.type_champs.fetch(:date) }
end end
factory :type_de_champ_datetime, class: 'TypesDeChamp::DatetimeTypeDeChamp' do factory :type_de_champ_datetime do
type_champ { TypeDeChamp.type_champs.fetch(:datetime) } type_champ { TypeDeChamp.type_champs.fetch(:datetime) }
end end
factory :type_de_champ_drop_down_list, class: 'TypesDeChamp::DropDownListTypeDeChamp' 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 { create(:drop_down_list) }
end end
factory :type_de_champ_multiple_drop_down_list, class: 'TypesDeChamp::MultipleDropDownListTypeDeChamp' 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 { create(:drop_down_list) }
end end
factory :type_de_champ_linked_drop_down_list, class: 'TypesDeChamp::LinkedDropDownListTypeDeChamp' 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) } drop_down_list { create(:drop_down_list) }
end end
factory :type_de_champ_pays, class: 'TypesDeChamp::PaysTypeDeChamp' do factory :type_de_champ_pays do
type_champ { TypeDeChamp.type_champs.fetch(:pays) } type_champ { TypeDeChamp.type_champs.fetch(:pays) }
end end
factory :type_de_champ_regions, class: 'TypesDeChamp::RegionTypeDeChamp' do factory :type_de_champ_regions do
type_champ { TypeDeChamp.type_champs.fetch(:regions) } type_champ { TypeDeChamp.type_champs.fetch(:regions) }
end end
factory :type_de_champ_departements, class: 'TypesDeChamp::DepartementTypeDeChamp' do factory :type_de_champ_departements do
type_champ { TypeDeChamp.type_champs.fetch(:departements) } type_champ { TypeDeChamp.type_champs.fetch(:departements) }
end end
factory :type_de_champ_engagement, class: 'TypesDeChamp::EngagementTypeDeChamp' do factory :type_de_champ_engagement do
type_champ { TypeDeChamp.type_champs.fetch(:engagement) } type_champ { TypeDeChamp.type_champs.fetch(:engagement) }
end end
factory :type_de_champ_header_section, class: 'TypesDeChamp::HeaderSectionTypeDeChamp' do factory :type_de_champ_header_section do
type_champ { TypeDeChamp.type_champs.fetch(:header_section) } type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
end end
factory :type_de_champ_explication, class: 'TypesDeChamp::ExplicationTypeDeChamp' do factory :type_de_champ_explication do
type_champ { TypeDeChamp.type_champs.fetch(:explication) } type_champ { TypeDeChamp.type_champs.fetch(:explication) }
end end
factory :type_de_champ_dossier_link, class: 'TypesDeChamp::DossierLinkTypeDeChamp' do factory :type_de_champ_dossier_link do
libelle { 'Référence autre dossier' } libelle { 'Référence autre dossier' }
type_champ { TypeDeChamp.type_champs.fetch(:dossier_link) } type_champ { TypeDeChamp.type_champs.fetch(:dossier_link) }
end end
factory :type_de_champ_piece_justificative, class: 'TypesDeChamp::PieceJustificativeTypeDeChamp' do factory :type_de_champ_piece_justificative do
type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) } type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) }
end end
factory :type_de_champ_siret, class: 'TypesDeChamp::SiretTypeDeChamp' do factory :type_de_champ_siret do
type_champ { TypeDeChamp.type_champs.fetch(:siret) } type_champ { TypeDeChamp.type_champs.fetch(:siret) }
end end

View file

@ -1,18 +1,16 @@
require 'features/new_user/dossier_shared_examples.rb'
describe 'Dossier details:' do describe 'Dossier details:' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:simple_procedure) do let(:procedure) { create(:simple_procedure) }
tdcs = [create(:type_de_champ, libelle: 'texte obligatoire')] let(:dossier) { create(:dossier, :en_construction, :for_individual, :with_commentaires, user: user, procedure: procedure) }
create(:procedure, :published, :for_individual, types_de_champ: tdcs)
end
let(:dossier) { create(:dossier, :en_construction, :for_individual, :with_commentaires, user: user, procedure: simple_procedure) }
before do before do
Flipflop::FeatureSet.current.test!.switch!(:new_dossier_details, true) Flipflop::FeatureSet.current.test!.switch!(:new_dossier_details, true)
visit_dossier dossier
end end
scenario 'the user can see the summary of the dossier status' do scenario 'the user can see the summary of the dossier status' do
visit_dossier dossier
expect(page).to have_current_path(dossier_path(dossier)) expect(page).to have_current_path(dossier_path(dossier))
expect(page).to have_content(dossier.id) expect(page).to have_content(dossier.id)
expect(page).to have_selector('.status-explanation') expect(page).to have_selector('.status-explanation')
@ -20,68 +18,29 @@ describe 'Dossier details:' do
end end
describe "the user can see the mean time they are expected to wait" do describe "the user can see the mean time they are expected to wait" do
context "the dossier is in construction" do context "when the dossier is in construction" do
before do before do
other_dossier = create(:dossier, :accepte, :for_individual, procedure: simple_procedure, en_construction_at: 10.days.ago, en_instruction_at: Time.now) other_dossier = create(:dossier, :accepte, :for_individual, procedure: procedure, en_construction_at: 10.days.ago, en_instruction_at: Time.now)
visit dossier_path(dossier)
end end
it "show the proper wait time" do it { expect(page).to have_text("Le temps moyen de vérification pour cette démarche est de 10 jours.") }
visit_dossier dossier
expect(page).to have_text("Le temps moyen de vérification pour cette démarche est de 10 jours.")
end
end end
context "the dossier is in instruction" do context "when the dossier is in instruction" do
let(:dossier) { create(:dossier, :en_instruction, :for_individual, :with_commentaires, user: user, procedure: simple_procedure) } let(:dossier) { create(:dossier, :en_instruction, :for_individual, :with_commentaires, user: user, procedure: procedure) }
before do before do
other_dossier = create(:dossier, :accepte, :for_individual, procedure: simple_procedure, en_instruction_at: 2.months.ago, processed_at: Time.now) other_dossier = create(:dossier, :accepte, :for_individual, procedure: procedure, en_instruction_at: 2.months.ago, processed_at: Time.now)
visit dossier_path(dossier)
end end
it "show the proper wait time" do it { expect(page).to have_text("Le temps moyen dinstruction pour cette démarche est de 2 mois.") }
visit_dossier dossier
expect(page).to have_text("Le temps moyen dinstruction pour cette démarche est de 2 mois.")
end
end end
end end
scenario 'the user can see and edit dossier before instruction' do it_behaves_like 'the user can edit the submitted demande'
visit_dossier dossier it_behaves_like 'the user can send messages to the instructeur'
click_on 'Demande'
expect(page).to have_current_path(demande_dossier_path(dossier))
click_on 'Modifier le dossier'
expect(page).to have_current_path(modifier_dossier_path(dossier))
fill_in('texte obligatoire', with: 'Nouveau texte')
click_on 'Enregistrer les modifications du dossier'
expect(page).to have_current_path(demande_dossier_path(dossier))
expect(page).to have_content('Nouveau texte')
end
context 'with messages' do
let!(:commentaire) { create(:commentaire, dossier: dossier, email: 'instructeur@exemple.fr', body: 'Message envoyé à lusager') }
let(:message_body) { 'Message envoyé à linstructeur' }
scenario 'the user can send a message' do
visit_dossier dossier
click_on 'Messagerie'
expect(page).to have_current_path(messagerie_dossier_path(dossier))
expect(page).to have_content(commentaire.body)
fill_in 'commentaire_body', with: message_body
click_on 'Envoyer'
expect(page).to have_current_path(messagerie_dossier_path(dossier))
expect(page).to have_content('Message envoyé')
expect(page).to have_content(commentaire.body)
expect(page).to have_content(message_body)
end
end
private private

View file

@ -0,0 +1,41 @@
RSpec.shared_examples 'the user can edit the submitted demande' do
scenario js: true do
visit dossier_path(dossier)
expect(page).to have_current_path(dossier_path(dossier))
click_on 'Demande'
expect(page).to have_current_path(demande_dossier_path(dossier))
click_on 'Modifier le dossier'
expect(page).to have_current_path(modifier_dossier_path(dossier))
fill_in('Texte obligatoire', with: 'Nouveau texte')
click_on 'Enregistrer les modifications du dossier'
expect(page).to have_current_path(demande_dossier_path(dossier))
expect(page).to have_content('Nouveau texte')
end
end
RSpec.shared_examples 'the user can send messages to the instructeur' do
let!(:commentaire) { create(:commentaire, dossier: dossier, email: 'instructeur@exemple.fr', body: 'Message envoyé à lusager') }
let(:message_body) { 'Message envoyé à linstructeur' }
scenario js: true do
visit dossier_path(dossier)
expect(page).to have_current_path(dossier_path(dossier))
click_on 'Messagerie'
expect(page).to have_current_path(messagerie_dossier_path(dossier))
expect(page).to have_content(commentaire.body)
fill_in 'commentaire_body', with: message_body
click_on 'Envoyer'
expect(page).to have_current_path(messagerie_dossier_path(dossier))
expect(page).to have_content('Message envoyé')
expect(page).to have_content(commentaire.body)
expect(page).to have_content(message_body)
end
end

View file

@ -1,19 +1,20 @@
require 'spec_helper' require 'spec_helper'
require 'features/new_user/dossier_shared_examples.rb'
feature 'Invitations' do feature 'Invitations' do
let(:user) { create(:user) } let(:owner) { create(:user) }
let(:invited_user) { create(:user, email: 'user_invite@exemple.fr') } let(:invited_user) { create(:user, email: 'user_invite@exemple.fr') }
let(:procedure) { create(:procedure, :published, :with_type_de_champ) } let(:procedure) { create(:simple_procedure) }
let(:invite) { create(:invite_user, user: invited_user, dossier: dossier) } let(:invite) { create(:invite_user, user: invited_user, dossier: dossier) }
context 'when the dossier is a brouillon' do context 'when the dossier is a brouillon' do
let!(:dossier) { create(:dossier, :for_individual, state: Dossier.states.fetch(:brouillon), user: user, procedure: procedure) } let!(:dossier) { create(:dossier, :for_individual, state: Dossier.states.fetch(:brouillon), user: owner, procedure: procedure) }
scenario 'on the form, a user can invite another user to collaborate on the dossier', js: true do scenario 'on the form, the owner of a dossier can invite another user to collaborate on the dossier', js: true do
log_in(user) log_in(owner)
navigate_to_brouillon(dossier) navigate_to_brouillon(dossier)
fill_in 'Libelle du champ', with: 'Some edited value' fill_in 'Texte obligatoire', with: 'Some edited value'
send_invite_to "user_invite@exemple.fr" send_invite_to "user_invite@exemple.fr"
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
@ -21,7 +22,7 @@ feature 'Invitations' do
expect(page).to have_text("user_invite@exemple.fr") expect(page).to have_text("user_invite@exemple.fr")
# Ensure unsaved edits to the form are not lost # Ensure unsaved edits to the form are not lost
expect(page).to have_field('Libelle du champ', with: 'Some edited value') expect(page).to have_field('Texte obligatoire', with: 'Some edited value')
end end
context 'when inviting someone without an existing account' do context 'when inviting someone without an existing account' do
@ -51,24 +52,19 @@ feature 'Invitations' do
end end
scenario 'an invited user can see and edit the draft', js: true do scenario 'an invited user can see and edit the draft', js: true do
visit users_dossiers_invite_path(invite) navigate_to_invited_dossier(invite)
expect(page).to have_current_path(new_user_session_path)
submit_login_form(invited_user.email, invited_user.password)
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
expect(page).to have_no_selector('.button.invite-user-action') expect(page).to have_no_selector('.button.invite-user-action')
fill_in 'Libelle du champ', with: 'Some edited value' fill_in 'Texte obligatoire', with: 'Some edited value'
click_button 'Enregistrer le brouillon' click_button 'Enregistrer le brouillon'
expect(page).to have_text('Votre brouillon a bien été sauvegardé') expect(page).to have_text('Votre brouillon a bien été sauvegardé')
expect(page).to have_field('Libelle du champ', with: 'Some edited value') expect(page).to have_field('Texte obligatoire', with: 'Some edited value')
end end
scenario 'an invited user cannot submit the draft' do scenario 'an invited user cannot submit the draft' do
visit users_dossiers_invite_path(invite) navigate_to_invited_dossier(invite)
expect(page).to have_current_path(new_user_session_path)
submit_login_form(invited_user.email, invited_user.password)
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
expect(page).to have_button('Soumettre le dossier', disabled: true) expect(page).to have_button('Soumettre le dossier', disabled: true)
@ -77,10 +73,39 @@ feature 'Invitations' do
end end
context 'when the dossier is en_construction' do context 'when the dossier is en_construction' do
let!(:dossier) { create(:dossier, :for_individual, :en_construction, user: user, procedure: procedure) } let!(:dossier) { create(:dossier, :for_individual, :en_construction, user: owner, procedure: procedure) }
before do
Flipflop::FeatureSet.current.test!.switch!(:new_dossier_details, true)
end
scenario 'on dossier details, the owner of a dossier can invite another user to collaborate on the dossier', js: true do
log_in(owner)
navigate_to_dossier(dossier)
send_invite_to "user_invite@exemple.fr"
expect(page).to have_current_path(dossier_path(dossier))
expect(page).to have_text("Une invitation a été envoyée à user_invite@exemple.fr.")
expect(page).to have_text("user_invite@exemple.fr")
end
context 'as an invited user' do
before do
navigate_to_invited_dossier(invite)
expect(page).to have_current_path(dossier_path(invite.dossier))
end
it_behaves_like 'the user can edit the submitted demande'
it_behaves_like 'the user can send messages to the instructeur'
end
end
context 'when the dossier is en_construction (legacy UI)' do
let!(:dossier) { create(:dossier, :for_individual, :en_construction, user: owner, procedure: procedure) }
scenario 'on dossier details, a user can invite another user to collaborate on the dossier', js: true do scenario 'on dossier details, a user can invite another user to collaborate on the dossier', js: true do
log_in(user) log_in(owner)
navigate_to_recapitulatif(dossier) navigate_to_recapitulatif(dossier)
legacy_send_invite_to "user_invite@exemple.fr" legacy_send_invite_to "user_invite@exemple.fr"
@ -105,7 +130,7 @@ feature 'Invitations' do
visit brouillon_dossier_path(dossier) visit brouillon_dossier_path(dossier)
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
fill_in "Libelle du champ", with: "Some edited value" fill_in "Texte obligatoire", with: "Some edited value"
click_button "Enregistrer les modifications du dossier" click_button "Enregistrer les modifications du dossier"
expect(page).to have_current_path(users_dossiers_invite_path(invite)) expect(page).to have_current_path(users_dossiers_invite_path(invite))
@ -134,6 +159,18 @@ feature 'Invitations' do
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
end end
def navigate_to_dossier(dossier)
expect(page).to have_current_path(dossiers_path)
click_on(dossier.id)
expect(page).to have_current_path(dossier_path(dossier))
end
def navigate_to_invited_dossier(invite)
visit users_dossiers_invite_path(invite)
expect(page).to have_current_path(new_user_session_path)
submit_login_form(invited_user.email, invited_user.password)
end
def navigate_to_recapitulatif(dossier) def navigate_to_recapitulatif(dossier)
expect(page).to have_current_path(dossiers_path) expect(page).to have_current_path(dossiers_path)
click_on(dossier.id) click_on(dossier.id)

View file

@ -7,6 +7,7 @@ RSpec.describe AutoReceiveDossiersForProcedureJob, type: :job do
before do before do
Timecop.freeze(date) Timecop.freeze(date)
create(:attestation_template, procedure: nouveau_dossier1.procedure)
AutoReceiveDossiersForProcedureJob.new.perform(procedure_id, state) AutoReceiveDossiersForProcedureJob.new.perform(procedure_id, state)
end end
@ -41,10 +42,12 @@ RSpec.describe AutoReceiveDossiersForProcedureJob, type: :job do
it { expect(nouveau_dossier1.reload.accepte?).to be true } it { expect(nouveau_dossier1.reload.accepte?).to be true }
it { expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) } it { expect(nouveau_dossier1.reload.en_instruction_at).to eq(date) }
it { expect(nouveau_dossier1.reload.processed_at).to eq(date) } it { expect(nouveau_dossier1.reload.processed_at).to eq(date) }
it { expect(nouveau_dossier1.reload.attestation).to be_present }
it { expect(nouveau_dossier2.reload.accepte?).to be true } it { expect(nouveau_dossier2.reload.accepte?).to be true }
it { expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) } it { expect(nouveau_dossier2.reload.en_instruction_at).to eq(date) }
it { expect(nouveau_dossier2.reload.processed_at).to eq(date) } it { expect(nouveau_dossier2.reload.processed_at).to eq(date) }
it { expect(nouveau_dossier2.reload.attestation).to be_present }
it { expect(dossier_recu.reload.en_instruction?).to be true } it { expect(dossier_recu.reload.en_instruction?).to be true }
it { expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) } it { expect(dossier_recu.reload.en_instruction_at).to eq(instruction_date) }

View file

@ -3,7 +3,7 @@ describe '2018_05_14_add_annotation_privee_to_procedure' do
let!(:procedure) do let!(:procedure) do
procedure = create(:procedure) procedure = create(:procedure)
10.times do |i| 10.times do |i|
TypesDeChamp::NumberTypeDeChamp.create( TypeDeChamp.create(
procedure: procedure, procedure: procedure,
private: false, private: false,
libelle: 'libelle', libelle: 'libelle',
@ -11,7 +11,7 @@ describe '2018_05_14_add_annotation_privee_to_procedure' do
type_champ: 'number' type_champ: 'number'
) )
TypesDeChamp::NumberTypeDeChamp.create( TypeDeChamp.create(
procedure: procedure, procedure: procedure,
private: true, private: true,
libelle: 'libelle', libelle: 'libelle',

View file

@ -95,7 +95,7 @@ describe '2018_07_31_nutriscore' do
context 'with champ type mismatch' do context 'with champ type mismatch' do
let!(:type_champ_to) { create(:type_de_champ_text, order_place: 1, libelle: 'texte', procedure: proc_to) } let!(:type_champ_to) { create(:type_de_champ_text, order_place: 1, libelle: 'texte', procedure: proc_to) }
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) } it { expect { run_task }.to raise_exception(/incorrect type champ textarea \(expected text\)$/) }
end end
context 'with champ mandatoriness mismatch' do context 'with champ mandatoriness mismatch' do
@ -114,13 +114,13 @@ describe '2018_07_31_nutriscore' do
context 'with siret mismatch on source' do context 'with siret mismatch on source' do
let!(:type_champ_siret_from) { create(:type_de_champ_textarea, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_from) } let!(:type_champ_siret_from) { create(:type_de_champ_textarea, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_from) }
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextareaTypeDeChamp \(expected TypesDeChamp::TextTypeDeChamp\), incorrect type champ textarea \(expected text\)$/) } it { expect { run_task }.to raise_exception(/incorrect type champ textarea \(expected text\)$/) }
end end
context 'with siret mismatch on destination' do context 'with siret mismatch on destination' do
let!(:type_champ_siret_to) { create(:type_de_champ_text, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_to) } let!(:type_champ_siret_to) { create(:type_de_champ_text, order_place: 2, libelle: 'Numéro SIRET', procedure: proc_to) }
it { expect { run_task }.to raise_exception(/incorrect type TypesDeChamp::TextTypeDeChamp \(expected TypesDeChamp::SiretTypeDeChamp\), incorrect type champ text \(expected siret\)$/) } it { expect { run_task }.to raise_exception(/incorrect type champ text \(expected siret\)$/) }
end end
end end
end end

View file

@ -750,7 +750,7 @@ describe Dossier do
it { expect(dossier.get_value('self', 'created_at')).to eq(dossier.created_at) } it { expect(dossier.get_value('self', 'created_at')).to eq(dossier.created_at) }
it { expect(dossier.get_value('user', 'email')).to eq(user.email) } it { expect(dossier.get_value('user', 'email')).to eq(user.email) }
it { expect(dossier.get_value('france_connect_information', 'gender')).to eq(user.france_connect_information.gender) } it { expect(dossier.get_value('france_connect_information', 'gender')).to eq(user.france_connect_information.gender) }
it { expect(dossier.get_value('entreprise', 'siren')).to eq(dossier.etablissement.entreprise_siren) } it { expect(dossier.get_value('etablissement', 'entreprise_siren')).to eq(dossier.etablissement.entreprise_siren) }
it { expect(dossier.get_value('etablissement', 'siret')).to eq(dossier.etablissement.siret) } it { expect(dossier.get_value('etablissement', 'siret')).to eq(dossier.etablissement.siret) }
it { expect(dossier.get_value('type_de_champ', @champ_public.type_de_champ.id.to_s)).to eq(dossier.champs.first.value) } it { expect(dossier.get_value('type_de_champ', @champ_public.type_de_champ.id.to_s)).to eq(dossier.champs.first.value) }
it { expect(dossier.get_value('type_de_champ_private', @champ_private.type_de_champ.id.to_s)).to eq(dossier.champs_private.first.value) } it { expect(dossier.get_value('type_de_champ_private', @champ_private.type_de_champ.id.to_s)).to eq(dossier.champs_private.first.value) }

View file

@ -21,7 +21,7 @@ shared_examples 'type_de_champ_spec' do
type_de_champ = create(:"type_de_champ_#{type_champ}") type_de_champ = create(:"type_de_champ_#{type_champ}")
champ = type_de_champ.champ.create champ = type_de_champ.champ.create
expect(type_de_champ.class.name).to match(/^TypesDeChamp::/) expect(type_de_champ.dynamic_type.class.name).to match(/^TypesDeChamp::/)
expect(champ.class.name).to match(/^Champs::/) expect(champ.class.name).to match(/^Champs::/)
end end
end end

View file

@ -3,12 +3,14 @@ require 'spec_helper'
describe TypesDeChamp::LinkedDropDownListTypeDeChamp do describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
describe '#unpack_options' do describe '#unpack_options' do
let(:drop_down_list) { build(:drop_down_list, value: menu_options) } let(:drop_down_list) { build(:drop_down_list, value: menu_options) }
let(:type_de_champ) { described_class.new(drop_down_list: drop_down_list) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) }
subject { type_de_champ.dynamic_type }
context 'with no options' do context 'with no options' do
let(:menu_options) { '' } let(:menu_options) { '' }
it { expect(type_de_champ.secondary_options).to eq({}) } it { expect(subject.secondary_options).to eq({}) }
it { expect(type_de_champ.primary_options).to eq([]) } it { expect(subject.primary_options).to eq([]) }
end end
context 'with two primary options' do context 'with two primary options' do
@ -25,7 +27,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
end end
it do it do
expect(type_de_champ.secondary_options).to eq( expect(subject.secondary_options).to eq(
{ {
'' => [], '' => [],
'Primary 1' => [ '', 'secondary 1.1', 'secondary 1.2'], 'Primary 1' => [ '', 'secondary 1.1', 'secondary 1.2'],
@ -34,7 +36,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
) )
end end
it { expect(type_de_champ.primary_options).to eq([ '', 'Primary 1', 'Primary 2' ]) } it { expect(subject.primary_options).to eq([ '', 'Primary 1', 'Primary 2' ]) }
end end
end end
end end

View file

@ -0,0 +1,29 @@
require 'spec_helper'
describe DossierFieldService do
describe '#filtered_ids' do
let(:procedure) { create(:procedure) }
context 'for etablissement table' do
context 'for entreprise_date_creation column' do
let!(:kept_dossier) { create(:dossier, procedure: procedure, etablissement: create(:etablissement, entreprise_date_creation: DateTime.new(2018, 6, 21))) }
let!(:discarded_dossier) { create(:dossier, procedure: procedure, etablissement: create(:etablissement, entreprise_date_creation: DateTime.new(2008, 6, 21))) }
subject { described_class.filtered_ids(procedure.dossiers, [{ 'table' => 'etablissement', 'column' => 'entreprise_date_creation', 'value' => '21/6/2018' }]) }
it { is_expected.to contain_exactly(kept_dossier.id) }
end
context 'for code_postal column' do
# All columns except entreprise_date_creation work exacly the same, just testing one
let!(:kept_dossier) { create(:dossier, procedure: procedure, etablissement: create(:etablissement, code_postal: '75017')) }
let!(:discarded_dossier) { create(:dossier, procedure: procedure, etablissement: create(:etablissement, code_postal: '25000')) }
subject { described_class.filtered_ids(procedure.dossiers, [{ 'table' => 'etablissement', 'column' => 'code_postal', 'value' => '75017' }]) }
it { is_expected.to contain_exactly(kept_dossier.id) }
end
end
end
end