diff --git a/edi_account_invoice_import/README.rst b/edi_account_invoice_import/README.rst new file mode 100644 index 000000000..6785b064d --- /dev/null +++ b/edi_account_invoice_import/README.rst @@ -0,0 +1,102 @@ +========================== +EDI Account Invoice Import +========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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%2Fedi-lightgray.png?logo=github + :target: https://github.com/OCA/edi/tree/14.0/edi_account_invoice_import + :alt: OCA/edi +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/edi-14-0/edi-14-0-edi_account_invoice_import + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/226/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Plug account_invoice_import into EDI machinery. + + +Control invoice confirmation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can decide if the invoice should be posted by exchange type. + +On your exchange type, go to advanced settings and add the following:: + + [...] + components: + process: + usage: input.process.account.invoice + [...] + account_invoice: + post_invoice: true + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Lois Rilo + +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. + +.. |maintainer-LoisRForgeFlow| image:: https://github.com/LoisRForgeFlow.png?size=40px + :target: https://github.com/LoisRForgeFlow + :alt: LoisRForgeFlow + +Current `maintainer `__: + +|maintainer-LoisRForgeFlow| + +This module is part of the `OCA/edi `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/edi_account_invoice_import/__init__.py b/edi_account_invoice_import/__init__.py new file mode 100644 index 000000000..1377f57f5 --- /dev/null +++ b/edi_account_invoice_import/__init__.py @@ -0,0 +1 @@ +from . import components diff --git a/edi_account_invoice_import/__manifest__.py b/edi_account_invoice_import/__manifest__.py new file mode 100644 index 000000000..8b026312e --- /dev/null +++ b/edi_account_invoice_import/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2022 ForgeFlow S.L. (https://www.forgeflow.com) +# @author: Lois Rilo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "EDI Account Invoice Import", + "summary": """Plug account_invoice_import into EDI machinery.""", + "version": "16.0.1.1.0", + "development_status": "Alpha", + "license": "AGPL-3", + "website": "https://github.com/OCA/edi-framework", + "author": "ForgeFlow,Odoo Community Association (OCA)", + "maintainers": ["LoisRForgeFlow"], + "depends": ["edi_oca", "account_invoice_import"], + "auto_install": True, + "data": ["templates/exchange_chatter_msg.xml"], +} diff --git a/edi_account_invoice_import/components/__init__.py b/edi_account_invoice_import/components/__init__.py new file mode 100644 index 000000000..bfb4ceb84 --- /dev/null +++ b/edi_account_invoice_import/components/__init__.py @@ -0,0 +1 @@ +from . import process diff --git a/edi_account_invoice_import/components/process.py b/edi_account_invoice_import/components/process.py new file mode 100644 index 000000000..50e4b05ef --- /dev/null +++ b/edi_account_invoice_import/components/process.py @@ -0,0 +1,67 @@ +# Copyright 2022 ForgeFlow S.L. (https://www.forgeflow.com) +# @author: Lois Rilo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import _ +from odoo.exceptions import UserError + +from odoo.addons.component.core import Component + + +class EDIExchangeSOInput(Component): + """Process Invoices (journal entries).""" + + _name = "edi.input.account.invoice.process" + _inherit = "edi.component.input.mixin" + _usage = "input.process.account.invoice" + + def __init__(self, work_context): + super().__init__(work_context) + self.settings = self.type_settings.get("account_invoice_import", {}) + + def process(self): + wiz = self._setup_wizard() + res = wiz.import_invoice() + if wiz.state == "update" and wiz.invoice_id: + invoice = wiz.invoice_id + msg = _("Invoice has already been imported before") + self._handle_existing_invoice(invoice, msg) + raise UserError(msg) + else: + invoice_id = res["res_id"] + invoice = self.env["account.move"].browse(invoice_id) + if self._invoice_should_be_posted(): + invoice.action_post() + self.exchange_record.sudo()._set_related_record(invoice) + return _("Invoice %s created") % invoice.name + raise UserError(_("Something went wrong with the importing wizard.")) + + def _setup_wizard(self): + """Init a `account.invoice.import` instance for current record.""" + ctx = self.settings.get("wiz_ctx", {}) + wiz = self.env["account.invoice.import"].with_context(**ctx).sudo().create({}) + wiz.invoice_file = self.exchange_record._get_file_content(binary=False) + wiz.invoice_filename = self.exchange_record.exchange_filename + return wiz + + def _invoice_should_be_posted(self): + return self.settings.get("post_invoice", False) + + def _handle_existing_invoice(self, invoice, message): + prev_record = self._get_previous_record(invoice) + self.exchange_record.message_post_with_view( + "edi_account_invoice_import.message_already_imported", + values={ + "invoice": invoice, + "prev_record": prev_record, + "message": message, + "level": "info", + }, + subtype_id=self.env.ref("mail.mt_note").id, + ) + + def _get_previous_record(self, invoice): + return self.env["edi.exchange.record"].search( + [("model", "=", "account.move"), ("res_id", "=", invoice.id)], limit=1 + ) diff --git a/edi_account_invoice_import/i18n/edi_account_invoice_import.pot b/edi_account_invoice_import/i18n/edi_account_invoice_import.pot new file mode 100644 index 000000000..3aeebfd2f --- /dev/null +++ b/edi_account_invoice_import/i18n/edi_account_invoice_import.pot @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * edi_account_invoice_import +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.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: edi_account_invoice_import +#: model_terms:ir.ui.view,arch_db:edi_account_invoice_import.message_already_imported +msgid "Invoice:" +msgstr "" + +#. module: edi_account_invoice_import +#: model_terms:ir.ui.view,arch_db:edi_account_invoice_import.message_already_imported +msgid "Message:" +msgstr "" + +#. module: edi_account_invoice_import +#: model_terms:ir.ui.view,arch_db:edi_account_invoice_import.message_already_imported +msgid "Previous record:" +msgstr "" + +#. module: edi_account_invoice_import +#: code:addons/edi_account_invoice_import/components/process.py:0 +#, python-format +msgid "Invoice %s created" +msgstr "" + +#. module: edi_account_invoice_import +#: code:addons/edi_account_invoice_import/components/process.py:0 +#, python-format +msgid "Invoice has already been imported before" +msgstr "" + +#. module: edi_account_invoice_import +#: code:addons/edi_account_invoice_import/components/process.py:0 +#, python-format +msgid "Something went wrong with the importing wizard." +msgstr "" diff --git a/edi_account_invoice_import/readme/CONTRIBUTORS.rst b/edi_account_invoice_import/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..77dfbe89e --- /dev/null +++ b/edi_account_invoice_import/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Lois Rilo diff --git a/edi_account_invoice_import/readme/DESCRIPTION.rst b/edi_account_invoice_import/readme/DESCRIPTION.rst new file mode 100644 index 000000000..15f04c197 --- /dev/null +++ b/edi_account_invoice_import/readme/DESCRIPTION.rst @@ -0,0 +1,17 @@ +Plug account_invoice_import into EDI machinery. + + +Control invoice confirmation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can decide if the invoice should be posted by exchange type. + +On your exchange type, go to advanced settings and add the following:: + + [...] + components: + process: + usage: input.process.account.invoice + [...] + account_invoice: + post_invoice: true diff --git a/edi_account_invoice_import/static/description/icon.png b/edi_account_invoice_import/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/edi_account_invoice_import/static/description/icon.png differ diff --git a/edi_account_invoice_import/static/description/index.html b/edi_account_invoice_import/static/description/index.html new file mode 100644 index 000000000..b4bd360a4 --- /dev/null +++ b/edi_account_invoice_import/static/description/index.html @@ -0,0 +1,436 @@ + + + + + + +EDI Account Invoice Import + + + +
+

EDI Account Invoice Import

+ + +

Alpha License: AGPL-3 OCA/edi Translate me on Weblate Try me on Runbot

+

Plug account_invoice_import into EDI machinery.

+
+

Control invoice confirmation

+

You can decide if the invoice should be posted by exchange type.

+

On your exchange type, go to advanced settings and add the following:

+
+[...]
+components:
+    process:
+        usage: input.process.account.invoice
+[...]
+account_invoice:
+    post_invoice: true
+
+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

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

+

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

+
+ +
+
+

Authors

+
    +
  • ForgeFlow
  • +
+
+
+

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.

+

Current maintainer:

+

LoisRForgeFlow

+

This module is part of the OCA/edi project on GitHub.

+

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

+
+
+ + diff --git a/edi_account_invoice_import/templates/exchange_chatter_msg.xml b/edi_account_invoice_import/templates/exchange_chatter_msg.xml new file mode 100644 index 000000000..f1b1a9472 --- /dev/null +++ b/edi_account_invoice_import/templates/exchange_chatter_msg.xml @@ -0,0 +1,37 @@ + + + + diff --git a/edi_account_invoice_import/tests/__init__.py b/edi_account_invoice_import/tests/__init__.py new file mode 100644 index 000000000..c2bb451dd --- /dev/null +++ b/edi_account_invoice_import/tests/__init__.py @@ -0,0 +1 @@ +from . import test_process diff --git a/edi_account_invoice_import/tests/test_process.py b/edi_account_invoice_import/tests/test_process.py new file mode 100644 index 000000000..3d6d461d8 --- /dev/null +++ b/edi_account_invoice_import/tests/test_process.py @@ -0,0 +1,117 @@ +# Copyright 2022 ForgeFlow S.L. (https://www.forgeflow.com) +# @author: Lois Rilo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import textwrap + +import mock + +from odoo import exceptions + +from odoo.addons.component.tests.common import TransactionComponentCase +from odoo.addons.edi_oca.tests.common import EDIBackendTestMixin + + +class TestProcessComponent(TransactionComponentCase, EDIBackendTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.backend = cls._get_backend() + cls.exc_type = cls._create_exchange_type( + name="Test SO import", + code="test_so_import", + direction="input", + exchange_file_ext="xml", + exchange_filename_pattern="{record.identifier}-{type.code}-{dt}", + backend_id=cls.backend.id, + advanced_settings_edit=textwrap.dedent( + """ + components: + process: + usage: input.process.account.invoice + account_invoice_import: + wiz_ctx: + random_key: custom + """ + ), + ) + cls.record = cls.backend.create_record("test_so_import", {}) + cls.record._set_file_content(b"") + cls.wiz_model = cls.env["account.invoice.import"] + + def test_lookup(self): + comp = self.backend._get_component(self.record, "process") + self.assertEqual(comp._name, "edi.input.account.invoice.process") + + def test_wizard_setup(self): + comp = self.backend._get_component(self.record, "process") + wiz = comp._setup_wizard() + self.assertEqual(wiz._name, self.wiz_model._name) + self.assertEqual(wiz.env.context["random_key"], "custom") + self.assertEqual( + base64.b64decode(wiz.invoice_file), b"" + ) + self.assertEqual(wiz.invoice_filename, self.record.exchange_filename) + + def test_settings(self): + self.exc_type.advanced_settings_edit = textwrap.dedent( + """ + components: + process: + usage: input.process.account.invoice + account_invoice_import: + post_invoice: true + """ + ) + comp = self.backend._get_component(self.record, "process") + self.assertTrue(comp._invoice_should_be_posted()) + + def test_existing_invoice(self): + invoice = self.env["account.move"].create( + {"partner_id": self.env["res.partner"].search([], limit=1).id} + ) + comp = self.backend._get_component(self.record, "process") + m1 = mock.patch.object(type(self.wiz_model), "import_invoice") + m2 = mock.patch.object( + type(self.wiz_model), + "invoice_id", + new_callable=mock.PropertyMock, + ) + m3 = mock.patch.object( + type(self.wiz_model), + "state", + new_callable=mock.PropertyMock, + ) + rec_msgs = self.record.message_ids + # Simulate the wizard detected an existing invoice state + with m1 as md_btn, m2 as md_inv_id, m3 as md_state: + md_inv_id.return_value = invoice + md_state.return_value = "update" + with self.assertRaisesRegex( + exceptions.UserError, "Invoice has already been imported before" + ): + comp.process() + md_btn.assert_called() + new_msg = self.record.message_ids - rec_msgs + self.assertIn("Invoice has already been imported before", new_msg.body) + self.assertIn( + f"/web#id={invoice.id}&model=account.move&view_type=form", + new_msg.body, + ) + + def test_new_invoice(self): + invoice = self.env["account.move"].create( + {"partner_id": self.env["res.partner"].search([], limit=1).id} + ) + comp = self.backend._get_component(self.record, "process") + mock_1 = mock.patch.object(type(self.wiz_model), "import_invoice") + self.assertFalse(self.record.record) + # Simulate the wizard detected an existing invoice state + with mock_1 as md_btn: + md_btn.return_value = {"res_id": invoice.id} + res = comp.process() + md_btn.assert_called() + self.assertEqual(res, f"Invoice {invoice.name} created") + + self.assertEqual(self.record.record, invoice) diff --git a/setup/edi_account_invoice_import/odoo/addons/edi_account_invoice_import b/setup/edi_account_invoice_import/odoo/addons/edi_account_invoice_import new file mode 120000 index 000000000..488fc2715 --- /dev/null +++ b/setup/edi_account_invoice_import/odoo/addons/edi_account_invoice_import @@ -0,0 +1 @@ +../../../../edi_account_invoice_import \ No newline at end of file diff --git a/setup/edi_account_invoice_import/setup.py b/setup/edi_account_invoice_import/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/edi_account_invoice_import/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 6d6292ce5..f224267ad 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,5 @@ odoo_test_helper xmlunittest +mock + +odoo-addon-account_invoice_import @ git+https://github.com/OCA/edi.git@refs/pull/753/head#subdirectory=setup/account_invoice_import