From 6e6d9f3b63a265f4656a0294ceca29d0719e12c3 Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Mon, 17 Jan 2022 15:43:46 +0000 Subject: [PATCH] [IMP] website_sale*: methods/routes cleanup * consistent/clear sale_get_order params (force_create is a boolean value, do not provide integers) * use one coherent way to get website current pricelist, through the dedicated computed field Part-of: odoo/odoo#82374 --- .../controllers/event_booth.py | 12 +- addons/website_event_sale/controllers/main.py | 26 +++-- addons/website_sale/controllers/main.py | 108 +++++++++--------- .../controllers/main.py | 16 +-- .../models/sale_order.py | 11 +- .../controllers/main.py | 4 +- .../models/sale_order.py | 14 +-- .../website_sale_stock/models/sale_order.py | 3 +- addons/website_sale_stock/models/website.py | 2 +- .../website_sale_wishlist/controllers/main.py | 36 +++--- 10 files changed, 116 insertions(+), 116 deletions(-) diff --git a/addons/website_event_booth_sale/controllers/event_booth.py b/addons/website_event_booth_sale/controllers/event_booth.py index f7160d7abad..9c06f02e68c 100644 --- a/addons/website_event_booth_sale/controllers/event_booth.py +++ b/addons/website_event_booth_sale/controllers/event_booth.py @@ -2,23 +2,21 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import json -import werkzeug -from odoo import http -from odoo.http import request +from odoo.http import request, route from odoo.addons.website_event.controllers.main import WebsiteEventController class WebsiteEventBoothController(WebsiteEventController): - @http.route() + @route() def event_booth_main(self, event): - pricelist = request.website.get_current_pricelist() + pricelist = request.website.pricelist_id if pricelist: event = event.with_context(pricelist=pricelist.id) return super(WebsiteEventBoothController, self).event_booth_main(event) - @http.route() + @route() def event_booth_registration_confirm(self, event, booth_category_id, event_booth_ids, **kwargs): """Override: Doesn't call the parent method because we go through the checkout process which will confirm the booths when receiving the payment.""" @@ -31,7 +29,7 @@ class WebsiteEventBoothController(WebsiteEventController): return json.dumps({'error': 'boothCategoryError'}) booth_values = self._prepare_booth_registration_values(event, kwargs) - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order(force_create=True) order._cart_update( product_id=booth_category.product_id.id, set_qty=1, diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py index 088873a74bb..bdf277ff6aa 100644 --- a/addons/website_event_sale/controllers/main.py +++ b/addons/website_event_sale/controllers/main.py @@ -1,25 +1,26 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import http, _ +from odoo import _ +from odoo.http import request, route + from odoo.addons.website_event.controllers.main import WebsiteEventController -from odoo.http import request class WebsiteEventSaleController(WebsiteEventController): - @http.route() + @route() def event_register(self, event, **post): event = event.with_context(pricelist=request.website.id) if not request.context.get('pricelist'): - pricelist = request.website.get_current_pricelist() + pricelist = request.website.pricelist_id if pricelist: event = event.with_context(pricelist=pricelist.id) - return super(WebsiteEventSaleController, self).event_register(event, **post) + return super().event_register(event, **post) def _process_tickets_form(self, event, form_details): """ Add price information on ticket order """ - res = super(WebsiteEventSaleController, self)._process_tickets_form(event, form_details) + res = super()._process_tickets_form(event, form_details) for item in res: item['price'] = item['ticket']['price'] if item['ticket'] else 0 return res @@ -27,7 +28,8 @@ class WebsiteEventSaleController(WebsiteEventController): def _create_attendees_from_registration_post(self, event, registration_data): # we have at least one registration linked to a ticket -> sale mode activate if any(info.get('event_ticket_id') for info in registration_data): - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order(force_create=True) + for info in [r for r in registration_data if r.get('event_ticket_id')]: ticket = request.env['event.event.ticket'].sudo().browse(info['event_ticket_id']) @@ -35,17 +37,17 @@ class WebsiteEventSaleController(WebsiteEventController): info['sale_order_id'] = order.id info['sale_order_line_id'] = cart_values.get('line_id') - return super(WebsiteEventSaleController, self)._create_attendees_from_registration_post(event, registration_data) + return super()._create_attendees_from_registration_post(event, registration_data) - @http.route() + @route() def registration_confirm(self, event, **post): - res = super(WebsiteEventSaleController, self).registration_confirm(event, **post) + res = super().registration_confirm(event, **post) registrations = self._process_attendees_form(event, post) # we have at least one registration linked to a ticket -> sale mode activate if any(info['event_ticket_id'] for info in registrations): - order = request.website.sale_get_order(force_create=False) + order = request.website.sale_get_order() if order.amount_total: return request.redirect("/shop/checkout") # free tickets -> order with amount = 0: auto-confirm, no checkout @@ -56,7 +58,7 @@ class WebsiteEventSaleController(WebsiteEventController): return res def _prepare_event_values(self, name, event_start, event_end, address_values=None): - values = super(WebsiteEventSaleController, self)._prepare_event_values(name, event_start, event_end, address_values) + values = super()._prepare_event_values(name, event_start, event_end, address_values) product = request.env.ref('event_sale.product_product_event', raise_if_not_found=False) if product: values.update({ diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index d553b6cae5f..50d14aa82b4 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -125,7 +125,7 @@ class Website(main.Website): def autocomplete(self, search_type=None, term=None, order=None, limit=5, max_nb_chars=999, options=None): options = options or {} if 'display_currency' not in options: - options['display_currency'] = request.website.get_current_pricelist().currency_id + options['display_currency'] = request.website.currency_id return super().autocomplete(search_type, term, order, limit, max_nb_chars, options) @http.route() @@ -153,17 +153,6 @@ class Website(main.Website): class WebsiteSale(http.Controller): - def _get_pricelist_context(self): - pricelist_context = dict(request.env.context) - pricelist = False - if not pricelist_context.get('pricelist'): - pricelist = request.website.get_current_pricelist() - pricelist_context['pricelist'] = pricelist.id - else: - pricelist = request.env['product.pricelist'].browse(pricelist_context['pricelist']) - - return pricelist_context, pricelist - def _get_search_order(self, post): # OrderBy will be parsed in orm and so no direct sql injection # id is added to be sure that order is a unique sort key @@ -217,10 +206,10 @@ class WebsiteSale(http.Controller): yield {'loc': loc} @http.route([ - '''/shop''', - '''/shop/page/''', - '''/shop/category/''', - '''/shop/category//page/''' + '/shop', + '/shop/page/', + '/shop/category/', + '/shop/category//page/', ], type='http', auth="public", website=True, sitemap=sitemap_shop) def shop(self, page=0, category=None, search='', min_price=0.0, max_price=0.0, ppg=False, **post): add_qty = int(post.get('add_qty', 1)) @@ -241,6 +230,7 @@ class WebsiteSale(http.Controller): else: category = Category + website = request.env['website'].get_current_website() if ppg: try: ppg = int(ppg) @@ -248,9 +238,9 @@ class WebsiteSale(http.Controller): except ValueError: ppg = False if not ppg: - ppg = request.env['website'].get_current_website().shop_ppg or 20 + ppg = website.shop_ppg or 20 - ppr = request.env['website'].get_current_website().shop_ppr or 4 + ppr = website.shop_ppr or 4 attrib_list = request.httprequest.args.getlist('attrib') attrib_values = [[int(x) for x in v.split("-")] for v in attrib_list if v] @@ -259,14 +249,15 @@ class WebsiteSale(http.Controller): keep = QueryURL('/shop', category=category and int(category), search=search, attrib=attrib_list, min_price=min_price, max_price=max_price, order=post.get('order')) - pricelist_context, pricelist = self._get_pricelist_context() + pricelist = website.get_current_pricelist() request.context = dict(request.context, pricelist=pricelist.id, partner=request.env.user.partner_id) - filter_by_price_enabled = request.website.is_view_active('website_sale.filter_products_price') + filter_by_price_enabled = website.is_view_active('website_sale.filter_products_price') if filter_by_price_enabled: - company_currency = request.website.company_id.currency_id - conversion_rate = request.env['res.currency']._get_conversion_rate(company_currency, pricelist.currency_id, request.website.company_id, fields.Date.today()) + company_currency = website.company_id.currency_id + conversion_rate = request.env['res.currency']._get_conversion_rate( + company_currency, pricelist.currency_id, request.website.company_id, fields.Date.today()) else: conversion_rate = 1 @@ -290,11 +281,11 @@ class WebsiteSale(http.Controller): 'display_currency': pricelist.currency_id, } # No limit because attributes are obtained from complete product list - product_count, details, fuzzy_search_term = request.website._search_with_fuzzy("products_only", search, + product_count, details, fuzzy_search_term = website._search_with_fuzzy("products_only", search, limit=None, order=self._get_search_order(post), options=options) search_product = details[0].get('results', request.env['product.template']).with_context(bin_size=True) - filter_by_price_enabled = request.website.is_view_active('website_sale.filter_products_price') + filter_by_price_enabled = website.is_view_active('website_sale.filter_products_price') if filter_by_price_enabled: # TODO Find an alternative way to obtain the domain through the search metadata. Product = request.env['product.template'].with_context(bin_size=True) @@ -324,10 +315,12 @@ class WebsiteSale(http.Controller): max_price = max_price if max_price >= available_min_price else available_max_price post['max_price'] = max_price - website_domain = request.website.website_domain() + website_domain = website.website_domain() categs_domain = [('parent_id', '=', False)] + website_domain if search: - search_categories = Category.search([('product_tmpl_ids', 'in', search_product.ids)] + website_domain).parents_and_self + search_categories = Category.search( + [('product_tmpl_ids', 'in', search_product.ids)] + website_domain + ).parents_and_self categs_domain.append(('id', 'in', search_categories.ids)) else: search_categories = Category @@ -336,7 +329,7 @@ class WebsiteSale(http.Controller): if category: url = "/shop/category/%s" % slug(category) - pager = request.website.pager(url=url, total=product_count, page=page, step=ppg, scope=7, url_args=post) + pager = website.pager(url=url, total=product_count, page=page, step=ppg, scope=7, url_args=post) offset = pager['offset'] products = search_product[offset:offset + ppg] @@ -352,7 +345,7 @@ class WebsiteSale(http.Controller): layout_mode = request.session.get('website_sale_shop_layout_mode') if not layout_mode: - if request.website.viewref('website_sale.products_list_view').active: + if website.viewref('website_sale.products_list_view').active: layout_mode = 'list' else: layout_mode = 'grid' @@ -475,8 +468,8 @@ class WebsiteSale(http.Controller): redirect = post.get('r', '/shop/cart') # empty promo code is used to reset/remove pricelist (see `sale_get_order()`) if promo: - pricelist = request.env['product.pricelist'].sudo().search([('code', '=', promo)], limit=1) - if (not pricelist or (pricelist and not request.website.is_pricelist_available(pricelist.id))): + pricelist_sudo = request.env['product.pricelist'].sudo().search([('code', '=', promo)], limit=1) + if not (pricelist_sudo and request.website.is_pricelist_available(pricelist_sudo.id)): return request.redirect("%s?code_not_available=1" % redirect) request.website.sale_get_order(code=promo) @@ -528,20 +521,22 @@ class WebsiteSale(http.Controller): return request.render("website_sale.cart", values) @http.route(['/shop/cart/update'], type='http', auth="public", methods=['POST'], website=True) - def cart_update(self, product_id, add_qty=1, set_qty=0, **kw): + def cart_update( + self, product_id, add_qty=1, set_qty=0, + product_custom_attribute_values=None, no_variant_attribute_values=None, + express=False, **kwargs + ): """This route is called when adding a product to cart (no options).""" sale_order = request.website.sale_get_order(force_create=True) if sale_order.state != 'draft': request.session['sale_order_id'] = None sale_order = request.website.sale_get_order(force_create=True) - product_custom_attribute_values = None - if kw.get('product_custom_attribute_values'): - product_custom_attribute_values = json_scriptsafe.loads(kw.get('product_custom_attribute_values')) + if product_custom_attribute_values: + product_custom_attribute_values = json_scriptsafe.loads(product_custom_attribute_values) - no_variant_attribute_values = None - if kw.get('no_variant_attribute_values'): - no_variant_attribute_values = json_scriptsafe.loads(kw.get('no_variant_attribute_values')) + if no_variant_attribute_values: + no_variant_attribute_values = json_scriptsafe.loads(no_variant_attribute_values) sale_order._cart_update( product_id=int(product_id), @@ -551,7 +546,7 @@ class WebsiteSale(http.Controller): no_variant_attribute_values=no_variant_attribute_values ) - if kw.get('express'): + if express: return request.redirect("/shop/checkout?express=1") return request.redirect("/shop/cart") @@ -564,17 +559,17 @@ class WebsiteSale(http.Controller): - When adding a product from the wishlist. - When adding a product to cart on the same page (without redirection). """ - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order(force_create=True) if order.state != 'draft': request.website.sale_reset() if kw.get('force_create'): - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order(force_create=True) else: return {} pcav = kw.get('product_custom_attribute_values') nvav = kw.get('no_variant_attribute_values') - value = order._cart_update( + values = order._cart_update( product_id=product_id, line_id=line_id, add_qty=add_qty, @@ -585,23 +580,26 @@ class WebsiteSale(http.Controller): if not order.cart_quantity: request.website.sale_reset() - return value + return values - order = request.website.sale_get_order() - value['cart_quantity'] = order.cart_quantity + values['cart_quantity'] = order.cart_quantity if not display: - return value + return values - value['website_sale.cart_lines'] = request.env['ir.ui.view']._render_template("website_sale.cart_lines", { - 'website_sale_order': order, - 'date': fields.Date.today(), - 'suggested_products': order._cart_accessories() - }) - value['website_sale.short_cart_summary'] = request.env['ir.ui.view']._render_template("website_sale.short_cart_summary", { - 'website_sale_order': order, - }) - return value + values['website_sale.cart_lines'] = request.env['ir.ui.view']._render_template( + "website_sale.cart_lines", { + 'website_sale_order': order, + 'date': fields.Date.today(), + 'suggested_products': order._cart_accessories() + } + ) + values['website_sale.short_cart_summary'] = request.env['ir.ui.view']._render_template( + "website_sale.short_cart_summary", { + 'website_sale_order': order, + } + ) + return values @http.route('/shop/save_shop_layout_mode', type='json', auth='public', website=True) def save_shop_layout_mode(self, layout_mode): @@ -637,7 +635,7 @@ class WebsiteSale(http.Controller): return request.redirect('/shop/payment/confirmation/%s' % order.id) def checkout_values(self, **kw): - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order(force_create=True) shippings = [] if order.partner_id != request.website.user_id.sudo().partner_id: Partner = order.partner_id.with_context(show_address=1).sudo() diff --git a/addons/website_sale_comparison/controllers/main.py b/addons/website_sale_comparison/controllers/main.py index eddc0fba853..e5b4e014a3c 100644 --- a/addons/website_sale_comparison/controllers/main.py +++ b/addons/website_sale_comparison/controllers/main.py @@ -21,19 +21,21 @@ class WebsiteSaleProductComparison(WebsiteSale): @http.route(['/shop/get_product_data'], type='json', auth="public", website=True) def get_product_data(self, product_ids, cookies=None): ret = {} - pricelist_context, pricelist = self._get_pricelist_context() - prods = request.env['product.product'].with_context(pricelist_context, display_default_code=False).search([('id', 'in', product_ids)]) + + website = request.env['website'].get_current_website() + pricelist = website.pricelist_id + products = request.env['product.product'].search([('id', 'in', product_ids)]) if cookies is not None: ret['cookies'] = json.dumps(request.env['product.product'].search([('id', 'in', list(set(product_ids + cookies)))]).ids) - prods.mapped('name') - for prod in prods: - ret[prod.id] = { + products = products.with_context(pricelist=pricelist.id, display_default_code=False) + for product in products: + ret[product.id] = { 'render': request.env['ir.ui.view']._render_template( "website_sale_comparison.product_product", - {'product': prod, 'website': request.website} + {'product': product, 'website': website} ), - 'product': dict(id=prod.id, name=prod.name, display_name=prod.display_name), + 'product': dict(id=product.id, name=product.name, display_name=product.display_name), } return ret diff --git a/addons/website_sale_delivery/models/sale_order.py b/addons/website_sale_delivery/models/sale_order.py index f7f1d5abafc..637fb024c5a 100644 --- a/addons/website_sale_delivery/models/sale_order.py +++ b/addons/website_sale_delivery/models/sale_order.py @@ -1,11 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import logging from odoo import api, fields, models -_logger = logging.getLogger(__name__) - class SaleOrder(models.Model): _inherit = 'sale.order' @@ -79,13 +76,13 @@ class SaleOrder(models.Model): def _cart_update(self, *args, **kwargs): """ Override to update carrier quotation if quantity changed """ - self._remove_delivery_line() - # When you update a cart, it is not enouf to remove the "delivery cost" line + # When you update a cart, it is not enough to remove the "delivery cost" line # The carrier might also be invalid, eg: if you bought things that are too heavy # -> this may cause a bug if you go to the checkout screen, choose a carrier, # then update your cart (the cart becomes uneditable) - self.write({'carrier_id': False}) + if self.carrier_id: + self.carrier_id = False - return super(SaleOrder, self)._cart_update(*args, **kwargs) + return super()._cart_update(*args, **kwargs) diff --git a/addons/website_sale_product_configurator/controllers/main.py b/addons/website_sale_product_configurator/controllers/main.py index 11241642138..eb29fbf4af4 100644 --- a/addons/website_sale_product_configurator/controllers/main.py +++ b/addons/website_sale_product_configurator/controllers/main.py @@ -26,7 +26,7 @@ class WebsiteSaleProductConfiguratorController(ProductConfiguratorController): return False if variant_values: kw["already_configured"] = True - return self.show_advanced_configurator(product_id, variant_values, request.website.get_current_pricelist(), **kw) + return self.show_advanced_configurator(product_id, variant_values, request.website.pricelist_id, **kw) @http.route(['/sale_product_configurator/optional_product_items_website'], type='json', auth="public", methods=['POST'], website=True) def optional_product_items_website(self, product_id, **kw): @@ -34,7 +34,7 @@ class WebsiteSaleProductConfiguratorController(ProductConfiguratorController): This route is called in JS by appending _website to the base route. """ kw.pop('pricelist_id') - return self.optional_product_items(product_id, request.website.get_current_pricelist(), **kw) + return self.optional_product_items(product_id, request.website.pricelist_id, **kw) class WebsiteSale(main.WebsiteSale): diff --git a/addons/website_sale_product_configurator/models/sale_order.py b/addons/website_sale_product_configurator/models/sale_order.py index 3d25c8f9769..9b853e8927c 100644 --- a/addons/website_sale_product_configurator/models/sale_order.py +++ b/addons/website_sale_product_configurator/models/sale_order.py @@ -1,24 +1,24 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, models +from odoo import models class SaleOrder(models.Model): _inherit = "sale.order" - def _cart_find_product_line(self, product_id=None, line_id=None, **kwargs): - lines = super(SaleOrder, self)._cart_find_product_line(product_id, line_id, **kwargs) + def _cart_find_product_line( + self, product_id=None, line_id=None, + linked_line_id=False, optional_product_ids=None, **kwargs + ): + lines = super()._cart_find_product_line(product_id, line_id, **kwargs) if line_id: # in this case we get the exact line we want, so filtering below would be wrong return lines - linked_line_id = kwargs.get('linked_line_id', False) - optional_product_ids = set(kwargs.get('optional_product_ids', [])) - lines = lines.filtered(lambda line: line.linked_line_id.id == linked_line_id) if optional_product_ids: # only match the lines with the same chosen optional products on the existing lines - lines = lines.filtered(lambda line: optional_product_ids == set(line.mapped('option_line_ids.product_id.id'))) + lines = lines.filtered(lambda line: optional_product_ids == set(line.option_line_ids.product_id.id)) else: lines = lines.filtered(lambda line: not line.option_line_ids) diff --git a/addons/website_sale_stock/models/sale_order.py b/addons/website_sale_stock/models/sale_order.py index 9240c52d222..115f28b00fd 100644 --- a/addons/website_sale_stock/models/sale_order.py +++ b/addons/website_sale_stock/models/sale_order.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models, api, fields -from odoo.tools.translate import _ +from odoo import fields, models, _ class SaleOrder(models.Model): diff --git a/addons/website_sale_stock/models/website.py b/addons/website_sale_stock/models/website.py index b83f941ae94..832141dba77 100644 --- a/addons/website_sale_stock/models/website.py +++ b/addons/website_sale_stock/models/website.py @@ -18,7 +18,7 @@ class Website(models.Model): def _get_warehouse_available(self): return ( - self.warehouse_id and self.warehouse_id.id or + self.warehouse_id.id or self.env['ir.default'].get('sale.order', 'warehouse_id', company_id=self.company_id.id) or self.env['ir.default'].get('sale.order', 'warehouse_id') or self.env['stock.warehouse'].sudo().search([('company_id', '=', self.company_id.id)], limit=1).id diff --git a/addons/website_sale_wishlist/controllers/main.py b/addons/website_sale_wishlist/controllers/main.py index 05f1c984831..b195c93302b 100644 --- a/addons/website_sale_wishlist/controllers/main.py +++ b/addons/website_sale_wishlist/controllers/main.py @@ -1,18 +1,22 @@ # -*- coding: utf-8 -*- -from odoo import http -from odoo.http import request -from odoo.addons.website_sale.controllers.main import WebsiteSale + import json +from odoo.http import request, route +from odoo.addons.website_sale.controllers.main import WebsiteSale + class WebsiteSaleWishlist(WebsiteSale): - @http.route(['/shop/wishlist/add'], type='json', auth="public", website=True) - def add_to_wishlist(self, product_id, price=False, **kw): - if not price: - pricelist_context, pl = self._get_pricelist_context() - p = request.env['product.product'].with_context(pricelist_context, display_default_code=False).browse(product_id) - price = p._get_combination_info_variant()['price'] + @route(['/shop/wishlist/add'], type='json', auth="public", website=True) + def add_to_wishlist(self, product_id, **kw): + website = request.env['website'].get_current_website() + pricelist = website.pricelist_id + product = request.env['product.product'].browse(product_id) + + price = product._get_combination_info_variant( + pricelist=website.pricelist_id, + )['price'] Wishlist = request.env['product.wishlist'] if request.website.is_public_user(): @@ -21,9 +25,9 @@ class WebsiteSaleWishlist(WebsiteSale): else: partner_id = request.env.user.partner_id.id - wish_id = Wishlist._add_to_wishlist( - pl.id, - pl.currency_id.id, + wish = Wishlist._add_to_wishlist( + pricelist.id, + pricelist.currency_id.id, request.website.id, price, product_id, @@ -31,11 +35,11 @@ class WebsiteSaleWishlist(WebsiteSale): ) if not partner_id: - request.session['wishlist_ids'] = request.session.get('wishlist_ids', []) + [wish_id.id] + request.session['wishlist_ids'] = request.session.get('wishlist_ids', []) + [wish.id] - return wish_id + return wish - @http.route(['/shop/wishlist'], type='http', auth="public", website=True, sitemap=False) + @route(['/shop/wishlist'], type='http', auth="public", website=True, sitemap=False) def get_wishlist(self, count=False, **kw): values = request.env['product.wishlist'].with_context(display_default_code=False).current() if count: @@ -46,7 +50,7 @@ class WebsiteSaleWishlist(WebsiteSale): return request.render("website_sale_wishlist.product_wishlist", dict(wishes=values)) - @http.route(['/shop/wishlist/remove/'], type='json', auth="public", website=True) + @route(['/shop/wishlist/remove/'], type='json', auth="public", website=True) def rm_from_wishlist(self, wish, **kw): if request.website.is_public_user(): wish_ids = request.session.get('wishlist_ids') or []