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;
}
}
.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)
procedure = Procedure.find(procedure_id)
attrs = case state
case state
when Dossier.states.fetch(:en_instruction)
{
procedure.dossiers.state_en_construction.update_all(
state: Dossier.states.fetch(:en_instruction),
en_instruction_at: DateTime.now
}
)
when Dossier.states.fetch(:accepte)
{
state: Dossier.states.fetch(:accepte),
en_instruction_at: DateTime.now,
processed_at: DateTime.now
}
procedure.dossiers.state_en_construction.find_each do |dossier|
dossier.update(
state: Dossier.states.fetch(:accepte),
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
raise "Receiving Procedure##{procedure_id} in invalid state \"#{state}\""
end
procedure.dossiers.state_en_construction.update_all(attrs)
end
end

View file

@ -1,5 +1,5 @@
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
if value.present?

View file

@ -1,4 +1,7 @@
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: {
text: 'text',
textarea: 'textarea',
@ -27,6 +30,10 @@ class TypeDeChamp < ApplicationRecord
belongs_to :procedure
after_initialize :set_dynamic_type
attr_reader :dynamic_type
scope :public_only, -> { where(private: false) }
scope :private_only, -> { where(private: true) }
scope :ordered, -> { order(order_place: :asc) }
@ -52,6 +59,15 @@ class TypeDeChamp < ApplicationRecord
before_validation :check_mandatory
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
{
private: private?,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,2 +1,2 @@
class TypesDeChamp::TextTypeDeChamp < TypeDeChamp
class TypesDeChamp::TextTypeDeChamp < TypesDeChamp::TypeDeChampBase
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)
when 'france_connect_information'
dossier.user.france_connect_information&.send(column)
when 'entreprise'
dossier.etablissement&.send(:"entreprise_#{column}")
when 'etablissement'
dossier.etablissement&.send(column)
when 'type_de_champ'
@ -79,19 +77,19 @@ class DossierFieldService
.includes(relation)
.where("champs.type_de_champ_id = ?", filter['column'].to_i)
.where("champs.value ILIKE ?", "%#{filter['value']}%")
when 'entreprise'
table = 'etablissement'
if filter['column'] == 'date_creation'
when 'etablissement'
table = filter['table']
if filter['column'] == 'entreprise_date_creation'
date = filter['value'].to_date rescue nil
dossiers
.includes(table)
.where("#{table.pluralize}.entreprise_#{filter['column']} = ?", date)
.where("#{table.pluralize}.#{filter['column']} = ?", date)
else
dossiers
.includes(table)
.where("#{table.pluralize}.entreprise_#{filter['column']} ILIKE ?", "%#{filter['value']}%")
.where("#{table.pluralize}.#{filter['column']} ILIKE ?", "%#{filter['value']}%")
end
when 'user', 'etablissement'
when 'user'
dossiers
.includes(filter['table'])
.where("#{filter['table'].pluralize}.#{filter['column']} ILIKE ?", "%#{filter['value']}%")

View file

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

View file

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

View file

@ -1,6 +1,12 @@
- content_for :footer do
= 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-panel.hero-panel
.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.
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
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"
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|
t.string "siret"
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)
end
new_tdc = TypesDeChamp::TextTypeDeChamp.create(
new_tdc = TypeDeChamp.create(
procedure_id: procedure_id,
private: true,
libelle: 'URL Espace de consultation',

View file

@ -34,7 +34,7 @@ namespace :'2018_07_31_nutriscore' do
end
discard_source_champ(
TypesDeChamp::TextTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'text',
order_place: siret_order_place,
libelle: 'Numéro SIRET'
@ -42,7 +42,7 @@ namespace :'2018_07_31_nutriscore' do
)
discard_source_champ(
TypesDeChamp::TextTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'text',
order_place: fonction_order_place,
libelle: 'Fonction'
@ -50,7 +50,7 @@ namespace :'2018_07_31_nutriscore' do
)
compute_destination_champ(
TypesDeChamp::TextTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'text',
order_place: fonction_order_place,
libelle: 'Fonction',
@ -66,7 +66,7 @@ namespace :'2018_07_31_nutriscore' do
end
compute_destination_champ(
TypesDeChamp::SiretTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'siret',
order_place: siret_order_place,
libelle: 'Numéro SIRET'
@ -80,7 +80,7 @@ namespace :'2018_07_31_nutriscore' do
end
compute_destination_champ(
TypesDeChamp::HeaderSectionTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'header_section',
order_place: 18,
libelle: 'PARTIE 3 : ZONE GEOGRAPHIQUE'
@ -90,7 +90,7 @@ namespace :'2018_07_31_nutriscore' do
end
compute_destination_champ(
TypesDeChamp::MultipleDropDownListTypeDeChamp.new(
TypeDeChamp.new(
type_champ: 'multiple_drop_down_list',
order_place: 19,
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)
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
else
@ -107,9 +107,6 @@ module Tasks
if actual_tdc.libelle != expected_tdc['libelle']
errors.append("incorrect libelle #{actual_tdc.libelle} (expected #{expected_tdc['libelle']})")
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']
errors.append("incorrect type champ #{actual_tdc.type_champ} (expected #{expected_tdc['type_champ']})")
end

View file

@ -22,6 +22,14 @@ FactoryBot.define do
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|
if procedure.module_api_carto.nil?
module_api_carto = create(:module_api_carto)

View file

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

View file

@ -1,18 +1,16 @@
require 'features/new_user/dossier_shared_examples.rb'
describe 'Dossier details:' do
let(:user) { create(:user) }
let(:simple_procedure) do
tdcs = [create(:type_de_champ, libelle: 'texte obligatoire')]
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) }
let(:procedure) { create(:simple_procedure) }
let(:dossier) { create(:dossier, :en_construction, :for_individual, :with_commentaires, user: user, procedure: procedure) }
before do
Flipflop::FeatureSet.current.test!.switch!(:new_dossier_details, true)
visit_dossier dossier
end
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_content(dossier.id)
expect(page).to have_selector('.status-explanation')
@ -20,68 +18,29 @@ describe 'Dossier details:' do
end
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
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
it "show the proper wait time" do
visit_dossier dossier
expect(page).to have_text("Le temps moyen de vérification pour cette démarche est de 10 jours.")
end
it { expect(page).to have_text("Le temps moyen de vérification pour cette démarche est de 10 jours.") }
end
context "the dossier is in instruction" do
let(:dossier) { create(:dossier, :en_instruction, :for_individual, :with_commentaires, user: user, procedure: simple_procedure) }
context "when the dossier is in instruction" do
let(:dossier) { create(:dossier, :en_instruction, :for_individual, :with_commentaires, user: user, procedure: procedure) }
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
it "show the proper wait time" do
visit_dossier dossier
expect(page).to have_text("Le temps moyen dinstruction pour cette démarche est de 2 mois.")
end
it { expect(page).to have_text("Le temps moyen dinstruction pour cette démarche est de 2 mois.") }
end
end
scenario 'the user can see and edit dossier before instruction' do
visit_dossier 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
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
it_behaves_like 'the user can edit the submitted demande'
it_behaves_like 'the user can send messages to the instructeur'
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 'features/new_user/dossier_shared_examples.rb'
feature 'Invitations' do
let(:user) { create(:user) }
let(:owner) { create(:user) }
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) }
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
log_in(user)
scenario 'on the form, the owner of a dossier can invite another user to collaborate on the dossier', js: true do
log_in(owner)
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"
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")
# 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
context 'when inviting someone without an existing account' do
@ -51,24 +52,19 @@ feature 'Invitations' do
end
scenario 'an invited user can see and edit the draft', js: true do
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)
navigate_to_invited_dossier(invite)
expect(page).to have_current_path(brouillon_dossier_path(dossier))
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'
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
scenario 'an invited user cannot submit the draft' do
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)
navigate_to_invited_dossier(invite)
expect(page).to have_current_path(brouillon_dossier_path(dossier))
expect(page).to have_button('Soumettre le dossier', disabled: true)
@ -77,10 +73,39 @@ feature 'Invitations' do
end
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
log_in(user)
log_in(owner)
navigate_to_recapitulatif(dossier)
legacy_send_invite_to "user_invite@exemple.fr"
@ -105,7 +130,7 @@ feature 'Invitations' do
visit 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"
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))
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)
expect(page).to have_current_path(dossiers_path)
click_on(dossier.id)

View file

@ -7,6 +7,7 @@ RSpec.describe AutoReceiveDossiersForProcedureJob, type: :job do
before do
Timecop.freeze(date)
create(:attestation_template, procedure: nouveau_dossier1.procedure)
AutoReceiveDossiersForProcedureJob.new.perform(procedure_id, state)
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.en_instruction_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.en_instruction_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_at).to eq(instruction_date) }

View file

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

View file

@ -95,7 +95,7 @@ describe '2018_07_31_nutriscore' do
context 'with champ type mismatch' do
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
context 'with champ mandatoriness mismatch' do
@ -114,13 +114,13 @@ describe '2018_07_31_nutriscore' 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) }
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
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) }
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

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('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('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('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) }

View file

@ -21,7 +21,7 @@ shared_examples 'type_de_champ_spec' do
type_de_champ = create(:"type_de_champ_#{type_champ}")
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::/)
end
end

View file

@ -3,12 +3,14 @@ require 'spec_helper'
describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
describe '#unpack_options' do
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
let(:menu_options) { '' }
it { expect(type_de_champ.secondary_options).to eq({}) }
it { expect(type_de_champ.primary_options).to eq([]) }
it { expect(subject.secondary_options).to eq({}) }
it { expect(subject.primary_options).to eq([]) }
end
context 'with two primary options' do
@ -25,7 +27,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
end
it do
expect(type_de_champ.secondary_options).to eq(
expect(subject.secondary_options).to eq(
{
'' => [],
'Primary 1' => [ '', 'secondary 1.1', 'secondary 1.2'],
@ -34,7 +36,7 @@ describe TypesDeChamp::LinkedDropDownListTypeDeChamp do
)
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

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