diff --git a/l10n_jp_partner_zip_address/README.rst b/l10n_jp_partner_zip_address/README.rst new file mode 100644 index 00000000..5b397172 --- /dev/null +++ b/l10n_jp_partner_zip_address/README.rst @@ -0,0 +1,82 @@ +========================= +Japan Partner Zip Address +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6d167f7fef2fae9586761ef7ecb539b7b4d2af58674cbcafa6cc222e586ce53c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--japan-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-japan/tree/17.0/l10n_jp_partner_zip_address + :alt: OCA/l10n-japan +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-japan-17-0/l10n-japan-17-0-l10n_jp_partner_zip_address + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-japan&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module introduces a function that automatically retrieves and fills +in the Japanese address details for a partner using the zipcloud +service, provided that the following conditions are met. + +- Country is Japan or no country is set for the partner. +- A valid postcode is entered for the partner. + +Note that in order to have the prefecture proposed automatically, you +need to have the prefecture records in Japanese (e.g. "福岡県" instead +of "Fukuoka"). This can be done by overriding the name of correspoinding +res.country.state records, or by installing the l10n_jp_country_state +module. + +**Table of contents** + +.. contents:: + :local: + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Quartile + +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-japan `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_jp_partner_zip_address/__init__.py b/l10n_jp_partner_zip_address/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/l10n_jp_partner_zip_address/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/l10n_jp_partner_zip_address/__manifest__.py b/l10n_jp_partner_zip_address/__manifest__.py new file mode 100644 index 00000000..6c7607c3 --- /dev/null +++ b/l10n_jp_partner_zip_address/__manifest__.py @@ -0,0 +1,13 @@ +# Copyright 2024 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Japan Partner Zip Address", + "version": "17.0.1.0.0", + "author": "Quartile, Odoo Community Association (OCA)", + "license": "AGPL-3", + "website": "https://github.com/OCA/l10n-japan", + "category": "Localization", + "depends": ["base"], + "external_dependencies": {"python": ["jaconv"]}, + "installable": True, +} diff --git a/l10n_jp_partner_zip_address/i18n/ja.po b/l10n_jp_partner_zip_address/i18n/ja.po new file mode 100644 index 00000000..cabdbc56 --- /dev/null +++ b/l10n_jp_partner_zip_address/i18n/ja.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_jp_partner_zip_address +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-07 08:04+0000\n" +"PO-Revision-Date: 2024-02-07 08:04+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_jp_partner_zip_address +#: model:ir.model,name:l10n_jp_partner_zip_address.model_res_partner +msgid "Contact" +msgstr "連絡先" + +#. module: l10n_jp_partner_zip_address +#. odoo-python +#: code:addons/l10n_jp_partner_zip_address/models/zip_search_mixin.py:0 +#, python-format +msgid "Only digits are allowed." +msgstr "数値のみで入力してください。" + +#. module: l10n_jp_partner_zip_address +#. odoo-python +#: code:addons/l10n_jp_partner_zip_address/models/zip_search_mixin.py:0 +#, python-format +msgid "Postcode should be 7 digits." +msgstr "郵便番号には7桁の数値を入れてください。" + +#. module: l10n_jp_partner_zip_address +#: model:ir.model,name:l10n_jp_partner_zip_address.model_zip_search_mixin +msgid "zip.search.mixin" +msgstr "" diff --git a/l10n_jp_partner_zip_address/i18n/l10n_jp_partner_zip_address.pot b/l10n_jp_partner_zip_address/i18n/l10n_jp_partner_zip_address.pot new file mode 100644 index 00000000..1d1c25e8 --- /dev/null +++ b/l10n_jp_partner_zip_address/i18n/l10n_jp_partner_zip_address.pot @@ -0,0 +1,36 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_jp_partner_zip_address +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \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_jp_partner_zip_address +#: model:ir.model,name:l10n_jp_partner_zip_address.model_res_partner +msgid "Contact" +msgstr "" + +#. module: l10n_jp_partner_zip_address +#. odoo-python +#: code:addons/l10n_jp_partner_zip_address/models/zip_search_mixin.py:0 +msgid "Only digits are allowed." +msgstr "" + +#. module: l10n_jp_partner_zip_address +#. odoo-python +#: code:addons/l10n_jp_partner_zip_address/models/zip_search_mixin.py:0 +msgid "Postcode should be 7 digits." +msgstr "" + +#. module: l10n_jp_partner_zip_address +#: model:ir.model,name:l10n_jp_partner_zip_address.model_zip_search_mixin +msgid "ZIP Search Mixin" +msgstr "" diff --git a/l10n_jp_partner_zip_address/models/__init__.py b/l10n_jp_partner_zip_address/models/__init__.py new file mode 100644 index 00000000..d73c1dbe --- /dev/null +++ b/l10n_jp_partner_zip_address/models/__init__.py @@ -0,0 +1,2 @@ +from . import zip_search_mixin +from . import res_partner diff --git a/l10n_jp_partner_zip_address/models/res_partner.py b/l10n_jp_partner_zip_address/models/res_partner.py new file mode 100644 index 00000000..c8cd5dfa --- /dev/null +++ b/l10n_jp_partner_zip_address/models/res_partner.py @@ -0,0 +1,9 @@ +# Copyright 2024 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class ResPartner(models.Model): + _name = "res.partner" + _inherit = ["res.partner", "zip.search.mixin"] diff --git a/l10n_jp_partner_zip_address/models/zip_search_mixin.py b/l10n_jp_partner_zip_address/models/zip_search_mixin.py new file mode 100644 index 00000000..2f86bede --- /dev/null +++ b/l10n_jp_partner_zip_address/models/zip_search_mixin.py @@ -0,0 +1,70 @@ +# Copyright 2024 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +import requests + +from odoo import _, api, models +from odoo.exceptions import UserError + +try: + import jaconv +except (OSError, ImportError) as err: + logging.getLogger(__name__).warning(err) + + +class ZipSearchMixin(models.AbstractModel): + _name = "zip.search.mixin" + _description = "ZIP Search Mixin" + + def sanitize_zip(self, zipcode): + field = jaconv.z2h(zipcode, ascii=True, digit=True).replace("-", "") + if not field.isdigit(): + raise UserError(_("Only digits are allowed.")) + elif len(field) != 7: + field = False + raise UserError(_("Postcode should be 7 digits.")) + return field + + def _make_zip_request(self, request_url): + try: + response = requests.get(request_url, timeout=10) + response.raise_for_status() # Raise HTTPError for bad responses + return response.json() + except requests.exceptions.HTTPError as http_err: + return {"status": response.status_code, "message": str(http_err)} + except requests.exceptions.RequestException as req_err: + return {"status": 500, "message": f"Request error: {str(req_err)}"} + + @api.onchange("zip") + def _onchange_zip(self): + japan = self.env.ref("base.jp") + if (self.country_id and self.country_id != japan) or not self.zip: + return + self.zip = self.sanitize_zip(self.zip) + request_url = f"http://zipcloud.ibsnet.co.jp/api/search?zipcode={self.zip}" + response_data = self._make_zip_request(request_url) + if response_data["status"] != 200: + raise UserError(response_data["message"]) + self.state_id = False + self.city = False + self.street = False + address_data = response_data["results"] + if address_data: + self.state_id = self.env["res.country.state"].search( + [("name", "=", address_data[0]["address1"])], limit=1 + ) + if ( + not self.state_id + and self.env.lang != "ja_JP" + and "ja_JP" in self.env["res.lang"].get_installed() + ): + self.state_id = ( + self.env["res.country.state"] + .with_context(lang="ja_JP") + .search([("name", "=", address_data[0]["address1"])], limit=1) + ) + self.city = address_data[0]["address2"] + self.street = address_data[0]["address3"] + self.country_id = japan diff --git a/l10n_jp_partner_zip_address/pyproject.toml b/l10n_jp_partner_zip_address/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/l10n_jp_partner_zip_address/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/l10n_jp_partner_zip_address/readme/DESCRIPTION.md b/l10n_jp_partner_zip_address/readme/DESCRIPTION.md new file mode 100644 index 00000000..9241ea50 --- /dev/null +++ b/l10n_jp_partner_zip_address/readme/DESCRIPTION.md @@ -0,0 +1,12 @@ +This module introduces a function that automatically retrieves and fills +in the Japanese address details for a partner using the zipcloud +service, provided that the following conditions are met. + +- Country is Japan or no country is set for the partner. +- A valid postcode is entered for the partner. + +Note that in order to have the prefecture proposed automatically, you +need to have the prefecture records in Japanese (e.g. "福岡県" instead +of "Fukuoka"). This can be done by overriding the name of correspoinding +res.country.state records, or by installing the l10n_jp_country_state +module. diff --git a/l10n_jp_partner_zip_address/static/description/icon.png b/l10n_jp_partner_zip_address/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/l10n_jp_partner_zip_address/static/description/icon.png differ diff --git a/l10n_jp_partner_zip_address/static/description/index.html b/l10n_jp_partner_zip_address/static/description/index.html new file mode 100644 index 00000000..3e42cc2a --- /dev/null +++ b/l10n_jp_partner_zip_address/static/description/index.html @@ -0,0 +1,424 @@ + + + + + +Japan Partner Zip Address + + + +
+

Japan Partner Zip Address

+ + +

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

+

This module introduces a function that automatically retrieves and fills +in the Japanese address details for a partner using the zipcloud +service, provided that the following conditions are met.

+
    +
  • Country is Japan or no country is set for the partner.
  • +
  • A valid postcode is entered for the partner.
  • +
+

Note that in order to have the prefecture proposed automatically, you +need to have the prefecture records in Japanese (e.g. “福岡県” instead +of “Fukuoka”). This can be done by overriding the name of correspoinding +res.country.state records, or by installing the l10n_jp_country_state +module.

+

Table of contents

+ +
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile
  • +
+
+
+

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-japan project on GitHub.

+

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

+
+
+
+ + diff --git a/l10n_jp_partner_zip_address/tests/__init__.py b/l10n_jp_partner_zip_address/tests/__init__.py new file mode 100644 index 00000000..2b0ff422 --- /dev/null +++ b/l10n_jp_partner_zip_address/tests/__init__.py @@ -0,0 +1 @@ +from . import test_jp_partner_zip_address diff --git a/l10n_jp_partner_zip_address/tests/test_jp_partner_zip_address.py b/l10n_jp_partner_zip_address/tests/test_jp_partner_zip_address.py new file mode 100644 index 00000000..212695bd --- /dev/null +++ b/l10n_jp_partner_zip_address/tests/test_jp_partner_zip_address.py @@ -0,0 +1,68 @@ +# Copyright 2024 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from requests import PreparedRequest, Session + +from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase, _super_send + + +class TestResPartner(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + + @classmethod + def _request_handler(cls, s: Session, r: PreparedRequest, /, **kw): + if r.url.startswith("http://zipcloud.ibsnet.co.jp"): + return _super_send(s, r, **kw) + return super()._request_handler(s, r, **kw) + + def test_onchange_zip_valid(self): + """Test _onchange_zip with a valid zip code.""" + # When country is Japan -> address should be updated + self.partner.country_id = self.env.ref("base.jp").id + self.partner.zip = "810-0041" + self.partner._onchange_zip() + self.assertTrue( + self.partner.city, "City should be updated with a valid zip code." + ) + self.assertTrue( + self.partner.street, "Street should be updated with a valid zip code." + ) + # When no country is set -> address should be updated + self.partner.country_id = False + self.partner.zip = "540-0002" + self.partner._onchange_zip() + self.assertTrue( + self.partner.city, "City should be updated with a valid zip code." + ) + self.assertTrue( + self.partner.street, "Stree should be updated with a valid zip code." + ) + self.assertTrue( + self.partner.country_id, "Country should be updated with a valid zip code." + ) + + def test_onchange_zip_another_country(self): + # When country is US -> address should NOT be updated + self.partner.country_id = self.env.ref("base.us").id + self.partner.zip = "810-0041" + self.partner._onchange_zip() + self.assertFalse(self.partner.city) + self.assertFalse(self.partner.street) + + def test_onchange_zip_invalid(self): + """Test _onchange_zip with an invalid zip code.""" + self.partner.zip = "999-9999" + self.partner._onchange_zip() + self.assertFalse(self.partner.city) + self.assertFalse(self.partner.street) + self.assertFalse(self.partner.country_id) + self.partner.zip = "11111" + with self.assertRaises(UserError): + self.partner._onchange_zip() + self.partner.zip = "test" + with self.assertRaises(UserError): + self.partner._onchange_zip() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..71191ac6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +jaconv