Skip to content

Commit b964ebe

Browse files
committed
[IMP] stock_release_channel_shipment_lead_time
Exclude deliveries planned after shipment date
1 parent 582bdfa commit b964ebe

File tree

6 files changed

+108
-19
lines changed

6 files changed

+108
-19
lines changed

stock_release_channel_shipment_lead_time/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Copyright 2023 Jacques-Etienne Baudoux (BCIM) <[email protected]>
12
# Copyright 2023 Camptocamp
23
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
34

@@ -11,7 +12,6 @@
1112
"maintainers": ["jbaudoux"],
1213
"website": "https://github.com/OCA/wms",
1314
"depends": [
14-
"web",
1515
"stock_release_channel", # OCA/wms
1616
"stock_release_channel_process_end_time", # OCA/wms
1717
"stock_warehouse_calendar", # OCA/stock-logistics-warehouse
Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,55 @@
1+
# Copyright 2023 Jacques-Etienne Baudoux (BCIM) <[email protected]>
12
# Copyright 2023 Camptocamp
23
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3-
from odoo import fields, models
4+
from odoo import api, fields, models
45

56

67
class StockPicking(models.Model):
7-
88
_inherit = "stock.picking"
99

1010
def _get_release_channel_possible_candidate_domain(self):
11-
"""
12-
override to exclude deliveries (OUT pickings) where
13-
the date_deadline is after the shipment date.
14-
"""
15-
self.ensure_one()
11+
# Exclude deliveries (OUT pickings) when the date_deadline is after the shipment date
1612
domain = super()._get_release_channel_possible_candidate_domain()
1713

18-
# date_deadline is datetime UTC => convert to timezone user to compare
19-
# with shipment_date is date
20-
if self.date_deadline:
21-
date_deadline = fields.Datetime.context_timestamp(
22-
self, self.date_deadline
14+
date = self.date_deadline
15+
if date:
16+
# date is datetime UTC => convert to local time to compare
17+
# with shipment_date which is local date
18+
tz = (
19+
self.picking_type_id.warehouse_id.partner_id.tz
20+
or self.company_id.partner_id.tz
21+
)
22+
date = fields.Datetime.context_timestamp(
23+
self.with_context(tz=tz), date
2324
).date()
2425

2526
domain.extend(
2627
[
2728
"|",
2829
("shipment_date", "=", False),
29-
("shipment_date", ">=", date_deadline),
30+
("shipment_date", ">=", date),
3031
]
3132
)
3233
return domain
34+
35+
@api.model
36+
def _search_scheduled_date_prior_to_channel_end_date_condition(self):
37+
self.env["stock.release.channel"].flush_model(
38+
["process_end_date", "shipment_date", "shipment_lead_time"]
39+
)
40+
self.env["stock.picking"].flush_model(["scheduled_date"])
41+
end_date = "stock_release_channel.shipment_date"
42+
# We don't consider warehouse calendar when there is no process end date
43+
lead_time = (
44+
"interval '1 day' * coalesce(stock_release_channel.shipment_lead_time, 0)"
45+
)
46+
now = fields.Datetime.now()
47+
cond = f"""
48+
CASE WHEN stock_release_channel.process_end_date is not null
49+
THEN date(stock_picking.scheduled_date at time zone 'UTC' at time zone wh.tz)
50+
< {end_date} + interval '1 day'
51+
ELSE date(stock_picking.scheduled_date at time zone 'UTC' at time zone wh.tz)
52+
< date(TIMESTAMP %s at time zone wh.tz) + {lead_time} + interval '1 day'
53+
END
54+
"""
55+
return cond, [now]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Jacques-Etienne Baudoux (BCIM) <[email protected]>
12
* `Trobz <https://trobz.com>`_:
23

34
* Hoang Diep <[email protected]>
Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
This module allows to set delivery lead time for release channel.
2-
When setting on shipment lead time on release channel, the shipment date is computed automatically base on
3-
lead time days or warehouse calendar. There are 2 main enhanced features with this module:
4-
- Filter deliveries base on shipment date defined on a channel
5-
- Set delivery date for shipment advice if picking is linked to a channel
1+
Manage shipment date and delivery lead time on release channel.
2+
The shipment date is computed automatically base on process end date + shipment
3+
lead time days and warehouse calendar.
4+
5+
Exclude deliveries promised after shipment date. A delivery with a deadline
6+
won't be assigned to a channel with a shipment date prior to the deadline. This
7+
allows to prevent to deliver a sales order with a commitment date in the
8+
future.
9+
10+
Adapt computation of release ready to take into account the shipment lead time.
11+
A delivery part of a release channel won't be counted as release ready if the
12+
scheduled date is after the shipment date.
13+
14+
Add the delivery date on the shipment advice.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from . import test_assign_channel_shipment_date
22
from . import test_release_shipment_date
3+
from . import test_release_end_date
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2024 Jacques-Etienne Baudoux (BCIM) <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from freezegun import freeze_time
4+
5+
from odoo import fields
6+
7+
from odoo.addons.stock_release_channel.tests.common import ChannelReleaseCase
8+
9+
10+
class ReleaseChannelEndDateCase(ChannelReleaseCase):
11+
@freeze_time("2023-01-27 10:00:00")
12+
def test_channel_counter_release_ready(self):
13+
self.env["ir.config_parameter"].sudo().set_param(
14+
"stock_release_channel_process_end_time.stock_release_use_channel_end_date",
15+
True,
16+
)
17+
# Remove existing jobs as some already exists to assign pickings to channel
18+
jobs_before = self.env["queue.job"].search([])
19+
jobs_before.unlink()
20+
# Set the end time
21+
self.channel.process_end_time = 23.0
22+
# Set picking scheduled date
23+
pickings = self.picking | self.picking2 | self.picking3
24+
pickings.write({"scheduled_date": fields.Datetime.now()})
25+
26+
# Asleep the release channel to void the process end date
27+
self.channel.action_sleep()
28+
self.channel.invalidate_recordset()
29+
# Execute the picking channel assignations
30+
self.channel.with_context(test_queue_job_no_delay=True).action_wake_up()
31+
32+
self.assertEqual(pickings, self.channel.picking_ids)
33+
# at this stage, the pickings are not ready to be released as the
34+
# qty available is not enough
35+
self.assertFalse(self.channel._get_pickings_to_release())
36+
37+
self._update_qty_in_location(self.loc_bin1, self.product1, 100.0)
38+
self._update_qty_in_location(self.loc_bin1, self.product2, 100.0)
39+
40+
self.assertEqual(pickings, self.channel._get_pickings_to_release())
41+
# if the scheduled date of one picking is changed to be on a time after the
42+
# process end date but on the same day, it should still be releasable
43+
pickings[0].scheduled_date = fields.Datetime.from_string("2023-01-27 23:30:00")
44+
self.assertEqual(pickings, self.channel._get_pickings_to_release())
45+
# if the scheduled date of one picking is changed to be on a date after the
46+
# process end date, it should not be releasable anymore
47+
pickings[0].scheduled_date = fields.Datetime.from_string("2023-01-28 00:00:00")
48+
self.assertEqual(pickings[1:], self.channel._get_pickings_to_release())
49+
50+
# Now set channel lead time. It back releasable
51+
self.channel.shipment_lead_time = 1
52+
self.assertEqual(pickings, self.channel._get_pickings_to_release())
53+
# Set date after lead time, it is excluded
54+
pickings[0].scheduled_date = fields.Datetime.from_string("2023-01-29 00:00:00")
55+
self.assertEqual(pickings[1:], self.channel._get_pickings_to_release())

0 commit comments

Comments
 (0)