165 lines
6.3 KiB
Python
165 lines
6.3 KiB
Python
# Copyright 2025 Criptomart
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
import logging
|
|
|
|
from odoo import api
|
|
from odoo import fields
|
|
from odoo import models
|
|
|
|
# Pylint: the explicit 'string' parameter is intentional for clarity in views.
|
|
# Some fields may trigger 'attribute-string-redundant' warnings; silence them
|
|
# locally where appropriate.
|
|
# pylint: disable=attribute-string-redundant
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = "sale.order"
|
|
|
|
def _get_pickup_day_selection(self):
|
|
"""Return pickup day selection options with translations."""
|
|
return [
|
|
("0", self.env._("Monday")),
|
|
("1", self.env._("Tuesday")),
|
|
("2", self.env._("Wednesday")),
|
|
("3", self.env._("Thursday")),
|
|
("4", self.env._("Friday")),
|
|
("5", self.env._("Saturday")),
|
|
("6", self.env._("Sunday")),
|
|
]
|
|
|
|
pickup_day = fields.Selection(
|
|
selection=_get_pickup_day_selection,
|
|
help="Day of week when this order will be picked up",
|
|
)
|
|
|
|
group_order_id = fields.Many2one(
|
|
"group.order",
|
|
help="Reference to the consumer group order that originated this sale order",
|
|
)
|
|
|
|
consumer_group_id = fields.Many2one(
|
|
"res.partner",
|
|
domain="[('is_group', '=', True)]",
|
|
help="Consumer group for this order",
|
|
)
|
|
|
|
pickup_date = fields.Date(
|
|
help="Pickup/delivery date",
|
|
)
|
|
|
|
pickup_slot_label = fields.Char(
|
|
string="Pickup Slot Label",
|
|
compute="_compute_pickup_slot_label",
|
|
store=True,
|
|
readonly=True,
|
|
)
|
|
|
|
home_delivery = fields.Boolean(
|
|
default=False,
|
|
help="Whether this order includes home delivery",
|
|
)
|
|
|
|
@api.depends(
|
|
"group_order_id",
|
|
"group_order_id.next_pickup_slot_id",
|
|
"group_order_id.next_pickup_slot_id.label",
|
|
"group_order_id.next_pickup_slot_id.start_hour",
|
|
"group_order_id.next_pickup_slot_id.end_hour",
|
|
"pickup_date",
|
|
"pickup_day",
|
|
)
|
|
def _compute_pickup_slot_label(self):
|
|
"""Compute a human readable label for the pickup information.
|
|
|
|
Priority:
|
|
1. Use the group order's current `next_pickup_slot_id` if available
|
|
2. Fallback to legacy `pickup_day` / `pickup_date` fields
|
|
Note: we deliberately do NOT store a Many2one reference to the
|
|
slot on the sale.order anymore — we compute the label dynamically
|
|
from the related group order to avoid persisting slot IDs.
|
|
"""
|
|
for order in self:
|
|
slot = False
|
|
if order.group_order_id and order.group_order_id.next_pickup_slot_id:
|
|
slot = order.group_order_id.next_pickup_slot_id
|
|
|
|
if slot:
|
|
if slot.label:
|
|
label = slot.label
|
|
else:
|
|
sh = float(slot.start_hour or 0.0)
|
|
eh = float(slot.end_hour or 0.0)
|
|
sh_h = int(sh)
|
|
sh_m = int(round((sh - sh_h) * 60))
|
|
eh_h = int(eh)
|
|
eh_m = int(round((eh - eh_h) * 60))
|
|
label = f"{sh_h:02d}:{sh_m:02d}-{eh_h:02d}:{eh_m:02d}"
|
|
|
|
if order.pickup_date:
|
|
try:
|
|
date_str = (
|
|
order.pickup_date.strftime("%d/%m/%Y")
|
|
if hasattr(order.pickup_date, "strftime")
|
|
else str(order.pickup_date)
|
|
)
|
|
label = f"{label} ({date_str})"
|
|
except (
|
|
Exception
|
|
) as exc: # log format errors, but don't break compute
|
|
_logger.debug(
|
|
"_compute_pickup_slot_label: failed to format pickup_date for order %s: %s",
|
|
order.id if order and order.id else None,
|
|
exc,
|
|
exc_info=True,
|
|
)
|
|
order.pickup_slot_label = label
|
|
else:
|
|
# Fallback to single-day fields
|
|
if order.pickup_day:
|
|
try:
|
|
day_map = dict(order._get_pickup_day_selection())
|
|
day_name = day_map.get(order.pickup_day, order.pickup_day)
|
|
except Exception as exc:
|
|
_logger.debug(
|
|
"_compute_pickup_slot_label: failed to map pickup_day for order %s: %s",
|
|
order.id if order and order.id else None,
|
|
exc,
|
|
exc_info=True,
|
|
)
|
|
day_name = order.pickup_day
|
|
|
|
if order.pickup_date:
|
|
try:
|
|
date_str = (
|
|
order.pickup_date.strftime("%d/%m/%Y")
|
|
if hasattr(order.pickup_date, "strftime")
|
|
else str(order.pickup_date)
|
|
)
|
|
order.pickup_slot_label = f"{day_name} ({date_str})"
|
|
except Exception as exc:
|
|
_logger.debug(
|
|
"_compute_pickup_slot_label: failed to format pickup_date (fallback) for order %s: %s",
|
|
order.id if order and order.id else None,
|
|
exc,
|
|
exc_info=True,
|
|
)
|
|
order.pickup_slot_label = day_name
|
|
else:
|
|
order.pickup_slot_label = day_name
|
|
else:
|
|
order.pickup_slot_label = False
|
|
|
|
def _get_name_portal_content_view(self):
|
|
"""Override to return custom portal content template with group order info.
|
|
|
|
This method is called by the portal template to determine which content
|
|
template to render. We return our custom template that includes the
|
|
group order information (Consumer Group, Delivery/Pickup info, etc.)
|
|
"""
|
|
self.ensure_one()
|
|
if self.group_order_id:
|
|
return "website_sale_aplicoop.sale_order_portal_content_aplicoop"
|
|
return super()._get_name_portal_content_view()
|