From 4504efd9617f81e26a4b8415527223bf31a04248 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 20 Oct 2021 20:59:42 +0200 Subject: [PATCH 01/19] Rename module to l10n_fr_siret_lookup Rename wizard obj to fr.siret.lookup Test on stdnum version number --- l10n_fr_siret_lookup/README.rst | 21 ++ l10n_fr_siret_lookup/__init__.py | 2 + l10n_fr_siret_lookup/__manifest__.py | 24 ++ l10n_fr_siret_lookup/i18n/fr.po | 231 +++++++++++++ l10n_fr_siret_lookup/models/__init__.py | 1 + l10n_fr_siret_lookup/models/res_partner.py | 306 ++++++++++++++++++ l10n_fr_siret_lookup/readme/CONTRIBUTORS.rst | 3 + l10n_fr_siret_lookup/readme/CREDITS.rst | 3 + l10n_fr_siret_lookup/readme/DESCRIPTION.rst | 17 + l10n_fr_siret_lookup/readme/USAGE.rst | 5 + .../security/ir.model.access.csv | 3 + .../static/description/icon.png | Bin 0 -> 9455 bytes l10n_fr_siret_lookup/views/res_partner.xml | 14 + l10n_fr_siret_lookup/wizard/__init__.py | 1 + .../wizard/fr_siret_lookup.py | 127 ++++++++ .../wizard/fr_siret_lookup_view.xml | 97 ++++++ 16 files changed, 855 insertions(+) create mode 100644 l10n_fr_siret_lookup/README.rst create mode 100644 l10n_fr_siret_lookup/__init__.py create mode 100644 l10n_fr_siret_lookup/__manifest__.py create mode 100644 l10n_fr_siret_lookup/i18n/fr.po create mode 100644 l10n_fr_siret_lookup/models/__init__.py create mode 100644 l10n_fr_siret_lookup/models/res_partner.py create mode 100644 l10n_fr_siret_lookup/readme/CONTRIBUTORS.rst create mode 100644 l10n_fr_siret_lookup/readme/CREDITS.rst create mode 100644 l10n_fr_siret_lookup/readme/DESCRIPTION.rst create mode 100644 l10n_fr_siret_lookup/readme/USAGE.rst create mode 100644 l10n_fr_siret_lookup/security/ir.model.access.csv create mode 100644 l10n_fr_siret_lookup/static/description/icon.png create mode 100644 l10n_fr_siret_lookup/views/res_partner.xml create mode 100644 l10n_fr_siret_lookup/wizard/__init__.py create mode 100644 l10n_fr_siret_lookup/wizard/fr_siret_lookup.py create mode 100644 l10n_fr_siret_lookup/wizard/fr_siret_lookup_view.xml diff --git a/l10n_fr_siret_lookup/README.rst b/l10n_fr_siret_lookup/README.rst new file mode 100644 index 000000000..21cd7854d --- /dev/null +++ b/l10n_fr_siret_lookup/README.rst @@ -0,0 +1,21 @@ +**This file is going to be generated by oca-gen-addon-readme.** + +*Manual changes will be overwritten.* + +Please provide content in the ``readme`` directory: + +* **DESCRIPTION.rst** (required) +* INSTALL.rst (optional) +* CONFIGURE.rst (optional) +* **USAGE.rst** (optional, highly recommended) +* DEVELOP.rst (optional) +* ROADMAP.rst (optional) +* HISTORY.rst (optional, recommended) +* **CONTRIBUTORS.rst** (optional, highly recommended) +* CREDITS.rst (optional) + +Content of this README will also be drawn from the addon manifest, +from keys such as name, authors, maintainers, development_status, +and license. + +A good, one sentence summary in the manifest is also highly recommended. diff --git a/l10n_fr_siret_lookup/__init__.py b/l10n_fr_siret_lookup/__init__.py new file mode 100644 index 000000000..9b4296142 --- /dev/null +++ b/l10n_fr_siret_lookup/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizard diff --git a/l10n_fr_siret_lookup/__manifest__.py b/l10n_fr_siret_lookup/__manifest__.py new file mode 100644 index 000000000..caba2c12f --- /dev/null +++ b/l10n_fr_siret_lookup/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright 2018-2021 Le Filament () +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "SIRET Lookup", + "summary": "Lookup partner via an API on the SIRENE directory", + "version": "14.0.1.0.0", + "category": "Partner", + "website": "https://github.com/OCA/l10n-france", + "author": "Le Filament, Akretion, Odoo Community Association (OCA)", + "maintainers": ["remi-filament"], + "license": "AGPL-3", + "depends": [ + "l10n_fr_siret", + ], + "external_dependencies": {"python": ["requests", "python-stdnum"]}, + "data": [ + "wizard/fr_siret_lookup_view.xml", + "views/res_partner.xml", + "security/ir.model.access.csv", + ], + "installable": True, +} diff --git a/l10n_fr_siret_lookup/i18n/fr.po b/l10n_fr_siret_lookup/i18n/fr.po new file mode 100644 index 000000000..d448de8fe --- /dev/null +++ b/l10n_fr_siret_lookup/i18n/fr.po @@ -0,0 +1,231 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_fr_siren_lookup +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-12-04 14:28+0000\n" +"PO-Revision-Date: 2018-12-04 14:28+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_staff +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_staff +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_staff +msgid "# Staff" +msgstr "Effectifs" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_ape +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_ape +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_ape +msgid "APE Code" +msgstr "Code APE" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_ape_label +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_ape_label +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_ape_label +msgid "APE Label" +msgstr "Libellé APE" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +msgid "Address" +msgstr "Adresse" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_zip +msgid "CP" +msgstr "CP" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_category +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_category +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_category +msgid "Category" +msgstr "Catégorie" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_city +msgid "City" +msgstr "Ville" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Close" +msgstr "Fermer" + +#. module: l10n_fr_siren_lookup +#: model:ir.model,name:l10n_fr_siren_lookup.model_siren_wizard_company +msgid "Companies Selection" +msgstr "Sélection d'Entreprises" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_name +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +msgid "Company" +msgstr "Société" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.partner_form_siren_view +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +msgid "Company Infos" +msgstr "Infos Entreprise" + +#. module: l10n_fr_siren_lookup +#: model:ir.model,name:l10n_fr_siren_lookup.model_siren_wizard_line +msgid "Company Selection" +msgstr "Sélection Entreprise" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Confirm selected company ?" +msgstr "Valider l'entreprise sélectionnée ?" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_create_uid +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_create_date +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_create_date +msgid "Created on" +msgstr "Créé le" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_creation_date +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_creation_date +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_creation_date +msgid "Creation date" +msgstr "Date de création" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_display_name +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: l10n_fr_siren_lookup +#: model:ir.model,name:l10n_fr_siren_lookup.model_siren_wizard +msgid "Get values from companies" +msgstr "Obtenir les informations sur les entreprises" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_id +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_id +msgid "ID" +msgstr "ID" + +#. module: l10n_fr_siren_lookup +#: model:ir.actions.act_window,name:l10n_fr_siren_lookup.siren_wizard_action +msgid "Informations base Siren" +msgstr "Informations base Siren" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard___last_update +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line___last_update +msgid "Last Modified on" +msgstr "Dernière Modification le" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_write_uid +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_write_date +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.partner_form_siren_view +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +msgid "Legal Infos" +msgstr "Infos Légales" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_legal_type +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_legal_type +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_legal_type +msgid "Legal Type" +msgstr "Forme Juridique" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Lookup" +msgstr "Recherche" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Lookup Company" +msgstr "Rechercher une Entreprise" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_name +msgid "Name" +msgstr "Nom" + +#. module: l10n_fr_siren_lookup +#: model:ir.model,name:l10n_fr_siren_lookup.model_res_partner +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_partner_id +msgid "Partner" +msgstr "Partenaire" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.partner_form_siren_view +msgid "Pre-Fill / Update" +msgstr "Pré-Remplir / Mettre à jour" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_ids +msgid "Results" +msgstr "Résultats" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_siren +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_siren +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_siren +msgid "SIREN" +msgstr "SIREN" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_partner_siret +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_res_users_siret +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_siret +msgid "SIRET" +msgstr "SIRET" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Search" +msgstr "Rechercher" + +#. module: l10n_fr_siren_lookup +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_line_view_form +#: model:ir.ui.view,arch_db:l10n_fr_siren_lookup.siren_wizard_view_form +msgid "Select" +msgstr "Sélectionner" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_street +msgid "Street" +msgstr "Rue" + +#. module: l10n_fr_siren_lookup +#: model:ir.model.fields,field_description:l10n_fr_siren_lookup.field_siren_wizard_line_wizard_id +msgid "Wizard" +msgstr "Assistant" + diff --git a/l10n_fr_siret_lookup/models/__init__.py b/l10n_fr_siret_lookup/models/__init__.py new file mode 100644 index 000000000..91fed54d4 --- /dev/null +++ b/l10n_fr_siret_lookup/models/__init__.py @@ -0,0 +1 @@ +from . import res_partner diff --git a/l10n_fr_siret_lookup/models/res_partner.py b/l10n_fr_siret_lookup/models/res_partner.py new file mode 100644 index 000000000..a0f7a2764 --- /dev/null +++ b/l10n_fr_siret_lookup/models/res_partner.py @@ -0,0 +1,306 @@ +# Copyright 2018-2021 Le Filament () +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +import requests + +from odoo import _, api, models +from odoo.exceptions import UserError + +logger = logging.getLogger(__name__) +try: + from stdnum import __version__ as stdnum_version + from stdnum.eu.vat import check_vies + from stdnum.fr.siren import is_valid as siren_is_valid, to_tva as siren_to_vat + from stdnum.fr.siret import is_valid as siret_is_valid +except ImportError: + logger.debug("Cannot import stdnum") + + +class ResPartner(models.Model): + _inherit = "res.partner" + + @api.model + def _opendatasoft_fields_list(self): + return [ + "datefermetureunitelegale", + "datefermetureetablissement", + "denominationunitelegale", + "l1_adressage_unitelegale", + "adresseetablissement", + "codepostaletablissement", + "libellecommuneetablissement", + "siren", + "nic", + "codedepartementetablissement", + # for the wizard + "siret", + "categorieentreprise", + "datecreationunitelegale", + "activiteprincipaleunitelegale", + "divisionunitelegale", + "naturejuridiqueunitelegale", + "trancheeffectifsunitelegale", + ] + + @api.model + def _opendatasoft_get_raw_data( + self, query, raise_if_fail=False, exclude_dead=False, rows=10 + ): + assert isinstance(query, str) + assert isinstance(rows, int) and rows > 0 + url = "https://data.opendatasoft.com/api/records/1.0/search/" + params = { + "dataset": "economicref-france-sirene-v3@public", + "q": query, + "rows": rows, + "fields": ",".join(self._opendatasoft_fields_list()), + } + # It seems that datefermetureetablissement and datefermetureunitelegale + # often have a value for a SIRET that is still open + # For example, SIRET 55208131766522 (siège social d'EDF) + # has datefermetureetablissement=2009-02-22 + # and datefermetureunitelegale=2018-12-01 !!! + # So I now set exclude_dead=False by default + if exclude_dead: + params[ + "q" + ] += " AND #null(datefermetureetablissement) AND #null(datefermetureunitelegale)" + try: + logger.info("Sending query to https://data.opendatasoft.com/api") + logger.debug("url=%s params=%s", url, params) + res = requests.get(url, params=params) + if res.status_code in (200, 201): + res_json = res.json() + # from pprint import pprint + + # pprint(res_json) + return res_json + else: + logger.warning( + "HTTP error %s returned by GET on data.opendatasoft.com/api", + res.status_code, + ) + if raise_if_fail: + raise UserError( + _( + "The webservice data.opendatasoft.com " + "returned an HTTP error code %s." + ) + % res.status_code + ) + except Exception as e: + logger.warning("Failure in the GET request on data.opendatasoft.com: %s", e) + if raise_if_fail: + raise UserError( + _( + "Failure in the request on data.opendatasoft.com " + "to create or update partner from SIREN or SIRET. " + "Technical error: %s." + ) + % e + ) + return False + + @api.model + def _opendatasoft_parse_record( + self, raw_record, exclude_dead=False, vat_vies_query=True + ): + res = False + if raw_record and isinstance(raw_record, dict): + if exclude_dead and raw_record.get("datefermetureunitelegale"): + return res + if exclude_dead and raw_record.get("datefermetureetablissement"): + return res + res = { + "name": raw_record.get("denominationunitelegale") + or raw_record.get("l1_adressage_unitelegale"), + "street": raw_record.get("adresseetablissement"), + "zip": raw_record.get("codepostaletablissement"), + "city": raw_record.get("libellecommuneetablissement"), + "siren": raw_record.get("siren") and str(raw_record["siren"]) or False, + "nic": raw_record.get("nic"), + } + if raw_record.get("codedepartementetablissement"): + dpt_code = raw_record["codedepartementetablissement"] + res["country_id"] = self._opendatasoft_dpt2country(dpt_code) + # set lang to French if installed + fr_lang = self.env["res.lang"].search([("code", "=", "fr_FR")]) + if fr_lang: + res["lang"] = "fr_FR" + if res.get("siren") and vat_vies_query: + vat = self._siren2vat_vies(res["siren"]) + if vat is not None: + res["vat"] = vat + return res + + @api.model + def _opendatasoft_dpt2country(self, dpt_code): + domtom2xmlid = { + "971": "gp", + "972": "mq", + "973": "gf", + "974": "re", + "975": "pm", # Saint Pierre and Miquelon + "976": "yt", # Mayotte + "977": "bl", # Saint-Barthélemy + "978": "mf", # Saint-Martin + "986": "wf", # Wallis-et-Futuna + "987": "pf", # Polynésie française + "988": "nc", # Nouvelle calédonie + } + country_id = False + if dpt_code and len(dpt_code) == 2: + country_id = self.env.ref("base.fr").id + elif dpt_code in domtom2xmlid: + country_xmlid = "base.%s" % domtom2xmlid[dpt_code] + country_id = self.env.ref(country_xmlid).id + return country_id + + @api.model + def _siren2vat_vies(self, siren, raise_if_fail=False): + vat = "FR%s" % siren_to_vat(siren) + logger.info("VIES check of VAT %s" % vat) + vies_res = False + res = False + try: + stdnum_version_float = float(stdnum_version) + except Exception: + stdnum_version_float = 1.8 + try: + if stdnum_version_float < 1.9: + vies_res = check_vies(vat) + else: + vies_res = check_vies(vat, timeout=5) + logger.debug("VIES answer vies_res.valid=%s", vies_res.valid) + except Exception as e: + logger.error("VIES query failed: %s", e) + if raise_if_fail: + raise UserError(_("Failed to query VIES.\nTechnical error: %s.") % e) + return None + if vies_res and vies_res.valid: + res = vat + return res + + @api.model + def _opendatasoft_get_first_result( + self, query, raise_if_fail=False, vat_vies_query=True + ): + res_json = self._opendatasoft_get_raw_data(query, raise_if_fail=raise_if_fail) + if res_json and "records" in res_json: + if len(res_json["records"]) > 0: + raw_record = res_json["records"][0].get("fields") + if raw_record: + return self._opendatasoft_parse_record( + raw_record, vat_vies_query=vat_vies_query + ) + else: + logger.warning("The query on opendatasoft.com returned 0 records") + return False + + @api.model + def _opendatasoft_get_from_siren(self, siren, vat_vies_query=True): + if siren and siren_is_valid(siren): + vals = self._opendatasoft_get_first_result( + "siren:%s AND etablissementsiege:oui" % siren, + vat_vies_query=vat_vies_query, + ) + if vals and vals.get("siren") == siren: + return vals + return False + + @api.model + def _opendatasoft_get_from_siret(self, siret, vat_vies_query=True): + if siret and siret_is_valid(siret): + vals = self._opendatasoft_get_first_result( + "siret:%s" % siret, vat_vies_query=vat_vies_query + ) + if vals and vals.get("siren") and vals.get("nic"): + vals_siret = vals["siren"] + vals["nic"] + if vals_siret == siret: + return vals + return False + + @api.onchange("siren") + def siren_onchange(self): + if ( + self.siren + and siren_is_valid(self.siren) + and not self.name + and self.is_company + and not self.parent_id + ): + if self.nic: + # We only execute the query if the full SIRET is OK + vals = False + if siret_is_valid(self.siren + self.nic): + siret = self.siren + self.nic + vals = self._opendatasoft_get_from_siret(siret) + else: + vals = self._opendatasoft_get_from_siren(self.siren) + if vals: + self.update(vals) + + @api.onchange("siret") + def siret_onchange(self): + if ( + self.siret + and siret_is_valid(self.siret) + and not self.name + and self.is_company + and not self.parent_id + ): + vals = self._opendatasoft_get_from_siret(self.siret) + if vals: + self.update(vals) + + @api.onchange("vat") + def vat_onchange(self): + if ( + self.vat + and not self.name + and not self.siren + and not self.siret + and self.is_company + and not self.parent_id + ): + vat = self.vat.replace(" ", "").upper() + if vat and vat.startswith("FR") and len(vat) == 13: + siren = vat[4:] + if siren_is_valid(siren): + vals = self._opendatasoft_get_from_siren(siren) + if vals: + self.update(vals) + + @api.onchange("name") + def siren_siret_vat_in_name_onchange(self): + if ( + self.name + and self.is_company + and not self.parent_id + and not self.siren + and not self.nic + and not self.siret + and not self.street + and not self.city + and not self.zip + ): + name = self.name.replace(" ", "") + if name: + vals = False + if len(name) == 9 and name.isdigit() and siren_is_valid(name): + vals = self._opendatasoft_get_from_siren(name) + elif len(name) == 14 and name.isdigit() and siret_is_valid(name): + vals = self._opendatasoft_get_from_siret(name) + elif ( + len(name) == 13 + and name[:2] == "FR" + and name[2:].isdigit() + and siren_is_valid(name[4:]) + ): + vals = self._opendatasoft_get_from_siren(name[4:]) + if vals: + self.update(vals) diff --git a/l10n_fr_siret_lookup/readme/CONTRIBUTORS.rst b/l10n_fr_siret_lookup/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..19f388ec9 --- /dev/null +++ b/l10n_fr_siret_lookup/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Benjamin Rivier (https://le-filament.com) +* Remi Cazenave (https://le-filament.com) +* Alexis de Lattre diff --git a/l10n_fr_siret_lookup/readme/CREDITS.rst b/l10n_fr_siret_lookup/readme/CREDITS.rst new file mode 100644 index 000000000..964968d6c --- /dev/null +++ b/l10n_fr_siret_lookup/readme/CREDITS.rst @@ -0,0 +1,3 @@ +The development of this module has been financially supported by: + +* Le Filament diff --git a/l10n_fr_siret_lookup/readme/DESCRIPTION.rst b/l10n_fr_siret_lookup/readme/DESCRIPTION.rst new file mode 100644 index 000000000..2a1f6ad21 --- /dev/null +++ b/l10n_fr_siret_lookup/readme/DESCRIPTION.rst @@ -0,0 +1,17 @@ +This modules updates partner fields via the `SIRENE database `. It uses the dataset *economicref-france-sirene-v3* of `opendatasoft `. It computes a theorical VAT number from the SIREN and then checks the validity of the VAT number on `VIES `_ (if invalid, the VAT number is discarded). + +The module supports 2 scenarios: + +* update of an existing partner via the menu *Action > SIREN Lookup*, +* creation of a new partner: start by setting the VAT number field, the SIREN field or SIRET field and Odoo will set the other fields. For usability purposes, it also work when you write the VAT number, SIREN or SIRET in the company name field. + +In the 2 scenarios, it will update the following fields: + +* Company Name +* Street +* Postal Code +* City +* Country +* SIREN and NIC (i.e. SIRET) +* VAT Number +* Language (creation scenario only) diff --git a/l10n_fr_siret_lookup/readme/USAGE.rst b/l10n_fr_siret_lookup/readme/USAGE.rst new file mode 100644 index 000000000..3a3291f34 --- /dev/null +++ b/l10n_fr_siret_lookup/readme/USAGE.rst @@ -0,0 +1,5 @@ +To update an existing parter, go to the partner form view and click on *Action > SIREN Lookup*. + +By default, the search field is filled with Company name. To get more accurate results, you may want to add the City name where the company is registered. Then click on *Lookup*. + +A list of company is displayed. You may want to click on one in order to see corresponding information or directly selecting company from tree view. Once a company is selected, the partner information is updated and a message is logged in the chatter. diff --git a/l10n_fr_siret_lookup/security/ir.model.access.csv b/l10n_fr_siret_lookup/security/ir.model.access.csv new file mode 100644 index 000000000..2a47e4486 --- /dev/null +++ b/l10n_fr_siret_lookup/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_fr_siret_lookup,Full access on fr.siret.lookup to partner manager,model_fr_siret_lookup,base.group_partner_manager,1,1,1,1 +access_fr_siret_lookup_line,Full access on fr.siret.lookup.line to partner manager,model_fr_siret_lookup_line,base.group_partner_manager,1,1,1,1 diff --git a/l10n_fr_siret_lookup/static/description/icon.png b/l10n_fr_siret_lookup/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/l10n_fr_siret_lookup/views/res_partner.xml b/l10n_fr_siret_lookup/views/res_partner.xml new file mode 100644 index 000000000..5366fd743 --- /dev/null +++ b/l10n_fr_siret_lookup/views/res_partner.xml @@ -0,0 +1,14 @@ + + + + + SIREN Lookup + fr.siret.lookup + form + new + + + form + + + diff --git a/l10n_fr_siret_lookup/wizard/__init__.py b/l10n_fr_siret_lookup/wizard/__init__.py new file mode 100644 index 000000000..af1ed13a3 --- /dev/null +++ b/l10n_fr_siret_lookup/wizard/__init__.py @@ -0,0 +1 @@ +from . import fr_siret_lookup diff --git a/l10n_fr_siret_lookup/wizard/fr_siret_lookup.py b/l10n_fr_siret_lookup/wizard/fr_siret_lookup.py new file mode 100644 index 000000000..eff588806 --- /dev/null +++ b/l10n_fr_siret_lookup/wizard/fr_siret_lookup.py @@ -0,0 +1,127 @@ +# Copyright 2018-2021 Le Filament () +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class FrSiretLookup(models.TransientModel): + _name = "fr.siret.lookup" + _description = "Get values from companies" + + name = fields.Char(string="Name to Search", required=True) + line_ids = fields.One2many( + "fr.siret.lookup.line", "wizard_id", string="Results", readonly=True + ) + partner_id = fields.Many2one("res.partner", "Partner", readonly=True, required=True) + + @api.model + def default_get(self, fields_list): + res = super().default_get(fields_list) + if ( + self.env.context.get("active_id") + and self.env.context.get("active_model") == "res.partner" + ): + partner = self.env["res.partner"].browse(self.env.context["active_id"]) + if not partner.is_company: + raise UserError( + _("Partner '%s' is not a company. This action is not relevant.") + % partner.display_name + ) + res.update( + { + "name": partner.name, + "partner_id": partner.id, + } + ) + return res + + # Action + @api.model + def _prepare_partner_from_data(self, data): + country_id = False + if data.get("codedepartementetablissement"): + country_id = self.env["res.partner"]._opendatasoft_dpt2country( + data["codedepartementetablissement"] + ) + return { + "name": data.get("denominationunitelegale") + or data.get("l1_adressage_unitelegale"), + "street": data.get("adresseetablissement"), + "zip": data.get("codepostaletablissement"), + "city": data.get("libellecommuneetablissement"), + "country_id": country_id, + "siren": data.get("siren") and str(data["siren"]) or False, + "siret": data.get("siret") and str(data["siret"]) or False, + "category": data.get("categorieentreprise"), + "creation_date": data.get("datecreationunitelegale"), + "ape": data.get("activiteprincipaleunitelegale"), + "ape_label": data.get("divisionunitelegale"), + "legal_type": data.get("naturejuridiqueunitelegale"), + "staff": data.get("trancheeffectifsunitelegale", 0), + } + + def get_lines(self): + self.ensure_one() + self.line_ids.unlink() + # Get request + res_json = self.env["res.partner"]._opendatasoft_get_raw_data( + self.name, raise_if_fail=True, rows=30 + ) + # Fill new company lines + companies_vals = [] + for company in res_json["records"]: + res = self._prepare_partner_from_data(company["fields"]) + companies_vals.append((0, 0, res)) + self.line_ids = companies_vals + return { + "context": self.env.context, + "view_mode": "form", + "res_model": self._name, + "res_id": self.id, + "view_id": False, + "type": "ir.actions.act_window", + "target": "new", + } + + +class FrSiretLookupLine(models.TransientModel): + _name = "fr.siret.lookup.line" + _description = "Company Selection" + + wizard_id = fields.Many2one("fr.siret.lookup", string="Wizard", ondelete="cascade") + name = fields.Char(string="Name") + street = fields.Char(string="Street") + zip = fields.Char(string="Zip") + city = fields.Char(string="City") + country_id = fields.Many2one("res.country", string="Country") + legal_type = fields.Char("Legal Type") + siren = fields.Char("SIREN") + siret = fields.Char("SIRET") + ape = fields.Char("APE Code") + ape_label = fields.Char("APE Label") + creation_date = fields.Date("Creation date") + staff = fields.Char("# Staff") + category = fields.Char("Category") + + def _prepare_partner_values(self): + self.ensure_one() + vat = self.env["res.partner"]._siren2vat_vies(self.siren, raise_if_fail=True) + vals = { + "name": self.name, + "street": self.street, + "zip": self.zip, + "city": self.city, + "country_id": self.country_id.id or False, + "siret": self.siret, + "vat": vat, + } + return vals + + def update_partner(self): + self.ensure_one() + partner = self.wizard_id.partner_id + partner.write(self._prepare_partner_values()) + partner.message_post(body=_("Partner updated via the opendatasoft.com API.")) diff --git a/l10n_fr_siret_lookup/wizard/fr_siret_lookup_view.xml b/l10n_fr_siret_lookup/wizard/fr_siret_lookup_view.xml new file mode 100644 index 000000000..94c3306ff --- /dev/null +++ b/l10n_fr_siret_lookup/wizard/fr_siret_lookup_view.xml @@ -0,0 +1,97 @@ + + + + + fr.siret.lookup + +
+ + + +