Compare commits

...

2 commits

Author SHA1 Message Date
GitHub Copilot
48597ae8c7 add l10n_es_partner dependency for commercial name field. 2026-06-04 15:14:53 +02:00
GitHub Copilot
965c5c2495 [FIX] website_sale_aplicoop: stamp localStorage cart with cycle and evict on rollover
The cart was reappearing on stage with ghost items that had never been
saved as drafts on the server. Root cause: the localStorage cart had no
cycle awareness. Users who added items but never clicked Save left the
items in localStorage forever, and the only existing eviction path
(_clearCurrentOrderCartSilently via _checkGroupOrderStatus) only fires
when cutoff_passed flips true — which it rarely does, because the
stored cutoff_date is normally in the future for an active cycle. On
the next visit, _loadCart happily rehydrated the stale items and
_autoLoadDraftOnInit short-circuited because the cart was no longer
empty.

Stamp every cart written to localStorage with the cutoff_date it
belongs to and reject on cycle mismatch in _loadCart. The cutoff_date
is captured from /eskaera/check-status (which already returned it).
Legacy unstamped values and corrupt JSON are also dropped, so existing
browsers self-heal on first reload after the deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-04 15:14:04 +02:00
2 changed files with 71 additions and 8 deletions

View file

@ -19,6 +19,7 @@
"stock_picking_batch", "stock_picking_batch",
"account", "account",
"product_get_price_helper", "product_get_price_helper",
"l10n_es_partner",
], ],
"data": [ "data": [
# Datos: Grupos propios # Datos: Grupos propios

View file

@ -436,18 +436,74 @@
_loadCart: function () { _loadCart: function () {
var cartKey = "eskaera_" + this.orderId + "_cart"; var cartKey = "eskaera_" + this.orderId + "_cart";
var savedCart = localStorage.getItem(cartKey); var raw = localStorage.getItem(cartKey);
this.cart = savedCart ? JSON.parse(savedCart) : {}; this.cart = {};
console.log("Cart loaded from localStorage[" + cartKey + "]:", this.cart); if (!raw) {
console.log("Raw localStorage value:", savedCart); console.log("Cart loaded: localStorage[" + cartKey + "] is empty");
return;
}
var parsed;
try {
parsed = JSON.parse(raw);
} catch (e) {
console.warn("Cart load: invalid JSON in localStorage, dropping", e);
localStorage.removeItem(cartKey);
return;
}
// Legacy / corrupt shape (raw items object without cycle stamp) → drop.
if (
!parsed ||
typeof parsed !== "object" ||
!parsed.items ||
!("cutoff_date" in parsed)
) {
console.log(
"Cart load: legacy/unstamped value, dropping localStorage[" + cartKey + "]"
);
localStorage.removeItem(cartKey);
return;
}
// Cycle mismatch (or no current cycle known) → drop. This is the
// primary defence against stale carts surviving cycle rollover.
if (!this._currentCutoffDate || parsed.cutoff_date !== this._currentCutoffDate) {
console.log(
"Cart load: cycle mismatch (stored=" +
parsed.cutoff_date +
", current=" +
this._currentCutoffDate +
"), dropping localStorage[" +
cartKey +
"]"
);
localStorage.removeItem(cartKey);
return;
}
this.cart = parsed.items;
console.log(
"Cart loaded from localStorage[" +
cartKey +
"] (cycle " +
parsed.cutoff_date +
"):",
this.cart
);
}, },
_saveCart: function () { _saveCart: function () {
var cartKey = "eskaera_" + this.orderId + "_cart"; var cartKey = "eskaera_" + this.orderId + "_cart";
var cartJson = JSON.stringify(this.cart); var payload = JSON.stringify({
localStorage.setItem(cartKey, cartJson); cutoff_date: this._currentCutoffDate || null,
console.log("Cart saved to localStorage[" + cartKey + "]:", this.cart); items: this.cart,
console.log("Verification - immediately read back:", localStorage.getItem(cartKey)); });
localStorage.setItem(cartKey, payload);
console.log(
"Cart saved to localStorage[" +
cartKey +
"] (cycle " +
(this._currentCutoffDate || "unknown") +
"):",
this.cart
);
}, },
_clearCurrentOrderCartSilently: function () { _clearCurrentOrderCartSilently: function () {
@ -493,11 +549,15 @@
xhr.onload = function () { xhr.onload = function () {
if (xhr.status !== 200) { if (xhr.status !== 200) {
self._currentCutoffDate = null;
done(); done();
return; return;
} }
try { try {
var data = JSON.parse(xhr.responseText || "{}"); var data = JSON.parse(xhr.responseText || "{}");
// Capture current cycle marker so _loadCart can evict a
// localStorage cart that belongs to a previous cycle.
self._currentCutoffDate = data && data.cutoff_date ? data.cutoff_date : null;
// Clear cart if order is closed, action requests clearance, or cutoff already passed // Clear cart if order is closed, action requests clearance, or cutoff already passed
var shouldClear = false; var shouldClear = false;
if (data) { if (data) {
@ -527,12 +587,14 @@
} }
} }
} catch (e) { } catch (e) {
self._currentCutoffDate = null;
console.warn("[groupOrderShop] check-status parse error", e); console.warn("[groupOrderShop] check-status parse error", e);
} }
done(); done();
}; };
xhr.onerror = function () { xhr.onerror = function () {
self._currentCutoffDate = null;
done(); done();
}; };