diff --git a/l10n_be_bpost_address_validation/README.rst b/l10n_be_bpost_address_validation/README.rst new file mode 100644 index 000000000..1f19f41cc --- /dev/null +++ b/l10n_be_bpost_address_validation/README.rst @@ -0,0 +1,127 @@ +======================== +Bpost address validation +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--belgium-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-belgium/tree/16.0/l10n_be_bpost_address_validation + :alt: OCA/l10n-belgium +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-belgium-16-0/l10n-belgium-16-0-l10n_be_bpost_address_validation + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/l10n-belgium&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to check partner's addresses validity in one click. +If address is not valid a proposal change will be displayed and you will be free to keep it or not. +If you accept it, the partner's address will be automatically updated. + +The validation of the address is done throught the bpost API available here: https://www.bpost.be/en/addressing-web-service-widgets-address-validation. +Bpost is Belgium's leading postal operator and plays a key role in maintaining the country's economic and social fabric. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +This module can be installed in the usual way. + +Usage +===== + +Once your user has the correct permissions, open a partner that has a belgian +address and click on Check address validity button. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_new_partner.png + :width: 90% + :alt: Partner form with Check address validity button + :align: center + +If address is not valid, a popup will appear telling you that the address is not valid and will suggest a possible change. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_click.png + :width: 90% + :alt: Popup with the suggest change. + :align: center + +If you decide to keep the change, partner's address will be automatically updated. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_apply_changes.png + :width: 90% + :alt: Partner form updated. + :align: center + +Now, if you click again on Check address validity button, you will see that the address is valid. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_success.png + :width: 90% + :alt: Partner form updated. + :align: center + +Be careful not to provide an invalid or incomplete address. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_invalid_address_form.png + :width: 90% + :alt: Partner form with invalid address. + :align: center + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_invalid_address.png + :width: 90% + :alt: Error popup. + :align: center + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Samuel Kouff + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/l10n-belgium `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_be_bpost_address_validation/__init__.py b/l10n_be_bpost_address_validation/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/l10n_be_bpost_address_validation/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/l10n_be_bpost_address_validation/__manifest__.py b/l10n_be_bpost_address_validation/__manifest__.py new file mode 100644 index 000000000..e3345ea9b --- /dev/null +++ b/l10n_be_bpost_address_validation/__manifest__.py @@ -0,0 +1,28 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Bpost address validation", + "summary": ( + "Check the validity of your partner's addresses " + "or make a change with a change proposal." + ), + "version": "16.0.1.0.0", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/l10n-belgium", + "depends": ["base", "web"], + "data": [ + "security/ir.model.access.csv", + "wizards/bpost_address_validation.xml", + "views/res_partner.xml", + ], + "assets": { + "web.assets_backend": [ + ("include", "web._assets_helpers"), + "web/static/src/scss/pre_variables.scss", + "web/static/lib/bootstrap/scss/_variables.scss", + ("include", "web._assets_bootstrap"), + ] + }, + "installable": True, +} diff --git a/l10n_be_bpost_address_validation/i18n/fr_BE.po b/l10n_be_bpost_address_validation/i18n/fr_BE.po new file mode 100644 index 000000000..a96721a1c --- /dev/null +++ b/l10n_be_bpost_address_validation/i18n/fr_BE.po @@ -0,0 +1,151 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_be_bpost_address_validation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-02 09:25+0000\n" +"PO-Revision-Date: 2023-05-02 09:25+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_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Success ! The address given is valid." +msgstr "Succès ! L'adresse encodée est valide." + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "" +"An error has been detected in the given address. Would you like to keep the " +"suggest change ?" +msgstr "" +"Une erreur a été détectée dans l'adresse renseignée. Voulez-vous appliquer " +"les changements ?" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "An error occurred when fetching data from bpost API." +msgstr "" +"Une erreur est survenue lors de la récupération des données de l'API de " +"bpost." + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Apply changes" +msgstr "Appliquer les changements" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__bad_address +msgid "Bad Address" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__bpost_address +msgid "Bpost Address" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Cancel" +msgstr "Annuler" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/models/res_partner.py:0 +#, python-format +msgid "Check Address Validity" +msgstr "Vérifier la validité de l'adresse" + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.res_partner_form_view +msgid "Check address validity" +msgstr "Vérifier la validité de l'adresse" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model,name:l10n_be_bpost_address_validation.model_res_partner +msgid "Contact" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__id +msgid "ID" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_res_partner__is_be +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_res_users__is_be +msgid "Is Be" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__is_valid +msgid "Is Valid" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__partner_id +msgid "Partner" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__suggest_changes +msgid "Suggest Changes" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "The given address is not complete or the address cannot be found." +msgstr "L'adresse encodée n'est pas complète ou est introuvable." + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__warning_message +msgid "Warning Message" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model,name:l10n_be_bpost_address_validation.model_bpost_address_validation_wizard +msgid "bpost.address.validation.wizard" +msgstr "" diff --git a/l10n_be_bpost_address_validation/i18n/l10n_be_bpost_address_validation.pot b/l10n_be_bpost_address_validation/i18n/l10n_be_bpost_address_validation.pot new file mode 100644 index 000000000..e31c29478 --- /dev/null +++ b/l10n_be_bpost_address_validation/i18n/l10n_be_bpost_address_validation.pot @@ -0,0 +1,147 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_be_bpost_address_validation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-05-02 09:24+0000\n" +"PO-Revision-Date: 2023-05-02 09:24+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_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Success ! The address given is valid." +msgstr "" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "" +"An error has been detected in the given address. Would you like to keep the " +"suggest change ?" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "An error occurred when fetching data from bpost API." +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Apply changes" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__bad_address +msgid "Bad Address" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__bpost_address +msgid "Bpost Address" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.view_check_address_validity_form +msgid "Cancel" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/models/res_partner.py:0 +#, python-format +msgid "Check Address Validity" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model_terms:ir.ui.view,arch_db:l10n_be_bpost_address_validation.res_partner_form_view +msgid "Check address validity" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model,name:l10n_be_bpost_address_validation.model_res_partner +msgid "Contact" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__id +msgid "ID" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_res_partner__is_be +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_res_users__is_be +msgid "Is Be" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__is_valid +msgid "Is Valid" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__partner_id +msgid "Partner" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__suggest_changes +msgid "Suggest Changes" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#. odoo-python +#: code:addons/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py:0 +#, python-format +msgid "The given address is not complete or the address cannot be found." +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model.fields,field_description:l10n_be_bpost_address_validation.field_bpost_address_validation_wizard__warning_message +msgid "Warning Message" +msgstr "" + +#. module: l10n_be_bpost_address_validation +#: model:ir.model,name:l10n_be_bpost_address_validation.model_bpost_address_validation_wizard +msgid "bpost.address.validation.wizard" +msgstr "" diff --git a/l10n_be_bpost_address_validation/models/__init__.py b/l10n_be_bpost_address_validation/models/__init__.py new file mode 100644 index 000000000..6bfd9942d --- /dev/null +++ b/l10n_be_bpost_address_validation/models/__init__.py @@ -0,0 +1,2 @@ +from . import res_partner +from . import bpost_address diff --git a/l10n_be_bpost_address_validation/models/bpost_address.py b/l10n_be_bpost_address_validation/models/bpost_address.py new file mode 100644 index 000000000..1ec375f37 --- /dev/null +++ b/l10n_be_bpost_address_validation/models/bpost_address.py @@ -0,0 +1,80 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +class BpostAddress: + def __init__(self, result): + """Transforms the JSON result into a BpostAddress object""" + + validated_address_result = result["ValidateAddressesResponse"][ + "ValidatedAddressResultList" + ]["ValidatedAddressResult"][0] + validated_address = validated_address_result["ValidatedAddressList"][ + "ValidatedAddress" + ][0] + postal_address = validated_address["PostalAddress"] + ( + self.street_number, + self.street_name, + self.postal_code, + self.municipality_name, + self.latitude, + self.longitude, + self.street_number, + self.error, + ) = (None, None, None, None, None, None, None, None) + + if ( + "StructuredDeliveryPointLocation" in postal_address + and "StructuredPostalCodeMunicipality" in postal_address + ): + self.street_name = postal_address["StructuredDeliveryPointLocation"][ + "StreetName" + ] + self.postal_code = postal_address["StructuredPostalCodeMunicipality"][ + "PostalCode" + ] + self.municipality_name = postal_address["StructuredPostalCodeMunicipality"][ + "MunicipalityName" + ] + + if "ServicePointDetail" in validated_address: + geographical_location = validated_address["ServicePointDetail"][ + "GeographicalLocationInfo" + ]["GeographicalLocation"] + self.latitude = geographical_location["Latitude"] + self.longitude = geographical_location["Longitude"] + + if "StreetNumber" in postal_address["StructuredDeliveryPointLocation"]: + self.street_number = postal_address["StructuredDeliveryPointLocation"][ + "StreetNumber" + ] + + if "Error" in validated_address_result: + self.error = validated_address_result["Error"] + + def toJson(self): + """Convert the BpostAdress object to JSON""" + + json = {} + if ( + self.street_name is not None + and self.postal_code is not None + and self.municipality_name is not None + and self.latitude is not None + and self.longitude is not None + ): + json = { + "street_name": self.street_name, + "postal_code": self.postal_code, + "municipality_name": self.municipality_name, + "latitude": self.latitude, + "longitude": self.longitude, + } + if self.street_number is not None: + json.update({"street_number": self.street_number}) + if self.error is not None: + json.update({"error": self.error}) + else: + json.update({"error": self.error}) + return json diff --git a/l10n_be_bpost_address_validation/models/res_partner.py b/l10n_be_bpost_address_validation/models/res_partner.py new file mode 100644 index 000000000..07cd4885e --- /dev/null +++ b/l10n_be_bpost_address_validation/models/res_partner.py @@ -0,0 +1,28 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + is_be = fields.Boolean(compute="_compute_is_be") + + @api.depends("country_id") + def _compute_is_be(self): + for rec in self: + if rec.country_id.code == "BE": + rec.is_be = True + else: + rec.is_be = False + + def action_check_address_validity(self): + return { + "name": _("Check Address Validity"), + "type": "ir.actions.act_window", + "view_mode": "form", + "res_model": "bpost.address.validation.wizard", + "target": "new", + "context": {"default_partner_id": self.ids[0]}, + } diff --git a/l10n_be_bpost_address_validation/readme/CONTRIBUTORS.rst b/l10n_be_bpost_address_validation/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..11e4f73cc --- /dev/null +++ b/l10n_be_bpost_address_validation/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Samuel Kouff diff --git a/l10n_be_bpost_address_validation/readme/DESCRIPTION.rst b/l10n_be_bpost_address_validation/readme/DESCRIPTION.rst new file mode 100644 index 000000000..d233e33eb --- /dev/null +++ b/l10n_be_bpost_address_validation/readme/DESCRIPTION.rst @@ -0,0 +1,6 @@ +This module allows you to check partner's addresses validity in one click. +If address is not valid a proposal change will be displayed and you will be free to keep it or not. +If you accept it, the partner's address will be automatically updated. + +The validation of the address is done throught the bpost API available here: https://www.bpost.be/en/addressing-web-service-widgets-address-validation. +Bpost is Belgium's leading postal operator and plays a key role in maintaining the country's economic and social fabric. diff --git a/l10n_be_bpost_address_validation/readme/HISTORY.rst b/l10n_be_bpost_address_validation/readme/HISTORY.rst new file mode 100644 index 000000000..e69de29bb diff --git a/l10n_be_bpost_address_validation/readme/INSTALL.rst b/l10n_be_bpost_address_validation/readme/INSTALL.rst new file mode 100644 index 000000000..c9aa2a0f4 --- /dev/null +++ b/l10n_be_bpost_address_validation/readme/INSTALL.rst @@ -0,0 +1 @@ +This module can be installed in the usual way. diff --git a/l10n_be_bpost_address_validation/readme/USAGE.rst b/l10n_be_bpost_address_validation/readme/USAGE.rst new file mode 100644 index 000000000..3b06cf13b --- /dev/null +++ b/l10n_be_bpost_address_validation/readme/USAGE.rst @@ -0,0 +1,40 @@ +Once your user has the correct permissions, open a partner that has a belgian +address and click on Check address validity button. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_new_partner.png + :width: 90% + :alt: Partner form with Check address validity button + :align: center + +If address is not valid, a popup will appear telling you that the address is not valid and will suggest a possible change. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_click.png + :width: 90% + :alt: Popup with the suggest change. + :align: center + +If you decide to keep the change, partner's address will be automatically updated. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_apply_changes.png + :width: 90% + :alt: Partner form updated. + :align: center + +Now, if you click again on Check address validity button, you will see that the address is valid. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_on_success.png + :width: 90% + :alt: Partner form updated. + :align: center + +Be careful not to provide an invalid or incomplete address. + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_invalid_address_form.png + :width: 90% + :alt: Partner form with invalid address. + :align: center + +.. figure:: https://raw.githubusercontent.com/OCA/l10n-belgium/c89841d84b63052e5c6d63049a2d81b473490fb4/l10n_be_bpost_address_validation/static/description/doc_invalid_address.png + :width: 90% + :alt: Error popup. + :align: center diff --git a/l10n_be_bpost_address_validation/security/ir.model.access.csv b/l10n_be_bpost_address_validation/security/ir.model.access.csv new file mode 100644 index 000000000..f74781632 --- /dev/null +++ b/l10n_be_bpost_address_validation/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_bpost_validation_wizard,access_bpost_validation_wizard,model_bpost_address_validation_wizard,base.group_user,1,1,1,1 diff --git a/l10n_be_bpost_address_validation/static/description/doc_invalid_address.png b/l10n_be_bpost_address_validation/static/description/doc_invalid_address.png new file mode 100644 index 000000000..ab0de5484 Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_invalid_address.png differ diff --git a/l10n_be_bpost_address_validation/static/description/doc_invalid_address_form.png b/l10n_be_bpost_address_validation/static/description/doc_invalid_address_form.png new file mode 100644 index 000000000..ede0b9278 Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_invalid_address_form.png differ diff --git a/l10n_be_bpost_address_validation/static/description/doc_new_partner.png b/l10n_be_bpost_address_validation/static/description/doc_new_partner.png new file mode 100644 index 000000000..55adcffc8 Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_new_partner.png differ diff --git a/l10n_be_bpost_address_validation/static/description/doc_on_apply_changes.png b/l10n_be_bpost_address_validation/static/description/doc_on_apply_changes.png new file mode 100644 index 000000000..6717b27ec Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_on_apply_changes.png differ diff --git a/l10n_be_bpost_address_validation/static/description/doc_on_click.png b/l10n_be_bpost_address_validation/static/description/doc_on_click.png new file mode 100644 index 000000000..5a121b2d3 Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_on_click.png differ diff --git a/l10n_be_bpost_address_validation/static/description/doc_on_success.png b/l10n_be_bpost_address_validation/static/description/doc_on_success.png new file mode 100644 index 000000000..44d9fe0ce Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/doc_on_success.png differ diff --git a/l10n_be_bpost_address_validation/static/description/icon.png b/l10n_be_bpost_address_validation/static/description/icon.png new file mode 100644 index 000000000..73465a17e Binary files /dev/null and b/l10n_be_bpost_address_validation/static/description/icon.png differ diff --git a/l10n_be_bpost_address_validation/static/description/index.html b/l10n_be_bpost_address_validation/static/description/index.html new file mode 100644 index 000000000..058249a11 --- /dev/null +++ b/l10n_be_bpost_address_validation/static/description/index.html @@ -0,0 +1,456 @@ + + + + + + +Bpost address validation + + + +
+

Bpost address validation

+ + +

Beta License: AGPL-3 OCA/l10n-belgium Translate me on Weblate Try me on Runboat

+

This module allows you to check partner’s addresses validity in one click. +If address is not valid a proposal change will be displayed and you will be free to keep it or not. +If you accept it, the partner’s address will be automatically updated.

+

The validation of the address is done throught the bpost API available here: https://www.bpost.be/en/addressing-web-service-widgets-address-validation. +Bpost is Belgium’s leading postal operator and plays a key role in maintaining the country’s economic and social fabric.

+

Table of contents

+ +
+

Installation

+

This module can be installed in the usual way.

+
+
+

Usage

+

Once your user has the correct permissions, open a partner that has a belgian +address and click on Check address validity button.

+
+Partner form with Check address validity button +
+

If address is not valid, a popup will appear telling you that the address is not valid and will suggest a possible change.

+
+Popup with the suggest change. +
+

If you decide to keep the change, partner’s address will be automatically updated.

+
+Partner form updated. +
+

Now, if you click again on Check address validity button, you will see that the address is valid.

+
+Partner form updated. +
+

Be careful not to provide an invalid or incomplete address.

+
+Partner form with invalid address. +
+
+Error popup. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ACSONE SA/NV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/l10n-belgium project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_be_bpost_address_validation/tests/__init__.py b/l10n_be_bpost_address_validation/tests/__init__.py new file mode 100644 index 000000000..c138b70a4 --- /dev/null +++ b/l10n_be_bpost_address_validation/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_bpost_address_validation_wizard +from . import test_res_partner diff --git a/l10n_be_bpost_address_validation/tests/test_bpost_address_validation_wizard.py b/l10n_be_bpost_address_validation/tests/test_bpost_address_validation_wizard.py new file mode 100644 index 000000000..b132122a7 --- /dev/null +++ b/l10n_be_bpost_address_validation/tests/test_bpost_address_validation_wizard.py @@ -0,0 +1,161 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import responses + +from odoo.tests.common import TransactionCase + + +class TestBpostAddressValidationWizard(TransactionCase): + @classmethod + @responses.activate + def setUpClass(cls): + super(TestBpostAddressValidationWizard, cls).setUpClass() + + cls.country = cls.env["res.country"].search([("code", "=", "BE")]) + cls.luxembourg = cls.env["res.country"].search([("code", "=", "LU")]) + cls.partner = cls.env["res.partner"].create( + { + "name": "Acsone", + "street": "Quai Banneng 6", + "city": "Liège", + "zip": "4000", + "country_id": cls.country.id, + } + ) + cls.partner_lu = cls.env["res.partner"].create( + { + "name": "Acsone", + "street": "Zone industrielle 22", + "city": "Kehlen", + "zip": "8287", + "country_id": cls.luxembourg.id, + } + ) + cls.return_value = { + "ValidateAddressesResponse": { + "ValidatedAddressResultList": { + "ValidatedAddressResult": [ + { + "@id": "1", + "ValidatedAddressList": { + "ValidatedAddress": [ + { + "PostalAddress": { + "StructuredDeliveryPointLocation": { + "StreetName": "QUAI BANNING", + "StreetNumber": "6", + }, + "StructuredPostalCodeMunicipality": { + "PostalCode": "4000", + "MunicipalityName": "LIÈGE", + }, + "CountryName": "BELGIQUE", + }, + "AddressLanguage": "fr", + "ServicePointDetail": { + "GeographicalLocationInfo": { + "GeographicalLocation": { + "Latitude": { + "Value": "50.61389", + "CoordinateType": "DEGDEC", + }, + "Longitude": { + "Value": "5.575775", + "CoordinateType": "DEGDEC", + }, + } + } + }, + "Label": { + "Line": ["QUAI BANNING 6", "4000 LIÈGE"] + }, + } + ] + }, + "Error": [ + { + "ComponentRef": "UnstructuredDeliveryPointLocation", + "ErrorCode": "anomaly_in_field", + "ErrorSeverity": "warning", + } + ], + "DetectedInputAddressLanguage": "fr", + "FormattedSubmittedAddress": { + "Line": ["Quai Banneng 6", "4000 Liège"] + }, + "TransactionID": "10379d53-2072-420e-b875-e83148ef94e0", + } + ] + } + } + } + responses.add( + method=responses.POST, + url="https://webservices-pub.bpost.be/ws/" + + "ExternalMailingAddressProofingCSREST_v1/address/validateAddresses", + json=cls.return_value, + ) + cls.wizard = cls.env["bpost.address.validation.wizard"].create( + {"partner_id": cls.partner.id} + ) + cls.wizard._compute_response_address() + + @classmethod + def tearDownClass(cls): + super(TestBpostAddressValidationWizard, cls).tearDownClass() + + def test_is_not_valid(self): + self.assertFalse(self.wizard.is_valid) + + def test_apply_changes(self): + self.wizard.apply_changes() + + self.assertEqual("QUAI BANNING 6", self.partner.street) + self.assertEqual("LIÈGE", self.partner.city) + self.assertEqual("4000", self.partner.zip) + + def test_suggest_changes(self): + self.assertEqual("QUAI BANNING 6 4000, LIÈGE", self.wizard.suggest_changes) + self.assertFalse(self.wizard.bad_address) + self.assertFalse(self.wizard.is_valid) + + def test_invalid_address(self): + self.partner.street = "Quai Banning" + self.wizard._compute_response_address() + self.assertTrue(self.wizard.bad_address) + self.assertFalse(self.wizard.is_valid) + + def test_valid_address(self): + self.partner.street = "Quai Banning 6" + self.wizard._compute_response_address() + self.assertTrue(self.wizard.is_valid) + self.assertFalse(self.wizard.bad_address) + + def test_partner_from_another_country(self): + wizard = self.env["bpost.address.validation.wizard"].create( + {"partner_id": self.partner_lu.id} + ) + wizard._compute_response_address() + self.assertTrue(wizard.is_valid) + self.assertFalse(wizard.bad_address) + + def test_invalid_address_and_apply_changes(self): + self.partner.street = "Quai Banning" + self.wizard._compute_response_address() + self.wizard.apply_changes() + self.assertTrue(self.wizard.bad_address) + self.assertFalse(self.wizard.is_valid) + self.assertEqual( + "The given address is not complete or the address cannot be found.", + self.wizard.warning_message, + ) + + self.assertNotEqual("QUAI BANNING", self.partner.street) + self.assertNotEqual("LIÈGE", self.partner.city) + + def test_address_not_found(self): + self.partner.street = "benneng" + self.wizard._compute_response_address() + self.assertTrue(self.wizard.bad_address) + self.assertFalse(self.wizard.is_valid) diff --git a/l10n_be_bpost_address_validation/tests/test_res_partner.py b/l10n_be_bpost_address_validation/tests/test_res_partner.py new file mode 100644 index 000000000..c5ec174be --- /dev/null +++ b/l10n_be_bpost_address_validation/tests/test_res_partner.py @@ -0,0 +1,43 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestResPartner(TransactionCase): + @classmethod + def setUpClass(cls): + super(TestResPartner, cls).setUpClass() + + cls.belgium = cls.env["res.country"].search([("code", "=", "BE")]) + cls.luxembourg = cls.env["res.country"].search([("code", "=", "LU")]) + + cls.partner_be = cls.env["res.partner"].create( + { + "name": "Acsone", + "street": "Quai Banning 6", + "city": "Liège", + "zip": "4000", + "country_id": cls.belgium.id, + } + ) + + cls.partner_lu = cls.env["res.partner"].create( + { + "name": "Acsone", + "street": "Zone industrielle 22", + "city": "Kehlen", + "zip": "8287", + "country_id": cls.luxembourg.id, + } + ) + + @classmethod + def tearDownClass(cls): + super(TestResPartner, cls).tearDownClass() + + def test_country_is_belgium(self): + self.assertTrue(self.partner_be.is_be) + + def test_country_is_not_belgium(self): + self.assertFalse(self.partner_lu.is_be) diff --git a/l10n_be_bpost_address_validation/views/res_partner.xml b/l10n_be_bpost_address_validation/views/res_partner.xml new file mode 100644 index 000000000..0bc69a0cb --- /dev/null +++ b/l10n_be_bpost_address_validation/views/res_partner.xml @@ -0,0 +1,35 @@ + + + + res.partner.form (in l10n_be_bpost_address_validation) + res.partner + + + + +
+
+
+ + +
+
+
+
+
+
diff --git a/l10n_be_bpost_address_validation/wizards/__init__.py b/l10n_be_bpost_address_validation/wizards/__init__.py new file mode 100644 index 000000000..fb393f635 --- /dev/null +++ b/l10n_be_bpost_address_validation/wizards/__init__.py @@ -0,0 +1 @@ +from . import bpost_address_validation diff --git a/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py b/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py new file mode 100644 index 000000000..d790e5de5 --- /dev/null +++ b/l10n_be_bpost_address_validation/wizards/bpost_address_validation.py @@ -0,0 +1,135 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import requests + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + +from ..models.bpost_address import BpostAddress + + +class BpostAddressValidationWizard(models.TransientModel): + _name = "bpost.address.validation.wizard" + _description = "Check address validity and propose change if needed" + + partner_id = fields.Many2one("res.partner", readonly=True) + is_valid = fields.Boolean(compute="_compute_response_address") + bad_address = fields.Boolean() + warning_message = fields.Char(readonly=True) + suggest_changes = fields.Char(readonly=True) + bpost_address = fields.Json() + + @api.depends("partner_id") + def _compute_response_address(self): + for rec in self: + partner = rec.partner_id + if partner.country_id.code == "BE": + # This is the JSON that should be sent as input to the API. + response = self.send_request(partner) + if response.ok: + json = response.json() + # Transform the result into a BpostAddress object. + rec.bpost_address = BpostAddress(json).toJson() + if "error" in rec.bpost_address: + if ( + "street_name" in rec.bpost_address + and "postal_code" in rec.bpost_address + and "municipality_name" in rec.bpost_address + and "street_number" in rec.bpost_address + ): + self.invalid_address_and_suggest_changes(rec) + else: + self.invalid_address(rec) + else: + rec.is_valid = True + else: + raise UserError( + _("An error occurred when fetching data from bpost API.") + ) + else: + rec.is_valid = True + + def invalid_address(self, rec): + rec.warning_message = _( + "The given address is not complete or the address cannot be found." + ) + rec.bad_address = True + rec.is_valid = False + + def invalid_address_and_suggest_changes(self, rec): + rec.warning_message = _( + "An error has been detected in the given address. " + + "Would you like to keep the suggest change ?" + ) + changes = "{} {} {}, {}".format( + rec.bpost_address["street_name"], + rec.bpost_address["street_number"], + rec.bpost_address["postal_code"], + rec.bpost_address["municipality_name"], + ) + + rec.suggest_changes = changes + rec.bad_address = False + rec.is_valid = False + + def send_request(self, partner): + playload = { + "ValidateAddressesRequest": { + "AddressToValidateList": { + "AddressToValidate": [ + { + "@id": "1", + "PostalAddress": { + "DeliveryPointLocation": { + "UnstructuredDeliveryPointLocation": partner.street + }, + "PostalCodeMunicipality": { + "UnstructuredPostalCodeMunicipality": partner.zip + + " " + + partner.city + }, + }, + } + ] + }, + "ValidateAddressOptions": { + "IncludeFormatting": "true", + "IncludeSuggestions": "true", + "IncludeSubmittedAddress": "true", + "IncludeListOfBoxes": "true", + "IncludeNumberOfBoxes": "true", + "IncludeDefaultGeoLocation": "true", + "IncludeDefaultGeoLocationForBoxes": "true", + }, + } + } + response = requests.post( + "https://webservices-pub.bpost.be/ws/" + + "ExternalMailingAddressProofingCSREST_v1/address/validateAddresses", + json=playload, + timeout=10, + headers={"content-type": "application/json"}, + ) + + return response + + def apply_changes(self): + for rec in self: + if ( + "street_name" in rec.bpost_address + and "postal_code" in rec.bpost_address + and "municipality_name" in rec.bpost_address + and "street_number" in rec.bpost_address + ): + rec.is_valid = True + partner = rec.partner_id + partner.street = ( + rec.bpost_address["street_name"] + + " " + + rec.bpost_address["street_number"] + ) + partner.city = rec.bpost_address["municipality_name"] + partner.zip = rec.bpost_address["postal_code"] + rec.suggest_changes = "" + rec.bad_address = False diff --git a/l10n_be_bpost_address_validation/wizards/bpost_address_validation.xml b/l10n_be_bpost_address_validation/wizards/bpost_address_validation.xml new file mode 100644 index 000000000..21eb3cce6 --- /dev/null +++ b/l10n_be_bpost_address_validation/wizards/bpost_address_validation.xml @@ -0,0 +1,41 @@ + + + + bpost.address.validation.wizard.form + bpost.address.validation.wizard + +
+ + + + +
+ + + + +
+
+ Success ! The address given is valid. +
+ + +
+
+
diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt deleted file mode 100644 index 90c269ab3..000000000 --- a/setup/_metapackage/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -16.0.20221208.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py deleted file mode 100644 index b658aa128..000000000 --- a/setup/_metapackage/setup.py +++ /dev/null @@ -1,19 +0,0 @@ -import setuptools - -with open('VERSION.txt', 'r') as f: - version = f.read().strip() - -setuptools.setup( - name="odoo-addons-oca-l10n-belgium", - description="Meta package for oca-l10n-belgium Odoo addons", - version=version, - install_requires=[ - 'odoo-addon-companyweb_base>=16.0dev,<16.1dev', - 'odoo-addon-companyweb_payment_info>=16.0dev,<16.1dev', - ], - classifiers=[ - 'Programming Language :: Python', - 'Framework :: Odoo', - 'Framework :: Odoo :: 16.0', - ] -) diff --git a/setup/l10n_be_bpost_address_validation/odoo/addons/l10n_be_bpost_address_validation b/setup/l10n_be_bpost_address_validation/odoo/addons/l10n_be_bpost_address_validation new file mode 120000 index 000000000..f4434dd43 --- /dev/null +++ b/setup/l10n_be_bpost_address_validation/odoo/addons/l10n_be_bpost_address_validation @@ -0,0 +1 @@ +../../../../l10n_be_bpost_address_validation \ No newline at end of file diff --git a/setup/l10n_be_bpost_address_validation/setup.py b/setup/l10n_be_bpost_address_validation/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/l10n_be_bpost_address_validation/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/test-requirements.txt b/test-requirements.txt index e86a95237..a84b9c1d4 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,3 @@ freezegun vcrpy-unittest +responses