Merge pull request #7790 from betagouv/feature/add_rna_type_de_champs
Ajouter champ RNA à une procédure
This commit is contained in:
commit
8499c0327d
41 changed files with 761 additions and 44 deletions
|
@ -455,6 +455,13 @@
|
|||
min-height: 1px;
|
||||
}
|
||||
|
||||
.rna-info {
|
||||
margin-top: -$default-fields-spacer;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
// Ensure the bottom-margin is not collapsed when the element is empty
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.send-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
|
2
app/components/editable_champ/rna_component.rb
Normal file
2
app/components/editable_champ/rna_component.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class EditableChamp::RNAComponent < EditableChamp::EditableChampBaseComponent
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
en:
|
||||
placeholder: "W503726238"
|
||||
title: "The RNA number must begin with a capital W followed by 9 digits"
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fr:
|
||||
placeholder: "W503726238"
|
||||
title: "Le numéro RNA doit commencer par un W majuscule suivi de 9 chiffres"
|
|
@ -0,0 +1,12 @@
|
|||
= @form.text_field :value,
|
||||
id: @champ.input_id,
|
||||
aria: { describedby: @champ.describedby_id },
|
||||
placeholder: t(".placeholder"),
|
||||
data: { controller: 'turbo-input', turbo_input_url_value: champs_rna_path(@champ.id) },
|
||||
required: @champ.mandatory?,
|
||||
pattern: "W[0-9]{9}",
|
||||
title: t(".title"),
|
||||
class: "width-33-desktop",
|
||||
maxlength: 10
|
||||
.rna-info{ id: dom_id(@champ, :rna_info) }
|
||||
= render 'shared/champs/rna/association', champ: @champ, network_error: false, rna: @champ.value
|
16
app/controllers/champs/rna_controller.rb
Normal file
16
app/controllers/champs/rna_controller.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class Champs::RNAController < ApplicationController
|
||||
before_action :authenticate_logged_user!
|
||||
|
||||
def show
|
||||
@champ = policy_scope(Champ).find(params[:champ_id])
|
||||
@rna = read_param_value(@champ.input_name, 'value')
|
||||
@network_error = false
|
||||
begin
|
||||
data = APIEntreprise::RNAAdapter.new(@rna, @champ.procedure_id).to_params
|
||||
@champ.update!(data: data, value: @rna)
|
||||
rescue APIEntreprise::API::Error, ActiveRecord::RecordInvalid => error
|
||||
@network_error = true if error.try(:network_error?) && !APIEntrepriseService.api_up?
|
||||
@champ.update(data: nil, value: nil)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -448,7 +448,6 @@ module Users
|
|||
if @dossier.champs.any?(&:changed_for_autosave?)
|
||||
@dossier.last_champ_updated_at = Time.zone.now
|
||||
end
|
||||
|
||||
if !@dossier.save(**validation_options)
|
||||
errors += @dossier.errors.full_messages
|
||||
elsif should_change_groupe_instructeur?
|
||||
|
|
|
@ -2205,6 +2205,11 @@ enum TypeDeChamp {
|
|||
"""
|
||||
repetition
|
||||
|
||||
"""
|
||||
RNA
|
||||
"""
|
||||
rna
|
||||
|
||||
"""
|
||||
SIRET
|
||||
"""
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class APIEntreprise::AssociationJob < APIEntreprise::Job
|
||||
def perform(etablissement_id, procedure_id)
|
||||
find_etablissement(etablissement_id)
|
||||
etablissement_params = APIEntreprise::RNAAdapter.new(etablissement.siret, procedure_id).to_params
|
||||
etablissement_params = APIEntreprise::RNAAdapter.new(etablissement.siret, procedure_id, true).to_params
|
||||
etablissement.update!(etablissement_params)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
class APIEntreprise::Adapter
|
||||
UNAVAILABLE = 'Donnée indisponible'
|
||||
|
||||
def initialize(siret, procedure_id)
|
||||
def initialize(siret, procedure_id, depreciated = false)
|
||||
@siret = siret
|
||||
@procedure_id = procedure_id
|
||||
@depreciated = depreciated
|
||||
end
|
||||
|
||||
def api(procedure_id = nil)
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
require 'json_schemer'
|
||||
|
||||
class APIEntreprise::RNAAdapter < APIEntreprise::Adapter
|
||||
class InvalidSchemaError < ::StandardError
|
||||
def initialize(errors)
|
||||
super(errors.map(&:to_json).join("\n"))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_resource
|
||||
|
@ -6,26 +14,23 @@ class APIEntreprise::RNAAdapter < APIEntreprise::Adapter
|
|||
end
|
||||
|
||||
def process_params
|
||||
# Sometimes the associations endpoints responses with a 206,
|
||||
# and these response are often useable as the they only
|
||||
# contain an error message.
|
||||
# Therefore here we make sure that our response seems valid
|
||||
# by checking that there is an association attribute.
|
||||
if !data_source.key?(:association)
|
||||
{}
|
||||
else
|
||||
association_id = data_source[:association][:id]
|
||||
params = data_source[:association].slice(*attr_to_fetch)
|
||||
params = data_source[:association]
|
||||
params = params&.slice(*attr_to_fetch) if @depreciated
|
||||
params[:rna] = data_source.dig(:association, :id)
|
||||
if params[:rna].present? && valid_params?(params)
|
||||
params = params.transform_keys { |k| :"association_#{k}" }.deep_stringify_keys
|
||||
raise InvalidSchemaError.new(schemer.validate(params).to_a) unless schemer.valid?(params)
|
||||
|
||||
if association_id.present? && valid_params?(params)
|
||||
params[:rna] = association_id
|
||||
params.transform_keys { |k| :"association_#{k}" }
|
||||
else
|
||||
{}
|
||||
end
|
||||
params
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
def schemer
|
||||
@schemer ||= JSONSchemer.schema(Rails.root.join('app/schemas/association.json'))
|
||||
end
|
||||
|
||||
def attr_to_fetch
|
||||
[
|
||||
:titre,
|
||||
|
|
|
@ -57,6 +57,7 @@ class Champ < ApplicationRecord
|
|||
:dgfip?,
|
||||
:pole_emploi?,
|
||||
:mesri?,
|
||||
:rna?,
|
||||
:siret?,
|
||||
:stable_id,
|
||||
to: :type_de_champ
|
||||
|
|
44
app/models/champs/rna_champ.rb
Normal file
44
app/models/champs/rna_champ.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
# == 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
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
# value_json :jsonb
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# dossier_id :integer not null
|
||||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# type_de_champ_id :integer not null
|
||||
#
|
||||
class Champs::RNAChamp < Champ
|
||||
validates :value, allow_blank: true, format: {
|
||||
with: /\AW[0-9]{9}\z/, message: I18n.t(:not_a_rna, scope: 'activerecord.errors.messages')
|
||||
}, if: -> { validation_context != :brouillon }
|
||||
|
||||
delegate :id, to: :procedure, prefix: true
|
||||
|
||||
def title
|
||||
data&.dig("association_titre")
|
||||
end
|
||||
|
||||
def identifier
|
||||
title.present? ? "#{value} (#{title})" : value
|
||||
end
|
||||
|
||||
def for_export
|
||||
identifier
|
||||
end
|
||||
|
||||
def search_terms
|
||||
etablissement.present? ? etablissement.search_terms : [value]
|
||||
end
|
||||
end
|
|
@ -55,6 +55,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
explication: CADRE,
|
||||
dossier_link: CADRE,
|
||||
piece_justificative: STANDARD,
|
||||
rna: REFERENTIEL_EXTERNE,
|
||||
siret: PAIEMENT_IDENTIFICATION,
|
||||
carte: REFERENTIEL_EXTERNE,
|
||||
repetition: CADRE,
|
||||
|
@ -92,6 +93,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
explication: 'explication',
|
||||
dossier_link: 'dossier_link',
|
||||
piece_justificative: 'piece_justificative',
|
||||
rna: 'rna',
|
||||
carte: 'carte',
|
||||
repetition: 'repetition',
|
||||
titre_identite: 'titre_identite',
|
||||
|
@ -311,6 +313,10 @@ class TypeDeChamp < ApplicationRecord
|
|||
type_champ == TypeDeChamp.type_champs.fetch(:cnaf)
|
||||
end
|
||||
|
||||
def rna?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:rna)
|
||||
end
|
||||
|
||||
def dgfip?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:dgfip)
|
||||
end
|
||||
|
|
5
app/models/types_de_champ/rna_type_de_champ.rb
Normal file
5
app/models/types_de_champ/rna_type_de_champ.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class TypesDeChamp::RNATypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||
def estimated_fill_duration(revision)
|
||||
FILL_DURATION_MEDIUM
|
||||
end
|
||||
end
|
236
app/schemas/association.json
Normal file
236
app/schemas/association.json
Normal file
|
@ -0,0 +1,236 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "http://demarches-simplifiees.fr/association.schema.json",
|
||||
"title": "Association",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"association_titre": {
|
||||
"type": "string"
|
||||
},
|
||||
"association_objet": {
|
||||
"type": "string"
|
||||
},
|
||||
"association_rna": {
|
||||
"type": "string"
|
||||
},
|
||||
"association_date_creation": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"association_date_declaration": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"association_date_publication": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"association_date_dissolution": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_mise_a_jour": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_siret": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_siret_siege_social": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_code_civilite_dirigeant": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_civilite_dirigeant": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_code_etat": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_etat": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_code_groupement": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_groupement": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"association_address_siege": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"complement": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"numero_voie": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type_voie": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"libelle_voie": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"distribution": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"code_insee": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"code_postal": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"commune": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"association_titre",
|
||||
"association_rna",
|
||||
"association_date_creation",
|
||||
"association_date_declaration",
|
||||
"association_date_publication"
|
||||
]
|
||||
}
|
1
app/views/champs/rna/show.turbo_stream.haml
Normal file
1
app/views/champs/rna/show.turbo_stream.haml
Normal file
|
@ -0,0 +1 @@
|
|||
= turbo_stream.update dom_id(@champ, :rna_info), partial: 'shared/champs/rna/association', locals: { champ: @champ, network_error: @network_error, rna: @rna }
|
6
app/views/shared/champs/rna/_association.html.haml
Normal file
6
app/views/shared/champs/rna/_association.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
- if network_error
|
||||
%p.pt-1= t('.network_error')
|
||||
- elsif @rna.present? && champ.data.blank?
|
||||
%p.pt-1= t('.not_found')
|
||||
- elsif champ.value.present?
|
||||
%p.pt-1= t('.data_fetched', title: champ.title)
|
16
app/views/shared/champs/rna/_show.html.haml
Normal file
16
app/views/shared/champs/rna/_show.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
- if champ.value.blank?
|
||||
%p= t('.not_filled')
|
||||
- elsif profile == 'instructeur'
|
||||
- if champ.data.blank?
|
||||
%p= t('.not_found', rna: champ.value)
|
||||
- else
|
||||
%p= t('.data_fetched_title', rna: champ.value)
|
||||
%ul
|
||||
- ['association_titre', 'association_objet', ].each do |scope|
|
||||
- if champ.data[scope].present?
|
||||
%li #{t("activemodel.attributes.rna_champ.data.#{scope}")} : #{champ.data[scope].capitalize}
|
||||
- ['association_date_creation', 'association_date_declaration', 'association_date_publication'].each do |scope|
|
||||
- if champ.data[scope].present?
|
||||
%li #{t("activemodel.attributes.rna_champ.data.#{scope}")} : #{l(champ.data[scope].to_date)}
|
||||
- else
|
||||
%p= champ.identifier
|
|
@ -50,6 +50,8 @@
|
|||
= render partial: "shared/champs/communes/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:regions)
|
||||
= render partial: "shared/champs/regions/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:rna)
|
||||
= render partial: "shared/champs/rna/show", locals: { champ: c, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:date)
|
||||
= c.to_s
|
||||
- when TypeDeChamp.type_champs.fetch(:datetime)
|
||||
|
|
|
@ -311,6 +311,7 @@ en:
|
|||
errors:
|
||||
messages:
|
||||
not_a_phone: 'Invalid phone number'
|
||||
not_a_rna: 'Invalid RNA number'
|
||||
models:
|
||||
attestation_template:
|
||||
attributes:
|
||||
|
|
|
@ -305,9 +305,12 @@ fr:
|
|||
<< : *default_attributes
|
||||
procedure:
|
||||
zone: La démarche est mise en œuvre par
|
||||
champs:
|
||||
value: Valeur du champ
|
||||
errors:
|
||||
messages:
|
||||
not_a_phone: 'Numéro de téléphone invalide'
|
||||
not_a_rna: 'Numéro RNA invalide'
|
||||
models:
|
||||
attestation_template:
|
||||
attributes:
|
||||
|
|
10
config/locales/models/champs/rna_champ/en.yml
Normal file
10
config/locales/models/champs/rna_champ/en.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
en:
|
||||
activemodel:
|
||||
attributes:
|
||||
rna_champ:
|
||||
data:
|
||||
association_titre: Association name
|
||||
association_objet: Association purpose
|
||||
association_date_creation: Creation date
|
||||
association_date_declaration: Declaration date
|
||||
association_date_publication: Publication date
|
11
config/locales/models/champs/rna_champ/fr.yml
Normal file
11
config/locales/models/champs/rna_champ/fr.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
fr:
|
||||
activemodel:
|
||||
attributes:
|
||||
rna_champ:
|
||||
value: Numéro RNA
|
||||
data:
|
||||
association_titre: Nom de l'association
|
||||
association_objet: Objet de l'association
|
||||
association_date_creation: Date de création
|
||||
association_date_declaration: Date de déclaration
|
||||
association_date_publication: Date de publication
|
43
config/locales/models/type_de_champ/en.yml
Normal file
43
config/locales/models/type_de_champ/en.yml
Normal file
|
@ -0,0 +1,43 @@
|
|||
fr:
|
||||
activerecord:
|
||||
models:
|
||||
type_de_champ: 'Field type'
|
||||
attributes:
|
||||
type_de_champ:
|
||||
type_champs:
|
||||
text: 'Text'
|
||||
textarea: 'Text area'
|
||||
date: 'Date'
|
||||
datetime: 'Datetime'
|
||||
number: 'Number'
|
||||
decimal_number: 'Decimal number'
|
||||
integer_number: 'Integer number'
|
||||
checkbox: 'Checkbox'
|
||||
civilite: 'Civility'
|
||||
email: 'Email'
|
||||
phone: 'Phone'
|
||||
address: 'Adress'
|
||||
yes_no: 'Yes/No'
|
||||
drop_down_list: 'Dropdown list'
|
||||
multiple_drop_down_list: 'Multiple dropdown list'
|
||||
linked_drop_down_list: 'Linked dropdown list'
|
||||
pays: 'Country'
|
||||
regions: 'Regions'
|
||||
departements: 'County'
|
||||
communes: 'Municipality'
|
||||
engagement: 'Commitment'
|
||||
header_section: 'Header section'
|
||||
explication: 'Explication'
|
||||
dossier_link: 'File link'
|
||||
piece_justificative: 'Supporting document'
|
||||
siret: 'SIRET'
|
||||
rna: 'RNA'
|
||||
carte: 'Card'
|
||||
repetition: 'Repetition'
|
||||
titre_identite: 'Identity title'
|
||||
iban: 'Iban'
|
||||
annuaire_education: 'Schooling directory'
|
||||
cnaf: 'Data from Caisse nationale des allocations familiales'
|
||||
dgfip: 'Data from Direction générale des Finances publiques'
|
||||
pole_emploi: 'Pôle emploi status'
|
||||
mesri: "Data from Ministère de l'Enseignement Supérieur, de la Recherche et de l'Innovation"
|
|
@ -36,9 +36,11 @@ fr:
|
|||
communes: 'Communes'
|
||||
header_section: 'Titre de section'
|
||||
explication: 'Explication'
|
||||
engagement: 'Engagement'
|
||||
dossier_link: 'Lien vers un autre dossier'
|
||||
piece_justificative: 'Pièce justificative'
|
||||
siret: 'SIRET'
|
||||
rna: 'RNA'
|
||||
carte: 'Carte'
|
||||
repetition: 'Bloc répétable'
|
||||
titre_identite: 'Titre identité'
|
||||
|
|
|
@ -20,6 +20,15 @@ en:
|
|||
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"
|
||||
rna:
|
||||
show:
|
||||
not_filled: not filled
|
||||
not_found: "RNA number %{rna} (no association found)"
|
||||
data_fetched_title: Data received from RNA number "%{rna}"
|
||||
association:
|
||||
data_fetched: "This RNA number is linked to %{title}"
|
||||
not_found: "No association found"
|
||||
network_error: "A network error has prevented the association associated with this RNA to be fetched"
|
||||
dgfip:
|
||||
show:
|
||||
not_filled: not filled
|
||||
|
|
|
@ -22,6 +22,15 @@ fr:
|
|||
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"
|
||||
rna:
|
||||
show:
|
||||
not_filled: non renseigné
|
||||
not_found: "RNA %{rna} (aucun établissement trouvé)"
|
||||
data_fetched_title: Données obtenues grâce au RNA "%{rna}"
|
||||
association:
|
||||
data_fetched: "Ce RNA correspond à %{title}"
|
||||
not_found: "Aucun établissement trouvé"
|
||||
network_error: "Une erreur réseau a empêché l'association liée à ce RNA d'être trouvée"
|
||||
dgfip:
|
||||
show:
|
||||
not_filled: non renseigné
|
||||
|
|
|
@ -153,6 +153,7 @@ Rails.application.routes.draw do
|
|||
|
||||
namespace :champs do
|
||||
get ':champ_id/siret', to: 'siret#show', as: :siret
|
||||
get ':champ_id/rna', to: 'rna#show', as: :rna
|
||||
get ':champ_id/dossier_link', to: 'dossier_link#show', as: :dossier_link
|
||||
post ':champ_id/repetition', to: 'repetition#add', as: :repetition
|
||||
delete ':champ_id/repetition', to: 'repetition#remove'
|
||||
|
|
13
db/schema.rb
13
db/schema.rb
|
@ -185,7 +185,7 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
create_table "champs", id: :serial, force: :cascade do |t|
|
||||
t.datetime "created_at"
|
||||
t.jsonb "data"
|
||||
t.integer "dossier_id"
|
||||
t.integer "dossier_id", null: false
|
||||
t.integer "etablissement_id"
|
||||
t.string "external_id"
|
||||
t.string "fetch_external_data_exceptions", array: true
|
||||
|
@ -194,7 +194,7 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
t.datetime "rebased_at"
|
||||
t.integer "row"
|
||||
t.string "type"
|
||||
t.integer "type_de_champ_id"
|
||||
t.integer "type_de_champ_id", null: false
|
||||
t.datetime "updated_at"
|
||||
t.string "value"
|
||||
t.jsonb "value_json"
|
||||
|
@ -874,11 +874,11 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
end
|
||||
|
||||
create_table "zone_labels", force: :cascade do |t|
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.bigint "zone_id", null: false
|
||||
t.date "designated_on", null: false
|
||||
t.string "name", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.bigint "zone_id", null: false
|
||||
t.index ["zone_id"], name: "index_zone_labels_on_zone_id"
|
||||
end
|
||||
|
||||
|
@ -890,6 +890,7 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
t.index ["acronym"], name: "index_zones_on_acronym", unique: true
|
||||
end
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "administrateurs", "users"
|
||||
add_foreign_key "administrateurs_instructeurs", "administrateurs"
|
||||
|
@ -906,6 +907,9 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
add_foreign_key "bulk_messages_groupe_instructeurs", "bulk_messages"
|
||||
add_foreign_key "bulk_messages_groupe_instructeurs", "groupe_instructeurs"
|
||||
add_foreign_key "champs", "champs", column: "parent_id"
|
||||
add_foreign_key "champs", "dossiers"
|
||||
add_foreign_key "champs", "etablissements"
|
||||
add_foreign_key "champs", "types_de_champ"
|
||||
add_foreign_key "closed_mails", "procedures"
|
||||
add_foreign_key "commentaires", "dossiers"
|
||||
add_foreign_key "commentaires", "experts"
|
||||
|
@ -915,6 +919,7 @@ ActiveRecord::Schema.define(version: 2022_10_07_113737) do
|
|||
add_foreign_key "dossiers", "groupe_instructeurs"
|
||||
add_foreign_key "dossiers", "procedure_revisions", column: "revision_id"
|
||||
add_foreign_key "dossiers", "users"
|
||||
add_foreign_key "etablissements", "dossiers"
|
||||
add_foreign_key "experts", "users"
|
||||
add_foreign_key "experts_procedures", "experts"
|
||||
add_foreign_key "experts_procedures", "procedures"
|
||||
|
|
159
spec/controllers/champs/rna_controller_spec.rb
Normal file
159
spec/controllers/champs/rna_controller_spec.rb
Normal file
|
@ -0,0 +1,159 @@
|
|||
describe Champs::RNAController, type: :controller do
|
||||
let(:user) { create(:user) }
|
||||
let(:procedure) { create(:procedure, :published, :with_rna) }
|
||||
|
||||
describe '#show' do
|
||||
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
|
||||
let(:champ) { dossier.champs.first }
|
||||
|
||||
let(:champs_attributes) do
|
||||
champ_attributes = []
|
||||
champ_attributes[champ.id] = { value: rna }
|
||||
champ_attributes
|
||||
end
|
||||
let(:params) do
|
||||
{
|
||||
champ_id: champ.id,
|
||||
dossier: {
|
||||
champs_attributes: champs_attributes
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when the user is signed in' do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in user
|
||||
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/associations\//)
|
||||
.to_return(body: body, status: status)
|
||||
allow_any_instance_of(APIEntrepriseToken).to receive(:expired?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when the RNA is empty' do
|
||||
let(:rna) { '' }
|
||||
let(:status) { 422 }
|
||||
let(:body) { '' }
|
||||
|
||||
subject! { get :show, params: params, format: :turbo_stream }
|
||||
|
||||
it 'clears the data and value on the model' do
|
||||
champ.reload
|
||||
expect(champ.data).to eq({})
|
||||
expect(champ.value).to eq("")
|
||||
end
|
||||
|
||||
it 'clears any information or error message' do
|
||||
expect(response.body).to include(ActionView::RecordIdentifier.dom_id(champ, :rna_info))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the RNA is invalid' do
|
||||
let(:rna) { '1234' }
|
||||
let(:status) { 422 }
|
||||
let(:body) { '' }
|
||||
|
||||
subject! { get :show, params: params, format: :turbo_stream }
|
||||
|
||||
it 'clears the data and value on the model' do
|
||||
champ.reload
|
||||
expect(champ.data).to be_nil
|
||||
expect(champ.value).to be_nil
|
||||
end
|
||||
|
||||
it 'displays a “RNA is invalid” error message' do
|
||||
expect(response.body).to include("Aucun établissement trouvé")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the RNA is unknow' do
|
||||
let(:rna) { 'W111111111' }
|
||||
let(:status) { 404 }
|
||||
let(:body) { '' }
|
||||
|
||||
subject! { get :show, params: params, format: :turbo_stream }
|
||||
|
||||
it 'clears the data on the model' do
|
||||
champ.reload
|
||||
expect(champ.data).to eq({})
|
||||
end
|
||||
|
||||
it 'displays a “RNA is invalid” error message' do
|
||||
expect(response.body).to include("Aucun établissement trouvé")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the API is unavailable due to network error' do
|
||||
let(:rna) { 'W595001988' }
|
||||
let(:status) { 503 }
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||||
|
||||
before do
|
||||
expect(APIEntrepriseService).to receive(:api_up?).and_return(false)
|
||||
end
|
||||
|
||||
subject! { get :show, params: params, format: :turbo_stream }
|
||||
|
||||
it 'clears the data and value on the model' do
|
||||
champ.reload
|
||||
expect(champ.data).to be_nil
|
||||
expect(champ.value).to be_nil
|
||||
end
|
||||
|
||||
it 'displays a “API is unavailable” error message' do
|
||||
expect(response.body).to include("Une erreur réseau a empêché l'association liée à ce RNA d'être trouvée")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the RNA informations are retrieved successfully' do
|
||||
let(:rna) { 'W595001988' }
|
||||
let(:status) { 200 }
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||||
let(:expected_data) do
|
||||
{
|
||||
"association_id" => "W595001988",
|
||||
"association_titre" => "UN SUR QUATRE",
|
||||
"association_objet" => "valoriser, transmettre et partager auprès des publics les plus larges possibles, les bienfaits de l'immigration, la richesse de la diversité et la curiosité de l'autre autrement",
|
||||
"association_siret" => nil,
|
||||
"association_date_creation" => "2014-01-23",
|
||||
"association_date_declaration" => "2014-01-24",
|
||||
"association_date_publication" => "2014-02-08",
|
||||
"association_date_dissolution" => "0001-01-01",
|
||||
"association_adresse_siege" => {
|
||||
"complement" => "",
|
||||
"numero_voie" => "61",
|
||||
"type_voie" => "RUE",
|
||||
"libelle_voie" => "des Noyers",
|
||||
"distribution" => "_",
|
||||
"code_insee" => "93063",
|
||||
"code_postal" => "93230",
|
||||
"commune" => "Romainville"
|
||||
},
|
||||
"association_code_civilite_dirigeant" => "PM",
|
||||
"association_civilite_dirigeant" => "Monsieur le Président",
|
||||
"association_code_etat" => "A",
|
||||
"association_etat" => "Active",
|
||||
"association_code_groupement" => "S",
|
||||
"association_groupement" => "simple",
|
||||
"association_mise_a_jour" => 1392295833,
|
||||
"association_rna" => "W595001988"
|
||||
}
|
||||
end
|
||||
|
||||
subject! { get :show, params: params, format: :turbo_stream }
|
||||
|
||||
it 'populates the data and RNA on the model' do
|
||||
champ.reload
|
||||
expect(champ.value).to eq(rna)
|
||||
expect(champ.data).to eq(expected_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not signed in' do
|
||||
subject! { get :show, params: { champ_id: champ.id }, format: :turbo_stream }
|
||||
|
||||
it { expect(response.code).to eq('401') }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -206,6 +206,12 @@ FactoryBot.define do
|
|||
value { '44011762001530' }
|
||||
end
|
||||
|
||||
factory :champ_rna, class: 'Champs::RNAChamp' do
|
||||
type_de_champ { association :type_de_champ_rna, procedure: dossier.procedure }
|
||||
association :etablissement, factory: [:etablissement]
|
||||
value { 'W173847273' }
|
||||
end
|
||||
|
||||
factory :champ_repetition, class: 'Champs::RepetitionChamp' do
|
||||
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
|
||||
|
||||
|
|
|
@ -250,6 +250,12 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :with_rna do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_rna, procedure: procedure)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_dgfip do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_dgfip, procedure: procedure)
|
||||
|
|
|
@ -140,6 +140,9 @@ FactoryBot.define do
|
|||
factory :type_de_champ_siret do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:siret) }
|
||||
end
|
||||
factory :type_de_champ_rna do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:rna) }
|
||||
end
|
||||
factory :type_de_champ_iban do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:iban) }
|
||||
end
|
||||
|
|
30
spec/fixtures/files/api_entreprise/associations_invalid.json
vendored
Normal file
30
spec/fixtures/files/api_entreprise/associations_invalid.json
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"association": {
|
||||
"id": "W595001988",
|
||||
"titre": "UN SUR QUATRE",
|
||||
"objet": "valoriser, transmettre et partager auprès des publics les plus larges possibles, les bienfaits de l'immigration, la richesse de la diversité et la curiosité de l'autre autrement",
|
||||
"siret": null,
|
||||
"date_creation": "test",
|
||||
"date_declaration": "2014-01-24",
|
||||
"date_publication": "2014-02-08",
|
||||
"date_dissolution": "0001-01-01",
|
||||
"adresse_siege": {
|
||||
"complement": "",
|
||||
"numero_voie": "61",
|
||||
"type_voie": "RUE",
|
||||
"libelle_voie": "des Noyers",
|
||||
"distribution": "_",
|
||||
"code_insee": "93063",
|
||||
"code_postal": "93230",
|
||||
"commune": "Romainville"
|
||||
},
|
||||
"code_civilite_dirigeant": "PM",
|
||||
"civilite_dirigeant": "Monsieur le Président",
|
||||
"code_etat": "A",
|
||||
"etat": "Active",
|
||||
"code_groupement": "S",
|
||||
"groupement": "simple",
|
||||
"mise_a_jour": 1392295833
|
||||
},
|
||||
"date_extraction_donnees": 1427210585
|
||||
}
|
|
@ -12,7 +12,7 @@ describe APIEducation::AnnuaireEducationAdapter do
|
|||
let(:body) { File.read('spec/fixtures/files/api_education/annuaire_education.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
it '#to_params return vaid hash' do
|
||||
it '#to_params return valid hash' do
|
||||
expect(subject).to be_an_instance_of(Hash)
|
||||
expect(subject['identifiant_de_l_etablissement']).to eq(search_term)
|
||||
expect(subject['code_type_contrat_prive']).to eq(99)
|
||||
|
@ -23,7 +23,7 @@ describe APIEducation::AnnuaireEducationAdapter do
|
|||
let(:body) { File.read('spec/fixtures/files/api_education/annuaire_education_bug.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
it '#to_params return vaid hash' do
|
||||
it '#to_params return valid hash' do
|
||||
expect(subject).to be_an_instance_of(Hash)
|
||||
expect(subject['identifiant_de_l_etablissement']).to eq(search_term)
|
||||
expect(subject['code_type_contrat_prive']).to eq(99)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
describe APIEntreprise::RNAAdapter do
|
||||
let(:siret) { '50480511000013' }
|
||||
let(:rna) { 'W111111111' }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:procedure_id) { procedure.id }
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||||
let(:status) { 200 }
|
||||
let(:adapter) { described_class.new(siret, procedure_id) }
|
||||
let(:adapter) { described_class.new(rna, procedure_id) }
|
||||
|
||||
subject { adapter.to_params }
|
||||
|
||||
|
@ -14,27 +12,45 @@ describe APIEntreprise::RNAAdapter do
|
|||
allow_any_instance_of(APIEntrepriseToken).to receive(:expired?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when siret is not valid' do
|
||||
let(:siret) { '234567' }
|
||||
context 'when rna is not valid' do
|
||||
let(:rna) { '234567' }
|
||||
let(:body) { '' }
|
||||
let(:status) { 404 }
|
||||
|
||||
it { is_expected.to eq({}) }
|
||||
end
|
||||
|
||||
it { expect(subject).to be_an_instance_of(Hash) }
|
||||
context "when responds with valid schema" do
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
describe 'Attributs Associations' do
|
||||
it { expect(subject[:association_rna]).to eq('W595001988') }
|
||||
it '#to_params return valid hash' do
|
||||
expect(subject).to be_an_instance_of(Hash)
|
||||
expect(subject["association_rna"]).to eq('W595001988')
|
||||
expect(subject["association_titre"]).to eq('UN SUR QUATRE')
|
||||
expect(subject["association_objet"]).to eq("valoriser, transmettre et partager auprès des publics les plus larges possibles, les bienfaits de l'immigration, la richesse de la diversité et la curiosité de l'autre autrement")
|
||||
expect(subject["association_date_creation"]).to eq('2014-01-23')
|
||||
expect(subject["association_date_declaration"]).to eq('2014-01-24')
|
||||
expect(subject["association_date_publication"]).to eq('2014-02-08')
|
||||
end
|
||||
end
|
||||
|
||||
it { expect(subject[:association_titre]).to eq('UN SUR QUATRE') }
|
||||
context "when responds with invalid schema" do
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations_invalid.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
it { expect(subject[:association_objet]).to eq("valoriser, transmettre et partager auprès des publics les plus larges possibles, les bienfaits de l'immigration, la richesse de la diversité et la curiosité de l'autre autrement") }
|
||||
it '#to_params raise exception' do
|
||||
expect { subject }.to raise_exception(APIEntreprise::RNAAdapter::InvalidSchemaError)
|
||||
end
|
||||
end
|
||||
|
||||
it { expect(subject[:association_date_creation]).to eq('2014-01-23') }
|
||||
context "when depreciated adapter is used" do
|
||||
let(:adapter) { described_class.new(rna, procedure_id, true) }
|
||||
let(:body) { File.read('spec/fixtures/files/api_entreprise/associations.json') }
|
||||
let(:status) { 200 }
|
||||
|
||||
it { expect(subject[:association_date_declaration]).to eq('2014-01-24') }
|
||||
|
||||
it { expect(subject[:association_date_publication]).to eq('2014-02-08') }
|
||||
it '#to_params filter the keys' do
|
||||
expect(subject.keys).to eq(["association_titre", "association_objet", "association_date_creation", "association_date_declaration", "association_date_publication", "association_rna"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,9 +14,9 @@ describe '20220705164551_remove_unused_champs' do
|
|||
|
||||
describe 'remove_unused_champs' do
|
||||
it "with bad champs" do
|
||||
expect(Champ.where(dossier: dossier).count).to eq(38)
|
||||
expect(Champ.where(dossier: dossier).count).to eq(39)
|
||||
run_task
|
||||
expect(Champ.where(dossier: dossier).count).to eq(37)
|
||||
expect(Champ.where(dossier: dossier).count).to eq(38)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
25
spec/models/champs/rna_champ_spec.rb
Normal file
25
spec/models/champs/rna_champ_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
describe Champs::RNAChamp do
|
||||
let(:champ) { create(:champ_rna, value: "W182736273") }
|
||||
|
||||
describe '#valid?' do
|
||||
it { expect(build(:champ_rna, value: nil)).to be_valid }
|
||||
it { expect(build(:champ_rna, value: "2736251627")).to_not be_valid }
|
||||
it { expect(build(:champ_rna, value: "A172736283")).to_not be_valid }
|
||||
it { expect(build(:champ_rna, value: "W1827362718")).to_not be_valid }
|
||||
it { expect(build(:champ_rna, value: "W182736273")).to be_valid }
|
||||
end
|
||||
|
||||
describe "#export" do
|
||||
context "with association title" do
|
||||
before do
|
||||
champ.update(data: { association_titre: "Super asso" })
|
||||
end
|
||||
|
||||
it { expect(champ.for_export).to eq("W182736273 (Super asso)") }
|
||||
end
|
||||
|
||||
context "no association title" do
|
||||
it { expect(champ.for_export).to eq("W182736273") }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -72,6 +72,7 @@ describe ProcedureExportService do
|
|||
"pays",
|
||||
"dossier_link",
|
||||
"piece_justificative",
|
||||
"rna",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"iban",
|
||||
|
@ -163,6 +164,7 @@ describe ProcedureExportService do
|
|||
"pays",
|
||||
"dossier_link",
|
||||
"piece_justificative",
|
||||
"rna",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"iban",
|
||||
|
@ -249,6 +251,7 @@ describe ProcedureExportService do
|
|||
"pays",
|
||||
"dossier_link",
|
||||
"piece_justificative",
|
||||
"rna",
|
||||
"carte",
|
||||
"titre_identite",
|
||||
"iban",
|
||||
|
|
|
@ -17,7 +17,8 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
let(:champ3) { create(:champ_explication, dossier: dossier, value: "mazette") }
|
||||
let(:champ4) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
|
||||
let(:champ5) { create(:champ_textarea, dossier: dossier, value: "Some long text in a textarea.") }
|
||||
let(:champs) { [champ1, champ2, champ3, champ4, champ5] }
|
||||
let(:champ6) { create(:champ_rna, value: "W173847273") }
|
||||
let(:champs) { [champ1, champ2, champ3, champ4, champ5, champ6] }
|
||||
|
||||
it "renders titles and values of champs" do
|
||||
expect(subject).to include(champ1.libelle)
|
||||
|
@ -29,7 +30,9 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
expect(subject).to include(dossier.text_summary)
|
||||
|
||||
expect(subject).to include(champ5.libelle)
|
||||
expect(subject).to include(champ5.libelle)
|
||||
expect(subject).to include(champ5.value)
|
||||
expect(subject).to include(champ6.libelle)
|
||||
expect(subject).to include(champ6.value)
|
||||
end
|
||||
|
||||
it "doesn't render explication champs" do
|
||||
|
|
Loading…
Reference in a new issue