Targeted Qt
This commit is contained in:
@@ -1579,6 +1579,24 @@ class Line(metaclass=PoolMeta):
|
|||||||
def get_targeted_qt(self, name):
|
def get_targeted_qt(self, name):
|
||||||
return self._tolerance_actual_quantity()
|
return self._tolerance_actual_quantity()
|
||||||
|
|
||||||
|
def check_targeted_qt_tolerance(self):
|
||||||
|
if not getattr(self, 'lots', None):
|
||||||
|
return
|
||||||
|
theoretical = self._tolerance_theoretical_quantity()
|
||||||
|
if not theoretical:
|
||||||
|
return
|
||||||
|
targeted = self._tolerance_actual_quantity()
|
||||||
|
tol_min = -self.get_tolerance_min('tolerance_min')
|
||||||
|
tol_max = self.get_tolerance_max('tolerance_max')
|
||||||
|
min_qt = theoretical * (Decimal(1) - tol_min / Decimal(100))
|
||||||
|
max_qt = theoretical * (Decimal(1) + tol_max / Decimal(100))
|
||||||
|
if targeted < min_qt:
|
||||||
|
raise UserError(
|
||||||
|
"Targeted Qt is below the tolerance minimum.")
|
||||||
|
if targeted > max_qt:
|
||||||
|
raise UserError(
|
||||||
|
"Targeted Qt exceeds the tolerance maximum.")
|
||||||
|
|
||||||
def get_progress(self,name):
|
def get_progress(self,name):
|
||||||
PS = Pool().get('purchase.pricing.summary')
|
PS = Pool().get('purchase.pricing.summary')
|
||||||
ps = PS.search(['line','=',self.id])
|
ps = PS.search(['line','=',self.id])
|
||||||
@@ -1953,6 +1971,7 @@ class Line(metaclass=PoolMeta):
|
|||||||
for tr in pc.triggers:
|
for tr in pc.triggers:
|
||||||
line.check_from_to(tr)
|
line.check_from_to(tr)
|
||||||
line.check_pricing()
|
line.check_pricing()
|
||||||
|
line.check_targeted_qt_tolerance()
|
||||||
#no lot need to create one with line quantity
|
#no lot need to create one with line quantity
|
||||||
if not line.created_by_code:
|
if not line.created_by_code:
|
||||||
if cls._sync_initial_quantity_from_theorical(line):
|
if cls._sync_initial_quantity_from_theorical(line):
|
||||||
|
|||||||
@@ -1569,6 +1569,24 @@ class SaleLine(metaclass=PoolMeta):
|
|||||||
def get_targeted_qt(self, name):
|
def get_targeted_qt(self, name):
|
||||||
return self._tolerance_actual_quantity()
|
return self._tolerance_actual_quantity()
|
||||||
|
|
||||||
|
def check_targeted_qt_tolerance(self):
|
||||||
|
if not getattr(self, 'lots', None):
|
||||||
|
return
|
||||||
|
theoretical = self._tolerance_theoretical_quantity()
|
||||||
|
if not theoretical:
|
||||||
|
return
|
||||||
|
targeted = self._tolerance_actual_quantity()
|
||||||
|
tol_min = -self.get_tolerance_min('tolerance_min')
|
||||||
|
tol_max = self.get_tolerance_max('tolerance_max')
|
||||||
|
min_qt = theoretical * (Decimal(1) - tol_min / Decimal(100))
|
||||||
|
max_qt = theoretical * (Decimal(1) + tol_max / Decimal(100))
|
||||||
|
if targeted < min_qt:
|
||||||
|
raise UserError(
|
||||||
|
"Targeted Qt is below the tolerance minimum.")
|
||||||
|
if targeted > max_qt:
|
||||||
|
raise UserError(
|
||||||
|
"Targeted Qt exceeds the tolerance maximum.")
|
||||||
|
|
||||||
def get_progress(self,name):
|
def get_progress(self,name):
|
||||||
PS = Pool().get('sale.pricing.summary')
|
PS = Pool().get('sale.pricing.summary')
|
||||||
ps = PS.search(['sale_line','=',self.id])
|
ps = PS.search(['sale_line','=',self.id])
|
||||||
@@ -2071,6 +2089,7 @@ class SaleLine(metaclass=PoolMeta):
|
|||||||
for tr in pc.triggers:
|
for tr in pc.triggers:
|
||||||
line.check_from_to(tr)
|
line.check_from_to(tr)
|
||||||
line.check_pricing()
|
line.check_pricing()
|
||||||
|
line.check_targeted_qt_tolerance()
|
||||||
#no lot need to create one with line quantity
|
#no lot need to create one with line quantity
|
||||||
logger.info("FROM_VALIDATE_LINE:%s",line.created_by_code)
|
logger.info("FROM_VALIDATE_LINE:%s",line.created_by_code)
|
||||||
if not line.created_by_code:
|
if not line.created_by_code:
|
||||||
|
|||||||
@@ -2965,6 +2965,43 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
|||||||
line.get_tolerance_used('tolerance_used'),
|
line.get_tolerance_used('tolerance_used'),
|
||||||
Decimal('-5.00000'))
|
Decimal('-5.00000'))
|
||||||
|
|
||||||
|
def test_purchase_line_targeted_qt_blocks_above_tolerance(self):
|
||||||
|
'purchase line targeted quantity must stay inside tolerance bounds'
|
||||||
|
physical = Mock(lot_type='physic')
|
||||||
|
physical.get_current_quantity_converted.return_value = Decimal('111')
|
||||||
|
line = purchase_module.Line()
|
||||||
|
line.quantity_theorical = Decimal('100')
|
||||||
|
line.quantity = Decimal('100')
|
||||||
|
line.lots = [physical]
|
||||||
|
line.inherit_tol = False
|
||||||
|
line.tol_min = Decimal('5')
|
||||||
|
line.tol_max = Decimal('10')
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
line.check_targeted_qt_tolerance()
|
||||||
|
|
||||||
|
def test_sale_line_targeted_qt_blocks_below_tolerance(self):
|
||||||
|
'sale line targeted quantity must not fall below tolerance minimum'
|
||||||
|
unit = Mock()
|
||||||
|
virtual = Mock(id=20, lot_type='virtual')
|
||||||
|
line = sale_module.SaleLine()
|
||||||
|
line.unit = unit
|
||||||
|
line.quantity_theorical = Decimal('100')
|
||||||
|
line.quantity = Decimal('100')
|
||||||
|
line.lots = [virtual]
|
||||||
|
line.inherit_tol = False
|
||||||
|
line.tol_min = Decimal('5')
|
||||||
|
line.tol_max = Decimal('10')
|
||||||
|
lot_qt_model = Mock()
|
||||||
|
lot_qt_model.search.return_value = [
|
||||||
|
Mock(lot_quantity=Decimal('-94'), lot_unit=unit)]
|
||||||
|
pool = Mock()
|
||||||
|
pool.get.return_value = lot_qt_model
|
||||||
|
|
||||||
|
with patch.object(sale_module, 'Pool', return_value=pool):
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
line.check_targeted_qt_tolerance()
|
||||||
|
|
||||||
def test_lot_context_group_defaults_to_all(self):
|
def test_lot_context_group_defaults_to_all(self):
|
||||||
'lots management opens without grouping by physical lot'
|
'lots management opens without grouping by physical lot'
|
||||||
self.assertEqual(lot_module.LotContext.default_group(), 'all')
|
self.assertEqual(lot_module.LotContext.default_group(), 'all')
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<label name="tolerance_used"/>
|
<label name="tolerance_used"/>
|
||||||
<field name="tolerance_used" widget="tolerance_gauge"
|
<field name="tolerance_used" widget="tolerance_gauge"
|
||||||
min_field="tolerance_min" max_field="tolerance_max"
|
min_field="tolerance_min" max_field="tolerance_max"
|
||||||
xexpand="1" xfill="1"/>
|
width="360" xexpand="0" xfill="0"/>
|
||||||
<label name="targeted_qt"/>
|
<label name="targeted_qt"/>
|
||||||
<field name="targeted_qt"/>
|
<field name="targeted_qt" width="160"/>
|
||||||
<field name="tolerance_min" invisible="1"/>
|
<field name="tolerance_min" invisible="1"/>
|
||||||
<field name="tolerance_max" invisible="1"/>
|
<field name="tolerance_max" invisible="1"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<label name="tolerance_used"/>
|
<label name="tolerance_used"/>
|
||||||
<field name="tolerance_used" widget="tolerance_gauge"
|
<field name="tolerance_used" widget="tolerance_gauge"
|
||||||
min_field="tolerance_min" max_field="tolerance_max"
|
min_field="tolerance_min" max_field="tolerance_max"
|
||||||
xexpand="1" xfill="1"/>
|
width="360" xexpand="0" xfill="0"/>
|
||||||
<label name="targeted_qt"/>
|
<label name="targeted_qt"/>
|
||||||
<field name="targeted_qt"/>
|
<field name="targeted_qt" width="160"/>
|
||||||
<field name="tolerance_min" invisible="1"/>
|
<field name="tolerance_min" invisible="1"/>
|
||||||
<field name="tolerance_max" invisible="1"/>
|
<field name="tolerance_max" invisible="1"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
|
|||||||
Reference in New Issue
Block a user