forked from Mapan/odoo17e
103 lines
4.8 KiB
Python
103 lines
4.8 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import timedelta
|
|
|
|
from odoo import _, fields, models
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = 'sale.order'
|
|
|
|
def _get_cart_and_free_qty(self, product, line=None):
|
|
""" Override to take the rental product specificity into account
|
|
|
|
For rental lines or product, the cart quantity is the maximum amount of the same product
|
|
rented at the same time. The free quantity is the minimum available quantity during the same
|
|
period plus the maximum cart quantity.
|
|
|
|
Note: self.ensure_one()
|
|
"""
|
|
if not product.rent_ok:
|
|
return super()._get_cart_and_free_qty(product, line=line)
|
|
from_date = self.rental_start_date and (
|
|
self.rental_start_date - timedelta(hours=product.preparation_time))
|
|
to_date = self.rental_return_date
|
|
common_lines = self._get_common_product_lines(line=line, product=product)
|
|
qty_available = product.with_context(
|
|
from_date=from_date, to_date=to_date, warehouse=self.warehouse_id.id
|
|
).qty_available
|
|
qty_available += product.with_context(warehouse=self.warehouse_id.id).qty_in_rent
|
|
product_rented_qties, product_key_dates = product._get_rented_quantities(
|
|
from_date, to_date, domain=[('order_id', '!=', self.id)]
|
|
)
|
|
so_rented_qties, so_key_dates = common_lines._get_rented_quantities([from_date, to_date])
|
|
current_cart_qty = max_cart_qty = 0
|
|
current_available_qty = min_available_qty = qty_available
|
|
key_dates = list(set(so_key_dates + product_key_dates))
|
|
key_dates.sort()
|
|
for i in range(1, len(key_dates)):
|
|
start_dt = key_dates[i-1]
|
|
if start_dt >= to_date:
|
|
break
|
|
current_cart_qty += so_rented_qties[start_dt] # defaultdict
|
|
current_available_qty -= product_rented_qties[start_dt] # defaultdict
|
|
max_cart_qty = max(max_cart_qty, current_cart_qty)
|
|
min_available_qty = min(min_available_qty, current_available_qty - current_cart_qty)
|
|
|
|
return max_cart_qty, max_cart_qty + min_available_qty
|
|
|
|
def _build_warning_renting(self, product):
|
|
""" Override to add the message regarding the preparation time
|
|
"""
|
|
message = super()._build_warning_renting(product)
|
|
reservation_begin = self.rental_start_date - timedelta(hours=product.preparation_time)
|
|
if reservation_begin < fields.Datetime.now() <= self.rental_start_date:
|
|
message += _("""Your rental product cannot be prepared on time, please rent later.""")
|
|
|
|
return message
|
|
|
|
def _verify_updated_quantity(self, order_line, product_id, new_qty, **kwargs):
|
|
""" Override to ensure the cart has dates before checking the stock validity. """
|
|
product = self.env['product.product'].browse(product_id)
|
|
if product.rent_ok and not self.has_rented_products:
|
|
if kwargs.get('start_date') and kwargs.get('end_date'):
|
|
self.update({
|
|
'rental_start_date': kwargs.get('start_date'),
|
|
'rental_return_date': kwargs.get('end_date'),
|
|
})
|
|
else:
|
|
self._rental_set_dates()
|
|
return super()._verify_updated_quantity(order_line, product_id, new_qty, **kwargs)
|
|
|
|
def _is_valid_renting_dates(self):
|
|
""" Override to take into account the preparation time."""
|
|
res = super()._is_valid_renting_dates()
|
|
rental_order_lines = self.order_line.filtered('reservation_begin')
|
|
if not rental_order_lines or not res:
|
|
return res
|
|
max_padding_time = max(rental_order_lines.product_id.mapped('preparation_time'), default=0)
|
|
initial_time = self.rental_start_date - timedelta(hours=max_padding_time)
|
|
# 15 minutes of allowed time between adding the product to cart and paying it.
|
|
return initial_time >= fields.Datetime.now() - timedelta(minutes=15)
|
|
|
|
def _all_product_available(self):
|
|
self.ensure_one()
|
|
return super(SaleOrder, self.with_context(
|
|
start_date=self.rental_start_date, end_date=self.rental_return_date
|
|
))._all_product_available()
|
|
|
|
def _available_dates_for_renting(self):
|
|
"""Override to take into account the stock availability.
|
|
"""
|
|
res = super()._available_dates_for_renting()
|
|
if not res:
|
|
return False
|
|
for line in self.order_line:
|
|
product = line.product_id
|
|
if product.type == 'product' and not product.allow_out_of_stock_order:
|
|
cart_qty, avl_qty = self._get_cart_and_free_qty(product, line=line)
|
|
if cart_qty > avl_qty:
|
|
line._set_shop_warning_stock(cart_qty, max(avl_qty, 0))
|
|
return False
|
|
return True
|