website_sale_stock/models/sale_order.py

123 lines
5.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _, models
from odoo.exceptions import ValidationError
class SaleOrder(models.Model):
_inherit = 'sale.order'
def _get_warehouse_available(self):
self.ensure_one()
warehouse = self.website_id._get_warehouse_available()
if not warehouse and self.user_id and self.company_id:
warehouse = self.user_id.with_company(self.company_id.id)._get_default_warehouse_id()
if not warehouse:
warehouse = self.env.user._get_default_warehouse_id()
return warehouse
def _compute_warehouse_id(self):
website_orders = self.filtered('website_id')
super(SaleOrder, self - website_orders)._compute_warehouse_id()
for order in website_orders:
order.warehouse_id = order._get_warehouse_available()
def _verify_updated_quantity(self, order_line, product_id, new_qty, **kwargs):
self.ensure_one()
product = self.env['product.product'].browse(product_id)
if product.type == 'product' and not product.allow_out_of_stock_order:
product_qty_in_cart, available_qty = self._get_cart_and_free_qty(
product, line=order_line
)
old_qty = order_line.product_uom_qty if order_line else 0
added_qty = new_qty - old_qty
total_cart_qty = product_qty_in_cart + added_qty
if available_qty < total_cart_qty:
allowed_line_qty = available_qty - (product_qty_in_cart - old_qty)
if allowed_line_qty > 0:
if order_line:
order_line._set_shop_warning_stock(total_cart_qty, available_qty)
else:
self._set_shop_warning_stock(total_cart_qty, available_qty)
returned_warning = order_line.shop_warning or self.shop_warning
else: # 0 or negative allowed_qty
# if existing line: it will be deleted
# if no existing line: no line will be created
if order_line:
self.shop_warning = _(
"Some products became unavailable and your cart has been updated. We're"
" sorry for the inconvenience."
)
returned_warning = self.shop_warning
else:
returned_warning = _(
"The item has not been added to your cart since it is not available."
)
return allowed_line_qty, returned_warning
return super()._verify_updated_quantity(order_line, product_id, new_qty, **kwargs)
def _get_cart_and_free_qty(self, product, line=None):
""" Get cart quantity and free quantity for given product or line's product.
Note: self.ensure_one()
:param ProductProduct product: The product
:param SaleOrderLine line: The optional line
"""
self.ensure_one()
if not line and not product:
return 0, 0
cart_qty = sum(self._get_common_product_lines(line, product).mapped('product_uom_qty'))
free_qty = (product or line.product_id).with_context(warehouse=self.warehouse_id.id).free_qty
return cart_qty, free_qty
def _get_common_product_lines(self, line=None, product=None):
""" Get the lines with the same product or line's product
:param SaleOrderLine line: The optional line
:param ProductProduct product: The optional product
"""
if not line and not product:
return self.env['sale.order.line']
product = product or line.product_id
return self.order_line.filtered(lambda l: l.product_id == product)
def _check_cart_is_ready_to_be_paid(self):
values = []
for line in self.order_line:
if line.product_id.type == 'product' and not line.product_id.allow_out_of_stock_order:
cart_qty, avl_qty = self._get_cart_and_free_qty(line.product_id, line=line)
if cart_qty > avl_qty:
line._set_shop_warning_stock(cart_qty, max(avl_qty, 0))
values.append(line.shop_warning)
if values:
raise ValidationError(' '.join(values))
return super()._check_cart_is_ready_to_be_paid()
def _set_shop_warning_stock(self, desired_qty, new_qty):
self.ensure_one()
self.shop_warning = _(
'You ask for %(desired_qty)s products but only %(new_qty)s is available',
desired_qty=desired_qty, new_qty=new_qty
)
return self.shop_warning
def _filter_can_send_abandoned_cart_mail(self):
""" Filter sale orders on their product availability. """
return super()._filter_can_send_abandoned_cart_mail().filtered(
lambda so: so._all_product_available()
)
def _all_product_available(self):
self.ensure_one()
for line in self.with_context(website_sale_stock_get_quantity=True).order_line:
product = line.product_id
if product.type != 'product' or product.allow_out_of_stock_order:
continue
free_qty = self.website_id._get_product_available_qty(product)
if free_qty == 0:
return False
return True