odoo18/addons/website_sale/controllers/combo_configurator.py

137 lines
6.1 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _
from odoo.exceptions import UserError
from odoo.http import request, route
from odoo.tools.image import image_data_uri
from odoo.addons.sale.controllers.combo_configurator import SaleComboConfiguratorController
from odoo.addons.website_sale.controllers.main import WebsiteSale
class WebsiteSaleComboConfiguratorController(SaleComboConfiguratorController, WebsiteSale):
@route(
route='/website_sale/combo_configurator/get_data',
type='json',
auth='public',
website=True,
)
def website_sale_combo_configurator_get_data(self, *args, **kwargs):
self._populate_currency_and_pricelist(kwargs)
request.update_context(display_default_code=False) # Hide internal product reference
res = super().sale_combo_configurator_get_data(*args, **kwargs)
is_quantity_view_enabled = request.website.is_view_active('website_sale.product_quantity')
res.update({
'show_quantity': (
# if view doesn't exist default to true
is_quantity_view_enabled if is_quantity_view_enabled is not None else True
),
})
return res
@route(
route='/website_sale/combo_configurator/get_price',
type='json',
auth='public',
website=True,
)
def website_sale_combo_configurator_get_price(self, *args, **kwargs):
self._populate_currency_and_pricelist(kwargs)
return super().sale_combo_configurator_get_price(*args, **kwargs)
@route(
route='/website_sale/combo_configurator/update_cart',
type='json',
auth='public',
methods=['POST'],
website=True,
)
def website_sale_combo_configurator_update_cart(
self, combo_product_id, quantity, selected_combo_items, **kwargs
):
""" Add the provided combo product and selected combo items to the cart.
:param int combo_product_id: The combo product to add, as a `product.product` id.
:param int quantity: The quantity to add.
:param list(dict) selected_combo_items: The selected combo items to add.
:param dict kwargs: Locally unused data passed to `_cart_update`.
:rtype: dict
:return: A dict containing information about the cart update.
"""
if not selected_combo_items:
raise UserError(_("A combo product can't be empty. Please select at least one option."))
order_sudo = request.website.sale_get_order(force_create=True)
if order_sudo.state != 'draft':
request.session['sale_order_id'] = None
order_sudo = request.website.sale_get_order(force_create=True)
combo_quantity, warning = order_sudo._verify_updated_quantity(
request.env['sale.order.line'], combo_product_id, quantity, **kwargs
)
# A combo product and its items should have the same quantity (by design). So, if the
# requested quantity isn't available for one or more combo items, we should lower the
# quantity of the combo product and its items to the maximum available quantity of the
# combo item with the least available quantity.
for combo_item in selected_combo_items:
combo_item_quantity, warning = order_sudo._verify_updated_quantity(
request.env['sale.order.line'], combo_item['product_id'], quantity, **kwargs
)
combo_quantity = min(combo_quantity, combo_item_quantity)
values = order_sudo._cart_update(
product_id=combo_product_id,
set_qty=combo_quantity,
**kwargs,
)
line_ids = [values['line_id']]
if selected_combo_items and values['line_id']:
for combo_item in selected_combo_items:
item_values = order_sudo._cart_update(
product_id=combo_item['product_id'],
set_qty=combo_quantity,
product_custom_attribute_values=combo_item['product_custom_attribute_values'],
no_variant_attribute_value_ids=[
int(value_id) for value_id in combo_item['no_variant_attribute_value_ids']
],
linked_line_id=values['line_id'],
combo_item_id=combo_item['combo_item_id'],
**kwargs,
)
line_ids.append(item_values['line_id'])
# The price of a combo product (and thus whether it can be added to the cart) can only be
# computed after creating all of its combo item lines.
combo_product_line = request.env['sale.order.line'].browse(values['line_id'])
if (
combo_product_line
and sum(combo_product_line._get_lines_with_price().mapped('price_unit')) == 0
and combo_product_line.order_id.website_id.prevent_zero_price_sale
):
raise UserError(_(
"The given product does not have a price therefore it cannot be added to cart.",
))
values['notification_info'] = self._get_cart_notification_information(order_sudo, line_ids)
values['cart_quantity'] = order_sudo.cart_quantity
request.session['website_sale_cart_quantity'] = order_sudo.cart_quantity
return values
def _get_combo_item_data(
self, combo, combo_item, selected_combo_item, date, currency, pricelist, **kwargs
):
data = super()._get_combo_item_data(
combo, combo_item, selected_combo_item, date, currency, pricelist, **kwargs
)
# To sell a product type 'combo', one doesn't need to publish all combo choices. This causes
# an issue when public users access the image of each choice via the /web/image route. To
# bypass this access check, we send the raw image URL if the product is inaccessible to the
# current user.
if (
not combo_item.product_id.sudo(False).has_access('read')
and (combo_item_image := combo_item.product_id.image_256)
):
data['product']['image_src'] = image_data_uri(combo_item_image)
return data