[FIX] website_sale_aplicoop: Critical date calculation fixes (v18.0.1.3.1)

- Fixed _compute_cutoff_date logic: Changed days_ahead <= 0 to days_ahead < 0 to allow cutoff_date same day as today
- Enabled store=True for delivery_date field to persist calculated values and enable database filtering
- Added constraint _check_cutoff_before_pickup to validate pickup_day >= cutoff_day in weekly orders
- Added @api.onchange methods for immediate UI feedback when changing cutoff_day or pickup_day
- Created daily cron job _cron_update_dates to automatically recalculate dates for active orders
- Added 'Calculated Dates' section in form view showing readonly cutoff_date, pickup_date, delivery_date
- Added 6 regression tests with @tagged('post_install', 'date_calculations')
- Updated documentation with comprehensive changelog

This is a more robust fix than v18.0.1.2.0, addressing edge cases in date calculations.
This commit is contained in:
snt 2026-02-18 17:45:45 +01:00
parent c70de71cff
commit 8b0a402ccf
6 changed files with 489 additions and 120 deletions

View file

@ -154,7 +154,7 @@ class GroupOrder(models.Model):
delivery_date = fields.Date(
string="Delivery Date",
compute="_compute_delivery_date",
store=False,
store=True,
readonly=True,
help="Calculated delivery date (pickup date + 1 day)",
)
@ -503,10 +503,11 @@ class GroupOrder(models.Model):
# Calculate days to NEXT occurrence of cutoff_day
days_ahead = target_weekday - current_weekday
if days_ahead <= 0:
# Target day already passed this week or is today
if days_ahead < 0:
# Target day already passed this week
# Jump to next week's occurrence
days_ahead += 7
# If days_ahead == 0, cutoff is today (allowed)
record.cutoff_date = reference_date + timedelta(days=days_ahead)
_logger.info(
@ -534,3 +535,64 @@ class GroupOrder(models.Model):
)
else:
record.delivery_date = None
# === Constraints ===
@api.constrains("cutoff_day", "pickup_day", "period")
def _check_cutoff_before_pickup(self):
"""Validate that pickup_day comes after or equals cutoff_day in weekly orders.
For weekly orders, if pickup_day < cutoff_day numerically, it means pickup
would be scheduled BEFORE cutoff in the same week cycle, which is illogical.
Example:
- cutoff_day=3 (Thursday), pickup_day=1 (Tuesday): INVALID
(pickup Tuesday would be before cutoff Thursday)
- cutoff_day=1 (Tuesday), pickup_day=5 (Saturday): VALID
(pickup Saturday is after cutoff Tuesday)
- cutoff_day=5 (Saturday), pickup_day=5 (Saturday): VALID
(same day allowed)
"""
for record in self:
if record.cutoff_day and record.pickup_day and record.period == "weekly":
cutoff = int(record.cutoff_day)
pickup = int(record.pickup_day)
if pickup < cutoff:
pickup_name = dict(self._get_day_selection())[str(pickup)]
cutoff_name = dict(self._get_day_selection())[str(cutoff)]
raise ValidationError(
_(
"For weekly orders, pickup day ({pickup}) must be after or equal to "
"cutoff day ({cutoff}) in the same week. Current configuration would "
"put pickup before cutoff, which is illogical."
).format(pickup=pickup_name, cutoff=cutoff_name)
)
# === Onchange Methods ===
@api.onchange("cutoff_day", "start_date")
def _onchange_cutoff_day(self):
"""Force recompute cutoff_date on UI change for immediate feedback."""
self._compute_cutoff_date()
@api.onchange("pickup_day", "cutoff_day", "start_date")
def _onchange_pickup_day(self):
"""Force recompute pickup_date on UI change for immediate feedback."""
self._compute_pickup_date()
# === Cron Methods ===
@api.model
def _cron_update_dates(self):
"""Cron job to recalculate dates for active orders daily.
This ensures that computed dates stay up-to-date as time passes.
Only updates orders in 'draft' or 'open' states.
"""
orders = self.search([("state", "in", ["draft", "open"])])
_logger.info("Cron: Updating dates for %d active group orders", len(orders))
for order in orders:
order._compute_cutoff_date()
order._compute_pickup_date()
order._compute_delivery_date()
_logger.info("Cron: Date update completed")