diff --git a/l10n_mx_res_partner_csf/README.rst b/l10n_mx_res_partner_csf/README.rst new file mode 100644 index 0000000..be7feaf --- /dev/null +++ b/l10n_mx_res_partner_csf/README.rst @@ -0,0 +1,95 @@ +====================== +Contact CSF for Mexico +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:218019f2862d69bc3801e33c068ccfece5081fb367b2c248c6134113d324ea56 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--mexico-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-mexico/tree/17.0/l10n_mx_res_partner_csf + :alt: OCA/l10n-mexico +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-mexico-17-0/l10n-mexico-17-0-l10n_mx_res_partner_csf + :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-mexico&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to upload the proof of tax situation (Constancia +de situacion fiscal) from the Mexican Tax Authority (SAT) and update the +information of a partner. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Go to Contacts +- Click on "Create" +- Click on "Upload CSF" +- Select the pdf document and click "Upload" + +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 +------- + +* Open Source Integrators + +Contributors +------------ + +- `Open Source Integrators `__: + + - Maxime Chambreuil + - Murtaza Mithaiwala + - Samuel Macias + +Other credits +------------- + +- Open Source Integrators + +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-mexico `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_mx_res_partner_csf/__init__.py b/l10n_mx_res_partner_csf/__init__.py new file mode 100644 index 0000000..64acdf9 --- /dev/null +++ b/l10n_mx_res_partner_csf/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2023 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import models +from . import wizard diff --git a/l10n_mx_res_partner_csf/__manifest__.py b/l10n_mx_res_partner_csf/__manifest__.py new file mode 100644 index 0000000..356099a --- /dev/null +++ b/l10n_mx_res_partner_csf/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright (C) 2023 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Contact CSF for Mexico", + "summary": "Scan and extract information from CSF", + "version": "17.0.1.0.0", + "license": "AGPL-3", + "website": "https://github.com/OCA/l10n-mexico", + "author": "Open Source Integrators, " "Odoo Community Association (OCA)", + "category": "Localization", + "depends": ["contacts"], + "data": [ + "security/ir.model.access.csv", + "wizard/import_csf.xml", + "views/res_partner_view.xml", + ], + "external_dependencies": { + "python": ["pdfminer.six==20220319"], + }, +} diff --git a/l10n_mx_res_partner_csf/i18n/l10n_mx_res_partner_csf.pot b/l10n_mx_res_partner_csf/i18n/l10n_mx_res_partner_csf.pot new file mode 100644 index 0000000..708f25c --- /dev/null +++ b/l10n_mx_res_partner_csf/i18n/l10n_mx_res_partner_csf.pot @@ -0,0 +1,98 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_mx_res_partner_csf +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.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_mx_res_partner_csf +#: model_terms:ir.ui.view,arch_db:l10n_mx_res_partner_csf.import_csf +msgid "Cancel" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model,name:l10n_mx_res_partner_csf.model_res_partner +msgid "Contact" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__create_uid +msgid "Created by" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__create_date +msgid "Created on" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__display_name +msgid "Display Name" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__file +msgid "File" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__file_name +msgid "File Name" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__id +msgid "ID" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#. odoo-python +#: code:addons/l10n_mx_res_partner_csf/models/res_partner.py:0 +#, python-format +msgid "Import CSF File" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf____last_update +msgid "Last Modified on" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model.fields,field_description:l10n_mx_res_partner_csf.field_import_csf__write_date +msgid "Last Updated on" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model_terms:ir.ui.view,arch_db:l10n_mx_res_partner_csf.view_partner_form_inherit_cfs +msgid "Subir CSF" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model_terms:ir.ui.view,arch_db:l10n_mx_res_partner_csf.import_csf +msgid "Upload" +msgstr "" + +#. module: l10n_mx_res_partner_csf +#. odoo-python +#: code:addons/l10n_mx_res_partner_csf/wizard/import_csf.py:0 +#, python-format +msgid "Uploaded file is not in PDF format (%s)." +msgstr "" + +#. module: l10n_mx_res_partner_csf +#: model:ir.model,name:l10n_mx_res_partner_csf.model_import_csf +msgid "import.csf" +msgstr "" diff --git a/l10n_mx_res_partner_csf/models/__init__.py b/l10n_mx_res_partner_csf/models/__init__.py new file mode 100644 index 0000000..04fac8e --- /dev/null +++ b/l10n_mx_res_partner_csf/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2019 Wissen MX +# Copyright (C) 2020 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import res_partner diff --git a/l10n_mx_res_partner_csf/models/res_partner.py b/l10n_mx_res_partner_csf/models/res_partner.py new file mode 100644 index 0000000..1a72fff --- /dev/null +++ b/l10n_mx_res_partner_csf/models/res_partner.py @@ -0,0 +1,16 @@ +# Copyright (C) 2023 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import _, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + def action_upload_csf(self): + return { + "name": _("Import CSF File"), + "type": "ir.actions.act_window", + "view_mode": "form", + "res_model": "import.csf", + "target": "new", + } diff --git a/l10n_mx_res_partner_csf/pyproject.toml b/l10n_mx_res_partner_csf/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/l10n_mx_res_partner_csf/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/l10n_mx_res_partner_csf/readme/CONTRIBUTORS.md b/l10n_mx_res_partner_csf/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..8a998d1 --- /dev/null +++ b/l10n_mx_res_partner_csf/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [Open Source Integrators](https://www.opensourceintegrators.com): + - Maxime Chambreuil \<\> + - Murtaza Mithaiwala \<\> + - Samuel Macias \<\> diff --git a/l10n_mx_res_partner_csf/readme/CREDITS.md b/l10n_mx_res_partner_csf/readme/CREDITS.md new file mode 100644 index 0000000..705e63b --- /dev/null +++ b/l10n_mx_res_partner_csf/readme/CREDITS.md @@ -0,0 +1 @@ +- Open Source Integrators diff --git a/l10n_mx_res_partner_csf/readme/DESCRIPTION.md b/l10n_mx_res_partner_csf/readme/DESCRIPTION.md new file mode 100644 index 0000000..dcff7ad --- /dev/null +++ b/l10n_mx_res_partner_csf/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module allows you to upload the proof of tax situation (Constancia +de situacion fiscal) from the Mexican Tax Authority (SAT) and update the +information of a partner. diff --git a/l10n_mx_res_partner_csf/readme/INSTALLATION.rst b/l10n_mx_res_partner_csf/readme/INSTALLATION.rst new file mode 100644 index 0000000..99a10e3 --- /dev/null +++ b/l10n_mx_res_partner_csf/readme/INSTALLATION.rst @@ -0,0 +1,7 @@ +This module requires the unaccent extension of PostgreSQL: + +.. code-block:: sql + + create extension "unaccent" ; + +and `unaccent=True` in Odoo configuration file. diff --git a/l10n_mx_res_partner_csf/readme/USAGE.md b/l10n_mx_res_partner_csf/readme/USAGE.md new file mode 100644 index 0000000..016cb2b --- /dev/null +++ b/l10n_mx_res_partner_csf/readme/USAGE.md @@ -0,0 +1,4 @@ +- Go to Contacts +- Click on "Create" +- Click on "Upload CSF" +- Select the pdf document and click "Upload" diff --git a/l10n_mx_res_partner_csf/security/ir.model.access.csv b/l10n_mx_res_partner_csf/security/ir.model.access.csv new file mode 100644 index 0000000..11a45fb --- /dev/null +++ b/l10n_mx_res_partner_csf/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_import_csf,import_csf,model_import_csf,,1,1,1,1 diff --git a/l10n_mx_res_partner_csf/static/description/icon.png b/l10n_mx_res_partner_csf/static/description/icon.png new file mode 100644 index 0000000..3a0328b Binary files /dev/null and b/l10n_mx_res_partner_csf/static/description/icon.png differ diff --git a/l10n_mx_res_partner_csf/static/description/index.html b/l10n_mx_res_partner_csf/static/description/index.html new file mode 100644 index 0000000..0a850cb --- /dev/null +++ b/l10n_mx_res_partner_csf/static/description/index.html @@ -0,0 +1,445 @@ + + + + + + +Contact CSF for Mexico + + + +
+

Contact CSF for Mexico

+ + +

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

+

This module allows you to upload the proof of tax situation (Constancia +de situacion fiscal) from the Mexican Tax Authority (SAT) and update the +information of a partner.

+

Table of contents

+ +
+

Usage

+
    +
  • Go to Contacts
  • +
  • Click on “Create”
  • +
  • Click on “Upload CSF”
  • +
  • Select the pdf document and click “Upload”
  • +
+
+
+

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

+
    +
  • Open Source Integrators
  • +
+
+ +
+

Other credits

+
    +
  • Open Source Integrators
  • +
+
+
+

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

+

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

+
+
+
+ + diff --git a/l10n_mx_res_partner_csf/tests/__init__.py b/l10n_mx_res_partner_csf/tests/__init__.py new file mode 100644 index 0000000..0e76298 --- /dev/null +++ b/l10n_mx_res_partner_csf/tests/__init__.py @@ -0,0 +1,3 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_contact diff --git a/l10n_mx_res_partner_csf/tests/demo.pdf b/l10n_mx_res_partner_csf/tests/demo.pdf new file mode 100644 index 0000000..ad0a072 Binary files /dev/null and b/l10n_mx_res_partner_csf/tests/demo.pdf differ diff --git a/l10n_mx_res_partner_csf/tests/test_contact.py b/l10n_mx_res_partner_csf/tests/test_contact.py new file mode 100644 index 0000000..80c78d5 --- /dev/null +++ b/l10n_mx_res_partner_csf/tests/test_contact.py @@ -0,0 +1,49 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import base64 +import os + +from odoo import tools +from odoo.exceptions import UserError +from odoo.tests import TransactionCase + + +class TestContact(TransactionCase): + def setUp(self): + super().setUp() + self.country_id = self.env.ref("base.mx") + self.import_obj = self.env["import.csf"] + self.partner = self.env["res.partner"].create( + { + "name": "Demo", + } + ) + + def test_import_csf_pdf_file(self): + generated_file = os.path.join("l10n_mx_res_partner_csf", "tests", "demo.pdf") + generated_file = tools.misc.file_open(generated_file, "rb") + data = base64.encodebytes(generated_file.read()) + + record1 = self.import_obj.with_context(active_id=self.partner.id).create( + {"file": data, "file_name": "demo.pdf"} + ) + + record1.upload_csf() + + self.assertEqual("OSI220401JP1", self.partner.vat) + self.assertEqual("OPEN SOURCE INTEGRATORS", self.partner.name) + self.assertEqual("76100", self.partner.zip) + self.assertEqual("AVENIDA (AV.) ANTEA 1032", self.partner.street) + self.assertEqual(" JURICA", self.partner.street2) + self.assertEqual("QUERETARO", self.partner.city) + self.assertEqual(self.country_id.id, self.partner.country_id.id) + + def test_import_csf_txt_file(self): + action = self.partner.action_upload_csf() + record_csf = ( + self.env[action.get("res_model")] + .with_context(active_id=self.partner.id) + .create({"file": "fake_data", "file_name": "demo.txt"}) + ) + with self.assertRaises(UserError): + record_csf.upload_csf() diff --git a/l10n_mx_res_partner_csf/views/res_partner_view.xml b/l10n_mx_res_partner_csf/views/res_partner_view.xml new file mode 100644 index 0000000..1fa45dd --- /dev/null +++ b/l10n_mx_res_partner_csf/views/res_partner_view.xml @@ -0,0 +1,19 @@ + + + res.partner.form.inherit + + res.partner + + +
+
+
+
+
+
diff --git a/l10n_mx_res_partner_csf/wizard/__init__.py b/l10n_mx_res_partner_csf/wizard/__init__.py new file mode 100644 index 0000000..1a0fdb0 --- /dev/null +++ b/l10n_mx_res_partner_csf/wizard/__init__.py @@ -0,0 +1 @@ +from . import import_csf diff --git a/l10n_mx_res_partner_csf/wizard/import_csf.py b/l10n_mx_res_partner_csf/wizard/import_csf.py new file mode 100644 index 0000000..d17921a --- /dev/null +++ b/l10n_mx_res_partner_csf/wizard/import_csf.py @@ -0,0 +1,91 @@ +import base64 +import logging +import tempfile + +from odoo import _, fields, models +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + +try: + from pdfminer.high_level import extract_text +except ImportError as err: + _logger.debug(err) + + +class ImportCSF(models.TransientModel): + _name = "import.csf" + + file = fields.Binary(required=True, attachment=True) + file_name = fields.Char() + + def attach_csf(self): + self.env["ir.attachment"].create( + { + "name": self.file_name, + "datas": self.file, + "res_model": "res.partner", + "res_id": self._context.get("active_id"), + } + ) + + def upload_csf(self): + partner_obj = self.env["res.partner"] + temp_path = tempfile.gettempdir() + file_data = base64.decodebytes(self.file) + fp = open(temp_path + "/csf.pdf", "wb+") + fp.write(file_data) + fp.close() + try: + text = extract_text(temp_path + "/csf.pdf") + except Exception as e: + raise UserError(_("Uploaded file is not in PDF format (%s).") % e) from e + vals = self.prepare_res_partner_values(text) + partner_obj.browse(self._context.get("active_id")).write(vals) + self.attach_csf() + + def prepare_res_partner_values(self, text): + state_obj = self.env["res.country.state"] + split_data = text.split("\n") + vat = name = zip = city = street = street2 = state = "" + for index, line in enumerate(split_data): + if "CÉDULA DE IDENTIFICACIÓN FISCAL" in line: + vat += split_data[index + 2].strip() + elif "Registro Federal de Contribuyentes" in line: + name += split_data[index + 2].strip() + if split_data[index + 3] == "": + name += " " + split_data[index + 4].strip() + elif split_data[index + 3].isupper(): + name += " " + split_data[index + 3].strip() + elif "Código Postal" in line: + zip += line.split(":")[-1].strip() + elif "Tipo de Vialidad" in line: + street += line.split("Tipo de Vialidad:")[-1].strip() + " " + elif "Nombre de Vialidad" in line: + street += line.split("Nombre de Vialidad:")[-1].strip() + " " + elif "Número Exterior" in line: + street += line.split("Número Exterior:")[-1].strip() + elif "Número Interior" in line: + street2 += line.split("Número Interior:")[-1].strip() + " " + elif "Nombre de la Colonia" in line: + street2 += line.split("Nombre de la Colonia:")[-1].strip() + elif "Nombre del Municipio o Demarcación Territorial" in line: + city += line.split(":")[-1].strip() + elif "Nombre de la Entidad Federativa" in line: + state = line.split("Nombre de la Entidad Federativa:")[-1].strip() + + country_id = self.env.ref("base.mx") + state_id = state_obj.search( + [("country_id", "=", country_id.id), ("name", "ilike", state)], limit=1 + ) + + return { + "vat": vat, + "name": name, + "zip": zip, + "city": city, + "street": street, + "street2": street2, + "state_id": state_id.id or False, + "country_id": country_id.id, + } diff --git a/l10n_mx_res_partner_csf/wizard/import_csf.xml b/l10n_mx_res_partner_csf/wizard/import_csf.xml new file mode 100644 index 0000000..a633fe7 --- /dev/null +++ b/l10n_mx_res_partner_csf/wizard/import_csf.xml @@ -0,0 +1,34 @@ + + + + iimport.csf + import.csf + +
+ + + + + + + +
+
+
+
diff --git a/pandoc-3.1.9-1-amd64.deb b/pandoc-3.1.9-1-amd64.deb new file mode 100644 index 0000000..77ae8bb Binary files /dev/null and b/pandoc-3.1.9-1-amd64.deb differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..95a6776 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +pdfminer.six==20220319