diff --git a/edi_sale_input_oca/demo/edi_exchange_type.xml b/edi_sale_input_oca/demo/edi_exchange_type.xml
index bec19fddc4..ae1e05f744 100644
--- a/edi_sale_input_oca/demo/edi_exchange_type.xml
+++ b/edi_sale_input_oca/demo/edi_exchange_type.xml
@@ -5,7 +5,7 @@
Demo Sale Order
- demo_SaleOrder_in
+ demo_edi_sale_input_so_in
input
xml
diff --git a/edi_sale_oca/__manifest__.py b/edi_sale_oca/__manifest__.py
index 1a5c93ac3a..a371e6a50d 100644
--- a/edi_sale_oca/__manifest__.py
+++ b/edi_sale_oca/__manifest__.py
@@ -18,12 +18,15 @@
"sale",
],
"data": [
+ "data/edi_configuration.xml",
"views/res_partner.xml",
"views/sale_order.xml",
+ "views/res_partner.xml",
"views/edi_exchange_record.xml",
],
"demo": [
"demo/edi_backend.xml",
"demo/edi_exchange_type.xml",
+ "demo/edi_configuration.xml",
],
}
diff --git a/edi_sale_oca/components/__init__.py b/edi_sale_oca/components/__init__.py
index e69de29bb2..a441d8bd1f 100644
--- a/edi_sale_oca/components/__init__.py
+++ b/edi_sale_oca/components/__init__.py
@@ -0,0 +1 @@
+from . import listeners
diff --git a/edi_sale_oca/components/listeners.py b/edi_sale_oca/components/listeners.py
new file mode 100644
index 0000000000..c213d646a2
--- /dev/null
+++ b/edi_sale_oca/components/listeners.py
@@ -0,0 +1,27 @@
+# Copyright 2024 Camptocamp SA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.addons.component.core import Component
+
+
+class EDIConfigSOListener(Component):
+ _name = "edi.listener.config.sale.order"
+ _inherit = "base.event.listener"
+ _apply_on = ["sale.order"]
+
+ def on_record_create(self, record, fields=None):
+ trigger = "on_record_create"
+ return self._exec_conf(record, trigger)
+
+ def on_record_write(self, record, fields=None):
+ trigger = "on_record_write"
+ return self._exec_conf(record, trigger)
+
+ def on_edi_sale_order_state_change(self, record, state=None):
+ trigger = "on_edi_sale_order_state_change"
+ return self._exec_conf(record, trigger)
+
+ def _exec_conf(self, record, trigger, conf_field="edi_sale_conf_ids"):
+ confs = record.partner_id[conf_field].edi_get_conf(trigger)
+ for conf in confs:
+ conf.edi_exec_snippet_do(record)
diff --git a/edi_sale_oca/data/edi_configuration.xml b/edi_sale_oca/data/edi_configuration.xml
new file mode 100644
index 0000000000..3ddd6d7bd1
--- /dev/null
+++ b/edi_sale_oca/data/edi_configuration.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ On SO state change
+ on_edi_sale_order_state_change
+ Trigger when a sale order state changes
+
+
+
diff --git a/edi_sale_oca/demo/edi_configuration.xml b/edi_sale_oca/demo/edi_configuration.xml
new file mode 100644
index 0000000000..514cc2c49d
--- /dev/null
+++ b/edi_sale_oca/demo/edi_configuration.xml
@@ -0,0 +1,38 @@
+
+
+
+ Demo Sale OrderResponse - order confirmed
+ Show case how you can send out an order response automatically
+
+
+
+
+
+# STATES
+# ('draft', 'Quotation'),
+# ('sent', 'Quotation Sent'),
+# ('sale', 'Sales Order'),
+# ('done', 'Locked'),
+# ('cancel', 'Cancelled'),
+if record.state == 'sale':
+ record._edi_send_via_edi(conf.type_id)
+
+
+
+ Demo Sale OrderResponse - order done
+ Show case how you can send out an order response automatically
+
+
+
+
+
+if record.state == 'done':
+ record._edi_send_via_edi(conf.type_id)
+
+
+
+
diff --git a/edi_sale_oca/demo/edi_exchange_type.xml b/edi_sale_oca/demo/edi_exchange_type.xml
index 49d9d08083..a1a6f3b47f 100644
--- a/edi_sale_oca/demo/edi_exchange_type.xml
+++ b/edi_sale_oca/demo/edi_exchange_type.xml
@@ -1,23 +1,24 @@
-
-
Demo Sale Order
demo_SaleOrder_in
input
xml
-
-components:
- process:
- usage: input.process.sale.order
- env_ctx:
- default_price_source: 'pricelist'
- default_import_type: 'xml'
- random_key: custom
-
- -->
+
diff --git a/edi_sale_oca/models/__init__.py b/edi_sale_oca/models/__init__.py
index 6aacb75313..c0ee851195 100644
--- a/edi_sale_oca/models/__init__.py
+++ b/edi_sale_oca/models/__init__.py
@@ -1 +1,2 @@
from . import sale_order
+from . import res_partner
diff --git a/edi_sale_oca/models/res_partner.py b/edi_sale_oca/models/res_partner.py
new file mode 100644
index 0000000000..ea2a15c227
--- /dev/null
+++ b/edi_sale_oca/models/res_partner.py
@@ -0,0 +1,19 @@
+# Copyright 2024 Camptocamp SA
+# @author: Simone Orsi
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+
+from odoo import fields, models
+
+
+class ResPartner(models.Model):
+ _inherit = "res.partner"
+
+ edi_sale_conf_ids = fields.Many2many(
+ string="EDI sale configuration",
+ comodel_name="edi.configuration",
+ relation="res_partner_edi_sale_configuration_rel",
+ column1="partner_id",
+ column2="conf_id",
+ domain=[("model_name", "=", "sale.order")],
+ )
diff --git a/edi_sale_oca/tests/__init__.py b/edi_sale_oca/tests/__init__.py
index e6fb64b6b6..975f7f7956 100644
--- a/edi_sale_oca/tests/__init__.py
+++ b/edi_sale_oca/tests/__init__.py
@@ -1 +1,2 @@
from . import test_order
+from . import test_generate
diff --git a/edi_sale_oca/tests/common.py b/edi_sale_oca/tests/common.py
index 523642abb6..3ffd7c1e81 100644
--- a/edi_sale_oca/tests/common.py
+++ b/edi_sale_oca/tests/common.py
@@ -15,7 +15,11 @@ def _create_sale_order(cls, **kw):
model = cls.env["sale.order"]
vals = dict(commitment_date=fields.Date.today())
vals.update(kw)
- so_vals = model.play_onchanges(vals, [])
+ # Loose dependency on onchange_helper
+ if hasattr(model, "play_onchanges"):
+ so_vals = model.play_onchanges(vals, [])
+ else:
+ so_vals = vals.copy()
if "order_line" in so_vals:
so_vals["order_line"] = [(0, 0, x) for x in vals["order_line"]]
return model.create(so_vals)
diff --git a/edi_sale_oca/tests/test_generate.py b/edi_sale_oca/tests/test_generate.py
new file mode 100644
index 0000000000..a9ef71208e
--- /dev/null
+++ b/edi_sale_oca/tests/test_generate.py
@@ -0,0 +1,108 @@
+# Copyright 2024 Camptocamp SA
+# @author: Simone Orsi
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
+
+
+from odoo.addons.component.tests.common import SavepointComponentRegistryCase
+from odoo.addons.edi_oca.tests.common import EDIBackendTestMixin
+from odoo.addons.edi_oca.tests.fake_components import (
+ FakeOutputGenerator,
+ FakeOutputSender,
+)
+
+
+class Generator(FakeOutputGenerator):
+ _backend_type = "sale_demo"
+ _exchange_type = "demo_SaleOrder_out"
+
+
+class Sender(FakeOutputSender):
+ _backend_type = "sale_demo"
+ _exchange_type = "demo_SaleOrder_out"
+
+
+class TestProcessComponent(SavepointComponentRegistryCase, EDIBackendTestMixin):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls._setup_env()
+ cls.backend = cls._get_backend()
+ cls.exc_type = cls.env.ref("edi_sale_oca.demo_edi_exc_type_order_out")
+ cls.edi_conf_confirmed = cls.env.ref(
+ "edi_sale_oca.demo_edi_configuration_confirmed"
+ )
+ cls.edi_conf_done = cls.env.ref("edi_sale_oca.demo_edi_configuration_done")
+ cls.partner = cls.env.ref("base.res_partner_2").copy({"name": "John Doe"})
+ cls._load_module_components(cls, "edi_oca")
+ cls._load_module_components(cls, "edi_sale_oca")
+ cls._build_components(
+ cls,
+ Generator,
+ Sender,
+ )
+
+ def setUp(self):
+ super().setUp()
+ Generator.reset_faked()
+ Sender.reset_faked()
+
+ @classmethod
+ def _get_backend(cls):
+ return cls.env.ref("edi_sale_oca.demo_edi_backend")
+
+ def test_lookup(self):
+ # Just ensuring test setup is done properly
+ record = self.backend.create_record(self.exc_type.code, {})
+ comp = self.backend._get_component(record, "generate")
+ self.assertEqual(comp._name, Generator._name)
+ comp = self.backend._get_component(record, "send")
+ self.assertEqual(comp._name, Sender._name)
+
+ def test_new_order_no_conf_no_output(self):
+ order = self.env["sale.order"].create(
+ {
+ "partner_id": self.partner.id,
+ }
+ )
+ order.action_confirm()
+ self.assertFalse(order.exchange_record_ids)
+
+ def test_new_order_1conf_output(self):
+ self.partner.edi_sale_conf_ids = self.edi_conf_confirmed
+ order = self.env["sale.order"].create(
+ {
+ "partner_id": self.partner.id,
+ }
+ )
+ self.assertFalse(order.exchange_record_ids)
+ order.with_context(fake_output="ORDER CONFIRM").action_confirm()
+ self.assertEqual(len(order.exchange_record_ids), 1)
+ record = order.exchange_record_ids[0]
+ self.assertEqual(record._get_file_content(), "ORDER CONFIRM")
+ self.assertEqual(record.type_id, self.exc_type)
+ # When done, nothing changes
+ order.action_done()
+ self.assertEqual(len(order.exchange_record_ids), 1)
+ record = order.exchange_record_ids[0]
+ self.assertEqual(record.type_id, self.exc_type)
+
+ def test_new_order_2conf_output(self):
+ self.partner.edi_sale_conf_ids = self.edi_conf_confirmed | self.edi_conf_done
+ order = self.env["sale.order"].create(
+ {
+ "partner_id": self.partner.id,
+ }
+ )
+ self.assertFalse(order.exchange_record_ids)
+ order.with_context(fake_output="ORDER CONFIRM").action_confirm()
+ self.assertEqual(len(order.exchange_record_ids), 1)
+ record = order.exchange_record_ids[0]
+ self.assertEqual(record._get_file_content(), "ORDER CONFIRM")
+ self.assertEqual(record.type_id, self.exc_type)
+ # When done, nothing changes
+ order.with_context(fake_output="ORDER DONE").action_done()
+ record1, record2 = order.exchange_record_ids
+ self.assertEqual(record1.type_id, self.exc_type)
+ self.assertEqual(record1._get_file_content(), "ORDER CONFIRM")
+ self.assertEqual(record2.type_id, self.exc_type)
+ self.assertEqual(record2._get_file_content(), "ORDER DONE")
diff --git a/edi_sale_oca/views/res_partner.xml b/edi_sale_oca/views/res_partner.xml
index c0afc4a76a..c327efb238 100644
--- a/edi_sale_oca/views/res_partner.xml
+++ b/edi_sale_oca/views/res_partner.xml
@@ -7,16 +7,18 @@
res.partner
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+