Merge pull request #6488 from betagouv/add_cnaf_champ
Ajoute le champ CNAF
This commit is contained in:
commit
b8946137c7
75 changed files with 651 additions and 40 deletions
30
app/assets/stylesheets/cnaf.scss
Normal file
30
app/assets/stylesheets/cnaf.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
@import "constants";
|
||||
@import "colors";
|
||||
|
||||
table.cnaf {
|
||||
margin: 2 * $default-padding 0 $default-padding $default-padding;
|
||||
width: 100%;
|
||||
|
||||
caption {
|
||||
font-weight: bold;
|
||||
margin-left: - $default-padding;
|
||||
margin-bottom: $default-spacer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
font-weight: normal;
|
||||
padding: $default-spacer;
|
||||
}
|
||||
|
||||
th.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.horizontal {
|
||||
th {
|
||||
border-bottom: 1px solid $grey;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -356,6 +356,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cnaf-inputs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
max-width: 700px;
|
||||
|
||||
input {
|
||||
width: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
input.aa-input,
|
||||
input.aa-hint {
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -337,8 +337,8 @@ module Users
|
|||
def champs_params
|
||||
params.permit(dossier: {
|
||||
champs_attributes: [
|
||||
:id, :value, :external_id, :primary_value, :secondary_value, :piece_justificative_file, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :external_id, :primary_value, :secondary_value, :piece_justificative_file, value: []]
|
||||
:id, :value, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: []]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
@ -382,7 +382,8 @@ module Users
|
|||
if @dossier.champs.any?(&:changed_for_autosave?)
|
||||
@dossier.last_champ_updated_at = Time.zone.now
|
||||
end
|
||||
if !@dossier.save
|
||||
|
||||
if !@dossier.save(**validation_options)
|
||||
errors += @dossier.errors.full_messages
|
||||
elsif change_groupe_instructeur?
|
||||
@dossier.assign_to_groupe_instructeur(groupe_instructeur_from_params)
|
||||
|
@ -453,5 +454,16 @@ module Users
|
|||
def save_draft?
|
||||
dossier.brouillon? && !params[:submit_draft]
|
||||
end
|
||||
|
||||
def validation_options
|
||||
if save_draft?
|
||||
{ context: :brouillon }
|
||||
else
|
||||
# rubocop:disable Lint/BooleanSymbol
|
||||
# Force ActiveRecord to re-validate associated records.
|
||||
{ context: :false }
|
||||
# rubocop:enable Lint/BooleanSymbol
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1869,6 +1869,11 @@ enum TypeDeChamp {
|
|||
"""
|
||||
civilite
|
||||
|
||||
"""
|
||||
Données de la Caisse nationale des allocations familiales
|
||||
"""
|
||||
cnaf
|
||||
|
||||
"""
|
||||
Communes
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class APIParticulier::CNAFAdapter
|
||||
class APIParticulier::CnafAdapter
|
||||
class InvalidSchemaError < ::StandardError
|
||||
def initialize(errors)
|
||||
super(errors.map(&:to_json).join("\n"))
|
||||
|
|
|
@ -14,7 +14,7 @@ module APIParticulier
|
|||
msg = <<~TEXT
|
||||
url: #{url}
|
||||
HTTP error code: #{http_error_code}
|
||||
#{response.body}
|
||||
#{response.body.force_encoding('UTF-8')}
|
||||
curl message: #{curl_message}
|
||||
total time: #{total_time}
|
||||
connect time: #{connect_time}
|
||||
|
|
|
@ -8,6 +8,7 @@ module APIParticulier
|
|||
def available_sources
|
||||
@procedure.api_particulier_scopes
|
||||
.map { |provider_and_scope| raw_scopes[provider_and_scope] }
|
||||
.compact
|
||||
.map { |provider, scope| extract_sources(provider, scope) }
|
||||
.reduce({}) { |acc, el| acc.deep_merge(el) }
|
||||
end
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
52
app/models/champs/cnaf_champ.rb
Normal file
52
app/models/champs/cnaf_champ.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: champs
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::CnafChamp < Champs::TextChamp
|
||||
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/cnaf-input-validation.middleware.ts
|
||||
validates :numero_allocataire, format: { with: /\A\d{1,7}\z/ }, if: -> { code_postal.present? && validation_context != :brouillon }
|
||||
validates :code_postal, format: { with: /\A\w{5}\z/ }, if: -> { numero_allocataire.present? && validation_context != :brouillon }
|
||||
|
||||
store_accessor :value_json, :numero_allocataire, :code_postal
|
||||
|
||||
def blank?
|
||||
external_id.nil?
|
||||
end
|
||||
|
||||
def fetch_external_data?
|
||||
true
|
||||
end
|
||||
|
||||
def fetch_external_data
|
||||
if valid?
|
||||
APIParticulier::CnafAdapter.new(
|
||||
procedure.api_particulier_token,
|
||||
numero_allocataire,
|
||||
code_postal,
|
||||
procedure.api_particulier_sources
|
||||
).to_params
|
||||
end
|
||||
end
|
||||
|
||||
def external_id
|
||||
if numero_allocataire.present? && code_postal.present?
|
||||
{ code_postal: code_postal, numero_allocataire: numero_allocataire }.to_json
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer
|
||||
|
|
|
@ -716,6 +716,10 @@ class Procedure < ApplicationRecord
|
|||
published_revision.touch(:published_at)
|
||||
end
|
||||
|
||||
def cnaf_enabled?
|
||||
api_particulier_sources['cnaf'].present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def before_publish
|
||||
|
|
|
@ -48,7 +48,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
repetition: 'repetition',
|
||||
titre_identite: 'titre_identite',
|
||||
iban: 'iban',
|
||||
annuaire_education: 'annuaire_education'
|
||||
annuaire_education: 'annuaire_education',
|
||||
cnaf: 'cnaf'
|
||||
}
|
||||
|
||||
belongs_to :revision, class_name: 'ProcedureRevision', optional: true
|
||||
|
@ -291,17 +292,26 @@ class TypeDeChamp < ApplicationRecord
|
|||
def self.type_de_champ_types_for(procedure, user)
|
||||
has_legacy_number = (procedure.types_de_champ + procedure.types_de_champ_private).any?(&:legacy_number?)
|
||||
|
||||
show_number = -> (tdc) { tdc != TypeDeChamp.type_champs.fetch(:number) || has_legacy_number }
|
||||
|
||||
enabled_featured_champ = -> (tdc) do
|
||||
filter_featured_tdc = -> (tdc) do
|
||||
feature_name = FEATURE_FLAGS[tdc]
|
||||
feature_name.blank? || Flipper.enabled?(feature_name, user)
|
||||
end
|
||||
|
||||
filter_tdc = -> (tdc) do
|
||||
case tdc
|
||||
when TypeDeChamp.type_champs.fetch(:number)
|
||||
has_legacy_number
|
||||
when TypeDeChamp.type_champs.fetch(:cnaf)
|
||||
procedure.cnaf_enabled?
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
type_champs
|
||||
.keys
|
||||
.filter(&show_number)
|
||||
.filter(&enabled_featured_champ)
|
||||
.filter(&filter_tdc)
|
||||
.filter(&filter_featured_tdc)
|
||||
.map { |tdc| [I18n.t("activerecord.attributes.type_de_champ.type_champs.#{tdc}"), tdc] }
|
||||
.sort_by(&:first)
|
||||
end
|
||||
|
|
2
app/models/types_de_champ/cnaf_type_de_champ.rb
Normal file
2
app/models/types_de_champ/cnaf_type_de_champ.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class TypesDeChamp::CnafTypeDeChamp < TypesDeChamp::TextTypeDeChamp
|
||||
end
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
.container
|
||||
.flex
|
||||
= link_to admin_procedure_api_particulier_jeton_path, class: 'card-admin' do
|
||||
= link_to admin_procedure_api_particulier_jeton_path, class: 'card-admin', id: 'add-jeton' do
|
||||
- if @procedure.api_particulier_token.blank?
|
||||
%div
|
||||
%span.icon.clock
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
%p.button Modifier
|
||||
|
||||
- if feature_enabled?(:api_particulier)
|
||||
= link_to admin_procedure_api_particulier_path(@procedure), class: 'card-admin' do
|
||||
= link_to admin_procedure_api_particulier_path(@procedure), class: 'card-admin', id: 'api-particulier' do
|
||||
- if @procedure.api_particulier_token.present?
|
||||
%div
|
||||
%span.icon.accept
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
- scopes.each do |scope_key, sources|
|
||||
%h3.explication-libelle= t("api_particulier.providers.#{provider_key}.scopes.#{scope_key}.libelle")
|
||||
%ul.procedure-admin-api-particulier-sources
|
||||
%ul.procedure-admin-api-particulier-sources{ id: scope_key }
|
||||
- sources.each do |source_key, enabled_hash|
|
||||
- enabled = (@procedure.api_particulier_sources.dig(provider_key, scope_key)&.include?(source_key)).present?
|
||||
%li
|
||||
|
|
10
app/views/shared/champs/cnaf/_adresse.html.haml
Normal file
10
app/views/shared/champs/cnaf/_adresse.html.haml
Normal file
|
@ -0,0 +1,10 @@
|
|||
%table.cnaf
|
||||
%caption #{t("api_particulier.providers.cnaf.scopes.adresse.libelle")} :
|
||||
- for key in ['identite', 'complementIdentite', 'numeroRue', 'complementIdentiteGeo', 'lieuDit', 'codePostalVille', 'pays'] do
|
||||
- if adresse[key].present?
|
||||
%tr
|
||||
%th= t("api_particulier.providers.cnaf.scopes.adresse.#{key}")
|
||||
%td= adresse[key]
|
||||
|
||||
|
||||
|
19
app/views/shared/champs/cnaf/_personnes.html.haml
Normal file
19
app/views/shared/champs/cnaf/_personnes.html.haml
Normal file
|
@ -0,0 +1,19 @@
|
|||
%table.cnaf.horizontal
|
||||
%caption #{t("api_particulier.providers.cnaf.scopes.#{scope}.libelle")} :
|
||||
%thead
|
||||
%tr
|
||||
- for key in ['nomPrenom', 'sexe', 'dateDeNaissance'] do
|
||||
- if personnes.first[key].present?
|
||||
%th{ class: "#{"text-right" if key == 'dateDeNaissance'}" }= t("api_particulier.providers.cnaf.scopes.personne.#{key}")
|
||||
%tbody
|
||||
- personnes.each do |personne|
|
||||
%tr
|
||||
- for key in ['nomPrenom', 'sexe', 'dateDeNaissance'] do
|
||||
- if personne[key].present?
|
||||
- case key
|
||||
- when 'dateDeNaissance'
|
||||
%td.text-right= try_format_datetime(Date.strptime(personne[key], "%d%m%Y"))
|
||||
- when 'sexe'
|
||||
%td= t("api_particulier.providers.cnaf.scopes.personne.#{personne[key]}")
|
||||
- else
|
||||
%td= personne[key]
|
14
app/views/shared/champs/cnaf/_quotient_familial.html.haml
Normal file
14
app/views/shared/champs/cnaf/_quotient_familial.html.haml
Normal file
|
@ -0,0 +1,14 @@
|
|||
%table.cnaf.horizontal
|
||||
%caption #{t("api_particulier.providers.cnaf.scopes.quotient_familial.libelle")} :
|
||||
%thead
|
||||
%tr
|
||||
- for key in ['quotientFamilial', 'mois', 'annee'] do
|
||||
- if quotient_familial[key].present?
|
||||
%th.text-right= t("api_particulier.providers.cnaf.scopes.quotient_familial.#{key}")
|
||||
%tbody
|
||||
%tr
|
||||
- for key in ['quotientFamilial', 'mois', 'annee'] do
|
||||
- if quotient_familial[key].present?
|
||||
%td.text-right= quotient_familial[key]
|
||||
- else
|
||||
%td
|
24
app/views/shared/champs/cnaf/_show.html.haml
Normal file
24
app/views/shared/champs/cnaf/_show.html.haml
Normal file
|
@ -0,0 +1,24 @@
|
|||
- if champ.blank?
|
||||
%p= t('.not_filled')
|
||||
- elsif champ.data.blank?
|
||||
%p= t('.fetching_data',
|
||||
numero_allocataire: champ.numero_allocataire,
|
||||
code_postal: champ.code_postal)
|
||||
- else
|
||||
- if profile == 'usager'
|
||||
%p= t('.data_fetched',
|
||||
sources: champ.procedure.api_particulier_sources['cnaf'].keys.map(&:to_s).join(', '),
|
||||
numero_allocataire: champ.numero_allocataire,
|
||||
code_postal: champ.code_postal)
|
||||
|
||||
- if profile == 'instructeur'
|
||||
%p= t('.data_fetched_title')
|
||||
|
||||
- ['adresse', 'quotient_familial', 'enfants', 'allocataires'].each do |scope|
|
||||
- if champ.data[scope].present?
|
||||
- if scope == 'quotient_familial'
|
||||
= render partial: 'shared/champs/cnaf/quotient_familial', locals: { quotient_familial: champ.data[scope] }
|
||||
- if scope.in? ['enfants', 'allocataires']
|
||||
= render partial: 'shared/champs/cnaf/personnes', locals: { scope: scope, personnes: champ.data[scope] }
|
||||
- elsif scope == 'adresse'
|
||||
= render partial: 'shared/champs/cnaf/adresse', locals: { adresse: champ.data[scope] }
|
|
@ -36,6 +36,8 @@
|
|||
= render partial: "shared/champs/textarea/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:annuaire_education)
|
||||
= render partial: "shared/champs/annuaire_education/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:cnaf)
|
||||
= render partial: "shared/champs/cnaf/show", locals: { champ: c, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:address)
|
||||
= render partial: "shared/champs/address/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:communes)
|
||||
|
|
16
app/views/shared/dossiers/editable_champs/_cnaf.html.haml
Normal file
16
app/views/shared/dossiers/editable_champs/_cnaf.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
.cnaf-inputs
|
||||
%div
|
||||
= form.label :numero_allocataire, t('.numero_allocataire_label')
|
||||
%p.notice= t('.numero_allocataire_notice')
|
||||
= form.text_field :numero_allocataire,
|
||||
required: champ.mandatory?,
|
||||
size: 7,
|
||||
aria: { describedby: describedby_id(champ) }
|
||||
|
||||
%div
|
||||
= form.label :code_postal, t('.code_postal_label')
|
||||
%p.notice= t('.code_postal_notice')
|
||||
= form.text_field :code_postal,
|
||||
size: 5,
|
||||
required: champ.mandatory?,
|
||||
aria: { describedby: describedby_id(champ) }
|
|
@ -14,7 +14,6 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|||
inflect.acronym 'JSON'
|
||||
inflect.acronym 'RNA'
|
||||
inflect.acronym 'URL'
|
||||
inflect.acronym 'CNAF'
|
||||
inflect.irregular 'type_de_champ', 'types_de_champ'
|
||||
inflect.irregular 'type_de_champ_private', 'types_de_champ_private'
|
||||
inflect.irregular 'procedure_revision_type_de_champ', 'procedure_revision_types_de_champ'
|
||||
|
|
32
config/locales/api_particulier.en.yml
Normal file
32
config/locales/api_particulier.en.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
en:
|
||||
api_particulier:
|
||||
providers:
|
||||
cnaf:
|
||||
libelle: Caisse nationale d’allocations familiales (CAF)
|
||||
scopes:
|
||||
personne: &personne
|
||||
nomPrenom: first and last name
|
||||
dateDeNaissance: birth date
|
||||
sexe: sex
|
||||
M: male
|
||||
F: female
|
||||
allocataires:
|
||||
libelle: beneficiaries
|
||||
<<: *personne
|
||||
enfants:
|
||||
libelle: children
|
||||
<<: *personne
|
||||
adresse:
|
||||
libelle: address
|
||||
identite: identity
|
||||
complementIdentite: complément d’identité
|
||||
complementIdentiteGeo: complément d’identité géographique
|
||||
numeroRue: number and street
|
||||
lieuDit: lieu-dit
|
||||
codePostalVille: postcode and city
|
||||
pays: country
|
||||
quotient_familial:
|
||||
libelle: quotient familial
|
||||
quotientFamilial: quotient familial
|
||||
mois: month
|
||||
annee: year
|
|
@ -2,12 +2,14 @@ fr:
|
|||
api_particulier:
|
||||
providers:
|
||||
cnaf:
|
||||
libelle: Caisse d’allocations familiales (CAF)
|
||||
libelle: Caisse nationale d’allocations familiales (CAF)
|
||||
scopes:
|
||||
personne: &personne
|
||||
nomPrenom: noms et prénoms
|
||||
dateDeNaissance: date de naissance
|
||||
sexe: genre
|
||||
sexe: sexe
|
||||
M: masculin
|
||||
F: féminin
|
||||
allocataires:
|
||||
libelle: allocataires
|
||||
<<: *personne
|
||||
|
|
|
@ -274,6 +274,12 @@ en:
|
|||
taken: is already used for procedure. You cannot use it because it belongs to another administrator.
|
||||
# taken_can_be_claimed: est identique à celui d’une autre de vos procedures publiées. Si vous publiez cette procedure, l’ancienne sera dépubliée et ne sera plus accessible au public. Les utilisateurs qui ont commencé un brouillon vont pouvoir le déposer.
|
||||
invalid: is not valid. It must countain between 3 and 50 characters among a-z, 0-9, '_' and '-'.
|
||||
"champs/cnaf_champ":
|
||||
attributes:
|
||||
numero_allocataire:
|
||||
invalid: "must be a maximum of 7 digits"
|
||||
code_postal:
|
||||
invalid: "must be 5 characters long"
|
||||
errors:
|
||||
messages:
|
||||
dossier_not_found: "The file does not exist or you do not have access to it."
|
||||
|
|
|
@ -280,6 +280,12 @@ fr:
|
|||
taken: est déjà utilisé par une démarche. Vous ne pouvez pas l’utiliser car il appartient à un autre administrateur.
|
||||
taken_can_be_claimed: est identique à celui d’une autre de vos démarches publiées. Si vous publiez cette démarche, l’ancienne sera dépubliée et ne sera plus accessible au public. Les utilisateurs qui ont commencé un brouillon vont pouvoir le déposer.
|
||||
invalid: n’est pas valide. Il doit comporter au moins 3 caractères, au plus 50 caractères et seuls les caractères a-z, 0-9, '_' et '-' sont autorisés.
|
||||
"champs/cnaf_champ":
|
||||
attributes:
|
||||
numero_allocataire:
|
||||
invalid: "doit être composé au maximum de 7 chiffres"
|
||||
code_postal:
|
||||
invalid: "doit posséder 5 caractères"
|
||||
errors:
|
||||
messages:
|
||||
saml_not_authorized: "Vous n’êtes pas autorisé à accéder à ce service."
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
fr:
|
||||
activerecord:
|
||||
attributes:
|
||||
champ:
|
||||
value: La valeur du champ
|
||||
piece_justificative_file: La pièce justificative
|
|
@ -36,3 +36,5 @@ fr:
|
|||
titre_identite: 'Titre identité'
|
||||
iban: 'Iban'
|
||||
annuaire_education: 'Annuaire de l’éducation'
|
||||
cnaf: 'Données de la Caisse nationale des allocations familiales'
|
||||
|
||||
|
|
16
config/locales/shared.en.yml
Normal file
16
config/locales/shared.en.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
en:
|
||||
shared:
|
||||
dossiers:
|
||||
editable_champs:
|
||||
cnaf:
|
||||
numero_allocataire_label: CAF benefit number
|
||||
numero_allocataire_notice: It is usually composed of 7 digits.
|
||||
code_postal_label: postal code
|
||||
code_postal_notice: It is usually composed of 5 digits.
|
||||
champs:
|
||||
cnaf:
|
||||
show:
|
||||
not_filled: not filled
|
||||
fetching_data: "Fetching data for recipient No. %{numero_allocataire} with postal code %{code_postal}."
|
||||
data_fetched: "Data concerning %{sources} linked to the account Nº %{numero_allocataire} with the postal code %{code_postal} has been received from the CAF."
|
||||
data_fetched_title: "Data received from la Caisse nationale d’allocations familiales"
|
16
config/locales/shared.fr.yml
Normal file
16
config/locales/shared.fr.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
fr:
|
||||
shared:
|
||||
dossiers:
|
||||
editable_champs:
|
||||
cnaf:
|
||||
numero_allocataire_label: Le numéro d’allocataire CAF
|
||||
numero_allocataire_notice: Il est généralement composé de 7 chiffres.
|
||||
code_postal_label: Le code postal
|
||||
code_postal_notice: Il est généralement composé de 5 chiffres.
|
||||
champs:
|
||||
cnaf:
|
||||
show:
|
||||
not_filled: non renseigné
|
||||
fetching_data: "La récupération automatique des données pour l’allocataire Nº %{numero_allocataire} avec le code postal %{code_postal} est en cours."
|
||||
data_fetched: "Des données concernant %{sources} liées au compte Nº %{numero_allocataire} avec le code postal %{code_postal} ont été reçues depuis la CAF."
|
||||
data_fetched_title: "Données obtenues de la Caisse nationale d’allocations familiales"
|
|
@ -0,0 +1,5 @@
|
|||
class AddValueJSONColumnToChamp < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :champs, :value_json, :jsonb
|
||||
end
|
||||
end
|
|
@ -189,6 +189,7 @@ ActiveRecord::Schema.define(version: 2021_10_06_164955) do
|
|||
t.jsonb "data"
|
||||
t.string "external_id"
|
||||
t.string "fetch_external_data_exceptions", array: true
|
||||
t.jsonb "value_json"
|
||||
t.index ["dossier_id"], name: "index_champs_on_dossier_id"
|
||||
t.index ["parent_id"], name: "index_champs_on_parent_id"
|
||||
t.index ["private"], name: "index_champs_on_private"
|
||||
|
|
|
@ -185,6 +185,10 @@ FactoryBot.define do
|
|||
type_de_champ { association :type_de_champ_annuaire_education, procedure: dossier.procedure }
|
||||
end
|
||||
|
||||
factory :champ_cnaf, class: 'Champs::CnafChamp' do
|
||||
type_de_champ { association :type_de_champ_cnaf, procedure: dossier.procedure }
|
||||
end
|
||||
|
||||
factory :champ_siret, class: 'Champs::SiretChamp' do
|
||||
association :type_de_champ, factory: [:type_de_champ_siret]
|
||||
association :etablissement, factory: [:etablissement]
|
||||
|
|
|
@ -205,6 +205,12 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :with_cnaf do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_cnaf, procedure: procedure)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_explication do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_explication, procedure: procedure)
|
||||
|
|
|
@ -151,6 +151,9 @@ FactoryBot.define do
|
|||
factory :type_de_champ_annuaire_education do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:annuaire_education) }
|
||||
end
|
||||
factory :type_de_champ_cnaf do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:cnaf) }
|
||||
end
|
||||
factory :type_de_champ_carte do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:carte) }
|
||||
end
|
||||
|
|
167
spec/features/api_particulier/api_particulier_spec.rb
Normal file
167
spec/features/api_particulier/api_particulier_spec.rb
Normal file
|
@ -0,0 +1,167 @@
|
|||
feature 'fetch API Particulier Data', js: true do
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
let(:expected_token) { 'd7e9c9f4c3ca00caadde31f50fd4521a' }
|
||||
|
||||
let(:expected_sources) do
|
||||
{
|
||||
"cnaf" =>
|
||||
{
|
||||
"adresse" => ["identite", "complementIdentite", "complementIdentiteGeo", "numeroRue", "lieuDit", "codePostalVille", "pays"],
|
||||
"allocataires" => ["nomPrenom", "dateDeNaissance", "sexe"],
|
||||
"enfants" => ["nomPrenom", "dateDeNaissance", "sexe"],
|
||||
"quotient_familial" => ["quotientFamilial", "annee", "mois"]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_const("API_PARTICULIER_URL", "https://particulier.api.gouv.fr/api")
|
||||
Flipper.enable(:api_particulier)
|
||||
end
|
||||
|
||||
context "when an administrateur is logged" do
|
||||
let(:procedure) do
|
||||
create(:procedure, :with_service, :with_instructeur,
|
||||
aasm_state: :brouillon,
|
||||
administrateurs: [administrateur],
|
||||
libelle: "libellé de la procédure",
|
||||
path: "libelle-de-la-procedure")
|
||||
end
|
||||
|
||||
before { login_as administrateur.user, scope: :user }
|
||||
|
||||
scenario 'it can enable api particulier' do
|
||||
visit admin_procedure_path(procedure)
|
||||
expect(page).to have_content("Configurer le jeton API particulier")
|
||||
|
||||
find('#api-particulier').click
|
||||
expect(page).to have_current_path(admin_procedure_api_particulier_path(procedure))
|
||||
|
||||
find('#add-jeton').click
|
||||
expect(page).to have_current_path(admin_procedure_api_particulier_jeton_path(procedure))
|
||||
|
||||
fill_in 'procedure_api_particulier_token', with: expected_token
|
||||
VCR.use_cassette("api_particulier/success/introspect") { click_on 'Enregistrer' }
|
||||
expect(page).to have_text('Le jeton a bien été mis à jour')
|
||||
expect(page).to have_current_path(admin_procedure_api_particulier_sources_path(procedure))
|
||||
|
||||
['allocataires', 'enfants'].each do |scope|
|
||||
within("##{scope}") do
|
||||
check('noms et prénoms')
|
||||
check('date de naissance')
|
||||
check('sexe')
|
||||
end
|
||||
end
|
||||
|
||||
within("#adresse") do
|
||||
check('identité')
|
||||
check('complément d’identité')
|
||||
check('complément d’identité géographique')
|
||||
check('numéro et rue')
|
||||
check('lieu-dit')
|
||||
check('code postal et ville')
|
||||
check('pays')
|
||||
end
|
||||
|
||||
within("#quotient_familial") do
|
||||
check('quotient familial')
|
||||
check('année')
|
||||
check('mois')
|
||||
end
|
||||
|
||||
click_on "Enregistrer"
|
||||
|
||||
within("#enfants") do
|
||||
expect(find('input[value=nomPrenom]')).to be_checked
|
||||
end
|
||||
|
||||
expect(procedure.reload.api_particulier_sources).to eq(expected_sources)
|
||||
|
||||
visit champs_admin_procedure_path(procedure)
|
||||
|
||||
add_champ
|
||||
select('Données de la Caisse nationale des allocations familiales', from: 'champ-0-type_champ')
|
||||
fill_in 'champ-0-libelle', with: 'libellé de champ'
|
||||
blur
|
||||
expect(page).to have_content('Formulaire enregistré')
|
||||
|
||||
visit admin_procedure_path(procedure)
|
||||
find('#publish-procedure-link').click
|
||||
expect(find_field('procedure_path').value).to eq procedure.path
|
||||
fill_in 'lien_site_web', with: 'http://some.website'
|
||||
click_on 'Publier'
|
||||
|
||||
expect(page).to have_text('Démarche publiée')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an user is logged' do
|
||||
let(:user) { create(:user) }
|
||||
let(:api_particulier_token) { '29eb50b65f64e8e00c0847a8bbcbd150e1f847' }
|
||||
let(:numero_allocataire) { '5843972' }
|
||||
let(:code_postal) { '92110' }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
|
||||
let(:procedure) do
|
||||
create(:procedure, :for_individual, :with_service, :with_cnaf, :published,
|
||||
libelle: "libellé de la procédure",
|
||||
path: "libelle-de-la-procedure",
|
||||
instructeurs: [instructeur],
|
||||
api_particulier_sources: expected_sources,
|
||||
api_particulier_token: api_particulier_token)
|
||||
end
|
||||
|
||||
before { login_as user, scope: :user }
|
||||
|
||||
scenario 'it can fill an cnaf champ' do
|
||||
visit commencer_path(path: procedure.path)
|
||||
click_on 'Commencer la démarche'
|
||||
|
||||
choose 'Monsieur'
|
||||
fill_in 'individual_nom', with: 'Nom'
|
||||
fill_in 'individual_prenom', with: 'Prenom'
|
||||
|
||||
click_button('Continuer')
|
||||
|
||||
fill_in 'Le numéro d’allocataire CAF', with: numero_allocataire
|
||||
fill_in 'Le code postal', with: 'wrong_code'
|
||||
|
||||
blur
|
||||
expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true)
|
||||
|
||||
dossier = Dossier.last
|
||||
expect(dossier.champs.first.code_postal).to eq('wrong_code')
|
||||
|
||||
click_on 'Déposer le dossier'
|
||||
expect(page).to have_content(/code postal doit posséder 5 caractères/)
|
||||
|
||||
fill_in 'Le code postal', with: code_postal
|
||||
|
||||
VCR.use_cassette("api_particulier/success/composition_familiale") do
|
||||
perform_enqueued_jobs { click_on 'Déposer le dossier' }
|
||||
end
|
||||
|
||||
visit demande_dossier_path(dossier)
|
||||
expect(page).to have_content(/Des données.*ont été reçues depuis la CAF/)
|
||||
|
||||
log_out
|
||||
|
||||
login_as instructeur.user, scope: :user
|
||||
|
||||
visit instructeur_dossier_path(procedure, dossier)
|
||||
|
||||
expect(page).to have_content('code postal et ville 92110 Clichy')
|
||||
expect(page).to have_content('identité Mr SNOW Eric')
|
||||
expect(page).to have_content('complément d’identité ne connait rien')
|
||||
expect(page).to have_content('numéro et rue 109 rue La Boétie')
|
||||
expect(page).to have_content('pays FRANCE')
|
||||
expect(page).to have_content('complément d’identité géographique au nord de paris')
|
||||
expect(page).to have_content('lieu-dit glagla')
|
||||
expect(page).to have_content('ERIC SNOW masculin 07/01/1991')
|
||||
expect(page).to have_content('SANSA SNOW féminin 15/01/1992')
|
||||
expect(page).to have_content('PAUL SNOW masculin 04/01/2018')
|
||||
expect(page).to have_content('1856 6 2021')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -63,7 +63,7 @@ feature 'The routing', js: true do
|
|||
|
||||
# publish
|
||||
publish_procedure(procedure)
|
||||
log_out(old_layout: true)
|
||||
log_out
|
||||
|
||||
# 2 users fill a dossier in each group
|
||||
user_send_dossier(scientifique_user, 'scientifique')
|
||||
|
@ -222,15 +222,4 @@ feature 'The routing', js: true do
|
|||
|
||||
expect(page).to have_text('Mot de passe enregistré')
|
||||
end
|
||||
|
||||
def log_out(old_layout: false)
|
||||
if old_layout
|
||||
page.all('.dropdown-button').first.click
|
||||
click_on 'Se déconnecter'
|
||||
else
|
||||
click_button(title: 'Mon compte')
|
||||
click_on 'Se déconnecter'
|
||||
end
|
||||
expect(page).to have_current_path(root_path)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://particulier-test.api.gouv.fr/api/v2/composition-familiale?codePostal=92110&numeroAllocataire=5843972
|
||||
uri: https://particulier.api.gouv.fr/api/v2/composition-familiale?codePostal=92110&numeroAllocataire=5843972
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://particulier-test.api.gouv.fr/api/v2/composition-familiale?codePostal=92110&numeroAllocataire=5843972
|
||||
uri: https://particulier.api.gouv.fr/api/v2/composition-familiale?codePostal=92110&numeroAllocataire=5843972
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
describe APIParticulier::CNAFAdapter do
|
||||
describe APIParticulier::CnafAdapter do
|
||||
let(:adapter) { described_class.new(api_particulier_token, numero_allocataire, code_postal, requested_sources) }
|
||||
|
||||
before { stub_const("API_PARTICULIER_URL", "https://particulier-test.api.gouv.fr/api") }
|
||||
before { stub_const("API_PARTICULIER_URL", "https://particulier.api.gouv.fr/api") }
|
||||
|
||||
describe '#to_params' do
|
||||
let(:api_particulier_token) { '29eb50b65f64e8e00c0847a8bbcbd150e1f847' }
|
||||
|
@ -63,7 +63,7 @@ describe APIParticulier::CNAFAdapter do
|
|||
context 'when no sources is requested' do
|
||||
let(:requested_sources) { {} }
|
||||
|
||||
it { expect { subject }.to raise_error(APIParticulier::CNAFAdapter::InvalidSchemaError) }
|
||||
it { expect { subject }.to raise_error(APIParticulier::CnafAdapter::InvalidSchemaError) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,6 +31,12 @@ describe APIParticulier::Services::SourcesService do
|
|||
|
||||
it { is_expected.to match(cnaf_allocataires_and_enfants) }
|
||||
end
|
||||
|
||||
context 'when a procedure has an unknown scope' do
|
||||
let(:api_particulier_scopes) { ['unknown_scope'] }
|
||||
|
||||
it { is_expected.to match({}) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#sanitize' do
|
||||
|
|
103
spec/models/champs/cnaf_champ_spec.rb
Normal file
103
spec/models/champs/cnaf_champ_spec.rb
Normal file
|
@ -0,0 +1,103 @@
|
|||
describe Champs::CnafChamp, type: :model do
|
||||
let(:champ) { described_class.new }
|
||||
|
||||
describe 'numero_allocataire and code_postal' do
|
||||
before do
|
||||
champ.numero_allocataire = '1234567'
|
||||
champ.code_postal = '12345'
|
||||
end
|
||||
|
||||
it 'saves numero_allocataire and code_postal' do
|
||||
expect(champ.numero_allocataire).to eq('1234567')
|
||||
expect(champ.code_postal).to eq('12345')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'external_id' do
|
||||
context 'when only one data is given' do
|
||||
before do
|
||||
champ.numero_allocataire = '1234567'
|
||||
champ.save
|
||||
end
|
||||
|
||||
it { expect(champ.external_id).to be_nil }
|
||||
end
|
||||
|
||||
context 'when all data required for an external fetch are given' do
|
||||
before do
|
||||
champ.numero_allocataire = '1234567'
|
||||
champ.code_postal = '12345'
|
||||
champ.save
|
||||
end
|
||||
|
||||
it { expect(JSON.parse(champ.external_id)).to eq({ "code_postal" => "12345", "numero_allocataire" => "1234567" }) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#validate' do
|
||||
let(:numero_allocataire) { '1234567' }
|
||||
let(:code_postal) { '12345' }
|
||||
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_cnaf)) }
|
||||
let(:validation_context) { :create }
|
||||
|
||||
subject { champ.valid?(validation_context) }
|
||||
|
||||
before do
|
||||
champ.numero_allocataire = numero_allocataire
|
||||
champ.code_postal = code_postal
|
||||
end
|
||||
|
||||
context 'when numero_allocataire and code_postal are valids' do
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
|
||||
context 'when numero_allocataire and code_postal are nil' do
|
||||
let(:numero_allocataire) { nil }
|
||||
let(:code_postal) { nil }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
|
||||
context 'when only code_postal is nil' do
|
||||
let(:code_postal) { nil }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Code postal doit posséder 5 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when only numero_allocataire is nil' do
|
||||
let(:numero_allocataire) { nil }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero allocataire doit être composé au maximum de 7 chiffres"])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when numero_allocataire is invalid' do
|
||||
let(:numero_allocataire) { '123456a' }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero allocataire doit être composé au maximum de 7 chiffres"])
|
||||
end
|
||||
|
||||
context 'and the validation_context is :brouillon' do
|
||||
let(:validation_context) { :brouillon }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when code_postal is invalid' do
|
||||
let(:code_postal) { '123456' }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Code postal doit posséder 5 caractères"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -77,6 +77,7 @@ describe ProcedureExportService do
|
|||
"titre_identite",
|
||||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -164,6 +165,7 @@ describe ProcedureExportService do
|
|||
"titre_identite",
|
||||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -247,6 +249,7 @@ describe ProcedureExportService do
|
|||
"titre_identite",
|
||||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
|
|
@ -142,6 +142,13 @@ module FeatureHelpers
|
|||
have_css("##{form_id_for(libelle)}[value=\"#{with}\"]")
|
||||
end
|
||||
|
||||
def log_out
|
||||
click_button(title: 'Mon compte')
|
||||
click_on 'Se déconnecter'
|
||||
|
||||
expect(page).to have_current_path(root_path)
|
||||
end
|
||||
|
||||
# Keep the brower window open after a test success of failure, to
|
||||
# allow inspecting the page or the console.
|
||||
#
|
||||
|
|
Loading…
Reference in a new issue