From b01794c319bfba1fc9d6263621741ed9c9ae6f7b Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Thu, 28 May 2026 13:51:37 +0200 Subject: [PATCH] [FIX] website_sale_aplicoop: clear cart when group order cutoff has passed Previously, when a user reopened a group order whose cutoff day had already passed, the /eskaera/check-status response correctly triggered the localStorage cart clear, but _autoLoadDraftOnInit immediately re-fetched the previous cycle's draft sale.order from /eskaera/load-draft (which only guarded on group_order.state, not cutoff_date) and the stale items reappeared in the cart, confusing users. Add a cutoff_date < today guard to load_draft_cart so the endpoint returns the existing clear_cart unavailable response, and short-circuit _autoLoadDraftOnInit on the frontend via a _skipDraftAutoLoad flag set in _checkGroupOrderStatus to avoid the now-pointless XHR round trip. Covered by a new regression test in tests/test_group_order_status_endpoint.py. Co-Authored-By: Claude Opus 4.7 --- .../controllers/website_sale.py | 6 +++- .../static/src/js/website_sale.js | 6 ++++ .../tests/test_group_order_status_endpoint.py | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/website_sale_aplicoop/controllers/website_sale.py b/website_sale_aplicoop/controllers/website_sale.py index aab682f..a9d6894 100644 --- a/website_sale_aplicoop/controllers/website_sale.py +++ b/website_sale_aplicoop/controllers/website_sale.py @@ -1558,7 +1558,11 @@ class AplicoopWebsiteSale(WebsiteSale): status=400, ) - if group_order.state != "open": + cutoff_passed = bool( + group_order.cutoff_date + and group_order.cutoff_date < fields.Date.today() + ) + if group_order.state != "open" or cutoff_passed: return self._build_group_order_unavailable_response(group_order) current_user = request.env.user diff --git a/website_sale_aplicoop/static/src/js/website_sale.js b/website_sale_aplicoop/static/src/js/website_sale.js index a47217b..bae18ef 100644 --- a/website_sale_aplicoop/static/src/js/website_sale.js +++ b/website_sale_aplicoop/static/src/js/website_sale.js @@ -117,6 +117,11 @@ console.log("Attempting to auto-load draft order..."); var self = this; + if (this._skipDraftAutoLoad) { + console.log("Auto-load draft skipped (order closed or cutoff passed)"); + return; + } + // Only auto-load if cart is empty var cartItemsCount = Object.keys(this.cart).length; if (cartItemsCount > 0) { @@ -506,6 +511,7 @@ shouldClear = true; } } + self._skipDraftAutoLoad = shouldClear; if (shouldClear) { console.log( "[groupOrderShop] check-status: clearing cart (reason:", diff --git a/website_sale_aplicoop/tests/test_group_order_status_endpoint.py b/website_sale_aplicoop/tests/test_group_order_status_endpoint.py index f97111f..082ba01 100644 --- a/website_sale_aplicoop/tests/test_group_order_status_endpoint.py +++ b/website_sale_aplicoop/tests/test_group_order_status_endpoint.py @@ -102,6 +102,38 @@ class TestGroupOrderStatusEndpoint(TransactionCase): self.assertEqual(data["state"], "closed") self.assertEqual(data["action"], "clear_cart") + def test_load_draft_endpoint_rejects_when_cutoff_passed(self): + """/eskaera/load-draft must refuse to load drafts when cutoff_date is in + the past, even if the group.order is still in 'open' state. + + Regression: previously the endpoint only checked group_order.state, so + when cutoff had passed the previous cycle's draft was returned and + repopulated the cart on the next page load. + """ + # Force cutoff_date into the past. The @api.depends compute always + # rolls forward to the next occurrence, so we have to write directly + # to the stored field to simulate a stale cycle. + past = fields.Date.today() - timedelta(days=1) + self.group_order.sudo().write({"cutoff_date": past}) + # Sanity: state remains open; only cutoff is stale. + self.assertEqual(self.group_order.state, "open") + self.assertLess(self.group_order.cutoff_date, fields.Date.today()) + + payload = {"order_id": self.group_order.id} + request_mock = self._build_request_mock(payload) + + with patch( + "odoo.addons.website_sale_aplicoop.controllers.website_sale.request", + request_mock, + ): + response = self.controller.load_draft_cart.__wrapped__(self.controller) + + data = json.loads(response.data.decode("utf-8")) + self.assertEqual(response.status, 403) + self.assertEqual(data.get("code"), "group_order_not_open") + self.assertEqual(data.get("action"), "clear_cart") + self.assertNotIn("items", data) + def test_save_order_endpoint_rejects_closed_group_order(self): """/eskaera/save-order must reject closed group order with clear_cart action.""" self.group_order.action_close()