From 11783a5c1b7890867ad35781fd5c150b5c8fbdf3 Mon Sep 17 00:00:00 2001 From: Mmequignon Date: Fri, 1 Dec 2023 12:10:46 +0100 Subject: [PATCH] fixup! fixup! sale_delivery_date: Fix late expeditions detection --- sale_delivery_date/models/stock_picking.py | 80 +++++++++++-------- .../tests/test_backorder_date.py | 13 +-- sale_delivery_date/tests/test_integration.py | 4 +- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/sale_delivery_date/models/stock_picking.py b/sale_delivery_date/models/stock_picking.py index 9faa0e237fe..f92490a71bd 100644 --- a/sale_delivery_date/models/stock_picking.py +++ b/sale_delivery_date/models/stock_picking.py @@ -42,6 +42,42 @@ def _get_delays(self): workload = max(customer_lead - security_lead, 0.0) return customer_lead, security_lead, workload + def _get_expected_expedition_date(self): + """Retrieves the latest expedition date from date_deadline""" + self.ensure_one() + sale_line_model = self.env["sale.order.line"] + delays = self._get_delays() + date_deadline = self.date_deadline + calendar = self._get_warehouse_calendar() + return sale_line_model._expedition_date_from_delivery_date( + date_deadline - timedelta(days=7), # TODO: we don't know the start of the date range + date_deadline, + delays, + calendar=calendar + ) + + def _get_warehouse_calendar(self): + self.ensure_one() + warehouse = self.location_id.get_warehouse() + return warehouse.calendar2_id or None + + def _is_late_to_ship(self, next_expedition_date): + self.ensure_one() + expected_expedition_date = self._get_expected_expedition_date() + return next_expedition_date.date() > expected_expedition_date.date() + + def _get_next_expedition_date(self, from_date): + self.ensure_one() + calendar = self._get_warehouse_calendar() + if calendar: + # plan_hours will return the same datetime if now is part of an attendance, + # otherwise the beginning of the next one. + # If the returned date is after the scheduled date, then we are late + # to ship, and we need to postpone the delivery dates of the moves. + return calendar.plan_hours(0, from_date, compute_leaves=True) + else: + return from_date + def _compute_expected_delivery_date(self): """Computes the expected delivery date. @@ -58,29 +94,16 @@ def _compute_expected_delivery_date(self): commitment_date > expected_date > date_done > scheduled_date """ now = fields.Datetime.now() - sale_line_model = self.env["sale.order.line"] + sol_model = self.env["sale.order.line"] for record in self: - sale_order = record.sale_id - warehouse = record.location_id.get_warehouse() delivery_date = record.date_deadline or record.date_done - calendar = warehouse.calendar2_id - if calendar: - # plan_hours will return the current attendance if now is part of one, - # otherwise the beginning of the next one. - # If the returned date is after the scheduled date, then we are late - # to ship. - # TODO: At some point, we might need a carrier cutoff or something. - next_expedition_date = calendar.plan_hours(0, now, compute_leaves=True) - else: - next_expedition_date = now - late_to_ship = next_expedition_date.date() > record.scheduled_date.date() - if late_to_ship: - delivery_datetime_aware = sale_line_model._add_delay( - next_expedition_date, 1, calendar=calendar - ) - tz_string = record.partner_id.tz or "UTC" - delivery_date = sale_line_model._get_naive_date_from_datetime( - delivery_datetime_aware, tz_string + next_expedition_date = record._get_next_expedition_date(now) + if record._is_late_to_ship(next_expedition_date): + delays = record._get_delays() + partner = record.partner_id + calendar = record._get_warehouse_calendar() + delivery_date = sol_model._delivery_date_from_expedition_date( + next_expedition_date, partner, calendar, delays ) record.expected_delivery_date = delivery_date @@ -196,20 +219,11 @@ def get_cutoff_time(self): def _create_backorder(self): res = super()._create_backorder() + sol_model = self.env["sale.order.line"] now = fields.Datetime.now() for picking in res: - warehouse = picking.location_id.get_warehouse() - calendar = warehouse.calendar2_id - if calendar: - # plan_hours will return the same datetime if now is part of an attendance, - # otherwise the beginning of the next one. - # If the returned date is after the scheduled date, then we are late - # to ship, and we need to postpone the delivery dates of the moves. - next_expedition_date = calendar.plan_hours(0, now, compute_leaves=True) - else: - next_expedition_date = now - late_to_ship = next_expedition_date.date() > picking.scheduled_date.date() - if late_to_ship: + next_expedition_date = self._get_next_expedition_date(now) + if picking._is_late_to_ship(next_expedition_date): for line in picking.move_lines: dates = line._get_delivery_dates(from_date=now) line.write(dates) diff --git a/sale_delivery_date/tests/test_backorder_date.py b/sale_delivery_date/tests/test_backorder_date.py index bc819df9f20..fba4a7b5c6d 100644 --- a/sale_delivery_date/tests/test_backorder_date.py +++ b/sale_delivery_date/tests/test_backorder_date.py @@ -73,8 +73,8 @@ def _increase_so_line_qty(cls, qty): def test_backorder_before_scheduled_date(self): # If we want the backorder to be delivered this week, then it has to be - # created before monday's cutoff. - # If so, it will be delivered friday, at 06:00 + # created before the planned expedition (THURSDAY) + # If so, scheduled date and date deadline won't be postponed. with freeze_time(f"{THURSDAY} {BEFORE_CUTOFF_UTC}"): backorder = self._create_backorder() self.assertEqual(str(backorder.scheduled_date), f"{THURSDAY} {CUTOFF_UTC}") @@ -83,10 +83,11 @@ def test_backorder_before_scheduled_date(self): ) def test_backorder_after_scheduled_date(self): - # If we want the backorder to be delivered this week, then it has to be - # created before monday's cutoff. - # If so, it will be delivered friday, at 06:00 - with freeze_time(f"{THURSDAY} {AFTER_CUTOFF_UTC}"): + # If we want the backorder to be delivered this week, it has to be created + # before the planned expedition(THURSDAY) + # Here, we're creating the backorder on FRIDAY, it should be postponed + # to next THURSDAY for preparation, and next FRIDAY for delivery + with freeze_time(f"{FRIDAY} {BEFORE_CUTOFF_UTC}"): backorder = self._create_backorder() self.assertEqual(str(backorder.scheduled_date), f"{NEXT_THURSDAY} {CUTOFF_UTC}") self.assertEqual( diff --git a/sale_delivery_date/tests/test_integration.py b/sale_delivery_date/tests/test_integration.py index 6ee24fed3b7..ab8d08f1143 100644 --- a/sale_delivery_date/tests/test_integration.py +++ b/sale_delivery_date/tests/test_integration.py @@ -147,7 +147,7 @@ def test_order_on_tuesday_after_cutoff(self): self.assertEqual(str(picking.scheduled_date.date()), expected_work_start_date) self.assertEqual(str(order.expected_date.date()), expected_delivery_date) - @freeze_time("2023-07-06 16:00:00") + @freeze_time("2023-07-06 15:00:00") def test_order_after_cutoff_to_delivery_tomorrow(self): # Let's say we can ask a guy in the warehouse to work on this order # right now to be ready to deliver today. @@ -207,7 +207,7 @@ def test_order_on_thursday_after_cutoff_late_commitment_date(self): str(picking.expected_delivery_date.date()), "2023-07-07" ) - @freeze_time("2023-08-18 13:05:50") + @freeze_time("2023-08-18 13:05:50") # 15:05:50 Europe/Brussels def test_friday_order_with_commitment_date(self): order = self.order_warehouse_cutoff commitment_date = "2023-08-23"