Skip to content

Commit

Permalink
sale_delivery_date: Only deliver on open days
Browse files Browse the repository at this point in the history
  • Loading branch information
mmequignon committed Oct 12, 2023
1 parent 2aa52dc commit 9a7911f
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 4 deletions.
41 changes: 37 additions & 4 deletions sale_delivery_date/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@

_logger = logging.getLogger(__name__)

# When postponing a delivery date based on calendar leaves, it could happen
# that we have to look far in the future for a valid day.
# I.E. when customer's time window is wednesday, and all wednesdays are leaves
# on the warehouse calendar.
# In such case, it would create an infinite loop, because no matter how
# far we look in the future, we will never find an open time window for this customer.
# In order to avoid this, we use LOOP_THRESHOLD as a hard limit about how
# far in the future we are willing to look for a valid delivery date.
# If no valid delivery_date date has been found within this date range,
# then the next day (with less restrictive constraints) will be used.
LOOP_THRESHOLD = 20


class SaleOrderLine(models.Model):
"""This override adds delays to the date_deadline and the date_planned.
Expand Down Expand Up @@ -259,11 +271,32 @@ def _delivery_date_from_expedition_date(
)
else:
earliest_delivery_date_naive = expedition_date
# /TODO extract
expected_delivery_date = self._apply_customer_window(
earliest_delivery_date_naive, partner
return self._get_next_open_customer_window(partner, calendar, from_date=earliest_delivery_date_naive)

def _get_next_open_customer_window(self, partner, calendar, from_date=None):
if from_date is None:
from_date = datetime.today()
# Try to find an opened customer window within LOOP_THRESHOLD
for days in range(LOOP_THRESHOLD):
window_date = self._apply_customer_window(
from_date + timedelta(days=days), partner
)
open_date = self._postpone_to_working_day(
datetime.combine(window_date, time.min),
calendar=calendar,
)
if window_date.date() == open_date.date():
# We found an opened delivery window
return window_date
# Fallback to the next customer window

# TODO should we log something?
window_date = self._apply_customer_window(from_date, partner)
_logger.warning(
f"Unable to find a valid delivery date for line {self.name}. "
f"Falling back to {str(window_date.date())}."
)
return expected_delivery_date
return window_date

@api.model
def _expedition_date_from_delivery_date(
Expand Down
56 changes: 56 additions & 0 deletions sale_delivery_date/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,59 @@ def test_friday_order_with_monday_leave(self):
picking = order.picking_ids
self.assertEqual(str(picking.scheduled_date), "2023-08-22 08:00:00")
self.assertEqual(str(picking.expected_delivery_date.date()), "2023-08-23")

@freeze_time("2023-10-09 08:00:00")
def test_delivery_window_on_public_holiday(self):
order = self.order_warehouse_cutoff
weekday_numbers = tuple(range(5))
time_ranges = [(8.0, 12.0), (13.0, 17.5)]
self._set_calendar_attendances(self.calendar, weekday_numbers, time_ranges)
# Set customer to receive goods on Wednesday, from 12 to 17
weekday_numbers = (2,) # Wednesday
time_window_ranges = [(12.00, 17.00), ]
self._set_partner_time_window(
self.customer_warehouse_cutoff, weekday_numbers, time_window_ranges
)
# add a public holiday the 11th of October
days = ["2023-10-11", ]
self._add_calendar_leaves(self.calendar, days)
order.action_confirm()
picking = order.picking_ids
self.assertEqual(str(picking.scheduled_date.date()), "2023-10-17")
self.assertEqual(str(picking.date_deadline.date()), "2023-10-18")

@freeze_time("2023-10-09 08:00:00")
def test_no_open_delivery_window_within_twenty_days(self):
order = self.order_warehouse_cutoff
weekday_numbers = tuple(range(5))
time_ranges = [(8.0, 12.0), (13.0, 17.5)]
self._set_calendar_attendances(self.calendar, weekday_numbers, time_ranges)
# Set customer to receive goods on Wednesday, from 12 to 17
weekday_numbers = (2,) # Wednesday
time_window_ranges = [(12.00, 17.00), ]
self._set_partner_time_window(
self.customer_warehouse_cutoff, weekday_numbers, time_window_ranges
)
# add a public holiday all fridays
days = [
"2023-10-11",
"2023-10-18",
"2023-10-25",
"2023-11-01",
]
self._add_calendar_leaves(self.calendar, days)
logger_name = "odoo.addons.sale_delivery_date.models.sale_order_line"
with self.assertLogs(logger_name, level="WARNING") as watcher:
line = order.order_line
order.action_confirm()
expected_message = (
f"WARNING:{logger_name}:"
f"Unable to find a valid delivery date for line {line.name}. "
f"Falling back to 2023-10-11."
)
self.assertEqual(watcher.output[0], expected_message)
picking = order.picking_ids
# since we weren't able to find an open friday within 20 days,
# we fell back on the first one, being the 11th of october
self.assertEqual(str(picking.scheduled_date.date()), "2023-10-10")
self.assertEqual(str(picking.date_deadline.date()), "2023-10-11")

0 comments on commit 9a7911f

Please sign in to comment.