feat(api particulier): add DGFiP field
This commit is contained in:
parent
08405226b7
commit
2110ef072c
32 changed files with 577 additions and 76 deletions
30
app/assets/stylesheets/dgfip.scss
Normal file
30
app/assets/stylesheets/dgfip.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
@import "constants";
|
||||
@import "colors";
|
||||
|
||||
table.dgfip {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -357,7 +357,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cnaf-inputs {
|
||||
.cnaf-inputs,
|
||||
.dgfip-inputs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
|
|
@ -348,8 +348,8 @@ module Users
|
|||
def champs_params
|
||||
params.permit(dossier: {
|
||||
champs_attributes: [
|
||||
:id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, :departement, :code_departement, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, :departement, :code_departement, value: []]
|
||||
:id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :numero_fiscal, :reference_avis, :piece_justificative_file, :departement, :code_departement, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :numero_fiscal, :reference_avis, :piece_justificative_file, :departement, :code_departement, value: []]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
|
|
@ -1933,6 +1933,11 @@ enum TypeDeChamp {
|
|||
"""
|
||||
departements
|
||||
|
||||
"""
|
||||
Données de la Direction générale des Finances publiques
|
||||
"""
|
||||
dgfip
|
||||
|
||||
"""
|
||||
Lien vers un autre dossier
|
||||
"""
|
||||
|
|
53
app/models/champs/dgfip_champ.rb
Normal file
53
app/models/champs/dgfip_champ.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
# == 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
|
||||
# etablissement_id :integer
|
||||
# external_id :string
|
||||
# parent_id :bigint
|
||||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::DgfipChamp < Champs::TextChamp
|
||||
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/dgfip-input-validation.middleware.ts
|
||||
validates :numero_fiscal, format: { with: /\A\w{13,14}\z/ }, if: -> { reference_avis.present? && validation_context != :brouillon }
|
||||
validates :reference_avis, format: { with: /\A\w{13,14}\z/ }, if: -> { numero_fiscal.present? && validation_context != :brouillon }
|
||||
|
||||
store_accessor :value_json, :numero_fiscal, :reference_avis
|
||||
|
||||
def blank?
|
||||
external_id.nil?
|
||||
end
|
||||
|
||||
def fetch_external_data?
|
||||
true
|
||||
end
|
||||
|
||||
def fetch_external_data
|
||||
if valid?
|
||||
APIParticulier::DgfipAdapter.new(
|
||||
procedure.api_particulier_token,
|
||||
numero_fiscal,
|
||||
reference_avis,
|
||||
procedure.api_particulier_sources
|
||||
).to_params
|
||||
end
|
||||
end
|
||||
|
||||
def external_id
|
||||
if numero_fiscal.present? && reference_avis.present?
|
||||
{ reference_avis: reference_avis, numero_fiscal: numero_fiscal }.to_json
|
||||
end
|
||||
end
|
||||
end
|
|
@ -726,6 +726,10 @@ class Procedure < ApplicationRecord
|
|||
api_particulier_sources['cnaf'].present?
|
||||
end
|
||||
|
||||
def dgfip_enabled?
|
||||
api_particulier_sources['dgfip'].present?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_for_publication?
|
||||
|
|
|
@ -50,7 +50,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
titre_identite: 'titre_identite',
|
||||
iban: 'iban',
|
||||
annuaire_education: 'annuaire_education',
|
||||
cnaf: 'cnaf'
|
||||
cnaf: 'cnaf',
|
||||
dgfip: 'dgfip'
|
||||
}
|
||||
|
||||
belongs_to :revision, class_name: 'ProcedureRevision', optional: true
|
||||
|
@ -324,6 +325,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
has_legacy_number
|
||||
when TypeDeChamp.type_champs.fetch(:cnaf)
|
||||
procedure.cnaf_enabled?
|
||||
when TypeDeChamp.type_champs.fetch(:dgfip)
|
||||
procedure.dgfip_enabled?
|
||||
else
|
||||
true
|
||||
end
|
||||
|
|
2
app/models/types_de_champ/dgfip_type_de_champ.rb
Normal file
2
app/models/types_de_champ/dgfip_type_de_champ.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class TypesDeChamp::DgfipTypeDeChamp < TypesDeChamp::TextTypeDeChamp
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
%table.dgfip
|
||||
%caption #{t("api_particulier.providers.dgfip.scopes.#{scope}.libelle")} :
|
||||
- agregats_fiscaux.slice('revenuBrutGlobal', 'revenuImposable', 'impotRevenuNetAvantCorrections', 'montantImpot', 'revenuFiscalReference', 'anneeImpots', 'anneeRevenus', 'erreurCorrectif', 'situationPartielle').keys.each do |key|
|
||||
%tr
|
||||
%th= t("api_particulier.providers.dgfip.scopes.#{scope}.#{key}")
|
||||
%td= agregats_fiscaux[key]
|
6
app/views/shared/champs/dgfip/_complements.html.haml
Normal file
6
app/views/shared/champs/dgfip/_complements.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
%table.dgfip
|
||||
%caption #{t("api_particulier.providers.dgfip.scopes.#{scope}.libelle")} :
|
||||
- complements.slice('erreurCorrectif', 'situationPartielle').keys.each do |key|
|
||||
%tr
|
||||
%th= t("api_particulier.providers.dgfip.scopes.#{scope}.#{key}")
|
||||
%td= complements[key]
|
6
app/views/shared/champs/dgfip/_declarant.html.haml
Normal file
6
app/views/shared/champs/dgfip/_declarant.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
%table.dgfip
|
||||
%caption #{t("api_particulier.providers.dgfip.scopes.#{scope}.libelle")} :
|
||||
- declarant.slice('nom', 'nomNaissance', 'prenoms', 'dateNaissance').keys.each do |key|
|
||||
%tr
|
||||
%th= t("api_particulier.providers.dgfip.scopes.#{scope}.#{key}")
|
||||
%td= declarant[key]
|
6
app/views/shared/champs/dgfip/_echeance_avis.html.haml
Normal file
6
app/views/shared/champs/dgfip/_echeance_avis.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
%table.dgfip
|
||||
%caption #{t("api_particulier.providers.dgfip.scopes.#{scope}.libelle")} :
|
||||
- echeance_avis.slice('dateRecouvrement', 'dateEtablissement').keys.each do |key|
|
||||
%tr
|
||||
%th= t("api_particulier.providers.dgfip.scopes.#{scope}.#{key}")
|
||||
%td= echeance_avis[key]
|
6
app/views/shared/champs/dgfip/_foyer_fiscal.html.haml
Normal file
6
app/views/shared/champs/dgfip/_foyer_fiscal.html.haml
Normal file
|
@ -0,0 +1,6 @@
|
|||
%table.dgfip
|
||||
%caption #{t("api_particulier.providers.dgfip.scopes.#{scope}.libelle")} :
|
||||
- foyer_fiscal.slice('annee', 'adresse', 'nombreParts', 'situationFamille', 'nombrePersonnesCharge').keys.each do |key|
|
||||
%tr
|
||||
%th= t("api_particulier.providers.dgfip.scopes.#{scope}.#{key}")
|
||||
%td= foyer_fiscal[key]
|
30
app/views/shared/champs/dgfip/_show.html.haml
Normal file
30
app/views/shared/champs/dgfip/_show.html.haml
Normal file
|
@ -0,0 +1,30 @@
|
|||
- if champ.blank?
|
||||
%p= t('.not_filled')
|
||||
- elsif champ.data.blank?
|
||||
%p= t('.fetching_data',
|
||||
numero_fiscal: champ.numero_fiscal,
|
||||
reference_avis: champ.reference_avis)
|
||||
- else
|
||||
- if profile == 'usager'
|
||||
- sources = champ.procedure.api_particulier_sources['dgfip'].keys
|
||||
- i18n_sources = sources.map { |s| I18n.t("#{s}.libelle", scope: 'api_particulier.providers.dgfip.scopes') }
|
||||
%p= t('.data_fetched',
|
||||
sources: i18n_sources.to_sentence,
|
||||
numero_fiscal: champ.numero_fiscal,
|
||||
reference_avis: champ.reference_avis)
|
||||
|
||||
- if profile == 'instructeur'
|
||||
%p= t('.data_fetched_title')
|
||||
|
||||
- champ.data.slice('declarant1', 'declarant2', 'echeance_avis', 'foyer_fiscal', 'agregats_fiscaux', 'complements').keys.each do |scope|
|
||||
- case scope
|
||||
- when 'declarant1', 'declarant2'
|
||||
= render partial: 'shared/champs/dgfip/declarant', locals: { scope: scope, declarant: champ.data[scope] }
|
||||
- when 'echeance_avis'
|
||||
= render partial: 'shared/champs/dgfip/echeance_avis', locals: { scope: scope, echeance_avis: champ.data[scope] }
|
||||
- when 'foyer_fiscal'
|
||||
= render partial: 'shared/champs/dgfip/foyer_fiscal', locals: { scope: scope, foyer_fiscal: champ.data[scope] }
|
||||
- when 'agregats_fiscaux'
|
||||
= render partial: 'shared/champs/dgfip/agregats_fiscaux', locals: { scope: scope, agregats_fiscaux: champ.data[scope] }
|
||||
- when 'complements'
|
||||
= render partial: 'shared/champs/dgfip/complements', locals: { scope: scope, complements: champ.data[scope] }
|
|
@ -38,6 +38,8 @@
|
|||
= 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(:dgfip)
|
||||
= render partial: "shared/champs/dgfip/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/_dgfip.html.haml
Normal file
16
app/views/shared/dossiers/editable_champs/_dgfip.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
.dgfip-inputs
|
||||
%div
|
||||
= form.label :numero_fiscal, t('.numero_fiscal_label')
|
||||
%p.notice= t('.numero_fiscal_notice')
|
||||
= form.text_field :numero_fiscal,
|
||||
required: champ.mandatory?,
|
||||
size: 14,
|
||||
aria: { describedby: describedby_id(champ) }
|
||||
|
||||
%div
|
||||
= form.label :reference_avis, t('.reference_avis_label')
|
||||
%p.notice= t('.reference_avis_notice')
|
||||
= form.text_field :reference_avis,
|
||||
size: 14,
|
||||
required: champ.mandatory?,
|
||||
aria: { describedby: describedby_id(champ) }
|
|
@ -291,6 +291,12 @@ en:
|
|||
invalid: "must be a maximum of 7 digits"
|
||||
code_postal:
|
||||
invalid: "must be 5 characters long"
|
||||
"champs/dgfip_champ":
|
||||
attributes:
|
||||
numero_fiscal:
|
||||
invalid: "must be 13 or 14 characters long"
|
||||
reference_avis:
|
||||
invalid: "must be 13 or 14 characters long"
|
||||
errors:
|
||||
messages:
|
||||
dossier_not_found: "The file does not exist or you do not have access to it."
|
||||
|
|
|
@ -299,6 +299,12 @@ fr:
|
|||
invalid: "doit être composé au maximum de 7 chiffres"
|
||||
code_postal:
|
||||
invalid: "doit posséder 5 caractères"
|
||||
"champs/dgfip_champ":
|
||||
attributes:
|
||||
numero_fiscal:
|
||||
invalid: "doit posséder 13 ou 14 caractères"
|
||||
reference_avis:
|
||||
invalid: "doit posséder 13 ou 14 caractères"
|
||||
errors:
|
||||
messages:
|
||||
saml_not_authorized: "Vous n’êtes pas autorisé à accéder à ce service."
|
||||
|
|
|
@ -37,4 +37,4 @@ fr:
|
|||
iban: 'Iban'
|
||||
annuaire_education: 'Annuaire de l’éducation'
|
||||
cnaf: 'Données de la Caisse nationale des allocations familiales'
|
||||
|
||||
dgfip: 'Données de la Direction générale des Finances publiques'
|
||||
|
|
|
@ -7,6 +7,11 @@ en:
|
|||
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.
|
||||
dgfip:
|
||||
numero_fiscal_label: Tax number
|
||||
numero_fiscal_notice: It is usually composed of 13 to 14 characters.
|
||||
reference_avis_label: Tax notice reference
|
||||
reference_avis_notice: It is usually composed of 13 to 14 characters.
|
||||
header:
|
||||
expires_at:
|
||||
brouillon: "Expires at %{date} (%{duree_conservation_totale} months after the creation of this file)"
|
||||
|
@ -22,3 +27,9 @@ 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"
|
||||
dgfip:
|
||||
show:
|
||||
not_filled: not filled
|
||||
fetching_data: "Fetching data for declarant No. %{numero_fiscal} with tax notice reference %{reference_avis}."
|
||||
data_fetched: "Data concerning %{sources} linked to the declarant Nº %{numero_fiscal} with tax notice reference %{reference_avis} has been received from the DGFiP."
|
||||
data_fetched_title: "Data received from la Direction générale des Finances publiques"
|
||||
|
|
|
@ -7,6 +7,11 @@ fr:
|
|||
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.
|
||||
dgfip:
|
||||
numero_fiscal_label: Le numéro fiscal
|
||||
numero_fiscal_notice: Il est généralement composé de 13 ou 14 caractères.
|
||||
reference_avis_label: La référence d'avis d'imposition
|
||||
reference_avis_notice: Elle est généralement composée de 13 ou 14 caractères.
|
||||
header:
|
||||
expires_at:
|
||||
brouillon: "Expirera le %{date} (%{duree_conservation_totale} mois après la création du dossier)"
|
||||
|
@ -24,3 +29,9 @@ 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"
|
||||
dgfip:
|
||||
show:
|
||||
not_filled: non renseigné
|
||||
fetching_data: "La récupération automatique des données pour le déclarant Nº %{numero_fiscal} avec la référence d'avis %{reference_avis} est en cours."
|
||||
data_fetched: "Des données concernant %{sources} liées au déclarant Nº %{numero_fiscal} avec la référence d'avis %{reference_avis} ont été reçues depuis la DGFiP."
|
||||
data_fetched_title: "Données obtenues de la Direction générale des Finances publiques"
|
||||
|
|
|
@ -45,9 +45,39 @@ describe Administrateurs::JetonParticulierController, type: :controller do
|
|||
it 'saves the jeton' do
|
||||
expect(flash.alert).to be_nil
|
||||
expect(flash.notice).to eq("Le jeton a bien été mis à jour")
|
||||
expect(procedure.reload.api_particulier_token).to eql(token)
|
||||
expect(procedure.reload.api_particulier_scopes).to contain_exactly("dgfip_avis_imposition", "dgfip_adresse", "cnaf_allocataires", "cnaf_enfants", "cnaf_adresse", "cnaf_quotient_familial", "mesri_statut_etudiant")
|
||||
expect(procedure.reload.api_particulier_sources).to be_empty
|
||||
procedure.reload
|
||||
expect(procedure.api_particulier_token).to eql(token)
|
||||
expect(procedure.api_particulier_scopes).to contain_exactly(
|
||||
'cnaf_adresse',
|
||||
'cnaf_allocataires',
|
||||
'cnaf_enfants',
|
||||
'cnaf_quotient_familial',
|
||||
'dgfip_adresse_fiscale_annee',
|
||||
'dgfip_adresse_fiscale_taxation',
|
||||
'dgfip_annee_impot',
|
||||
'dgfip_annee_revenus',
|
||||
'dgfip_date_etablissement',
|
||||
'dgfip_date_recouvrement',
|
||||
'dgfip_declarant1_date_naissance',
|
||||
'dgfip_declarant1_nom',
|
||||
'dgfip_declarant1_nom_naissance',
|
||||
'dgfip_declarant1_prenoms',
|
||||
'dgfip_declarant2_date_naissance',
|
||||
'dgfip_declarant2_nom',
|
||||
'dgfip_declarant2_nom_naissance',
|
||||
'dgfip_declarant2_prenoms',
|
||||
'dgfip_erreur_correctif',
|
||||
'dgfip_impot_revenu_net_avant_corrections',
|
||||
'dgfip_montant_impot',
|
||||
'dgfip_nombre_parts',
|
||||
'dgfip_nombre_personnes_a_charge',
|
||||
'dgfip_revenu_brut_global',
|
||||
'dgfip_revenu_fiscal_reference',
|
||||
'dgfip_revenu_imposable',
|
||||
'dgfip_situation_familiale',
|
||||
'dgfip_situation_partielle'
|
||||
)
|
||||
expect(procedure.api_particulier_sources).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -189,6 +189,10 @@ FactoryBot.define do
|
|||
type_de_champ { association :type_de_champ_cnaf, procedure: dossier.procedure }
|
||||
end
|
||||
|
||||
factory :champ_dgfip, class: 'Champs::DgfipChamp' do
|
||||
type_de_champ { association :type_de_champ_dgfip, procedure: dossier.procedure }
|
||||
end
|
||||
|
||||
factory :champ_siret, class: 'Champs::SiretChamp' do
|
||||
type_de_champ { association :type_de_champ_siret, procedure: dossier.procedure }
|
||||
association :etablissement, factory: [:etablissement]
|
||||
|
|
|
@ -200,6 +200,12 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :with_dgfip do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_dgfip, procedure: procedure)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_explication do
|
||||
after(:build) do |procedure, _evaluator|
|
||||
build(:type_de_champ_explication, procedure: procedure)
|
||||
|
|
|
@ -157,6 +157,9 @@ FactoryBot.define do
|
|||
factory :type_de_champ_cnaf do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:cnaf) }
|
||||
end
|
||||
factory :type_de_champ_dgfip do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:dgfip) }
|
||||
end
|
||||
factory :type_de_champ_carte do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:carte) }
|
||||
end
|
||||
|
|
|
@ -38,7 +38,6 @@ http_interactions:
|
|||
- max-age=15552000
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"_id":"1d99db5a-a099-4314-ad2f-2707c6b505a6","name":"Application de
|
||||
sandbox","scopes":["dgfip_avis_imposition","dgfip_adresse","cnaf_allocataires","cnaf_enfants","cnaf_adresse","cnaf_quotient_familial","mesri_statut_etudiant"]}'
|
||||
string: '{"_id":"1d99db5a-a099-4314-ad2f-2707c6b505a6","name":"Application de sandbox","scopes":["cnaf_allocataires","cnaf_enfants","cnaf_adresse","cnaf_quotient_familial","dgfip_declarant1_nom","dgfip_declarant1_nom_naissance","dgfip_declarant1_prenoms","dgfip_declarant1_date_naissance","dgfip_declarant2_nom","dgfip_declarant2_nom_naissance","dgfip_declarant2_prenoms","dgfip_declarant2_date_naissance","dgfip_date_recouvrement","dgfip_date_etablissement","dgfip_adresse_fiscale_taxation","dgfip_adresse_fiscale_annee","dgfip_nombre_parts","dgfip_nombre_personnes_a_charge","dgfip_situation_familiale","dgfip_revenu_brut_global","dgfip_revenu_imposable","dgfip_impot_revenu_net_avant_corrections","dgfip_montant_impot","dgfip_revenu_fiscal_reference","dgfip_annee_impot","dgfip_annee_revenus","dgfip_erreur_correctif","dgfip_situation_partielle"]}'
|
||||
recorded_at: Tue, 16 Mar 2021 15:25:24 GMT
|
||||
recorded_with: VCR 6.0.0
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"avis_imposition": {
|
||||
"declarant1": {
|
||||
"nom": "FERRI",
|
||||
"nomNaissance": "FERRI",
|
||||
|
@ -12,22 +11,27 @@
|
|||
"prenoms": "",
|
||||
"dateNaissance": "12/08/1978"
|
||||
},
|
||||
"echeance_avis": {
|
||||
"dateRecouvrement": "09/10/2020",
|
||||
"dateEtablissement": "07/07/2020",
|
||||
"dateEtablissement": "07/07/2020"
|
||||
},
|
||||
"foyer_fiscal": {
|
||||
"annee": 2020,
|
||||
"adresse": "13 rue de la Plage 97615 Pamanzi",
|
||||
"nombreParts": 1,
|
||||
"situationFamille": "Célibataire",
|
||||
"nombrePersonnesCharge": 0,
|
||||
"nombrePersonnesCharge": 0
|
||||
},
|
||||
"agregats_fiscaux": {
|
||||
"revenuBrutGlobal": 38814,
|
||||
"revenuImposable": 38814,
|
||||
"impotRevenuNetAvantCorrections": 38814,
|
||||
"montantImpot": 38814,
|
||||
"revenuFiscalReference": 38814,
|
||||
"anneeImpots": "2020",
|
||||
"anneeRevenus": "2020",
|
||||
"situationPartielle": "SUP DOM"
|
||||
"anneeRevenus": "2020"
|
||||
},
|
||||
"foyer_fiscal": {
|
||||
"annee": 2020,
|
||||
"adresse": "13 rue de la Plage 97615 Pamanzi"
|
||||
"complements": {
|
||||
"situationPartielle": "SUP DOM"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,36 @@ describe APIParticulier::API do
|
|||
|
||||
it "doit retourner une liste de scopes" do
|
||||
VCR.use_cassette("api_particulier/success/introspect") do
|
||||
expect(subject).to match_array(['dgfip_avis_imposition', 'dgfip_adresse', 'cnaf_allocataires', 'cnaf_enfants', 'cnaf_adresse', 'cnaf_quotient_familial', 'mesri_statut_etudiant'])
|
||||
expect(subject).to contain_exactly(
|
||||
'cnaf_adresse',
|
||||
'cnaf_allocataires',
|
||||
'cnaf_enfants',
|
||||
'cnaf_quotient_familial',
|
||||
'dgfip_adresse_fiscale_annee',
|
||||
'dgfip_adresse_fiscale_taxation',
|
||||
'dgfip_annee_impot',
|
||||
'dgfip_annee_revenus',
|
||||
'dgfip_date_etablissement',
|
||||
'dgfip_date_recouvrement',
|
||||
'dgfip_declarant1_date_naissance',
|
||||
'dgfip_declarant1_nom',
|
||||
'dgfip_declarant1_nom_naissance',
|
||||
'dgfip_declarant1_prenoms',
|
||||
'dgfip_declarant2_date_naissance',
|
||||
'dgfip_declarant2_nom',
|
||||
'dgfip_declarant2_nom_naissance',
|
||||
'dgfip_declarant2_prenoms',
|
||||
'dgfip_erreur_correctif',
|
||||
'dgfip_impot_revenu_net_avant_corrections',
|
||||
'dgfip_montant_impot',
|
||||
'dgfip_nombre_parts',
|
||||
'dgfip_nombre_personnes_a_charge',
|
||||
'dgfip_revenu_brut_global',
|
||||
'dgfip_revenu_fiscal_reference',
|
||||
'dgfip_revenu_imposable',
|
||||
'dgfip_situation_familiale',
|
||||
'dgfip_situation_partielle'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,26 +17,13 @@ describe APIParticulier::DgfipAdapter do
|
|||
context 'and all the sources are requested' do
|
||||
let(:requested_sources) do
|
||||
{
|
||||
'dgfip' => {
|
||||
'avis_imposition' => [
|
||||
{ 'declarant1' => ['dateNaissance', 'nom', 'nomNaissance', 'prenoms'] },
|
||||
{ 'declarant2' => ['dateNaissance', 'nom', 'nomNaissance', 'prenoms'] },
|
||||
'anneeImpots',
|
||||
'anneeRevenus',
|
||||
'dateEtablissement',
|
||||
'dateRecouvrement',
|
||||
'erreurCorrectif',
|
||||
'impotRevenuNetAvantCorrections',
|
||||
'montantImpot',
|
||||
'nombreParts',
|
||||
'nombrePersonnesCharge',
|
||||
'revenuBrutGlobal',
|
||||
'revenuFiscalReference',
|
||||
'revenuImposable',
|
||||
'situationFamille',
|
||||
'situationPartielle'
|
||||
],
|
||||
'foyer_fiscal' => ['adresse', 'annee']
|
||||
"dgfip" => {
|
||||
"declarant1" => ["nom", "nomNaissance", "prenoms", "dateNaissance"],
|
||||
"declarant2" => ["nom", "nomNaissance", "prenoms", "dateNaissance"],
|
||||
"echeance_avis" => ["dateRecouvrement", "dateEtablissement"],
|
||||
"foyer_fiscal" => ["adresse", "annee", "nombreParts", "nombrePersonnesCharge", "situationFamille"],
|
||||
"agregats_fiscaux" => ["revenuBrutGlobal", "revenuImposable", "impotRevenuNetAvantCorrections", "montantImpot", "revenuFiscalReference", "anneeImpots", "anneeRevenus"],
|
||||
"complements" => ["erreurCorrectif", "situationPartielle"]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
@ -53,15 +40,15 @@ describe APIParticulier::DgfipAdapter do
|
|||
end
|
||||
|
||||
context 'when a declarer name is requested' do
|
||||
let(:requested_sources) { { 'dgfip' => { 'avis_imposition' => [{ 'declarant1' => ['nom'] }] } } }
|
||||
let(:requested_sources) { { 'dgfip' => { 'declarant1' => ['nom'] } } }
|
||||
|
||||
it { is_expected.to eq('avis_imposition' => { 'declarant1' => { 'nom' => 'FERRI' } }) }
|
||||
it { is_expected.to eq('declarant1' => { 'nom' => 'FERRI' }) }
|
||||
end
|
||||
|
||||
context 'when a revenue is requested' do
|
||||
let(:requested_sources) { { 'dgfip' => { 'avis_imposition' => ['revenuBrutGlobal'] } } }
|
||||
let(:requested_sources) { { 'dgfip' => { 'agregats_fiscaux' => ['revenuBrutGlobal'] } } }
|
||||
|
||||
it { is_expected.to eq('avis_imposition' => { 'revenuBrutGlobal' => 38814 }) }
|
||||
it { is_expected.to eq('agregats_fiscaux' => { 'revenuBrutGlobal' => 38814 }) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
103
spec/models/champs/dgfip_champ_spec.rb
Normal file
103
spec/models/champs/dgfip_champ_spec.rb
Normal file
|
@ -0,0 +1,103 @@
|
|||
describe Champs::DgfipChamp, type: :model do
|
||||
let(:champ) { described_class.new }
|
||||
|
||||
describe 'numero_fiscal and reference_avis' do
|
||||
before do
|
||||
champ.numero_fiscal = '1122299999092'
|
||||
champ.reference_avis = 'FC22299999092'
|
||||
end
|
||||
|
||||
it 'saves numero_fiscal and reference_avis' do
|
||||
expect(champ.numero_fiscal).to eq('1122299999092')
|
||||
expect(champ.reference_avis).to eq('FC22299999092')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'external_id' do
|
||||
context 'when only one data is given' do
|
||||
before do
|
||||
champ.numero_fiscal = '1122299999092'
|
||||
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_fiscal = '1122299999092'
|
||||
champ.reference_avis = 'FC22299999092'
|
||||
champ.save
|
||||
end
|
||||
|
||||
it { expect(JSON.parse(champ.external_id)).to eq({ "reference_avis" => "FC22299999092", "numero_fiscal" => "1122299999092" }) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#validate' do
|
||||
let(:numero_fiscal) { '1122299999092' }
|
||||
let(:reference_avis) { 'FC22299999092' }
|
||||
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_dgfip)) }
|
||||
let(:validation_context) { :create }
|
||||
|
||||
subject { champ.valid?(validation_context) }
|
||||
|
||||
before do
|
||||
champ.numero_fiscal = numero_fiscal
|
||||
champ.reference_avis = reference_avis
|
||||
end
|
||||
|
||||
context 'when numero_fiscal and reference_avis are valid' do
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
|
||||
context 'when numero_fiscal and reference_avis are nil' do
|
||||
let(:numero_fiscal) { nil }
|
||||
let(:reference_avis) { nil }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
|
||||
context 'when only reference_avis is nil' do
|
||||
let(:reference_avis) { nil }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Reference avis doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when only numero_fiscal is nil' do
|
||||
let(:numero_fiscal) { nil }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero fiscal doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when numero_fiscal is invalid' do
|
||||
let(:numero_fiscal) { '11222' }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Numero fiscal doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
|
||||
context 'and the validation_context is :brouillon' do
|
||||
let(:validation_context) { :brouillon }
|
||||
|
||||
it { is_expected.to be true }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when reference_avis is invalid' do
|
||||
let(:reference_avis) { 'FC222' }
|
||||
|
||||
it do
|
||||
is_expected.to be false
|
||||
expect(champ.errors.full_messages).to eq(["Reference avis doit posséder 13 ou 14 caractères"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,6 +78,7 @@ describe ProcedureExportService do
|
|||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"dgfip",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -166,6 +167,7 @@ describe ProcedureExportService do
|
|||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"dgfip",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
@ -250,6 +252,7 @@ describe ProcedureExportService do
|
|||
"iban",
|
||||
"annuaire_education",
|
||||
"cnaf",
|
||||
"dgfip",
|
||||
"text"
|
||||
]
|
||||
end
|
||||
|
|
|
@ -5,35 +5,44 @@ describe 'fetch API Particulier Data', js: true do
|
|||
|
||||
let(:expected_sources) do
|
||||
{
|
||||
"cnaf" =>
|
||||
'cnaf' =>
|
||||
{
|
||||
"adresse" => ["identite", "complementIdentite", "complementIdentiteGeo", "numeroRue", "lieuDit", "codePostalVille", "pays"],
|
||||
"allocataires" => ["nomPrenom", "dateDeNaissance", "sexe"],
|
||||
"enfants" => ["nomPrenom", "dateDeNaissance", "sexe"],
|
||||
"quotient_familial" => ["quotientFamilial", "annee", "mois"]
|
||||
'adresse' => ['identite', 'complementIdentite', 'complementIdentiteGeo', 'numeroRue', 'lieuDit', 'codePostalVille', 'pays'],
|
||||
'allocataires' => ['nomPrenom', 'dateDeNaissance', 'sexe'],
|
||||
'enfants' => ['nomPrenom', 'dateDeNaissance', 'sexe'],
|
||||
'quotient_familial' => ['quotientFamilial', 'annee', 'mois']
|
||||
},
|
||||
'dgfip' =>
|
||||
{
|
||||
'declarant1' => ['dateNaissance', 'nom', 'nomNaissance', 'prenoms'],
|
||||
'declarant2' => ['dateNaissance', 'nom', 'nomNaissance', 'prenoms'],
|
||||
'echeance_avis' => ['dateEtablissement', 'dateRecouvrement'],
|
||||
'foyer_fiscal' => ['adresse', 'annee', 'nombreParts', 'nombrePersonnesCharge', 'situationFamille'],
|
||||
'agregats_fiscaux' => ['anneeImpots', 'anneeRevenus', 'impotRevenuNetAvantCorrections', 'montantImpot', 'revenuBrutGlobal', 'revenuFiscalReference', 'revenuImposable'],
|
||||
'complements' => ['situationPartielle', 'erreurCorrectif']
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
stub_const("API_PARTICULIER_URL", "https://particulier.api.gouv.fr/api")
|
||||
stub_const('API_PARTICULIER_URL', 'https://particulier.api.gouv.fr/api')
|
||||
Flipper.enable(:api_particulier)
|
||||
end
|
||||
|
||||
context "when an administrateur is logged" do
|
||||
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")
|
||||
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")
|
||||
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))
|
||||
|
@ -42,7 +51,7 @@ describe 'fetch API Particulier Data', js: true do
|
|||
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' }
|
||||
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))
|
||||
|
||||
|
@ -54,7 +63,7 @@ describe 'fetch API Particulier Data', js: true do
|
|||
end
|
||||
end
|
||||
|
||||
within("#adresse") do
|
||||
within('#adresse') do
|
||||
check('identité')
|
||||
check('complément d’identité')
|
||||
check('complément d’identité géographique')
|
||||
|
@ -64,19 +73,67 @@ describe 'fetch API Particulier Data', js: true do
|
|||
check('pays')
|
||||
end
|
||||
|
||||
within("#quotient_familial") do
|
||||
within('#quotient_familial') do
|
||||
check('quotient familial')
|
||||
check('année')
|
||||
check('mois')
|
||||
end
|
||||
|
||||
click_on "Enregistrer"
|
||||
['declarant1', 'declarant2'].each do |scope|
|
||||
within("##{scope}") do
|
||||
check('nom')
|
||||
check('nom de naissance')
|
||||
check('prénoms')
|
||||
check('date de naissance')
|
||||
end
|
||||
end
|
||||
|
||||
within("#enfants") do
|
||||
scroll_to(find('#echeance_avis'))
|
||||
within ('#echeance_avis') do
|
||||
check('date de recouvrement')
|
||||
check("date d’établissement")
|
||||
end
|
||||
|
||||
within('#foyer_fiscal') do
|
||||
check('année')
|
||||
check('adresse')
|
||||
check('nombre de parts')
|
||||
check('situation familiale')
|
||||
check('nombre de personnes à charge')
|
||||
end
|
||||
|
||||
within('#agregats_fiscaux') do
|
||||
check('revenu brut global')
|
||||
check('revenu imposable')
|
||||
check('impôt sur le revenu net avant correction')
|
||||
check("montant de l’impôt")
|
||||
check('revenu fiscal de référence')
|
||||
check("année d’imposition")
|
||||
check('année des revenus')
|
||||
end
|
||||
|
||||
within('#complements') do
|
||||
check('erreur correctif')
|
||||
check('situation partielle')
|
||||
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)
|
||||
procedure.reload
|
||||
|
||||
expect(procedure.api_particulier_sources.keys).to contain_exactly('cnaf', 'dgfip')
|
||||
expect(procedure.api_particulier_sources['cnaf'].keys).to contain_exactly('adresse', 'allocataires', 'enfants', 'quotient_familial')
|
||||
expect(procedure.api_particulier_sources['dgfip'].keys).to contain_exactly('declarant1', 'declarant2', 'echeance_avis', 'foyer_fiscal', 'agregats_fiscaux', 'complements')
|
||||
|
||||
procedure.api_particulier_sources.each do |provider, scopes|
|
||||
scopes.each do |scope, fields|
|
||||
expect(fields).to match_array(expected_sources[provider][scope])
|
||||
end
|
||||
end
|
||||
|
||||
visit champs_admin_procedure_path(procedure)
|
||||
|
||||
|
@ -101,12 +158,14 @@ describe 'fetch API Particulier Data', js: true do
|
|||
let(:api_particulier_token) { '29eb50b65f64e8e00c0847a8bbcbd150e1f847' }
|
||||
let(:numero_allocataire) { '5843972' }
|
||||
let(:code_postal) { '92110' }
|
||||
let(:numero_fiscal) { '2097699999077' }
|
||||
let(:reference_avis) { '2097699999077' }
|
||||
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",
|
||||
create(:procedure, :for_individual, :with_service, :with_cnaf, :with_dgfip, :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)
|
||||
|
@ -138,7 +197,7 @@ describe 'fetch API Particulier Data', js: true do
|
|||
|
||||
fill_in 'Le code postal', with: code_postal
|
||||
|
||||
VCR.use_cassette("api_particulier/success/composition_familiale") do
|
||||
VCR.use_cassette('api_particulier/success/composition_familiale') do
|
||||
perform_enqueued_jobs { click_on 'Déposer le dossier' }
|
||||
end
|
||||
|
||||
|
@ -163,5 +222,69 @@ describe 'fetch API Particulier Data', js: true do
|
|||
expect(page).to have_content('PAUL SNOW masculin 04/01/2018')
|
||||
expect(page).to have_content('1856 6 2021')
|
||||
end
|
||||
|
||||
scenario 'it can fill a DGFiP field' do
|
||||
visit commencer_path(path: procedure.path)
|
||||
click_on 'Commencer la démarche'
|
||||
|
||||
choose 'Madame'
|
||||
fill_in 'individual_nom', with: 'FERRI'
|
||||
fill_in 'individual_prenom', with: 'Karine'
|
||||
|
||||
click_button('Continuer')
|
||||
|
||||
fill_in 'Le numéro fiscal', with: numero_fiscal
|
||||
fill_in "La référence d'avis d'imposition", with: 'wrong_code'
|
||||
|
||||
blur
|
||||
expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true)
|
||||
|
||||
dossier = Dossier.last
|
||||
expect(dossier.champs.second.reference_avis).to eq('wrong_code')
|
||||
|
||||
click_on 'Déposer le dossier'
|
||||
expect(page).to have_content(/reference avis doit posséder 13 ou 14 caractères/)
|
||||
|
||||
fill_in "La référence d'avis d'imposition", with: reference_avis
|
||||
|
||||
VCR.use_cassette('api_particulier/success/avis_imposition') 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 DGFiP/)
|
||||
|
||||
log_out
|
||||
|
||||
login_as instructeur.user, scope: :user
|
||||
|
||||
visit instructeur_dossier_path(procedure, dossier)
|
||||
|
||||
expect(page).to have_content('nom FERRI')
|
||||
expect(page).to have_content('nom de naissance FERRI')
|
||||
expect(page).to have_content('prénoms Karine')
|
||||
expect(page).to have_content('date de naissance 12/08/1978')
|
||||
|
||||
expect(page).to have_content('date de recouvrement 09/10/2020')
|
||||
expect(page).to have_content("date d’établissement 07/07/2020")
|
||||
|
||||
expect(page).to have_content('année 2020')
|
||||
expect(page).to have_content("adresse fiscale de l’année passée 13 rue de la Plage 97615 Pamanzi")
|
||||
expect(page).to have_content('nombre de parts 1')
|
||||
expect(page).to have_content('situation familiale Célibataire')
|
||||
expect(page).to have_content('nombre de personnes à charge 0')
|
||||
|
||||
expect(page).to have_content('revenu brut global 38814')
|
||||
expect(page).to have_content('revenu imposable 38814')
|
||||
expect(page).to have_content('impôt sur le revenu net avant correction 38814')
|
||||
expect(page).to have_content("montant de l’impôt 38814")
|
||||
expect(page).to have_content('revenu fiscal de référence 38814')
|
||||
expect(page).to have_content("année d’imposition 2020")
|
||||
expect(page).to have_content('année des revenus 2020')
|
||||
|
||||
expect(page).to have_content('situation partielle SUP DOM')
|
||||
|
||||
expect(page).not_to have_content('erreur correctif')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue