[FIX] website_sale_aplicoop: scope draft lookup to active cycle window
The /eskaera/load-draft endpoint was returning previous-cycle drafts when group_order.cutoff_date was still in the future but group_order.pickup_date had not yet been recomputed (its compute only depends on pickup_day and start_date). Both the stale group_order.pickup_date and the old draft's pickup_date held the same past value, so the exact-pickup-date filter in _find_recent_draft_order matched the stale draft and the cart was repopulated with old products immediately after being cleared. Replace the pickup_date exact-match + current-week fallback with a single cutoff-anchored window: create_date in [cutoff_date - 6 days, cutoff_date]. Drafts created outside that window belong to a previous cycle and must not be reused. The change applies to all four callers (load-draft, clear-cart, save-order, confirm) so the merge/confirm paths also stop attaching to stale drafts. Covered by a new regression test that mirrors the production setup (matching pickup_date, draft create_date backdated 10 days). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
6125515772
commit
3b8cb7582b
2 changed files with 101 additions and 13 deletions
|
|
@ -63,28 +63,29 @@ def _get_salesperson_for_order(self, partner):
|
||||||
|
|
||||||
|
|
||||||
def _find_recent_draft_order(self, partner_id, group_order, request_obj=None):
|
def _find_recent_draft_order(self, partner_id, group_order, request_obj=None):
|
||||||
|
"""Return the active-cycle draft sale.order for the partner, or empty.
|
||||||
|
|
||||||
|
The active ordering period ends at group_order.cutoff_date and begins
|
||||||
|
6 days earlier (weekly cycle). Drafts created outside this window belong
|
||||||
|
to a previous cycle and must not be reused — otherwise stale carts come
|
||||||
|
back when the user re-enters the order page.
|
||||||
|
"""
|
||||||
req = request_obj or request
|
req = request_obj or request
|
||||||
from datetime import datetime
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
today = datetime.now().date()
|
if not group_order or not group_order.cutoff_date:
|
||||||
start_of_week = today - timedelta(days=today.weekday())
|
return req.env["sale.order"]
|
||||||
end_of_week = start_of_week + timedelta(days=6)
|
|
||||||
|
period_start = group_order.cutoff_date - timedelta(days=6)
|
||||||
|
period_end = group_order.cutoff_date
|
||||||
|
|
||||||
domain = [
|
domain = [
|
||||||
("partner_id", "=", partner_id),
|
("partner_id", "=", partner_id),
|
||||||
("group_order_id", "=", group_order.id),
|
("group_order_id", "=", group_order.id),
|
||||||
("state", "=", "draft"),
|
("state", "=", "draft"),
|
||||||
|
("create_date", ">=", f"{period_start} 00:00:00"),
|
||||||
|
("create_date", "<=", f"{period_end} 23:59:59"),
|
||||||
]
|
]
|
||||||
if group_order.pickup_date:
|
|
||||||
domain.append(("pickup_date", "=", group_order.pickup_date))
|
|
||||||
else:
|
|
||||||
domain.extend(
|
|
||||||
[
|
|
||||||
("create_date", ">=", f"{start_of_week} 00:00:00"),
|
|
||||||
("create_date", "<=", f"{end_of_week} 23:59:59"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
req.env["sale.order"].sudo().search(domain, order="create_date desc", limit=1)
|
req.env["sale.order"].sudo().search(domain, order="create_date desc", limit=1)
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,93 @@ class TestGroupOrderStatusEndpoint(TransactionCase):
|
||||||
self.assertEqual(data.get("action"), "clear_cart")
|
self.assertEqual(data.get("action"), "clear_cart")
|
||||||
self.assertNotIn("items", data)
|
self.assertNotIn("items", data)
|
||||||
|
|
||||||
|
def test_find_recent_draft_excludes_previous_cycle(self):
|
||||||
|
"""_find_recent_draft_order must only return drafts whose create_date
|
||||||
|
falls in [cutoff_date - 6 days, cutoff_date].
|
||||||
|
|
||||||
|
Regression (observed on stage.elikabilbo.eus): when the previous
|
||||||
|
cycle's draft still matched group_order.pickup_date (because both
|
||||||
|
were the same stale value), the helper returned it and the cart
|
||||||
|
was repopulated with old products on the next page load.
|
||||||
|
"""
|
||||||
|
partner = self.env.user.partner_id
|
||||||
|
|
||||||
|
# Ensure cutoff_date is in the (near) future so the active window is
|
||||||
|
# well-defined and the cutoff-passed guard is NOT what's being tested.
|
||||||
|
future_cutoff = fields.Date.today() + timedelta(days=2)
|
||||||
|
self.group_order.sudo().write({"cutoff_date": future_cutoff})
|
||||||
|
# Mirror production conditions where pickup_date matches between
|
||||||
|
# group_order and the stale draft — this is what made the old
|
||||||
|
# exact-pickup-date filter return the previous cycle's draft.
|
||||||
|
matching_pickup_date = self.group_order.pickup_date
|
||||||
|
|
||||||
|
previous_cycle_create = fields.Datetime.now() - timedelta(days=10)
|
||||||
|
stale_draft = self.env["sale.order"].create(
|
||||||
|
{
|
||||||
|
"partner_id": partner.id,
|
||||||
|
"group_order_id": self.group_order.id,
|
||||||
|
"pickup_date": matching_pickup_date,
|
||||||
|
"order_line": [
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
"product_id": self.product.id,
|
||||||
|
"product_uom_qty": 3,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# create_date is auto-stamped; backdate it directly to simulate a draft
|
||||||
|
# left over from a previous weekly cycle.
|
||||||
|
self.env.cr.execute(
|
||||||
|
"UPDATE sale_order SET create_date = %s WHERE id = %s",
|
||||||
|
(previous_cycle_create, stale_draft.id),
|
||||||
|
)
|
||||||
|
stale_draft.invalidate_recordset(["create_date"])
|
||||||
|
|
||||||
|
request_mock = self._build_request_mock({})
|
||||||
|
with patch(
|
||||||
|
"odoo.addons.website_sale_aplicoop.controllers.website_sale.request",
|
||||||
|
request_mock,
|
||||||
|
):
|
||||||
|
found = self.controller._find_recent_draft_order(
|
||||||
|
partner.id, self.group_order
|
||||||
|
)
|
||||||
|
self.assertFalse(
|
||||||
|
found,
|
||||||
|
"Previous-cycle draft must not be returned (create_date is outside "
|
||||||
|
"[cutoff-6, cutoff] window) even when pickup_date matches",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now create a current-cycle draft and confirm it IS returned.
|
||||||
|
current_draft = self.env["sale.order"].create(
|
||||||
|
{
|
||||||
|
"partner_id": partner.id,
|
||||||
|
"group_order_id": self.group_order.id,
|
||||||
|
"pickup_date": matching_pickup_date,
|
||||||
|
"order_line": [
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
"product_id": self.product.id,
|
||||||
|
"product_uom_qty": 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"odoo.addons.website_sale_aplicoop.controllers.website_sale.request",
|
||||||
|
request_mock,
|
||||||
|
):
|
||||||
|
found = self.controller._find_recent_draft_order(
|
||||||
|
partner.id, self.group_order
|
||||||
|
)
|
||||||
|
self.assertEqual(found.id, current_draft.id)
|
||||||
|
|
||||||
def test_save_order_endpoint_rejects_closed_group_order(self):
|
def test_save_order_endpoint_rejects_closed_group_order(self):
|
||||||
"""/eskaera/save-order must reject closed group order with clear_cart action."""
|
"""/eskaera/save-order must reject closed group order with clear_cart action."""
|
||||||
self.group_order.action_close()
|
self.group_order.action_close()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue