117 lines
5.2 KiB
Python
117 lines
5.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import models, _
|
|
|
|
|
|
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(
|
|
line=order_line, product=product, **kwargs
|
|
)
|
|
|
|
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)
|
|
else: # 0 or negative allowed_qty
|
|
# if existing line: it will be deleted
|
|
# if no existing line: no line will be created
|
|
self.shop_warning = _(
|
|
"Some products became unavailable and your cart has been updated. We're sorry for the inconvenience.")
|
|
return allowed_line_qty, order_line.shop_warning or self.shop_warning
|
|
return super()._verify_updated_quantity(order_line, product_id, new_qty, **kwargs)
|
|
|
|
def _get_cart_and_free_qty(self, line=None, product=None, **kwargs):
|
|
""" Get cart quantity and free quantity for given product or line's product.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:param SaleOrderLine line: The optional line
|
|
:param ProductProduct product: The optional product
|
|
"""
|
|
self.ensure_one()
|
|
if not line and not product:
|
|
return 0, 0
|
|
cart_qty = sum(
|
|
self._get_common_product_lines(line, product, **kwargs).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, **kwargs):
|
|
""" 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 _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 _get_cache_key_for_line(self, line):
|
|
return line.product_id
|
|
|
|
def _get_context_for_line(self, line):
|
|
return {
|
|
'website_sale_stock_get_quantity': True,
|
|
}
|
|
|
|
def _filter_can_send_abandoned_cart_mail(self):
|
|
""" Filter sale orders on their product availability. """
|
|
self = super()._filter_can_send_abandoned_cart_mail()
|
|
combination_info_cache = {}
|
|
|
|
def _are_all_product_available_for_purchase(sale_order):
|
|
for line in sale_order.order_line:
|
|
product = line.product_id
|
|
if product.type != 'product':
|
|
continue
|
|
cache_key = self._get_cache_key_for_line(line)
|
|
combination_info = combination_info_cache.get(cache_key)
|
|
if not combination_info:
|
|
combination_info = product.with_context(**self._get_context_for_line(line), website_id=sale_order.website_id.id)._get_combination_info_variant(add_qty=line.product_uom_qty)
|
|
combination_info_cache[cache_key] = combination_info
|
|
if not product.allow_out_of_stock_order and combination_info['free_qty'] == 0:
|
|
return False
|
|
return True
|
|
|
|
# If none of the products in the checkout are available for purchase (empty inventory, for example),
|
|
# then the email won't be sent.
|
|
return self.filtered(_are_all_product_available_for_purchase)
|