From 85b2e9ef44b7247245ff5e20a3c738b171e84dbf Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 30 Apr 2020 08:18:17 +0200 Subject: [PATCH 1/5] create bilans_bdf_adapter --- app/lib/api_entreprise/api.rb | 6 +++ app/lib/api_entreprise/bilans_bdf_adapter.rb | 23 +++++++++ .../api_entreprise/bilans_entreprise_bdf.json | 51 +++++++++++++++++++ spec/lib/api_entreprise/api_spec.rb | 27 ++++++++++ .../api_entreprise/bilans_bdf_adapter_spec.rb | 26 ++++++++++ 5 files changed, 133 insertions(+) create mode 100644 app/lib/api_entreprise/bilans_bdf_adapter.rb create mode 100644 spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json create mode 100644 spec/lib/api_entreprise/bilans_bdf_adapter_spec.rb diff --git a/app/lib/api_entreprise/api.rb b/app/lib/api_entreprise/api.rb index 3f9ec089f..1b8790d2c 100644 --- a/app/lib/api_entreprise/api.rb +++ b/app/lib/api_entreprise/api.rb @@ -7,6 +7,7 @@ class ApiEntreprise::API EFFECTIFS_ANNUELS_RESOURCE_NAME = "effectifs_annuels_acoss_covid" ATTESTATION_SOCIALE_RESOURCE_NAME = "attestations_sociales_acoss" ATTESTATION_FISCALE_RESOURCE_NAME = "attestations_fiscales_dgfip" + BILANS_BDF_RESOURCE_NAME = "bilans_entreprises_bdf" TIMEOUT = 15 @@ -51,6 +52,11 @@ class ApiEntreprise::API call(ATTESTATION_FISCALE_RESOURCE_NAME, siren, procedure_id, user_id) if procedure.api_entreprise_role?("attestations_fiscales") end + def self.bilans_bdf(siren, procedure_id) + procedure = Procedure.find(procedure_id) + call(BILANS_BDF_RESOURCE_NAME, siren, procedure_id) if procedure.api_entreprise_role?("bilans_entreprise_bdf") + end + private def self.call(resource_name, siret_or_siren, procedure_id, user_id = nil) diff --git a/app/lib/api_entreprise/bilans_bdf_adapter.rb b/app/lib/api_entreprise/bilans_bdf_adapter.rb new file mode 100644 index 000000000..69ee6b6ec --- /dev/null +++ b/app/lib/api_entreprise/bilans_bdf_adapter.rb @@ -0,0 +1,23 @@ +class ApiEntreprise::BilansBdfAdapter < ApiEntreprise::Adapter + def initialize(siren, procedure_id) + @siren = siren + @procedure_id = procedure_id + end + + private + + def get_resource + ApiEntreprise::API.bilans_bdf(@siren, @procedure_id) + end + + def process_params + if data_source[:bilans].present? + { + entreprise_bilans_bdf: data_source[:bilans], + entreprise_bilans_bdf_monnaie: data_source[:monnaie] + } + else + {} + end + end +end diff --git a/spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json b/spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json new file mode 100644 index 000000000..1f2350363 --- /dev/null +++ b/spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json @@ -0,0 +1,51 @@ +{ + "monnaie": "kEuros", + "bilans": [ + { + "duree_exercice": "12", + "valeur_ajoutee_bdf": "7848792", + "resultat_exercice": "347126", + "capitaux_propres_et_assimiles": "5928663", + "total_provisions_pour_risques_et_charges": "1957919", + "dettes1_emprunts_obligataires_et_convertibles": "0", + "dettes2_autres_emprunts_obligataires": "6552306", + "total_dettes_stables": "6552306", + "emprunts_et_dettes_financieres_divers": "430634", + "groupes_et_associes": "0", + "besoin_en_fonds_de_roulement": "-721507", + "disponibilites": "1983051", + "total_passif": "18478051", + "evolution_valeur_ajoutee_bdf": "", + "evolution_resultat_exercice": "", + "evolution_capitaux_propres_et_assimiles": "", + "evolution_total_provisions_pour_risques_et_charges": "", + "evolution_dettes1_emprunts_obligataires_et_convertibles": "", + "evolution_dettes2_autres_emprunts_obligataires": "", + "evolution_emprunts_et_dettes_financieres_divers": "", + "evolution_groupes_et_associes": "", + "evolution_besoin_en_fonds_de_roulement": "", + "evolution_disponibilites": "", + "evolution_total_passif": "", + "chiffre_affaires_ht": "12030700", + "capacite_autofinancement": "891914", + "date_arret_exercice": "201512", + "dettes3_emprunts_et_dettes_aupres_des_etablissements_de_credit": "0", + "dettes4_maturite_a_un_an_au_plus": "0", + "autres_fonds_propres": "0", + "capital_social_inclus_dans_capitaux_propres_et_assimiles": "3800000", + "excedent_brut_exploitation": "-1876863", + "evolution_chiffre_affaires_ht": "", + "evolution_capacite_autofinancement": "", + "evolution_dettes3_emprunts_et_dettes_aupres_des_etablissements_de_credit": "", + "evolution_dettes4_maturite_a_un_an_au_plus": "", + "evolution_autres_fonds_propres": "", + "evolution_capital_social_inclus_dans_capitaux_propres_et_assimiles": "", + "evolution_excedent_brut_exploitation": "", + "evolution_fonds_roulement_net_global": "", + "evolution_ratio_fonds_roulement_net_global_sur_besoin_en_fonds_de_roulement": "", + "evolution_total_dettes_stables": "", + "fonds_roulement_net_global": "2464585", + "ratio_fonds_roulement_net_global_sur_besoin_en_fonds_de_roulement": "-" + }, "bilan 2", "bilan 3" + ] +} diff --git a/spec/lib/api_entreprise/api_spec.rb b/spec/lib/api_entreprise/api_spec.rb index de537515d..81e50b35c 100644 --- a/spec/lib/api_entreprise/api_spec.rb +++ b/spec/lib/api_entreprise/api_spec.rb @@ -213,4 +213,31 @@ describe ApiEntreprise::API do it { expect(subject).to eq(JSON.parse(body, symbolize_names: true)) } end end + + describe '.bilans_bdf' do + let(:procedure) { create(:procedure, api_entreprise_token: token) } + let(:siren) { '418166096' } + let(:status) { 200 } + let(:body) { File.read('spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json') } + + before do + allow_any_instance_of(Procedure).to receive(:api_entreprise_roles).and_return(roles) + stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/bilans_entreprises_bdf\/#{siren}?.*token=#{token}/) + .to_return(body: body, status: status) + end + + subject { described_class.bilans_bdf(siren, procedure.id) } + + context 'when token not authorized' do + let(:roles) { ["entreprises"] } + + it { expect(subject).to eq(nil) } + end + + context 'when token is authorized' do + let(:roles) { ["bilans_entreprise_bdf"] } + + it { expect(subject).to eq(JSON.parse(body, symbolize_names: true)) } + end + end end diff --git a/spec/lib/api_entreprise/bilans_bdf_adapter_spec.rb b/spec/lib/api_entreprise/bilans_bdf_adapter_spec.rb new file mode 100644 index 000000000..79029fa2a --- /dev/null +++ b/spec/lib/api_entreprise/bilans_bdf_adapter_spec.rb @@ -0,0 +1,26 @@ +describe ApiEntreprise::BilansBdfAdapter do + let(:siren) { '418166096' } + let(:procedure) { create(:procedure) } + let(:procedure_id) { procedure.id } + let(:adapter) { described_class.new(siren, procedure_id) } + subject { adapter.to_params } + + before do + stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/bilans_entreprises_bdf\/#{siren}?.*token=/) + .to_return(body: body, status: status) + allow_any_instance_of(Procedure).to receive(:api_entreprise_roles).and_return(["bilans_entreprise_bdf"]) + end + + context "when the SIREN is valid" do + let(:body) { File.read('spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json') } + let(:status) { 200 } + + it '#to_params class est une Hash ?' do + expect(subject).to be_an_instance_of(Hash) + end + + it "returns bilans bdf" do + expect(subject[:entreprise_bilans_bdf][0][:valeur_ajoutee_bdf]).to eq("7848792") + end + end +end From b12226c667e0ee37a2aa59e469ee03c1e48ecdfb Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 30 Apr 2020 08:43:34 +0200 Subject: [PATCH 2/5] fetch and store bilans bdf --- app/services/api_entreprise_service.rb | 7 +++++++ .../20200429191305_add_bilans_bdf_to_etablissements.rb | 6 ++++++ db/schema.rb | 4 +++- spec/controllers/users/dossiers_controller_spec.rb | 9 ++++++++- spec/services/api_entreprise_service_spec.rb | 10 +++++++++- 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20200429191305_add_bilans_bdf_to_etablissements.rb diff --git a/app/services/api_entreprise_service.rb b/app/services/api_entreprise_service.rb index 5dc09baf5..3c7457075 100644 --- a/app/services/api_entreprise_service.rb +++ b/app/services/api_entreprise_service.rb @@ -46,6 +46,13 @@ class ApiEntrepriseService etablissement_params.merge!(attestation_fiscale_params) rescue ApiEntreprise::API::RequestFailed end + + begin + bilans_bdf_params = ApiEntreprise::BilansBdfAdapter.new(entreprise_params[:entreprise_siren], procedure_id).to_params + etablissement_params.merge!(bilans_bdf_params) + rescue ApiEntreprise::API::RequestFailed + end + etablissement_params.merge(entreprise_params) end end diff --git a/db/migrate/20200429191305_add_bilans_bdf_to_etablissements.rb b/db/migrate/20200429191305_add_bilans_bdf_to_etablissements.rb new file mode 100644 index 000000000..6e5f62851 --- /dev/null +++ b/db/migrate/20200429191305_add_bilans_bdf_to_etablissements.rb @@ -0,0 +1,6 @@ +class AddBilansBdfToEtablissements < ActiveRecord::Migration[5.2] + def change + add_column :etablissements, :entreprise_bilans_bdf, :jsonb + add_column :etablissements, :entreprise_bilans_bdf_monnaie, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 37ad540a3..455e700d5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_04_23_171759) do +ActiveRecord::Schema.define(version: 2020_04_29_191305) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -316,6 +316,8 @@ ActiveRecord::Schema.define(version: 2020_04_23_171759) do t.decimal "entreprise_effectif_mensuel" t.decimal "entreprise_effectif_annuel" t.string "entreprise_effectif_annuel_annee" + t.jsonb "entreprise_bilans_bdf" + t.string "entreprise_bilans_bdf_monnaie" t.index ["dossier_id"], name: "index_etablissements_on_dossier_id" end diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index b17bc68ff..5de3592da 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -227,6 +227,9 @@ describe Users::DossiersController, type: :controller do let(:api_entreprise_attestation_fiscale_status) { 200 } let(:api_entreprise_attestation_fiscale_body) { File.read('spec/fixtures/files/api_entreprise/attestation_fiscale.json') } + let(:api_entreprise_bilans_bdf_status) { 200 } + let(:api_entreprise_bilans_bdf_body) { File.read('spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json') } + def stub_api_entreprise_requests stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/) .to_return(status: api_etablissement_status, body: api_etablissement_body) @@ -248,12 +251,15 @@ describe Users::DossiersController, type: :controller do .to_return(body: api_entreprise_attestation_fiscale_body, status: api_entreprise_attestation_fiscale_status) stub_request(:get, "https://storage.entreprise.api.gouv.fr/siade/1569156756-f6b7779f99fa95cd60dc03c04fcb-attestation_fiscale_dgfip.pdf") .to_return(body: "body attestation", status: 200) + stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/bilans_entreprises_bdf\/#{siren}?.*token=/) + .to_return(body: api_entreprise_bilans_bdf_body, status: api_entreprise_bilans_bdf_status) end before do sign_in(user) stub_api_entreprise_requests - allow_any_instance_of(Procedure).to receive(:api_entreprise_roles).and_return(["attestations_fiscales", "attestations_sociales"]) + allow_any_instance_of(Procedure).to receive(:api_entreprise_roles) + .and_return(["attestations_fiscales", "attestations_sociales", "bilans_entreprise_bdf"]) end before { Timecop.freeze(Time.zone.local(2020, 3, 14)) } after { Timecop.return } @@ -351,6 +357,7 @@ describe Users::DossiersController, type: :controller do expect(dossier.etablissement.entreprise_effectif_annuel).to be_present expect(dossier.etablissement.entreprise_attestation_sociale).to be_attached expect(dossier.etablissement.entreprise_attestation_fiscale).to be_attached + expect(dossier.etablissement.entreprise_bilans_bdf).to be_present end end end diff --git a/spec/services/api_entreprise_service_spec.rb b/spec/services/api_entreprise_service_spec.rb index 7f6ea0375..2c0a5f11c 100644 --- a/spec/services/api_entreprise_service_spec.rb +++ b/spec/services/api_entreprise_service_spec.rb @@ -19,6 +19,8 @@ describe ApiEntrepriseService do .to_return(body: attestation_sociale_body, status: attestation_sociale_status) stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/attestations_fiscales_dgfip\/#{siren}?.*token=/) .to_return(body: attestation_fiscale_body, status: attestation_fiscale_status) + stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/bilans_entreprises_bdf\/#{siren}?.*token=/) + .to_return(body: bilans_bdf_body, status: bilans_bdf_status) end before { Timecop.freeze(Time.zone.local(2020, 3, 14)) } @@ -52,6 +54,10 @@ describe ApiEntrepriseService do let(:attestation_fiscale_body) { File.read('spec/fixtures/files/api_entreprise/attestation_fiscale.json') } let(:attestation_fiscale_url) { "https://storage.entreprise.api.gouv.fr/siade/1569156756-f6b7779f99fa95cd60dc03c04fcb-attestation_fiscale_dgfip.pdf" } + let(:bilans_bdf_status) { 200 } + let(:bilans_bdf_body) { File.read('spec/fixtures/files/api_entreprise/bilans_entreprise_bdf.json') } + let(:bilans_bdf) { JSON.parse(bilans_bdf_body, symbolize_names: true)[:bilans] } + let(:exercices_status) { 200 } let(:exercices_body) { File.read('spec/fixtures/files/api_entreprise/exercices.json') } @@ -62,7 +68,8 @@ describe ApiEntrepriseService do let(:result) { ApiEntrepriseService.get_etablissement_params_for_siret(siret, procedure.id) } before do - allow_any_instance_of(Procedure).to receive(:api_entreprise_roles).and_return(["attestations_sociales", "attestations_fiscales"]) + allow_any_instance_of(Procedure).to receive(:api_entreprise_roles) + .and_return(["attestations_sociales", "attestations_fiscales", "bilans_entreprise_bdf"]) end context 'when service is up' do @@ -75,6 +82,7 @@ describe ApiEntrepriseService do expect(result[:entreprise_effectif_annuel]).to eq(effectif_annuel) expect(result[:entreprise_attestation_sociale_url]).to eq(attestation_sociale_url) expect(result[:entreprise_attestation_fiscale_url]).to eq(attestation_fiscale_url) + expect(result[:entreprise_bilans_bdf]).to eq(bilans_bdf) end end From 22e2c2e133d839b11893e02b80ba2711dca0cbd3 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 30 Apr 2020 11:25:22 +0200 Subject: [PATCH 3/5] render csv bidf bilans --- app/controllers/instructeurs/dossiers_controller.rb | 4 ++++ app/models/etablissement.rb | 9 +++++++++ app/views/shared/dossiers/_identite_entreprise.html.haml | 7 +++++++ config/routes.rb | 1 + 4 files changed, 21 insertions(+) diff --git a/app/controllers/instructeurs/dossiers_controller.rb b/app/controllers/instructeurs/dossiers_controller.rb index c88e4108d..3b3bb6efd 100644 --- a/app/controllers/instructeurs/dossiers_controller.rb +++ b/app/controllers/instructeurs/dossiers_controller.rb @@ -31,6 +31,10 @@ module Instructeurs render 'admin/attestation_templates/show', formats: [:pdf] end + def bilans_bdf + render csv: dossier.etablissement.entreprise_bilans_bdf_to_csv + end + def show @demande_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.demande_seen_at diff --git a/app/models/etablissement.rb b/app/models/etablissement.rb index 724988afa..04274d820 100644 --- a/app/models/etablissement.rb +++ b/app/models/etablissement.rb @@ -138,6 +138,15 @@ class Etablissement < ApplicationRecord upload_attestation(url, entreprise_attestation_fiscale) end + def entreprise_bilans_bdf_to_csv + headers = ["bilans"].concat(entreprise_bilans_bdf[0].keys) + data = entreprise_bilans_bdf.each_with_index.map do |bilan, i| + month = I18n.l(Date.current - (i + 1).year, format: "%m/%Y") + [month].concat(bilan.values) + end + SpreadsheetArchitect.to_csv(headers: headers, data: data) + end + private def dossier_id_for_export diff --git a/app/views/shared/dossiers/_identite_entreprise.html.haml b/app/views/shared/dossiers/_identite_entreprise.html.haml index f9a3e8ed2..51e5625e1 100644 --- a/app/views/shared/dossiers/_identite_entreprise.html.haml +++ b/app/views/shared/dossiers/_identite_entreprise.html.haml @@ -78,6 +78,13 @@ %th.libelle Attestation fiscale %td= link_to "Consulter l'attestation", url_for(etablissement.entreprise_attestation_fiscale) + - if etablissement.entreprise_bilans_bdf_to_csv.present? + %tr + %th.libelle + Bilans Banque de France + = "en #{etablissement.entreprise_bilans_bdf_monnaie}" + %td= link_to "Consulter les bilans", bilans_bdf_instructeur_dossier_path + - if etablissement.association? %tr %th.libelle Numéro RNA : diff --git a/config/routes.rb b/config/routes.rb index ba024c094..c84893b20 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -318,6 +318,7 @@ Rails.application.routes.draw do get 'attestation' get 'geo_data' get 'apercu_attestation' + get 'bilans_bdf' get 'messagerie' get 'annotations-privees' => 'dossiers#annotations_privees' get 'avis' From 9873826dd4fbbf9bfc1a71f09fc189a7bed65465 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 30 Apr 2020 15:19:46 +0200 Subject: [PATCH 4/5] remove date computed column we will add it when more info of business --- app/models/etablissement.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/models/etablissement.rb b/app/models/etablissement.rb index 04274d820..a5b2b62f7 100644 --- a/app/models/etablissement.rb +++ b/app/models/etablissement.rb @@ -139,11 +139,8 @@ class Etablissement < ApplicationRecord end def entreprise_bilans_bdf_to_csv - headers = ["bilans"].concat(entreprise_bilans_bdf[0].keys) - data = entreprise_bilans_bdf.each_with_index.map do |bilan, i| - month = I18n.l(Date.current - (i + 1).year, format: "%m/%Y") - [month].concat(bilan.values) - end + headers = entreprise_bilans_bdf[0].keys + data = entreprise_bilans_bdf.map(&:values) SpreadsheetArchitect.to_csv(headers: headers, data: data) end From 9de2c7c85acee628d4db2edbb5ee5db0e6ffe44f Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 30 Apr 2020 16:03:05 +0200 Subject: [PATCH 5/5] improve csv generation for bilans bdf --- app/models/etablissement.rb | 6 ++++-- spec/models/etablissement_spec.rb | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/models/etablissement.rb b/app/models/etablissement.rb index a5b2b62f7..50585c6a2 100644 --- a/app/models/etablissement.rb +++ b/app/models/etablissement.rb @@ -139,8 +139,10 @@ class Etablissement < ApplicationRecord end def entreprise_bilans_bdf_to_csv - headers = entreprise_bilans_bdf[0].keys - data = entreprise_bilans_bdf.map(&:values) + headers = entreprise_bilans_bdf.flat_map(&:keys).uniq + data = entreprise_bilans_bdf.map do |bilan| + headers.map { |h| bilan[h] } + end SpreadsheetArchitect.to_csv(headers: headers, data: data) end diff --git a/spec/models/etablissement_spec.rb b/spec/models/etablissement_spec.rb index 31ae4acef..c329a519e 100644 --- a/spec/models/etablissement_spec.rb +++ b/spec/models/etablissement_spec.rb @@ -35,4 +35,28 @@ describe Etablissement do end end end + + describe '.entreprise_bilans_bdf_to_csv' do + let(:etablissement) { build(:etablissement, entreprise_bilans_bdf: bilans) } + let(:bilans) do + [ + { + "total_passif": "1200", + "chiffres_affaires_ht": "40000" + }, + { + "total_passif": "0", + "evolution_total_dettes_stables": "30" + } + ] + end + + subject { etablissement.entreprise_bilans_bdf_to_csv.split("\n") } + + it "build a csv with all keys" do + expect(subject[0].split(',').sort).to eq(["total_passif", "chiffres_affaires_ht", "evolution_total_dettes_stables"].sort) + expect(subject[1].split(',')).to eq(["1200", "40000"]) + expect(subject[2].split(',')).to eq(["0", "", "30"]) + end + end end