diff --git a/edi_purchase_ubl_output_oca/README.rst b/edi_purchase_ubl_output_oca/README.rst new file mode 100644 index 000000000..022885c57 --- /dev/null +++ b/edi_purchase_ubl_output_oca/README.rst @@ -0,0 +1,97 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================ +EDI UBL Purchase +================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:64740d2084509ea5c625aeb34e7e20f2a11ffa3a8e3cb2e13c107092a4b438b2 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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_purchase_ubl_output_oca + :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_purchase_ubl_output_oca + :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/edi&target_branch=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Handle purchase exchanges with the EDI framework. + +This module is mostly a glue module for `purchase_order_ubl` with `edi_oca`. + +Allows you to generate and send purchase orders as UBL XML files. + +.. 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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Simone Orsi + +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-simahawk| image:: https://github.com/simahawk.png?size=40px + :target: https://github.com/simahawk + :alt: simahawk + +Current `maintainer `__: + +|maintainer-simahawk| + +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_purchase_ubl_output_oca/__init__.py b/edi_purchase_ubl_output_oca/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/edi_purchase_ubl_output_oca/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/edi_purchase_ubl_output_oca/__manifest__.py b/edi_purchase_ubl_output_oca/__manifest__.py new file mode 100644 index 000000000..c9fcbbc7e --- /dev/null +++ b/edi_purchase_ubl_output_oca/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "EDI UBL Purchase", + "summary": """Handle outbound exchanges for purchases.""", + "version": "18.0.1.0.0", + "development_status": "Alpha", + "license": "AGPL-3", + "website": "https://github.com/OCA/edi-framework", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["simahawk"], + "depends": ["edi_purchase_oca", "edi_ubl_oca", "purchase_order_ubl"], + "demo": [ + "demo/edi_exchange_type.xml", + ], +} diff --git a/edi_purchase_ubl_output_oca/demo/edi_exchange_type.xml b/edi_purchase_ubl_output_oca/demo/edi_exchange_type.xml new file mode 100644 index 000000000..8d8cca6d1 --- /dev/null +++ b/edi_purchase_ubl_output_oca/demo/edi_exchange_type.xml @@ -0,0 +1,15 @@ + + + + + Demo UBL PO out + demo_UBL_PO_out + output + {record_name}-{type.code}-{dt} + xml + + + diff --git a/edi_purchase_ubl_output_oca/i18n/edi_purchase_ubl_output_oca.pot b/edi_purchase_ubl_output_oca/i18n/edi_purchase_ubl_output_oca.pot new file mode 100644 index 000000000..4d8b20f91 --- /dev/null +++ b/edi_purchase_ubl_output_oca/i18n/edi_purchase_ubl_output_oca.pot @@ -0,0 +1,13 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +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" diff --git a/edi_purchase_ubl_output_oca/i18n/it.po b/edi_purchase_ubl_output_oca/i18n/it.po new file mode 100644 index 000000000..9ce4346f6 --- /dev/null +++ b/edi_purchase_ubl_output_oca/i18n/it.po @@ -0,0 +1,14 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" diff --git a/edi_purchase_ubl_output_oca/models/__init__.py b/edi_purchase_ubl_output_oca/models/__init__.py new file mode 100644 index 000000000..f839b0d3b --- /dev/null +++ b/edi_purchase_ubl_output_oca/models/__init__.py @@ -0,0 +1 @@ +from . import generate diff --git a/edi_purchase_ubl_output_oca/models/generate.py b/edi_purchase_ubl_output_oca/models/generate.py new file mode 100644 index 000000000..8ef69669c --- /dev/null +++ b/edi_purchase_ubl_output_oca/models/generate.py @@ -0,0 +1,26 @@ +# Copyright 2021 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class EDIExchangePOGenerate(models.AbstractModel): + """Generate purchase orders.""" + + _description = "UBL output generator for purchase orders" + + _name = "edi.output.ubl.purchase.order" + _inherit = "edi.oca.handler.generate" + + def generate(self, exchange_record): + return self._generate_ubl_xml(exchange_record) + + def _generate_ubl_xml(self, exchange_record): + order = exchange_record.record + doc_type = order.get_ubl_purchase_order_doc_type() + if not doc_type: + raise NotImplementedError("TODO: handle no doc type") + version = order.get_ubl_version() + xml_string = order.generate_ubl_xml_string(doc_type, version=version) + return xml_string diff --git a/edi_purchase_ubl_output_oca/pyproject.toml b/edi_purchase_ubl_output_oca/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/edi_purchase_ubl_output_oca/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/edi_purchase_ubl_output_oca/readme/CONFIGURATION.rst b/edi_purchase_ubl_output_oca/readme/CONFIGURATION.rst new file mode 100644 index 000000000..df94d54c5 --- /dev/null +++ b/edi_purchase_ubl_output_oca/readme/CONFIGURATION.rst @@ -0,0 +1,7 @@ +On your exchange type configured for UBL outbound exchanges use this conf in `advanced_settings_edit`:: + + components: + generate: + usage: output.generate.purchase.order + +That's it. diff --git a/edi_purchase_ubl_output_oca/readme/CONTRIBUTORS.rst b/edi_purchase_ubl_output_oca/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..f1c71bce1 --- /dev/null +++ b/edi_purchase_ubl_output_oca/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Simone Orsi diff --git a/edi_purchase_ubl_output_oca/readme/DESCRIPTION.rst b/edi_purchase_ubl_output_oca/readme/DESCRIPTION.rst new file mode 100644 index 000000000..41f35c7a4 --- /dev/null +++ b/edi_purchase_ubl_output_oca/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +Handle purchase exchanges with the EDI framework. + +This module is mostly a glue module for `purchase_order_ubl` with `edi_oca`. + +Allows you to generate and send purchase orders as UBL XML files. diff --git a/edi_purchase_ubl_output_oca/static/description/icon.png b/edi_purchase_ubl_output_oca/static/description/icon.png new file mode 100644 index 000000000..1dcc49c24 Binary files /dev/null and b/edi_purchase_ubl_output_oca/static/description/icon.png differ diff --git a/edi_purchase_ubl_output_oca/static/description/index.html b/edi_purchase_ubl_output_oca/static/description/index.html new file mode 100644 index 000000000..ea1b01031 --- /dev/null +++ b/edi_purchase_ubl_output_oca/static/description/index.html @@ -0,0 +1,439 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

EDI UBL Purchase

+ +

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

+

Handle purchase exchanges with the EDI framework.

+

This module is mostly a glue module for purchase_order_ubl with edi_oca.

+

Allows you to generate and send purchase orders as UBL XML files.

+
+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+ +
+

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:

+

simahawk

+

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_purchase_ubl_output_oca/tests/__init__.py b/edi_purchase_ubl_output_oca/tests/__init__.py new file mode 100644 index 000000000..427d09a22 --- /dev/null +++ b/edi_purchase_ubl_output_oca/tests/__init__.py @@ -0,0 +1 @@ +from . import test_generate diff --git a/edi_purchase_ubl_output_oca/tests/test_generate.py b/edi_purchase_ubl_output_oca/tests/test_generate.py new file mode 100644 index 000000000..e96497eb3 --- /dev/null +++ b/edi_purchase_ubl_output_oca/tests/test_generate.py @@ -0,0 +1,98 @@ +# Copyright 2026 Camptocamp SA +# @author Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + +from odoo.addons.purchase_order_ubl.tests.common import PurchaseOrderUblMixin + + +class TestPurchaseUBLOutputGenerate(PurchaseOrderUblMixin, TransactionCase): + """Ensure ``edi.output.ubl.purchase.order`` produces a valid UBL XML file.""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, tracking_disable=True, edi__skip_quick_exec=True + ) + ) + cls._setup_purchase_ubl_records() + cls.backend_type = cls.env.ref("edi_ubl_oca.edi_backend_type_ubl") + cls.backend = cls.env["edi.backend"].create( + { + "name": "UBL purchase test backend", + "backend_type_id": cls.backend_type.id, + } + ) + generator_model = cls.env["ir.model"]._get("edi.output.ubl.purchase.order") + cls.exc_type = cls.env["edi.exchange.type"].create( + { + "name": "Test UBL PO out", + "code": "test_ubl_po_out", + "direction": "output", + "exchange_file_ext": "xml", + "exchange_filename_pattern": "{record.id}-{type.code}-{dt}", + "backend_id": cls.backend.id, + "backend_type_id": cls.backend_type.id, + "generate_model_id": generator_model.id, + } + ) + + def _create_exchange_record(self): + return self.backend.create_record( + self.exc_type.code, + {"model": self.order._name, "res_id": self.order.id}, + ) + + def _generate_xml(self, version): + record = self._create_exchange_record() + record.with_context(ubl_version=version).action_exchange_generate() + self.assertTrue(record.exchange_file) + return record._get_file_content() + + def test_generate_order_confirmed(self): + self.order.button_confirm() + self.assertEqual(self.order.state, "purchase") + for version in ("2.1", "2.2"): + with self.subTest(version=version): + xml_string = self._generate_xml(version) + self._assert_valid_ubl_xml(xml_string, "Order", version) + + def test_generate_rfq(self): + self.assertIn(self.order.state, self.order.get_rfq_states()) + for version in ("2.1", "2.2"): + with self.subTest(version=version): + xml_string = self._generate_xml(version) + self._assert_valid_ubl_xml(xml_string, "RequestForQuotation", version) + + def test_generate_skip_taxes_via_advanced_settings(self): + """``advanced_settings_edit`` must propagate ``env_ctx`` to generate. + + Setting ``ubl_add_item__skip_taxes: true`` on the ``generate`` + component env_ctx must result in no ``ClassifiedTaxCategory`` + nodes in the produced UBL XML. + """ + self.exc_type.advanced_settings_edit = ( + "components:\n" + " generate:\n" + " env_ctx:\n" + " ubl_add_item__skip_taxes: true\n" + ) + self.order.button_confirm() + xml_string = self._generate_xml("2.1") + parsed = self._assert_valid_ubl_xml(xml_string, "Order", "2.1") + tax_nodes = self._classified_tax_categories(parsed) + self.assertFalse( + tax_nodes, + "ClassifiedTaxCategory must be skipped when " + "ubl_add_item__skip_taxes is set via advanced_settings_edit", + ) + + def test_generate_taxes_included_by_default(self): + """Without any env_ctx, ClassifiedTaxCategory must be present.""" + self.order.button_confirm() + xml_string = self._generate_xml("2.1") + parsed = self._assert_valid_ubl_xml(xml_string, "Order", "2.1") + self.assertTrue(self._classified_tax_categories(parsed)) diff --git a/test-requirements.txt b/test-requirements.txt index a8133e4b5..fd9181bb0 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,6 @@ odoo-test-helper xmlunittest + +odoo-addon-edi_core_oca @ git+https://github.com/OCA/edi-framework@refs/pull/275/head#subdirectory=edi_core_oca +odoo-addon-edi_purchase_oca @ git+https://github.com/OCA/edi-framework@refs/pull/276/head#subdirectory=edi_purchase_oca +odoo-addon-purchase_order_ubl @ git+https://github.com/OCA/edi@refs/pull/1342/head#subdirectory=purchase_order_ubl