The "shop as a read-only catalog" behaviour lived inside website_sale_aplicoop, so every site that wanted the eskaera flow also lost the standard cart. It now ships as its own installable addon, with the redirect target configurable instead of hardcoded to /eskaera. - website_sale_disable_cart: hides the cart UI (12 header styles + the product card quick-add) and overrides the standard cart endpoints. Redirect URL is configurable in Website settings (default /shop); only site-internal paths are accepted, so a misconfigured value cannot turn the shop into an open redirect nor loop back into a disabled route. - Fixes carried over from the original code: /shop/cart/quantity is the Odoo 18 path (it was /shop/cart_quantity, which never matched), the boxed, sidebar and sales two/three/four headers were not covered (the cart link stayed visible on them), and the routes now override the standard methods instead of registering duplicate ones. - website_sale_aplicoop 18.0.1.12.0: drops the view file and the four redirect routes; installing it no longer touches the standard shop. Upgrade order matters: update website_sale_aplicoop first, then install website_sale_disable_cart in a second Odoo run — both use the same XPaths and obsolete records are only cleaned up at the end of a run. Tests: 8/8 in website_sale_disable_cart, aplicoop unaffected (its 2 failures predate this change). Verified live on a DB clone: /shop/cart returns 303 to the configured URL and no cart markup remains on /shop. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
102 lines
3.3 KiB
Python
102 lines
3.3 KiB
Python
# Copyright 2026 Criptomart
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
import logging
|
|
|
|
from odoo import http
|
|
from odoo.http import request
|
|
|
|
from odoo.addons.website_sale.controllers.main import WebsiteSale
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
DEFAULT_REDIRECT_URL = "/shop"
|
|
REDIRECT_URL_PARAM = "website_sale_disable_cart.redirect_url"
|
|
|
|
|
|
class WebsiteSaleDisableCart(WebsiteSale):
|
|
"""Neutralize the standard ``website_sale`` cart endpoints.
|
|
|
|
The shop keeps working as a plain catalog (listing, search and product
|
|
pages are untouched); only the cart itself becomes unreachable. HTTP
|
|
routes redirect to the configured URL, JSON routes answer with an inert
|
|
payload so any leftover frontend call is a no-op instead of an error.
|
|
"""
|
|
|
|
def _get_cart_redirect_url(self):
|
|
"""Return the internal path the disabled cart routes redirect to."""
|
|
url = (
|
|
request.env["ir.config_parameter"]
|
|
.sudo()
|
|
.get_param(REDIRECT_URL_PARAM, DEFAULT_REDIRECT_URL)
|
|
)
|
|
url = (url or "").strip()
|
|
# Only site-internal paths are accepted: an absolute or protocol
|
|
# relative URL would turn the shop into an open redirect, and a path
|
|
# back under /shop/cart would loop through the disabled routes.
|
|
if (
|
|
not url.startswith("/")
|
|
or url.startswith("//")
|
|
or url.startswith("/shop/cart")
|
|
):
|
|
_logger.warning(
|
|
"[DISABLE_CART] Invalid redirect URL %r, falling back to %s",
|
|
url,
|
|
DEFAULT_REDIRECT_URL,
|
|
)
|
|
return DEFAULT_REDIRECT_URL
|
|
return url
|
|
|
|
def _redirect_disabled_cart(self, route):
|
|
"""Redirect a disabled cart route to the configured URL."""
|
|
url = self._get_cart_redirect_url()
|
|
_logger.info("[DISABLE_CART] %s → %s", route, url)
|
|
return request.redirect(url)
|
|
|
|
@http.route()
|
|
def cart(self, access_token=None, revive="", **post):
|
|
"""Cart page is disabled: send the visitor to the configured URL."""
|
|
return self._redirect_disabled_cart("/shop/cart")
|
|
|
|
@http.route()
|
|
def cart_update(
|
|
self,
|
|
product_id=None,
|
|
add_qty=1,
|
|
set_qty=0,
|
|
product_custom_attribute_values=None,
|
|
no_variant_attribute_value_ids=None,
|
|
**kwargs,
|
|
):
|
|
"""Adding to cart is disabled: nothing is written, just redirect."""
|
|
return self._redirect_disabled_cart("/shop/cart/update")
|
|
|
|
@http.route()
|
|
def cart_update_json(
|
|
self,
|
|
product_id=None,
|
|
line_id=None,
|
|
add_qty=None,
|
|
set_qty=None,
|
|
display=True,
|
|
product_custom_attribute_values=None,
|
|
no_variant_attribute_value_ids=None,
|
|
**kwargs,
|
|
):
|
|
"""Adding to cart is disabled.
|
|
|
|
An empty dict is the response ``website_sale`` already returns when the
|
|
order cannot be updated, so callers handle it without breaking.
|
|
"""
|
|
_logger.info("[DISABLE_CART] /shop/cart/update_json ignored")
|
|
return {}
|
|
|
|
@http.route()
|
|
def cart_quantity(self):
|
|
"""The cart is always empty while this module is installed."""
|
|
return 0
|
|
|
|
@http.route()
|
|
def clear_cart(self):
|
|
"""Nothing to clear: the cart is never fed through the standard shop."""
|
|
return None
|