diff --git a/app/graphql/api/v2/schema.rb b/app/graphql/api/v2/schema.rb index 25ab2a8ae..e077a26f3 100644 --- a/app/graphql/api/v2/schema.rb +++ b/app/graphql/api/v2/schema.rb @@ -39,7 +39,8 @@ class API::V2::Schema < GraphQL::Schema end end - orphan_types Types::Champs::CarteChampType, + orphan_types Types::Champs::AddressChampType, + Types::Champs::CarteChampType, Types::Champs::CheckboxChampType, Types::Champs::CiviliteChampType, Types::Champs::DateChampType, diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 45fde0a8b..6debefe95 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -1,3 +1,107 @@ +type Address { + """ + code INSEE de la commune + """ + cityCode: String! + + """ + nom de la commune + """ + cityName: String! + + """ + n° de département + """ + departmentCode: String + + """ + nom de département + """ + departmentName: String + + """ + coordonnées géographique + """ + geometry: GeoJSON + + """ + libellé complet de l’adresse + """ + label: String! + + """ + code postal + """ + postalCode: String! + + """ + n° de region + """ + regionCode: String + + """ + nom de région + """ + regionName: String + + """ + numéro éventuel et nom de voie ou lieu dit + """ + streetAddress: String! + + """ + nom de voie ou lieu dit + """ + streetName: String + + """ + numéro avec indice de répétition éventuel (bis, ter, A, B) + """ + streetNumber: String + + """ + type de résultat trouvé + """ + type: AddressType! +} + +type AddressChamp implements Champ { + address: Address + id: ID! + + """ + Libellé du champ. + """ + label: String! + + """ + La valeur du champ sous forme texte. + """ + stringValue: String +} + +enum AddressType { + """ + numéro « à la plaque » + """ + housenumber + + """ + lieu-dit + """ + locality + + """ + numéro « à la commune » + """ + municipality + + """ + position « à la voie », placé approximativement au centre de celle-ci + """ + street +} + type Association { dateCreation: ISO8601Date! dateDeclaration: ISO8601Date! @@ -1362,21 +1466,22 @@ type ParcelleCadastrale implements GeoArea { } type PersonneMorale implements Demandeur { - adresse: String! + address: Address! + adresse: String! @deprecated(reason: "Utilisez le champ `address.label` à la place.") association: Association - codeInseeLocalite: String! - codePostal: String! - complementAdresse: String + codeInseeLocalite: String! @deprecated(reason: "Utilisez le champ `address.city_code` à la place.") + codePostal: String! @deprecated(reason: "Utilisez le champ `address.postal_code` à la place.") + complementAdresse: String @deprecated(reason: "Utilisez le champ `address` à la place.") entreprise: Entreprise id: ID! libelleNaf: String! - localite: String! + localite: String! @deprecated(reason: "Utilisez le champ `address.city_name` à la place.") naf: String! - nomVoie: String - numeroVoie: String + nomVoie: String @deprecated(reason: "Utilisez le champ `address.street_name` à la place.") + numeroVoie: String @deprecated(reason: "Utilisez le champ `address.street_number` à la place.") siegeSocial: Boolean! siret: String! - typeVoie: String + typeVoie: String @deprecated(reason: "Utilisez le champ `address.street_address` à la place.") } type PersonnePhysique implements Demandeur { diff --git a/app/graphql/types/address_type.rb b/app/graphql/types/address_type.rb new file mode 100644 index 000000000..99693ffb8 --- /dev/null +++ b/app/graphql/types/address_type.rb @@ -0,0 +1,29 @@ +module Types + class AddressType < Types::BaseObject + class AddressTypeType < Types::BaseEnum + value(:housenumber, "numéro « à la plaque »", value: :housenumber) + value(:street, "position « à la voie », placé approximativement au centre de celle-ci", value: :street) + value(:municipality, "numéro « à la commune »", value: :municipality) + value(:locality, "lieu-dit", value: :locality) + end + + field :label, String, "libellé complet de l’adresse", null: false + field :type, AddressTypeType, "type de résultat trouvé", null: false + + field :street_address, String, "numéro éventuel et nom de voie ou lieu dit", null: false + field :street_number, String, "numéro avec indice de répétition éventuel (bis, ter, A, B)", null: true + field :street_name, String, "nom de voie ou lieu dit", null: true + + field :postal_code, String, "code postal", null: false + field :city_name, String, "nom de la commune", null: false + field :city_code, String, "code INSEE de la commune", null: false + + field :department_name, String, "nom de département", null: true + field :department_code, String, "n° de département", null: true + + field :region_name, String, "nom de région", null: true + field :region_code, String, "n° de region", null: true + + field :geometry, Types::GeoJSON, "coordonnées géographique", null: true + end +end diff --git a/app/graphql/types/champ_type.rb b/app/graphql/types/champ_type.rb index d9769a2c0..4cb5bf989 100644 --- a/app/graphql/types/champ_type.rb +++ b/app/graphql/types/champ_type.rb @@ -9,6 +9,12 @@ module Types definition_methods do def resolve_type(object, context) case object + when ::Champs::AddressChamp + if context.has_fragment?(:AddressChamp) + Types::Champs::AddressChampType + else + Types::Champs::TextChampType + end when ::Champs::EngagementChamp, ::Champs::YesNoChamp, ::Champs::CheckboxChamp Types::Champs::CheckboxChampType when ::Champs::DateChamp diff --git a/app/graphql/types/champs/address_champ_type.rb b/app/graphql/types/champs/address_champ_type.rb new file mode 100644 index 000000000..4f7c3f8a2 --- /dev/null +++ b/app/graphql/types/champs/address_champ_type.rb @@ -0,0 +1,7 @@ +module Types::Champs + class AddressChampType < Types::BaseObject + implements Types::ChampType + + field :address, Types::AddressType, null: true + end +end diff --git a/app/graphql/types/personne_morale_type.rb b/app/graphql/types/personne_morale_type.rb index c84f0925d..0ba408fba 100644 --- a/app/graphql/types/personne_morale_type.rb +++ b/app/graphql/types/personne_morale_type.rb @@ -86,17 +86,34 @@ module Types field :siege_social, Boolean, null: false field :naf, String, null: false field :libelle_naf, String, null: false - field :adresse, String, null: false - field :numero_voie, String, null: true - field :type_voie, String, null: true - field :nom_voie, String, null: true - field :complement_adresse, String, null: true - field :code_postal, String, null: false - field :localite, String, null: false - field :code_insee_localite, String, null: false + + field :address, Types::AddressType, null: false + field :entreprise, EntrepriseType, null: true field :association, AssociationType, null: true + field :adresse, String, null: false, deprecation_reason: "Utilisez le champ `address.label` à la place." + field :numero_voie, String, null: true, deprecation_reason: "Utilisez le champ `address.street_number` à la place." + field :type_voie, String, null: true, deprecation_reason: "Utilisez le champ `address.street_address` à la place." + field :nom_voie, String, null: true, deprecation_reason: "Utilisez le champ `address.street_name` à la place." + field :code_postal, String, null: false, deprecation_reason: "Utilisez le champ `address.postal_code` à la place." + field :localite, String, null: false, deprecation_reason: "Utilisez le champ `address.city_name` à la place." + field :code_insee_localite, String, null: false, deprecation_reason: "Utilisez le champ `address.city_code` à la place." + field :complement_adresse, String, null: true, deprecation_reason: "Utilisez le champ `address` à la place." + + def address + { + label: object.adresse, + type: :housenumber, + street_number: object.numero_voie, + street_name: object.nom_voie, + street_address: object.nom_voie.present? ? [object.numero_voie, object.type_voie, object.nom_voie].compact.join(' ') : nil, + postal_code: object.code_postal, + city_name: object.localite, + city_code: object.code_insee_localite + } + end + def entreprise if object.entreprise_siren.present? object.entreprise diff --git a/app/jobs/champ_fetch_external_data_job.rb b/app/jobs/champ_fetch_external_data_job.rb new file mode 100644 index 000000000..ab8a09f7d --- /dev/null +++ b/app/jobs/champ_fetch_external_data_job.rb @@ -0,0 +1,11 @@ +class ChampFetchExternalDataJob < ApplicationJob + def perform(champ) + if champ.external_id.present? + data = champ.fetch_external_data + + if data.present? + champ.update!(data: data) + end + end + end +end diff --git a/app/lib/api_address/address_adapter.rb b/app/lib/api_address/address_adapter.rb new file mode 100644 index 000000000..d121479e1 --- /dev/null +++ b/app/lib/api_address/address_adapter.rb @@ -0,0 +1,46 @@ +require 'json_schemer' + +class APIAddress::AddressAdapter + class InvalidSchemaError < ::StandardError + def initialize(errors) + super(errors.map(&:to_json).join("\n")) + end + end + + def initialize(search_term) + @search_term = search_term + end + + def to_params + result = Geocoder.search(@search_term, limit: 1).first + if result.present? && result.national_address == @search_term + feature = result.data['features'].first + if schemer.valid?(feature) + { + label: result.national_address, + type: result.result_type, + street_address: result.street_address, + street_number: result.street_number, + street_name: result.street_name, + postal_code: result.postal_code, + city_name: result.city_name, + city_code: result.city_code, + department_name: result.department_name, + department_code: result.department_code, + region_name: result.region_name, + region_code: result.region_code, + geometry: result.geometry + } + else + errors = schemer.validate(feature).to_a + raise InvalidSchemaError.new(errors) + end + end + end + + private + + def schemer + @schemer ||= JSONSchemer.schema(Rails.root.join('app/schemas/adresse-ban.json')) + end +end diff --git a/app/models/champ.rb b/app/models/champ.rb index fb8dd3221..e2e688021 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -67,6 +67,8 @@ class Champ < ApplicationRecord before_create :set_dossier_id, if: :needs_dossier_id? before_validation :set_dossier_id, if: :needs_dossier_id? + before_save :cleanup_if_empty + after_update_commit :fetch_external_data_later validates :type_de_champ_id, uniqueness: { scope: [:dossier_id, :row] } @@ -143,6 +145,14 @@ class Champ < ApplicationRecord update_column(:fetch_external_data_exceptions, exceptions) end + def fetch_external_data? + false + end + + def fetch_external_data + raise NotImplemented.new(:fetch_external_data) + end + private def needs_dossier_id? @@ -152,4 +162,22 @@ class Champ < ApplicationRecord def set_dossier_id self.dossier_id = parent.dossier_id end + + def cleanup_if_empty + if external_id_changed? + self.data = nil + end + end + + def fetch_external_data_later + if fetch_external_data? && external_id.present? && data.nil? + ChampFetchExternalDataJob.perform_later(self) + end + end + + class NotImplemented < ::StandardError + def initialize(method) + super(":#{method} not implemented") + end + end end diff --git a/app/models/champs/address_champ.rb b/app/models/champs/address_champ.rb index 22bc171e8..d7cca4dc4 100644 --- a/app/models/champs/address_champ.rb +++ b/app/models/champs/address_champ.rb @@ -18,4 +18,47 @@ # type_de_champ_id :integer # class Champs::AddressChamp < Champs::TextChamp + def full_address? + data.present? + end + + def address + full_address? ? data : nil + end + + def address_label + full_address? ? data['label'] : value + end + + def search_terms + if full_address? + [data['label'], data['departement'], data['region'], data['city']] + else + [address_label] + end + end + + def to_s + address_label + end + + def for_tag + address_label + end + + def for_export + value.present? ? address_label : nil + end + + def for_api + address_label + end + + def fetch_external_data? + true + end + + def fetch_external_data + APIAddress::AddressAdapter.new(external_id).to_params + end end diff --git a/app/models/champs/annuaire_education_champ.rb b/app/models/champs/annuaire_education_champ.rb index 79293920a..542ab51a9 100644 --- a/app/models/champs/annuaire_education_champ.rb +++ b/app/models/champs/annuaire_education_champ.rb @@ -18,20 +18,11 @@ # type_de_champ_id :integer # class Champs::AnnuaireEducationChamp < Champs::TextChamp - before_save :cleanup_if_empty - after_update_commit :fetch_data - - private - - def cleanup_if_empty - if external_id_changed? - self.data = nil - end + def fetch_external_data? + true end - def fetch_data - if external_id.present? && data.nil? - AnnuaireEducationUpdateJob.perform_later(self) - end + def fetch_external_data + ApiEducation::AnnuaireEducationAdapter.new(external_id).to_params end end diff --git a/app/schemas/adresse-ban.json b/app/schemas/adresse-ban.json new file mode 100644 index 000000000..ccb236b5d --- /dev/null +++ b/app/schemas/adresse-ban.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://demarches-simplifiees.fr/adresse-ban.schema.json", + "title": "Adresse BAN", + "type": "object", + "properties": { + "properties": { + "type": "object", + "properties": { + "label": { "type": "string" }, + "housenumber": { "type": "string" }, + "name": { "type": "string" }, + "postcode": { "type": "string" }, + "citycode": { "type": "string" }, + "city": { "type": "string" }, + "district": { "type": "string" }, + "context": { "type": "string" }, + "type": { + "enum": ["housenumber", "street", "locality", "municipality"] + } + }, + "required": ["label", "type", "name", "postcode", "citycode", "city"] + }, + "geometry": { + "type": "object", + "properties": { + "type": { + "const": "Point" + }, + "coordinates": { + "type": "array", + "minItems": 2, + "maxItems": 2 + } + } + } + }, + "required": ["properties"] +} diff --git a/config/initializers/geocoder.rb b/config/initializers/geocoder.rb index 972505d47..169dcfb24 100644 --- a/config/initializers/geocoder.rb +++ b/config/initializers/geocoder.rb @@ -1 +1 @@ -Geocoder.configure(lookup: :ban_data_gouv_fr) +Geocoder.configure(lookup: :ban_data_gouv_fr, use_https: true) diff --git a/spec/fixtures/files/api_address/address.json b/spec/fixtures/files/api_address/address.json new file mode 100644 index 000000000..9ea803361 --- /dev/null +++ b/spec/fixtures/files/api_address/address.json @@ -0,0 +1,131 @@ +{ + "type": "FeatureCollection", + "version": "draft", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 2.347, + 48.859 + ] + }, + "properties": { + "label": "Paris", + "score": 0.9704590909090908, + "id": "75056", + "type": "municipality", + "name": "Paris", + "postcode": "75001", + "citycode": "75056", + "x": 652089.7, + "y": 6862305.26, + "population": 2190327, + "city": "Paris", + "context": "75, Paris, Île-de-France", + "importance": 0.67505 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 2.551187, + 48.357318 + ] + }, + "properties": { + "label": "Paris Foret 77760 Achères-la-Forêt", + "score": 0.8608, + "id": "77001_b064", + "name": "Paris Foret", + "postcode": "77760", + "citycode": "77001", + "x": 666753.6, + "y": 6806428.85, + "city": "Achères-la-Forêt", + "context": "77, Seine-et-Marne, Île-de-France", + "type": "street", + "importance": 0.4688 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 6.069561, + 43.415211 + ] + }, + "properties": { + "label": "Paris 83170 Brignoles", + "score": 0.8607481818181817, + "id": "83023_05n1tm", + "name": "Paris", + "postcode": "83170", + "citycode": "83023", + "x": 948661.53, + "y": 6262177.77, + "city": "Brignoles", + "context": "83, Var, Provence-Alpes-Côte d'Azur", + "type": "street", + "importance": 0.46823 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + -0.418837, + 44.758777 + ] + }, + "properties": { + "label": "Paris 33880 Saint-Caprais-de-Bordeaux", + "score": 0.8593318181818181, + "id": "33381_sy62ut", + "name": "Paris", + "postcode": "33880", + "citycode": "33381", + "x": 429522.28, + "y": 6412482.95, + "city": "Saint-Caprais-de-Bordeaux", + "context": "33, Gironde, Nouvelle-Aquitaine", + "type": "street", + "importance": 0.45265 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 0.156876, + 47.33671 + ] + }, + "properties": { + "label": "Paris Buton 37140 Bourgueil", + "score": 0.8570918181818181, + "id": "37031_b165", + "name": "Paris Buton", + "postcode": "37140", + "citycode": "37031", + "x": 485353.99, + "y": 6696795.92, + "city": "Bourgueil", + "context": "37, Indre-et-Loire, Centre-Val de Loire", + "type": "street", + "importance": 0.42801 + } + } + ], + "attribution": "BAN", + "licence": "ETALAB-2.0", + "query": "Paris", + "limit": 5 +} diff --git a/spec/fixtures/files/api_address/address_invalid.json b/spec/fixtures/files/api_address/address_invalid.json new file mode 100644 index 000000000..b79494b23 --- /dev/null +++ b/spec/fixtures/files/api_address/address_invalid.json @@ -0,0 +1,130 @@ +{ + "type": "FeatureCollection", + "version": "draft", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 2.347, + 48.859 + ] + }, + "properties": { + "label": "Paris", + "score": 0.9704590909090908, + "id": "75056", + "name": "Paris", + "postcode": "75001", + "citycode": "75056", + "x": 652089.7, + "y": 6862305.26, + "population": 2190327, + "city": "Paris", + "context": "75, Paris, Île-de-France", + "importance": 0.67505 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 2.551187, + 48.357318 + ] + }, + "properties": { + "label": "Paris Foret 77760 Achères-la-Forêt", + "score": 0.8608, + "id": "77001_b064", + "name": "Paris Foret", + "postcode": "77760", + "citycode": "77001", + "x": 666753.6, + "y": 6806428.85, + "city": "Achères-la-Forêt", + "context": "77, Seine-et-Marne, Île-de-France", + "type": "street", + "importance": 0.4688 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 6.069561, + 43.415211 + ] + }, + "properties": { + "label": "Paris 83170 Brignoles", + "score": 0.8607481818181817, + "id": "83023_05n1tm", + "name": "Paris", + "postcode": "83170", + "citycode": "83023", + "x": 948661.53, + "y": 6262177.77, + "city": "Brignoles", + "context": "83, Var, Provence-Alpes-Côte d'Azur", + "type": "street", + "importance": 0.46823 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + -0.418837, + 44.758777 + ] + }, + "properties": { + "label": "Paris 33880 Saint-Caprais-de-Bordeaux", + "score": 0.8593318181818181, + "id": "33381_sy62ut", + "name": "Paris", + "postcode": "33880", + "citycode": "33381", + "x": 429522.28, + "y": 6412482.95, + "city": "Saint-Caprais-de-Bordeaux", + "context": "33, Gironde, Nouvelle-Aquitaine", + "type": "street", + "importance": 0.45265 + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 0.156876, + 47.33671 + ] + }, + "properties": { + "label": "Paris Buton 37140 Bourgueil", + "score": 0.8570918181818181, + "id": "37031_b165", + "name": "Paris Buton", + "postcode": "37140", + "citycode": "37031", + "x": 485353.99, + "y": 6696795.92, + "city": "Bourgueil", + "context": "37, Indre-et-Loire, Centre-Val de Loire", + "type": "street", + "importance": 0.42801 + } + } + ], + "attribution": "BAN", + "licence": "ETALAB-2.0", + "query": "Paris", + "limit": 5 +} diff --git a/spec/fixtures/files/api_adresse/search_no_results.json b/spec/fixtures/files/api_adresse/search_no_results.json deleted file mode 100644 index 57f67f444..000000000 --- a/spec/fixtures/files/api_adresse/search_no_results.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "limit": 5, - "attribution": "BAN", - "version": "draft", - "licence": "ODbL 1.0", - "query": "Paris", - "type": "FeatureCollection", - "features": [] -} diff --git a/spec/fixtures/files/api_adresse/search_results.json b/spec/fixtures/files/api_adresse/search_results.json deleted file mode 100644 index 53b0773ee..000000000 --- a/spec/fixtures/files/api_adresse/search_results.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "limit": 5, - "attribution": "BAN", - "version": "draft", - "licence": "ODbL 1.0", - "query": "Paris", - "type": "FeatureCollection", - "features": [ - { - "geometry": { - "type": "Point", - "coordinates": [ - 2.3469, - 48.8589 - ] - }, - "properties": { - "adm_weight": "6", - "citycode": "75056", - "name": "Paris", - "city": "Paris", - "postcode": "75000", - "context": "75, \u00cele-de-France", - "score": 1.0, - "label": "Paris", - "id": "75056", - "type": "city", - "population": "2244" - }, - "type": "Feature" - }, - { - "geometry": { - "type": "Point", - "coordinates": [ - 4.366801, - 44.425528 - ] - }, - "properties": { - "citycode": "07330", - "postcode": "07150", - "name": "Paris", - "id": "07330_B095_bd3524", - "context": "07, Ard\u00e8che, Rh\u00f4ne-Alpes", - "score": 0.8291454545454544, - "label": "Paris 07150 Vallon-Pont-d'Arc", - "city": "Vallon-Pont-d'Arc", - "type": "locality" - }, - "type": "Feature" - }, - { - "geometry": { - "type": "Point", - "coordinates": [ - 3.564293, - 45.766413 - ] - }, - "properties": { - "citycode": "63125", - "postcode": "63120", - "name": "Paris", - "city": "Courpi\u00e8re", - "context": "63, Puy-de-D\u00f4me, Auvergne", - "score": 0.8255363636363636, - "label": "Paris 63120 Courpi\u00e8re", - "id": "63125_B221_03549b", - "type": "locality" - }, - "type": "Feature" - }, - { - "geometry": { - "type": "Point", - "coordinates": [ - 1.550208, - 44.673592 - ] - }, - "properties": { - "citycode": "46138", - "postcode": "46240", - "name": "PARIS (Vaillac)", - "city": "C\u0153ur de Causse", - "context": "46, Lot, Midi-Pyr\u00e9n\u00e9es", - "score": 0.824090909090909, - "label": "PARIS (Vaillac) 46240 C\u0153ur de Causse", - "id": "46138_XXXX_6ee4ec", - "type": "street" - }, - "type": "Feature" - }, - { - "geometry": { - "type": "Point", - "coordinates": [ - -0.526884, - 43.762253 - ] - }, - "properties": { - "citycode": "40282", - "postcode": "40500", - "name": "Paris", - "city": "Saint-Sever", - "context": "40, Landes, Aquitaine", - "score": 0.8236181818181818, - "label": "Paris 40500 Saint-Sever", - "id": "40282_B237_2364e3", - "type": "locality" - }, - "type": "Feature" - } - ] -} diff --git a/spec/lib/api_address/address_adapter_spec.rb b/spec/lib/api_address/address_adapter_spec.rb new file mode 100644 index 000000000..1655e731b --- /dev/null +++ b/spec/lib/api_address/address_adapter_spec.rb @@ -0,0 +1,45 @@ +describe APIAddress::AddressAdapter do + let(:search_term) { 'Paris' } + let(:adapter) { described_class.new(search_term) } + subject { adapter.to_params } + + before do + Geocoder.configure(lookup: :ban_data_gouv_fr, use_https: true) + stub_request(:get, /https:\/\/api-adresse.data.gouv.fr\/search/) + .to_return(body: body, status: status) + end + + after do + Geocoder.configure(lookup: :test) + end + + context "when responds with valid schema" do + let(:body) { File.read('spec/fixtures/files/api_address/address.json') } + let(:status) { 200 } + + it '#to_params returns a valid' do + expect(subject).to be_an_instance_of(Hash) + expect(subject[:city_name]).to eq(search_term) + expect(subject[:city_code]).to eq('75056') + end + end + + context "when responds with an address which is not a direct match to search term" do + let(:body) { File.read('spec/fixtures/files/api_address/address.json') } + let(:status) { 200 } + let(:search_term) { 'Lyon' } + + it '#to_params ignores the response' do + expect(subject).to be_nil + end + end + + context "when responds with invalid schema" do + let(:body) { File.read('spec/fixtures/files/api_address/address_invalid.json') } + let(:status) { 200 } + + it '#to_params raise exception' do + expect { subject }.to raise_exception(APIAddress::AddressAdapter::InvalidSchemaError) + end + end +end diff --git a/spec/models/champ_spec.rb b/spec/models/champ_spec.rb index 8d5ab3492..482a3433e 100644 --- a/spec/models/champ_spec.rb +++ b/spec/models/champ_spec.rb @@ -522,4 +522,31 @@ describe Champ do it { expect(champ.fetch_external_data_exceptions).to eq(['#']) } end end + + describe "fetch_external_data" do + let(:champ) { create(:champ_text, data: 'some data') } + + context "cleanup_if_empty" do + it "remove data if external_id changes" do + expect(champ.data).to_not be_nil + champ.update(external_id: 'external_id') + expect(champ.data).to be_nil + end + end + + context "fetch_external_data_later" do + include ActiveJob::TestHelper + let(:data) { 'some other data' } + + it "fill data from external source" do + expect(champ).to receive(:fetch_external_data?) { true } + expect_any_instance_of(Champs::TextChamp).to receive(:fetch_external_data) { data } + + perform_enqueued_jobs do + champ.update(external_id: 'external_id') + end + expect(champ.reload.data).to eq data + end + end + end end diff --git a/spec/models/champs/address_champ_spec.rb b/spec/models/champs/address_champ_spec.rb new file mode 100644 index 000000000..c56c4a0e9 --- /dev/null +++ b/spec/models/champs/address_champ_spec.rb @@ -0,0 +1,20 @@ +describe Champs::AddressChamp do + let(:champ) { Champs::AddressChamp.new(value: value, data: data, type_de_champ: create(:type_de_champ_address)) } + let(:value) { '' } + let(:data) { nil } + + context "with value but no data" do + let(:value) { 'Paris' } + + it { expect(champ.address_label).to eq('Paris') } + it { expect(champ.full_address?).to be_falsey } + end + + context "with value and data" do + let(:value) { 'Paris' } + let(:data) { { label: 'Paris' } } + + it { expect(champ.address_label).to eq('Paris') } + it { expect(champ.full_address?).to be_truthy } + end +end