-
-
Notifications
You must be signed in to change notification settings - Fork 366
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by jbaudoux
- Loading branch information
Showing
3 changed files
with
106 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# Copyright 2023 Jacques-Etienne Baudoux (BCIM) <[email protected]> | ||
# Copyright 2024 Michael Tietz (MT Software) <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from lxml import etree | ||
|
@@ -20,19 +21,31 @@ class StockPicking(models.Model): | |
delivery_notification_sent = fields.Boolean(default=False, copy=False) | ||
|
||
def _send_confirmation_email(self): | ||
picking_ids_skip_costs = [] | ||
for picking in self: | ||
skip_delivery_cost = picking._handle_send_to_shipper_at_operation() | ||
picking = picking.with_context(skip_delivery_cost=skip_delivery_cost) | ||
super(StockPicking, picking)._send_confirmation_email() | ||
if not picking._is_send_to_shipper_at_operation(): | ||
continue | ||
picking_ids_skip_costs.append(picking.id) | ||
picking.carrier_id = picking.ship_picking_id.carrier_id | ||
pickings_skip_costs = self.browse(picking_ids_skip_costs) | ||
if pickings_skip_costs: | ||
pickings_skip_costs._handle_send_to_shipper_at_operation() | ||
super(StockPicking, self - pickings_skip_costs)._send_confirmation_email() | ||
|
||
def _handle_send_to_shipper_at_operation(self): | ||
"""Send the delivery notice to the carrier from a specific operation type. | ||
We are only interested by sending the delivery notice, the delivery fee | ||
still have to be added to the SO by the ship operation. | ||
Return True if the operation has send the delivery notice. | ||
""" | ||
super().with_context(skip_delivery_cost=True)._send_confirmation_email() | ||
for picking in self: | ||
related_ship = picking.ship_picking_id | ||
values = picking._prepare_values_send_to_ship_at_operation(related_ship) | ||
related_ship.write(values) | ||
|
||
def _is_send_to_shipper_at_operation(self): | ||
"""Return True if the operation needs to send the delivery notice.""" | ||
self.ensure_one() | ||
if not self.carrier_id: | ||
# If the current operation has no carrier defined, but a carrier | ||
|
@@ -47,20 +60,23 @@ def _handle_send_to_shipper_at_operation(self): | |
and self.picking_type_id | ||
in carrier.send_delivery_notice_picking_type_ids | ||
): | ||
self.carrier_id = carrier | ||
self.with_context(skip_delivery_cost=True).send_to_shipper() | ||
# Flag the current operation and the ship one. | ||
# Mandatory to not execute twice 'send_to_shipper' method | ||
self.delivery_notification_sent = True | ||
related_ship.delivery_notification_sent = True | ||
related_ship.carrier_price = self.carrier_price | ||
if not related_ship.carrier_tracking_ref: | ||
related_ship.carrier_tracking_ref = self.carrier_tracking_ref | ||
else: | ||
related_ship.carrier_tracking_ref += "," + self.carrier_tracking_ref | ||
return True | ||
return False | ||
|
||
def _prepare_values_send_to_ship_at_operation(self, related_ship): | ||
self.ensure_one() | ||
related_ship.ensure_one() | ||
carrier_tracking_ref = related_ship.carrier_tracking_ref | ||
if carrier_tracking_ref: | ||
carrier_tracking_ref += "," + self.carrier_tracking_ref | ||
else: | ||
carrier_tracking_ref = self.carrier_tracking_ref | ||
return { | ||
"delivery_notification_sent": True, | ||
"carrier_price": self.carrier_price, | ||
"carrier_tracking_ref": carrier_tracking_ref, | ||
} | ||
|
||
def send_to_shipper(self): | ||
# Do not send delivery notice to the carrier if it has already been sent | ||
# through a previous operation (like a pack) | ||
|
@@ -111,3 +127,13 @@ def _fields_view_get_adapt_send_to_shipper_attrs(self, view_arch): | |
) | ||
transfer_modifiers_to_node(modifiers, field) | ||
return etree.tostring(doc, encoding="unicode") | ||
|
||
def _create_backorder(self): | ||
backorders = super()._create_backorder() | ||
for backorder in backorders: | ||
delivery_notification_sent = ( | ||
backorder.backorder_id.delivery_notification_sent | ||
) | ||
if delivery_notification_sent: | ||
backorder.delivery_notification_sent = delivery_notification_sent | ||
return backorders |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
* `Trobz <https://trobz.com>`_: | ||
* Nguyen Hoang Hiep <[email protected]> | ||
* Jacques-Etienne Baudoux (BCIM) <[email protected]> | ||
* Michael Tietz (MT Software) <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
# Copyright 2021 Camptocamp SA | ||
# Copyright 2024 Michael Tietz (MT Software) <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from unittest import mock | ||
|
||
from lxml import etree | ||
|
||
from odoo.tests.common import SavepointCase | ||
from odoo.tests.common import Form, SavepointCase | ||
from odoo.tools.safe_eval import safe_eval | ||
|
||
SEND_SHIPPING_RETURN_VALUE = [{"exact_price": 10.0, "tracking_number": "TEST"}] | ||
|
@@ -15,7 +16,11 @@ class TestDeliverySendToShipper(SavepointCase): | |
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) | ||
cls.env = cls.env( | ||
context=dict( | ||
cls.env.context, tracking_disable=True, set_default_package=False | ||
) | ||
) | ||
cls.wh = cls.env.ref("stock.warehouse0") | ||
cls.wh.delivery_steps = "pick_pack_ship" | ||
cls.stock_location = cls.env.ref("stock.stock_location_stock") | ||
|
@@ -82,10 +87,19 @@ def setUpClass(cls): | |
) | ||
(cls.picking | cls.packing | cls.shipping).sale_id = cls.order | ||
|
||
def _validate_picking(self, picking): | ||
def _validate_picking(self, picking, qty_done=None): | ||
for ml in picking.move_line_ids: | ||
ml.qty_done = ml.product_uom_qty | ||
picking._action_done() | ||
ml.qty_done = qty_done or ml.product_uom_qty | ||
action_data = picking.button_validate() | ||
if not action_data or action_data is True: | ||
return picking.browse() | ||
backorder_wizard = Form( | ||
self.env["stock.backorder.confirmation"].with_context( | ||
action_data["context"] | ||
) | ||
).save() | ||
backorder_wizard.process() | ||
return self.env["stock.picking"].search([("backorder_id", "=", picking.id)]) | ||
|
||
def test_send_to_shipper_on_ship(self): | ||
"""Check sending of delivery notification on ship. | ||
|
@@ -195,3 +209,47 @@ def test_picking_fields_view_get(self): | |
attrs_str = button_send_to_shipper.attrib["attrs"] | ||
attrs = safe_eval(attrs_str) | ||
self.assertIn(("delivery_notification_sent", "=", True), attrs["invisible"]) | ||
|
||
def test_send_to_shipper_on_partial_pack(self): | ||
"""Check that the field delivery_notification_sent | ||
is not set on a pack backorder | ||
but on the ship transfer | ||
""" | ||
with mock.patch.object( | ||
type(self.carrier_on_pack), | ||
"send_shipping", | ||
return_value=SEND_SHIPPING_RETURN_VALUE, | ||
): | ||
self.shipping.carrier_id = self.carrier_on_pack | ||
self._validate_picking(self.picking) | ||
pack_backorder = self._validate_picking(self.packing, 5) | ||
self.assertTrue(self.shipping.delivery_notification_sent) | ||
self.assertFalse(pack_backorder.delivery_notification_sent) | ||
self._validate_picking(pack_backorder, 5) | ||
self.assertTrue(self.shipping.delivery_notification_sent) | ||
backorder = self._validate_picking(self.shipping, 5) | ||
self.assertEqual(self.shipping.state, "done") | ||
self.assertTrue(self.shipping.delivery_notification_sent) | ||
self.assertTrue(backorder.delivery_notification_sent) | ||
backorder2 = self._validate_picking(backorder, 5) | ||
self.assertFalse(backorder2) | ||
self.assertTrue(backorder.delivery_notification_sent) | ||
|
||
def test_send_to_shipper_on_pack_partial_shipping(self): | ||
"""Check that delivery_notification_sent is set on a ship backorder""" | ||
with mock.patch.object( | ||
type(self.carrier_on_pack), | ||
"send_shipping", | ||
return_value=SEND_SHIPPING_RETURN_VALUE, | ||
): | ||
self.shipping.carrier_id = self.carrier_on_pack | ||
self._validate_picking(self.picking) | ||
self._validate_picking(self.packing) | ||
self.assertTrue(self.shipping.delivery_notification_sent) | ||
backorder = self._validate_picking(self.shipping, 5) | ||
self.assertEqual(self.shipping.state, "done") | ||
self.assertTrue(self.shipping.delivery_notification_sent) | ||
self.assertTrue(backorder.delivery_notification_sent) | ||
backorder2 = self._validate_picking(backorder, 5) | ||
self.assertFalse(backorder2) | ||
self.assertTrue(backorder.delivery_notification_sent) |