From 29f1353cdabb3604918046aa94af047b0ff2eec2 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Sun, 14 Aug 2022 09:56:21 +0200 Subject: [PATCH 01/35] Add edi_sale_ubl_oca --- edi_sale_ubl_oca/README.rst | 1 + edi_sale_ubl_oca/__init__.py | 0 edi_sale_ubl_oca/__manifest__.py | 30 ++++ edi_sale_ubl_oca/data/edi_exchange_type.xml | 63 ++++++++ .../data/exc_templ_order_response.xml | 35 +++++ edi_sale_ubl_oca/readme/CONTRIBUTORS.rst | 1 + edi_sale_ubl_oca/readme/DESCRIPTION.rst | 1 + .../templates/qweb_tmpl_order_response.xml | 121 ++++++++++++++++ .../templates/qweb_tmpl_party.xml | 37 +++++ edi_sale_ubl_oca/tests/__init__.py | 3 + edi_sale_ubl_oca/tests/common.py | 137 ++++++++++++++++++ edi_sale_ubl_oca/tests/test_order_in.py | 79 ++++++++++ .../tests/test_order_in_full_flow.py | 86 +++++++++++ .../tests/test_order_response_out.py | 66 +++++++++ 14 files changed, 660 insertions(+) create mode 100644 edi_sale_ubl_oca/README.rst create mode 100644 edi_sale_ubl_oca/__init__.py create mode 100644 edi_sale_ubl_oca/__manifest__.py create mode 100644 edi_sale_ubl_oca/data/edi_exchange_type.xml create mode 100644 edi_sale_ubl_oca/data/exc_templ_order_response.xml create mode 100644 edi_sale_ubl_oca/readme/CONTRIBUTORS.rst create mode 100644 edi_sale_ubl_oca/readme/DESCRIPTION.rst create mode 100644 edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml create mode 100644 edi_sale_ubl_oca/templates/qweb_tmpl_party.xml create mode 100644 edi_sale_ubl_oca/tests/__init__.py create mode 100644 edi_sale_ubl_oca/tests/common.py create mode 100644 edi_sale_ubl_oca/tests/test_order_in.py create mode 100644 edi_sale_ubl_oca/tests/test_order_in_full_flow.py create mode 100644 edi_sale_ubl_oca/tests/test_order_response_out.py diff --git a/edi_sale_ubl_oca/README.rst b/edi_sale_ubl_oca/README.rst new file mode 100644 index 0000000000..f8cab0d150 --- /dev/null +++ b/edi_sale_ubl_oca/README.rst @@ -0,0 +1 @@ +bot, please, take care of this! \ No newline at end of file diff --git a/edi_sale_ubl_oca/__init__.py b/edi_sale_ubl_oca/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/edi_sale_ubl_oca/__manifest__.py b/edi_sale_ubl_oca/__manifest__.py new file mode 100644 index 0000000000..9c4ba14144 --- /dev/null +++ b/edi_sale_ubl_oca/__manifest__.py @@ -0,0 +1,30 @@ +# Copyright 2022 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "EDI Sales", + "summary": """ + Configuration and special behaviors for EDI on sales. + """, + "version": "14.0.1.0.0", + "development_status": "Alpha", + "license": "AGPL-3", + "author": "Camptocamp,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/edi", + "depends": [ + "sale_order_import_ubl", + "edi_sale_oca", + "edi_ubl_oca", + "edi_xml_oca", + "edi_exchange_template_oca", + # This could be made optional + # but the delivery part would need another source of data + "sale_stock", + ], + "data": [ + "templates/qweb_tmpl_party.xml", + "templates/qweb_tmpl_order_response.xml", + "data/edi_exchange_type.xml", + "data/exc_templ_order_response.xml", + ], +} diff --git a/edi_sale_ubl_oca/data/edi_exchange_type.xml b/edi_sale_ubl_oca/data/edi_exchange_type.xml new file mode 100644 index 0000000000..e608304894 --- /dev/null +++ b/edi_sale_ubl_oca/data/edi_exchange_type.xml @@ -0,0 +1,63 @@ + + + + + + UBL Sale Order Response + UBL_SaleOrderResponse_out + output + {record_name}-{type.code}-{dt} + xml + + +components: + generate: + usage: ubl.generate.OrderResponse + validate: + usage: edi.xml + work_ctx: + schema_path: base_ubl:data/xsd-2.2/maindoc/UBL-OrderResponse-2.2.xsd + +auto: + "sale.order": + actions: + generate: + when: + - write + trigger_fields: + - state + - commitment_date + tracked_fields: + - state + - commitment_date + "sale.order.line": + actions: + generate: + when: + - write + trigger_fields: + - product_uom_qty + tracked_fields: + - product_uom_qty + target_record: order_id + + + + + + + UBL Sale Order + UBL_SaleOrder_in + input + xml + +components: + process: + usage: input.process.sale.order + + + + diff --git a/edi_sale_ubl_oca/data/exc_templ_order_response.xml b/edi_sale_ubl_oca/data/exc_templ_order_response.xml new file mode 100644 index 0000000000..c52e6ad46c --- /dev/null +++ b/edi_sale_ubl_oca/data/exc_templ_order_response.xml @@ -0,0 +1,35 @@ + + + + + UBL OrderResponse output + ubl.generate.OrderResponse + xml + + + + +seller = record.company_id.partner_id +buyer = record.partner_id + +seller_party = get_party_data(exchange_record, seller) +buyer_party = get_party_data(exchange_record, buyer) +delivery = record.picking_ids.filtered(lambda x: x.picking_type_id.code == "outgoing") + +_result = { + "seller_party": seller_party, + "buyer_party": buyer_party, + "delivery": delivery, +} + +provider = get_info_provider(exchange_record, work_ctx=_result) +if provider: + _result["info"] = provider.generate_info() + +result = _result + + + diff --git a/edi_sale_ubl_oca/readme/CONTRIBUTORS.rst b/edi_sale_ubl_oca/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..f1c71bce18 --- /dev/null +++ b/edi_sale_ubl_oca/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Simone Orsi diff --git a/edi_sale_ubl_oca/readme/DESCRIPTION.rst b/edi_sale_ubl_oca/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..1333ed77b7 --- /dev/null +++ b/edi_sale_ubl_oca/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +TODO diff --git a/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml new file mode 100644 index 0000000000..1881761d68 --- /dev/null +++ b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml @@ -0,0 +1,121 @@ + + + + + + + + + diff --git a/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml b/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml new file mode 100644 index 0000000000..5be8626059 --- /dev/null +++ b/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml @@ -0,0 +1,37 @@ + + + + + diff --git a/edi_sale_ubl_oca/tests/__init__.py b/edi_sale_ubl_oca/tests/__init__.py new file mode 100644 index 0000000000..ae2abc15ff --- /dev/null +++ b/edi_sale_ubl_oca/tests/__init__.py @@ -0,0 +1,3 @@ +from . import test_order_in +from . import test_order_response_out +from . import test_order_in_full_flow diff --git a/edi_sale_ubl_oca/tests/common.py b/edi_sale_ubl_oca/tests/common.py new file mode 100644 index 0000000000..51553a5921 --- /dev/null +++ b/edi_sale_ubl_oca/tests/common.py @@ -0,0 +1,137 @@ +# Copyright 2022 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +import os + +import xmlunittest + +from odoo import fields +from odoo.tests.common import Form, SavepointCase + +from odoo.addons.sale_order_import_ubl.tests.common import get_test_data + + +def get_xml_handler(backend, schema_path, model=None): + model = model or backend._name + return backend._find_component( + model, + ["edi.xml"], + work_ctx={"schema_path": schema_path}, + safe=False, + ) + + +def flatten(txt): + return "".join([x.strip() for x in txt.splitlines()]) + + +def dev_write_example_file(filename, content, test_file=None): + test_file = test_file or __file__ + from pathlib import Path + + path = Path(test_file).parent / ("examples/test." + filename) + with open(path, "w") as out: + out.write(content) + + +def read_test_file(filename): + path = os.path.join(os.path.dirname(__file__), "examples", filename) + with open(path, "r") as thefile: + return thefile.read() + + +# TODO: reuse common class from edi_xml_oca +class XMLBaseTestCase(SavepointCase, xmlunittest.XmlTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.backend = cls._get_backend() + + @classmethod + def _get_backend(cls): + raise NotImplementedError() + + +class OrderMixin(object): + @classmethod + def _create_sale_order(cls, values, view=None): + """Create a sale order + + :return: sale order + """ + form = Form(cls.env["sale.order"], view=view) + form.commitment_date = fields.Date.today() + for k, v in values.items(): + setattr(form, k, v) + return form.save() + + @classmethod + def _create_sale_order_line(cls, order, view=None, **kw): + """ + Create a sale order line for give order + :return: line + """ + values = {} + values.update(kw) + form = Form(order, view=view) + with form.order_line.new() as form_line: + for k, v in values.items(): + setattr(form_line, k, v) + return form.save() + + +class TestCaseBase(XMLBaseTestCase, OrderMixin): + @classmethod + def _setup_order(cls): + cls.product_a = cls.env.ref("product.product_product_4") + cls.product_a.barcode = "1" * 14 + cls.product_b = cls.env.ref("product.product_product_4b") + cls.product_b.barcode = "2" * 14 + cls.product_c = cls.env.ref("product.product_product_4c") + cls.product_c.barcode = "3" * 14 + cls.sale = cls._create_sale_order( + { + "partner_id": cls.env.ref("base.res_partner_10"), + "commitment_date": "2022-07-29", + } + ) + lines = [ + {"product_id": cls.product_a, "product_uom_qty": 300}, + {"product_id": cls.product_b, "product_uom_qty": 200}, + {"product_id": cls.product_c, "product_uom_qty": 100}, + ] + for line in lines: + cls._create_sale_order_line(cls.sale, **line) + + cls.sale.action_confirm() + + +class OrderInboundTestMixin: + @classmethod + def _setup_inbound_order(cls, backend): + cls.exc_type_in = cls.env.ref("edi_sale_ubl_oca.edi_exc_type_order_in") + cls.exc_type_out = cls.env.ref( + "edi_sale_ubl_oca.edi_exc_type_order_response_out" + ) + cls.exc_type_in.backend_id = backend + cls.exc_type_out.backend_id = backend + cls.exc_record_in = backend.create_record( + cls.exc_type_in.code, {"edi_exchange_state": "input_received"} + ) + cls.ubl_data = get_test_data(cls.env) + fname = "UBL-Order-2.1-Example.xml" + cls.order_data = cls.ubl_data[fname] + fcontent = cls.order_data._get_content() + cls.exc_record_in._set_file_content(fcontent) + cls.err_msg_already_imported = "Sales order has already been imported before" + + def _find_order(self): + return self.env["sale.order"].search( + [ + ("client_order_ref", "=", self.order_data.client_order_ref), + ("commercial_partner_id", "=", self.order_data.partner.parent_id.id), + ] + ) diff --git a/edi_sale_ubl_oca/tests/test_order_in.py b/edi_sale_ubl_oca/tests/test_order_in.py new file mode 100644 index 0000000000..c94ec7eb6c --- /dev/null +++ b/edi_sale_ubl_oca/tests/test_order_in.py @@ -0,0 +1,79 @@ +# Copyright 2022 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import exceptions +from odoo.tests.common import SavepointCase + +from odoo.addons.edi_oca.tests.common import EDIBackendTestMixin + +from .common import OrderInboundTestMixin + + +class TestOrderInbound(SavepointCase, EDIBackendTestMixin, OrderInboundTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.backend = cls._get_backend() + cls._setup_inbound_order(cls.backend) + + @classmethod + def _get_backend(cls): + return cls.env.ref("edi_ubl_oca.edi_backend_ubl_demo") + + def test_existing_order_break_on_error(self): + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") + self.env["sale.order"].create( + { + "partner_id": self.order_data.partner.id, + "client_order_ref": self.order_data.client_order_ref, + } + ) + with self.assertRaisesRegex( + exceptions.UserError, self.err_msg_already_imported + ): + self.exc_record_in.with_context( + _edi_process_break_on_error=True + ).action_exchange_process() + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") + + def test_existing_order(self): + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") + order = self.env["sale.order"].create( + { + "partner_id": self.order_data.partner.id, + "client_order_ref": self.order_data.client_order_ref, + } + ) + orig_rec_msgs = self.exc_record_in.message_ids + # Test w/ error handling + self.exc_record_in.action_exchange_process() + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed_error") + exc_rec_new_msg = self.exc_record_in.message_ids - orig_rec_msgs + err_msg = "Sales order has already been imported before" + self.assertEqual(self.exc_record_in.exchange_error, err_msg) + + def test_new_order(self): + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") + order = self._find_order() + self.assertFalse(order) + # Test w/ error handling + self.exc_record_in.action_exchange_process() + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed") + order = self._find_order() + self.assertEqual(self.exc_record_in.record, order) + order_msg = order.message_ids[0] + self.assertIn("Exchange processed successfully", order_msg.body) + self.assertIn(self.exc_record_in.identifier, order_msg.body) + self.assertIn( + f"/web#id={self.exc_record_in.id}&model=edi.exchange.record&view_type=form", + order_msg.body, + ) + + def _find_order(self): + return self.env["sale.order"].search( + [ + ("client_order_ref", "=", self.order_data.client_order_ref), + ("commercial_partner_id", "=", self.order_data.partner.parent_id.id), + ] + ) diff --git a/edi_sale_ubl_oca/tests/test_order_in_full_flow.py b/edi_sale_ubl_oca/tests/test_order_in_full_flow.py new file mode 100644 index 0000000000..3556c33ea0 --- /dev/null +++ b/edi_sale_ubl_oca/tests/test_order_in_full_flow.py @@ -0,0 +1,86 @@ +# Copyright 2022 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import SavepointCase + +from odoo.addons.edi_oca.tests.common import EDIBackendTestMixin + +from .common import OrderInboundTestMixin, get_xml_handler + +# TODO: split in different tests w/ SingleTransaction + + +class TestOrderInboundFull(SavepointCase, EDIBackendTestMixin, OrderInboundTestMixin): + + _schema_path = "base_ubl:data/xsd-2.2/maindoc/UBL-OrderResponse-2.2.xsd" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls._setup_env() + cls.backend = cls._get_backend() + cls._setup_inbound_order(cls.backend) + + @classmethod + def _get_backend(cls): + return cls.env.ref("edi_ubl_oca.edi_backend_ubl_demo") + + def test_new_order(self): + self.backend._check_input_exchange_sync() + self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed") + order = self._find_order() + self.assertEqual(self.exc_record_in.record, order) + order_msg = order.message_ids[0] + self.assertIn("Exchange processed successfully", order_msg.body) + self.assertIn(self.exc_record_in.identifier, order_msg.body) + # Test ack generated + self.assertEqual(self.exc_record_in.ack_exchange_id.type_id, self.exc_type_out) + order.invalidate_cache() + # Test relations + self.assertEqual(len(order.exchange_record_ids), 2) + exc_record = order.exchange_record_ids.filtered( + lambda x: x.type_id == self.exc_type_in + ) + ack_exc_record = order.exchange_record_ids.filtered( + lambda x: x.type_id == self.exc_type_out + ) + self.assertEqual(exc_record, self.exc_record_in) + self.assertEqual(ack_exc_record.parent_id, self.exc_record_in) + self.assertEqual(ack_exc_record.edi_exchange_state, "new") + # No ack generated + self.assertFalse(ack_exc_record._get_file_content()) + # Confirm the order + order.action_confirm() + # Should give us a valid order response + file_content = ack_exc_record._get_file_content() + self.assertTrue(file_content) + # TMP / + # path = "/tmp/order.response.test.xml" + # with open(path, "w") as out: + # out.write(file_content) + # / TMP + handler = get_xml_handler(self.backend, self._schema_path) + # Test is a valid file + err = handler.validate(file_content) + self.assertEqual(err, None, err) + + # TODO: new test + # Subsequent updates on some fields should trigger new exchanges + xml_data = handler.parse_xml(file_content) + old_qty = xml_data["cac:OrderLine"][0]["cac:LineItem"]["cbc:Quantity"] + line0 = order.order_line[0] + line0.write({"product_uom_qty": line0.product_uom_qty - 1}) + ack_exc_record = order.exchange_record_ids.filtered( + lambda x: x.type_id == self.exc_type_out and x != ack_exc_record + ) + self.assertEqual(ack_exc_record.parent_id, self.exc_record_in) + self.assertEqual(ack_exc_record.edi_exchange_state, "output_pending") + file_content = ack_exc_record._get_file_content() + self.assertTrue(file_content) + err = handler.validate(file_content) + self.assertEqual(err, None, err) + # Subsequent updates on some fields should trigger new exchanges + xml_data = handler.parse_xml(file_content) + new_qty = xml_data["cac:OrderLine"][0]["cac:LineItem"]["cbc:Quantity"] + self.assertGreater(old_qty, new_qty) diff --git a/edi_sale_ubl_oca/tests/test_order_response_out.py b/edi_sale_ubl_oca/tests/test_order_response_out.py new file mode 100644 index 0000000000..92214773a4 --- /dev/null +++ b/edi_sale_ubl_oca/tests/test_order_response_out.py @@ -0,0 +1,66 @@ +# Copyright 2022 Camptocamp SA +# @author: Simone Orsi +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from freezegun import freeze_time + +from .common import TestCaseBase, get_xml_handler + + +class TestOrderResponseOutbound(TestCaseBase): + + maxDiff = None + + _schema_path = "base_ubl:data/xsd-2.2/maindoc/UBL-OrderResponse-2.2.xsd" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls._setup_order() + cls.exc_type = cls.env.ref("edi_sale_ubl_oca.edi_exc_type_order_response_out") + cls.exc_tmpl = cls.env.ref( + "edi_sale_ubl_oca.edi_exc_template_order_response_out" + ) + vals = { + "model": cls.sale._name, + "res_id": cls.sale.id, + "type_id": cls.exc_type.id, + } + cls.record = cls.backend.create_record(cls.exc_type.code, vals) + + @classmethod + def _get_backend(cls): + return cls.env.ref("edi_ubl_oca.edi_backend_ubl_demo") + + def test_get_template(self): + template = self.backend._get_output_template(self.record) + self.assertEqual(template, self.exc_tmpl) + self.assertEqual( + template.template_id.key, + "edi_sale_ubl_oca.qwb_tmpl_ubl_order_response_out", + ) + + def test_render_values(self): + # TODO: test w/ some identifiers + def make_party(record): + return dict( + name=record.name, + identifiers=[], + endpoint={}, + ) + + values = self.exc_tmpl._get_render_values(self.record) + expected = [ + ("seller_party", make_party(self.sale.company_id)), + ("buyer_party", make_party(self.sale.partner_id)), + ] + for k, v in expected: + self.assertEqual(values[k], v, f"{k} is wrong") + + @freeze_time("2022-07-28 10:30:00") + def test_xml(self): + self.record.action_exchange_generate() + file_content = self.record._get_file_content() + handler = get_xml_handler(self.backend, self._schema_path) + err = handler.validate(file_content) + self.assertEqual(err, None, err) From 184b12ae5315c163332e52ba1a53484010edf2d1 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Wed, 14 Sep 2022 17:23:59 +0200 Subject: [PATCH 02/35] edi_sale_ubl: improve order response data --- .../templates/qweb_tmpl_order_response.xml | 102 +++++++++++------- .../templates/qweb_tmpl_party.xml | 57 ++++++---- edi_sale_ubl_oca/tests/common.py | 5 + edi_sale_ubl_oca/tests/test_order_in.py | 6 +- .../tests/test_order_in_full_flow.py | 18 ++-- .../tests/test_order_response_out.py | 2 + 6 files changed, 114 insertions(+), 76 deletions(-) diff --git a/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml index 1881761d68..dbba8a8492 100644 --- a/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml +++ b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml @@ -1,5 +1,7 @@ - + - - - - diff --git a/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml b/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml index 5be8626059..cc80d3c503 100644 --- a/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml +++ b/edi_sale_ubl_oca/templates/qweb_tmpl_party.xml @@ -1,37 +1,52 @@ - + + + + diff --git a/edi_sale_ubl_oca/tests/common.py b/edi_sale_ubl_oca/tests/common.py index 51553a5921..ca9d8cdea4 100644 --- a/edi_sale_ubl_oca/tests/common.py +++ b/edi_sale_ubl_oca/tests/common.py @@ -106,6 +106,7 @@ def _setup_order(cls): for line in lines: cls._create_sale_order_line(cls.sale, **line) + cls.sale.client_order_ref = "ABC123" cls.sale.action_confirm() @@ -122,6 +123,10 @@ def _setup_inbound_order(cls, backend): cls.exc_type_in.code, {"edi_exchange_state": "input_received"} ) cls.ubl_data = get_test_data(cls.env) + # Ensure all products have a barcode + for data in cls.ubl_data.values(): + for prod in data.products: + prod.barcode = prod.id * 14 fname = "UBL-Order-2.1-Example.xml" cls.order_data = cls.ubl_data[fname] fcontent = cls.order_data._get_content() diff --git a/edi_sale_ubl_oca/tests/test_order_in.py b/edi_sale_ubl_oca/tests/test_order_in.py index c94ec7eb6c..ba59eb3115 100644 --- a/edi_sale_ubl_oca/tests/test_order_in.py +++ b/edi_sale_ubl_oca/tests/test_order_in.py @@ -39,17 +39,15 @@ def test_existing_order_break_on_error(self): def test_existing_order(self): self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") - order = self.env["sale.order"].create( + self.env["sale.order"].create( { "partner_id": self.order_data.partner.id, "client_order_ref": self.order_data.client_order_ref, } ) - orig_rec_msgs = self.exc_record_in.message_ids # Test w/ error handling self.exc_record_in.action_exchange_process() self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed_error") - exc_rec_new_msg = self.exc_record_in.message_ids - orig_rec_msgs err_msg = "Sales order has already been imported before" self.assertEqual(self.exc_record_in.exchange_error, err_msg) @@ -69,6 +67,8 @@ def test_new_order(self): f"/web#id={self.exc_record_in.id}&model=edi.exchange.record&view_type=form", order_msg.body, ) + # TODO: test order data. To do so, first add such tests to sale_order_import + self.assertEqual(order.order_line.mapped("edi_id"), ["1", "2"]) def _find_order(self): return self.env["sale.order"].search( diff --git a/edi_sale_ubl_oca/tests/test_order_in_full_flow.py b/edi_sale_ubl_oca/tests/test_order_in_full_flow.py index 3556c33ea0..4243e09e05 100644 --- a/edi_sale_ubl_oca/tests/test_order_in_full_flow.py +++ b/edi_sale_ubl_oca/tests/test_order_in_full_flow.py @@ -34,25 +34,19 @@ def test_new_order(self): order_msg = order.message_ids[0] self.assertIn("Exchange processed successfully", order_msg.body) self.assertIn(self.exc_record_in.identifier, order_msg.body) - # Test ack generated - self.assertEqual(self.exc_record_in.ack_exchange_id.type_id, self.exc_type_out) order.invalidate_cache() # Test relations - self.assertEqual(len(order.exchange_record_ids), 2) + self.assertEqual(len(order.exchange_record_ids), 1) exc_record = order.exchange_record_ids.filtered( lambda x: x.type_id == self.exc_type_in ) - ack_exc_record = order.exchange_record_ids.filtered( - lambda x: x.type_id == self.exc_type_out - ) self.assertEqual(exc_record, self.exc_record_in) - self.assertEqual(ack_exc_record.parent_id, self.exc_record_in) - self.assertEqual(ack_exc_record.edi_exchange_state, "new") - # No ack generated - self.assertFalse(ack_exc_record._get_file_content()) # Confirm the order order.action_confirm() - # Should give us a valid order response + # Should give us a valid order response ack record + ack_exc_record = order.exchange_record_ids.filtered( + lambda x: x.type_id == self.exc_type_out + ) file_content = ack_exc_record._get_file_content() self.assertTrue(file_content) # TMP / @@ -83,4 +77,4 @@ def test_new_order(self): # Subsequent updates on some fields should trigger new exchanges xml_data = handler.parse_xml(file_content) new_qty = xml_data["cac:OrderLine"][0]["cac:LineItem"]["cbc:Quantity"] - self.assertGreater(old_qty, new_qty) + self.assertGreater(old_qty["$"], new_qty["$"]) diff --git a/edi_sale_ubl_oca/tests/test_order_response_out.py b/edi_sale_ubl_oca/tests/test_order_response_out.py index 92214773a4..e9df6ec0b9 100644 --- a/edi_sale_ubl_oca/tests/test_order_response_out.py +++ b/edi_sale_ubl_oca/tests/test_order_response_out.py @@ -61,6 +61,8 @@ def make_party(record): def test_xml(self): self.record.action_exchange_generate() file_content = self.record._get_file_content() + with open("/tmp/ordrsp.test.xml", "w") as ff: + ff.write(file_content) handler = get_xml_handler(self.backend, self._schema_path) err = handler.validate(file_content) self.assertEqual(err, None, err) From a9d78388d53dceb6470119984cf86a313b8b78e4 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Tue, 15 Nov 2022 09:05:29 +0100 Subject: [PATCH 03/35] edi_sale_ubl_oca: make exc type demo FIXME --- .../{data => demo}/edi_exchange_type.xml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) rename edi_sale_ubl_oca/{data => demo}/edi_exchange_type.xml (78%) diff --git a/edi_sale_ubl_oca/data/edi_exchange_type.xml b/edi_sale_ubl_oca/demo/edi_exchange_type.xml similarity index 78% rename from edi_sale_ubl_oca/data/edi_exchange_type.xml rename to edi_sale_ubl_oca/demo/edi_exchange_type.xml index e608304894..bf310511d9 100644 --- a/edi_sale_ubl_oca/data/edi_exchange_type.xml +++ b/edi_sale_ubl_oca/demo/edi_exchange_type.xml @@ -1,7 +1,7 @@ - + UBL Sale Order Response UBL_SaleOrderResponse_out @@ -33,22 +33,12 @@ auto: tracked_fields: - state - commitment_date - "sale.order.line": - actions: - generate: - when: - - write - trigger_fields: - - product_uom_qty - tracked_fields: - - product_uom_qty - target_record: order_id - + - + UBL Sale Order UBL_SaleOrder_in input From c57f8bab66415831fe02e4791298f6b9cd78a7e1 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Tue, 6 Dec 2022 12:01:46 +0100 Subject: [PATCH 04/35] edi_sale_ubl_oca: depend on party data --- edi_sale_ubl_oca/__manifest__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/edi_sale_ubl_oca/__manifest__.py b/edi_sale_ubl_oca/__manifest__.py index 9c4ba14144..94a2834a82 100644 --- a/edi_sale_ubl_oca/__manifest__.py +++ b/edi_sale_ubl_oca/__manifest__.py @@ -17,6 +17,7 @@ "edi_ubl_oca", "edi_xml_oca", "edi_exchange_template_oca", + "edi_exchange_template_party_data", # This could be made optional # but the delivery part would need another source of data "sale_stock", From 7f6c35506500b32d284d894e2342aa22a3152cb6 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Tue, 6 Dec 2022 12:02:44 +0100 Subject: [PATCH 05/35] edi_sale_ubl_oca: move data to demo --- edi_sale_ubl_oca/__manifest__.py | 6 ++++-- edi_sale_ubl_oca/demo/edi_exchange_type.xml | 2 -- .../{data => demo}/exc_templ_order_response.xml | 5 ++--- edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml | 5 ++++- edi_sale_ubl_oca/tests/common.py | 4 ++-- edi_sale_ubl_oca/tests/test_order_response_out.py | 6 ++++-- 6 files changed, 16 insertions(+), 12 deletions(-) rename edi_sale_ubl_oca/{data => demo}/exc_templ_order_response.xml (86%) diff --git a/edi_sale_ubl_oca/__manifest__.py b/edi_sale_ubl_oca/__manifest__.py index 94a2834a82..da6bc5ff3f 100644 --- a/edi_sale_ubl_oca/__manifest__.py +++ b/edi_sale_ubl_oca/__manifest__.py @@ -25,7 +25,9 @@ "data": [ "templates/qweb_tmpl_party.xml", "templates/qweb_tmpl_order_response.xml", - "data/edi_exchange_type.xml", - "data/exc_templ_order_response.xml", + ], + "demo": [ + "demo/edi_exchange_type.xml", + "demo/exc_templ_order_response.xml", ], } diff --git a/edi_sale_ubl_oca/demo/edi_exchange_type.xml b/edi_sale_ubl_oca/demo/edi_exchange_type.xml index bf310511d9..198fc713b8 100644 --- a/edi_sale_ubl_oca/demo/edi_exchange_type.xml +++ b/edi_sale_ubl_oca/demo/edi_exchange_type.xml @@ -29,10 +29,8 @@ auto: - write trigger_fields: - state - - commitment_date tracked_fields: - state - - commitment_date diff --git a/edi_sale_ubl_oca/data/exc_templ_order_response.xml b/edi_sale_ubl_oca/demo/exc_templ_order_response.xml similarity index 86% rename from edi_sale_ubl_oca/data/exc_templ_order_response.xml rename to edi_sale_ubl_oca/demo/exc_templ_order_response.xml index c52e6ad46c..91eac4c9d7 100644 --- a/edi_sale_ubl_oca/data/exc_templ_order_response.xml +++ b/edi_sale_ubl_oca/demo/exc_templ_order_response.xml @@ -1,15 +1,14 @@ - UBL OrderResponse output ubl.generate.OrderResponse xml - + seller = record.company_id.partner_id diff --git a/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml index dbba8a8492..5c78aba3bc 100644 --- a/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml +++ b/edi_sale_ubl_oca/templates/qweb_tmpl_order_response.xml @@ -3,7 +3,10 @@ TODO: no update. --> -