diff --git a/edi_sale_ubl_oca/__manifest__.py b/edi_sale_ubl_oca/__manifest__.py index 55a3944785..f1c23c0ac9 100644 --- a/edi_sale_ubl_oca/__manifest__.py +++ b/edi_sale_ubl_oca/__manifest__.py @@ -31,6 +31,7 @@ ], "demo": [ "demo/edi_exchange_type.xml", + "demo/edi_configuration.xml", "demo/exc_templ_order_response.xml", ], } diff --git a/edi_sale_ubl_oca/demo/edi_configuration.xml b/edi_sale_ubl_oca/demo/edi_configuration.xml new file mode 100644 index 0000000000..614521379a --- /dev/null +++ b/edi_sale_ubl_oca/demo/edi_configuration.xml @@ -0,0 +1,17 @@ + + + + Demo UBL Sale OrderResponse - order confirmed + Show case how you can send out an order response automatically + demo_ubl_edi_sale_ordrsp + + + + on_edi_sale_order_state_sale + +record._edi_send_via_edi(conf.type_id) + + + diff --git a/edi_sale_ubl_oca/demo/edi_exchange_type.xml b/edi_sale_ubl_oca/demo/edi_exchange_type.xml index 154bc12b48..a25b1be08a 100644 --- a/edi_sale_ubl_oca/demo/edi_exchange_type.xml +++ b/edi_sale_ubl_oca/demo/edi_exchange_type.xml @@ -3,6 +3,7 @@ + Demo UBL Sale Order Response demo_UBL_SaleOrderResponse_out output @@ -26,33 +27,9 @@ components: - - - - SO automatic demo - auto - [('disable_edi_auto', '=', False)] - -actions: - generate: - when: - - write - trigger_fields: - - state - - commitment_date - tracked_fields: - - state - - commitment_date - if: - snippet: result = todo.vals.get('state') in ('sale', 'sent', 'cancel') or "commitment_date" in todo.vals - - - + Demo UBL Sale Order demo_UBL_SaleOrder_in diff --git a/edi_sale_ubl_oca/models/sale_order.py b/edi_sale_ubl_oca/models/sale_order.py index 117873c74c..5d1b718779 100644 --- a/edi_sale_ubl_oca/models/sale_order.py +++ b/edi_sale_ubl_oca/models/sale_order.py @@ -83,17 +83,83 @@ def create(self, vals_list): .with_context(evt_from_create=None) ) + # FIXME: move to core + # TODO: test + def _edi_send_via_edi(self, exchange_type, force=False, **kw): + exchange_record = None + # If we are sending an ack, we must check if we can generate it + if exchange_type.ack_for_type_ids: + if self._edi_can_generate_ack(exchange_type): + __, exchange_record = self._edi_get_or_create_ack_record( + exchange_type, force=force + ) + else: + exchange_record = self._edi_create_exchange_record(exchange_type) + if exchange_record: + exchange_record.action_exchange_generate_send(**kw) + + def _edi_can_generate_ack(self, exchange_type, force=False): + """Have to generate ack for this exchange type? + + :param exchange_type: The exchange type to check. + + It should be generated if: + - automation is not disabled and not forced + - origin exchange record is set (means it was originated by another record) + - origin exchange type is compatible with the configured ack types + """ + if (self.disable_edi_auto and not force) or not self.origin_exchange_record_id: + return False + return self.origin_exchange_type_id in exchange_type.ack_for_type_ids + + def _edi_get_or_create_ack_record(self, exchange_type, force=False): + """ + Get or create a child record for the given exchange type. + + If the record has not been sent out yet for whatever reason + (job delayed, job failed, send failed, etc) + we still want to generate a new up to date record to be sent. + + :param exchange_type: The exchange type to create the record for. + :param force: If True, will force the creation of the record in case of ack type. + """ + if not self._edi_can_generate_ack(exchange_type, force=force): + return False, False + parent = self._edi_get_origin() + # Filter acks that are not valued yet. + exchange_record = self._get_exchange_record(exchange_type).filtered( + lambda x: not x.exchange_file + ) + created = False + # If the record has not been sent out yet for whatever reason + # (job delayed, job failed, send failed, etc) + # we still want to generate a new up to date record to be sent. + still_pending = exchange_record.edi_exchange_state in ( + "output_pending", + "output_error_on_send", + ) + if not exchange_record or still_pending: + vals = exchange_record._exchange_child_record_values() + vals["parent_id"] = parent.id + # NOTE: to fully automatize this, + # is recommended to enable `quick_exec` on the type + # otherwise records will have to wait for the cron to pass by. + exchange_record = self._edi_create_exchange_record(exchange_type, vals=vals) + created = True + return created, exchange_record + class SaleOrderLine(models.Model): _name = "sale.order.line" _inherit = [ "sale.order.line", - "edi.auto.exchange.consumer.mixin", "edi.id.mixin", "edi.state.consumer.mixin", ] def _edi_determine_lines_state(self, orig_vals): + # Make sure lines are up to date + self.flush() # Defaults for line in self: if not line.edi_exchange_ready: diff --git a/edi_sale_ubl_oca/tests/test_order_in.py b/edi_sale_ubl_oca/tests/test_order_in.py index 0375957308..9c62a81a0a 100644 --- a/edi_sale_ubl_oca/tests/test_order_in.py +++ b/edi_sale_ubl_oca/tests/test_order_in.py @@ -49,7 +49,7 @@ def test_existing_order(self): self.exc_record_in.action_exchange_process() self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed_error") err_msg = "Sales order has already been imported before" - self.assertEqual(self.exc_record_in.exchange_error, err_msg) + self.assertIn(err_msg, self.exc_record_in.exchange_error) def test_new_order(self): self.assertEqual(self.exc_record_in.edi_exchange_state, "input_received") 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 3fd6470ff1..1adbb47d40 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 @@ -2,7 +2,8 @@ # @author: Simone Orsi # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields +from unittest import mock + from odoo.tests.common import SavepointCase from odoo.addons.edi_oca.tests.common import EDIBackendTestMixin @@ -22,15 +23,21 @@ def setUpClass(cls): cls._setup_env() cls.backend = cls._get_backend() cls._setup_inbound_order(cls.backend) + cls.edi_conf = cls.env.ref( + "edi_sale_ubl_oca.demo_ubl_edi_configuration_confirmed" + ) @classmethod def _get_backend(cls): return cls.env.ref("edi_ubl_oca.edi_backend_ubl_demo") - def test_new_order(self): + # No need to test sending data + @mock.patch("odoo.addons.edi_oca.models.edi_backend.EDIBackend._exchange_send") + def test_new_order(self, mock_send): self.backend._check_input_exchange_sync() self.assertEqual(self.exc_record_in.edi_exchange_state, "input_processed") order = self._find_order() + order.partner_id.edi_sale_conf_ids = self.edi_conf self.assertEqual(self.exc_record_in.record, order) order_msg = order.message_ids[0] self.assertIn("Exchange processed successfully", order_msg.body) @@ -59,29 +66,4 @@ def test_new_order(self): # 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_date = order.commitment_date - new_date = fields.Date.add(order.commitment_date, days=2) - self.assertEqual( - xml_data["cac:Delivery"][0]["cbc:ActualDeliveryDate"], - fields.Date.to_string(old_date), - ) - order.write({"commitment_date": new_date}) - 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) - self.assertEqual( - xml_data["cac:Delivery"][0]["cbc:ActualDeliveryDate"], - fields.Date.to_string(new_date), - ) + # TODO: test data 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 7767af094a..ba7f164493 100644 --- a/edi_sale_ubl_oca/tests/test_order_response_out.py +++ b/edi_sale_ubl_oca/tests/test_order_response_out.py @@ -76,4 +76,4 @@ def test_xml(self): self.assertEqual(err, None, err) data = handler.parse_xml(file_content) # TODO: test all main data - self.assertEqual(data["cbc:OrderResponseCode"], "AP") + self.assertEqual(data["cbc:OrderResponseCode"], "CA") diff --git a/setup/edi_sale_ubl_oca/odoo/addons/edi_sale_ubl_oca b/setup/edi_sale_ubl_oca/odoo/addons/edi_sale_ubl_oca new file mode 120000 index 0000000000..8bed21b906 --- /dev/null +++ b/setup/edi_sale_ubl_oca/odoo/addons/edi_sale_ubl_oca @@ -0,0 +1 @@ +../../../../edi_sale_ubl_oca \ No newline at end of file diff --git a/setup/edi_sale_ubl_oca/setup.py b/setup/edi_sale_ubl_oca/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/edi_sale_ubl_oca/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)