diff --git a/CHANGELOG b/CHANGELOG
index b2e51af403..f587e26fbe 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Add notification on draft sale
* Add support for Python 3.10
* Remove support for Python 3.6
diff --git a/__init__.py b/__init__.py
index ee174d54cb..67c6dac9de 100644
--- a/__init__.py
+++ b/__init__.py
@@ -9,4 +9,5 @@ from . import sale
def register():
Pool.register(
sale.Sale,
+ sale.Line,
module='sale_stock_quantity', type_='model')
diff --git a/message.xml b/message.xml
index 0254d7bb62..70d2af7338 100644
--- a/message.xml
+++ b/message.xml
@@ -6,5 +6,8 @@ this repository contains the full copyright notices and license terms. -->
The forcast quantity (%(forecast_quantity)s%(default_uom)s) for line "%(line)s" is lower than its quantity (%(quantity)s%(unit)s).
+
+ The forecast quantity (%(forecast_quantity)s) of product "%(product)s" is lower than the quantity (%(quantity)s).
+
diff --git a/sale.py b/sale.py
index fa29793509..6bc3b165d2 100644
--- a/sale.py
+++ b/sale.py
@@ -5,7 +5,7 @@ import datetime
from collections import defaultdict
from trytond.i18n import gettext
-from trytond.model import ModelView, Workflow
+from trytond.model import ModelView, Workflow, fields
from trytond.pool import Pool, PoolMeta
from trytond.tools import grouped_slice
from trytond.transaction import Transaction
@@ -191,3 +191,54 @@ class Sale(metaclass=PoolMeta):
message_values['forecast_quantity'] = forecast_quantity
raise_(line.id, message_values)
date += datetime.timedelta(1)
+
+
+class Line(metaclass=PoolMeta):
+ __name__ = 'sale.line'
+
+ @fields.depends(methods=['_notify_stock_quantity'])
+ def on_change_notify(self):
+ notifications = super().on_change_notify()
+ notifications.extend(self._notify_stock_quantity())
+ return notifications
+
+ @fields.depends(
+ 'sale_state', 'product', 'quantity', 'unit', 'company',
+ 'sale', '_parent_sale.warehouse', '_parent_sale.sale_date')
+ def _notify_stock_quantity(self):
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Lang = pool.get('ir.lang')
+ Move = pool.get('stock.move')
+ Product = pool.get('product.product')
+ lang = Lang.get()
+ if (self.sale_state == 'draft'
+ and self.sale
+ and self.product
+ and self.product.type in Move.get_product_types()
+ and self.unit
+ and self.quantity is not None):
+ with Transaction().set_context(
+ company=self.company.id if self.company else None):
+ today = Date.today()
+ sale_date = self.sale.sale_date or today
+ if self.sale.warehouse:
+ locations = [self.sale.warehouse.id]
+ else:
+ locations = []
+ with Transaction().set_context(
+ locations=locations,
+ stock_date_end=sale_date,
+ uom=self.unit):
+ product = Product(self.product.id)
+ if product.forecast_quantity < self.quantity:
+ yield ('warning', gettext(
+ 'sale_stock_quantity'
+ '.msg_product_forecast_quantity_lower',
+ forecast_quantity=lang.format_number_symbol(
+ product.forecast_quantity, self.unit,
+ self.unit.digits),
+ product=self.product.rec_name,
+ quantity=lang.format_number_symbol(
+ self.quantity, self.unit,
+ self.unit.digits)))
diff --git a/tests/scenario_sale_stock_quantity.rst b/tests/scenario_sale_stock_quantity.rst
index 4325732fab..5a84fd4d1f 100644
--- a/tests/scenario_sale_stock_quantity.rst
+++ b/tests/scenario_sale_stock_quantity.rst
@@ -110,6 +110,8 @@ Sale 3 products with enough stock::
>>> sale_line = sale.lines.new()
>>> sale_line.product = product
>>> sale_line.quantity = 3.0
+ >>> len(sale_line.notifications())
+ 0
>>> sale.click('quote')
Sale 1 product with still enough stock::
@@ -120,6 +122,8 @@ Sale 1 product with still enough stock::
>>> sale_line = sale.lines.new()
>>> sale_line.product = product
>>> sale_line.quantity = 1.0
+ >>> len(sale_line.notifications())
+ 0
>>> sale.click('quote')
Sale 2 more products with not enough stock::
@@ -130,6 +134,8 @@ Sale 2 more products with not enough stock::
>>> sale_line = sale.lines.new()
>>> sale_line.product = product
>>> sale_line.quantity = 2.0
+ >>> len(sale_line.notifications())
+ 0
>>> sale.click('quote') # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
@@ -147,6 +153,8 @@ Sale 6 products with not enough stock::
>>> sale_line = sale.lines.new()
>>> sale_line.product = product
>>> sale_line.quantity = 6.0
+ >>> len(sale_line.notifications())
+ 1
>>> sale.click('quote') # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...