Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions stock_release_channel/models/stock_release_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
from collections import defaultdict
from copy import deepcopy
from datetime import timedelta
from operator import itemgetter

import pytz
Expand All @@ -21,6 +22,9 @@
time as safe_time,
)

# This limit is arbitrary but we expect to have a delivery slot within this limit
DELIVERY_DATE_COMPUTATION_LIMIT_DAYS = 120 # in days

_logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -949,10 +953,12 @@ def _get_earliest_delivery_date(self, partner, order_dt):
"""
self.ensure_one()
best_dt = order_dt
limit_dt = order_dt + timedelta(days=DELIVERY_DATE_COMPUTATION_LIMIT_DAYS)
for step in self._delivery_date_steps:
funcs = self._delivery_date_generators.get(step)
if not funcs:
continue
_logger.debug(f"Compute earliest delivery date for {step}")
generators = []
best_generators = []
start_dt = best_dt
Expand All @@ -968,14 +974,23 @@ def _get_earliest_delivery_date(self, partner, order_dt):
best_generators.append(gen)
# loop until all generators return the same last date
while len(generators) != len(best_generators):
if best_dt > limit_dt:
_logger.debug(
"Computation for earliest delivery date reached the limit"
)
best_dt = None
break
for gen in generators:
if gen in best_generators:
continue
best_dt = gen.send(previous_dt := best_dt)
if best_dt != previous_dt:
_logger.debug(f"New {step} date {best_dt} from {gen}")
best_generators = [gen]
else:
best_generators.append(gen)
for gen in generators:
gen.close()
if best_dt is None:
break
return best_dt
33 changes: 33 additions & 0 deletions stock_release_channel/tests/models/generator_test_impossible.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2025 Jacques-Etienne Baudoux (BCIM) <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from datetime import timedelta

from odoo import models


class StockReleaseChannel(models.Model):
_inherit = ( # pylint: disable=consider-merging-classes-inherited
"stock.release.channel"
)

@property
def _delivery_date_generators(self):
d = {}
d["preparation"] = [
self._next_delivery_date_one_day,
self._next_delivery_date_one_year,
]
return d

def _next_delivery_date_one_day(self, delivery_date, partner=None):
"""Get a next valid delivery date after 1 day"""
later = delivery_date + timedelta(days=1)
while True:
delivery_date = yield max(delivery_date, later)

def _next_delivery_date_one_year(self, delivery_date, partner=None):
"""Get a next valid delivery outside the limit"""
later = delivery_date + timedelta(days=365)
while True:
delivery_date = yield max(delivery_date, later)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

from odoo import fields

from .common import ReleaseChannelCase, StockReleaseChannelDeliveryDateCommon
from .common import (
FakeModelLoader,
ReleaseChannelCase,
StockReleaseChannelDeliveryDateCommon,
TransactionCase,
)

to_datetime = fields.Datetime.to_datetime

Expand All @@ -19,6 +24,32 @@ def test_delivery_date(self):
self.assertEqual(dt, to_datetime("2025-01-04 10:00:00"))


class TestReleaseChannelDeliveryDateImpossible(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .models.generator_test_impossible import StockReleaseChannel

cls.loader.update_registry((StockReleaseChannel,))

cls.partner = cls.env.ref("base.main_partner")
cls.channel = cls.env.ref("stock_release_channel.stock_release_channel_default")

@classmethod
def tearDownClass(cls):
cls.loader.restore_registry()
return super().tearDownClass()

@freeze_time("2025-01-02 10:00:00")
def test_delivery_date(self):
"""Test generator on channel object"""
now = fields.Datetime.now()
dt = self.channel._get_earliest_delivery_date(self.partner, now)
self.assertEqual(dt, None)


class TestReleaseChannelDeliveryDate(ReleaseChannelCase):
def test_compute_delivery_date(self):
"""Test delivery date computes with registered generators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class StockReleaseChannel(models.Model):
store=True,
)

@api.depends("delivery_weekday_ids", "shipment_lead_time")
@api.depends(
"delivery_weekday_ids", "shipment_lead_time", "warehouse_id.calendar_id"
)
def _compute_preparation_weekday_ids(self):
"""Preparation weekdays are delivery weekdays - lead time"""
for channel in self:
Expand Down