Targeted Qt
This commit is contained in:
@@ -445,7 +445,10 @@ class Purchase(metaclass=PoolMeta):
|
||||
getattr(line, 'quantity_theorical', None)
|
||||
or getattr(line, 'quantity', None)
|
||||
or 0))
|
||||
actual += self._line_lot_quantity_for_tolerance(line)
|
||||
if hasattr(line, '_tolerance_targeted_quantity'):
|
||||
actual += line._tolerance_targeted_quantity()
|
||||
else:
|
||||
actual += self._line_lot_quantity_for_tolerance(line)
|
||||
return theoretical, actual
|
||||
|
||||
def get_tolerance_used(self, name):
|
||||
@@ -1236,13 +1239,14 @@ class Line(metaclass=PoolMeta):
|
||||
def _set_initial_quantity_values(cls, values):
|
||||
if 'quantity_theorical' not in values:
|
||||
return
|
||||
if not cls._is_empty_quantity(values.get('quantity')):
|
||||
return
|
||||
quantity = values.get('quantity_theorical')
|
||||
if cls._is_empty_quantity(quantity):
|
||||
return
|
||||
values['quantity'] = Decimal(str(quantity)).quantize(
|
||||
Decimal("0.00001"))
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
if cls._is_empty_quantity(values.get('quantity')):
|
||||
values['quantity'] = quantity
|
||||
if cls._is_empty_quantity(values.get('targeted_qt')):
|
||||
values['targeted_qt'] = quantity
|
||||
|
||||
@classmethod
|
||||
def _set_quantity_counter_values_from_theorical(cls, records, values):
|
||||
@@ -1256,6 +1260,8 @@ class Line(metaclass=PoolMeta):
|
||||
else:
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
values['quantity'] = quantity
|
||||
if 'targeted_qt' not in values:
|
||||
values['targeted_qt'] = quantity
|
||||
|
||||
@classmethod
|
||||
def _fresh_lines_for_quantity_consistency(cls, lines):
|
||||
@@ -1367,8 +1373,7 @@ class Line(metaclass=PoolMeta):
|
||||
fields.Numeric("Tolerance min"), 'get_tolerance_min')
|
||||
tolerance_max = fields.Function(
|
||||
fields.Numeric("Tolerance max"), 'get_tolerance_max')
|
||||
targeted_qt = fields.Function(
|
||||
fields.Numeric("Targeted Qt", digits='unit'), 'get_targeted_qt')
|
||||
targeted_qt = fields.Numeric("Targeted Qt", digits='unit')
|
||||
# certification = fields.Selection([
|
||||
# (None, ''),
|
||||
# ('bci', 'BCI'),
|
||||
@@ -1466,11 +1471,12 @@ class Line(metaclass=PoolMeta):
|
||||
return " | ".join(filter(None, values))
|
||||
|
||||
@fields.depends(
|
||||
'quantity_theorical', 'quantity', 'lots',
|
||||
'quantity_theorical', 'quantity', 'lots', 'targeted_qt',
|
||||
methods=['_recompute_trade_price_fields'])
|
||||
def on_change_quantity_theorical(self):
|
||||
if self._sync_quantity_counter_from_theorical(self):
|
||||
self._recompute_trade_price_fields()
|
||||
self.targeted_qt = self._tolerance_theoretical_quantity()
|
||||
|
||||
@classmethod
|
||||
def default_price_type(cls):
|
||||
@@ -1556,12 +1562,19 @@ class Line(metaclass=PoolMeta):
|
||||
unit)
|
||||
return quantity
|
||||
|
||||
def _tolerance_targeted_quantity(self):
|
||||
targeted = getattr(self, 'targeted_qt', None)
|
||||
if not self._is_empty_quantity(targeted):
|
||||
return Decimal(str(targeted))
|
||||
return self._tolerance_theoretical_quantity()
|
||||
|
||||
@fields.depends('targeted_qt', 'quantity_theorical', 'quantity')
|
||||
def get_tolerance_used(self, name):
|
||||
theoretical = self._tolerance_theoretical_quantity()
|
||||
if not theoretical:
|
||||
return Decimal(0)
|
||||
return round(
|
||||
((self._tolerance_actual_quantity() - theoretical)
|
||||
((self._tolerance_targeted_quantity() - theoretical)
|
||||
/ theoretical) * Decimal(100), 5)
|
||||
|
||||
def get_tolerance_min(self, name):
|
||||
@@ -1576,16 +1589,13 @@ class Line(metaclass=PoolMeta):
|
||||
return Decimal(str(purchase.tol_max or 0))
|
||||
return Decimal(str(self.tol_max or 0))
|
||||
|
||||
def get_targeted_qt(self, name):
|
||||
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()
|
||||
if self._is_empty_quantity(getattr(self, 'targeted_qt', None)):
|
||||
self.targeted_qt = theoretical
|
||||
targeted = self._tolerance_targeted_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))
|
||||
|
||||
@@ -409,7 +409,10 @@ class Sale(metaclass=PoolMeta):
|
||||
getattr(line, 'quantity_theorical', None)
|
||||
or getattr(line, 'quantity', None)
|
||||
or 0)))
|
||||
actual += self._line_lot_quantity_for_tolerance(line)
|
||||
if hasattr(line, '_tolerance_targeted_quantity'):
|
||||
actual += line._tolerance_targeted_quantity()
|
||||
else:
|
||||
actual += self._line_lot_quantity_for_tolerance(line)
|
||||
return theoretical, actual
|
||||
|
||||
def get_tolerance_used(self, name):
|
||||
@@ -1195,13 +1198,14 @@ class SaleLine(metaclass=PoolMeta):
|
||||
def _set_initial_quantity_values(cls, values):
|
||||
if 'quantity_theorical' not in values:
|
||||
return
|
||||
if not cls._is_empty_quantity(values.get('quantity')):
|
||||
return
|
||||
quantity = values.get('quantity_theorical')
|
||||
if cls._is_empty_quantity(quantity):
|
||||
return
|
||||
values['quantity'] = Decimal(str(quantity)).quantize(
|
||||
Decimal("0.00001"))
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
if cls._is_empty_quantity(values.get('quantity')):
|
||||
values['quantity'] = quantity
|
||||
if cls._is_empty_quantity(values.get('targeted_qt')):
|
||||
values['targeted_qt'] = quantity
|
||||
|
||||
@classmethod
|
||||
def _set_quantity_counter_values_from_theorical(cls, records, values):
|
||||
@@ -1215,6 +1219,8 @@ class SaleLine(metaclass=PoolMeta):
|
||||
else:
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
values['quantity'] = quantity
|
||||
if 'targeted_qt' not in values:
|
||||
values['targeted_qt'] = quantity
|
||||
|
||||
@classmethod
|
||||
def _fresh_lines_for_quantity_consistency(cls, lines):
|
||||
@@ -1349,8 +1355,7 @@ class SaleLine(metaclass=PoolMeta):
|
||||
fields.Numeric("Tolerance min"), 'get_tolerance_min')
|
||||
tolerance_max = fields.Function(
|
||||
fields.Numeric("Tolerance max"), 'get_tolerance_max')
|
||||
targeted_qt = fields.Function(
|
||||
fields.Numeric("Targeted Qt", digits='unit'), 'get_targeted_qt')
|
||||
targeted_qt = fields.Numeric("Targeted Qt", digits='unit')
|
||||
certif = fields.Many2One('purchase.certification',"Certification",states={'readonly': (Eval('inherit_cer')),})
|
||||
# certification = fields.Selection([
|
||||
# (None, ''),
|
||||
@@ -1453,11 +1458,12 @@ class SaleLine(metaclass=PoolMeta):
|
||||
return " | ".join(filter(None, values))
|
||||
|
||||
@fields.depends(
|
||||
'quantity_theorical', 'quantity', 'lots',
|
||||
'quantity_theorical', 'quantity', 'lots', 'targeted_qt',
|
||||
methods=['_recompute_trade_price_fields'])
|
||||
def on_change_quantity_theorical(self):
|
||||
if self._sync_quantity_counter_from_theorical(self):
|
||||
self._recompute_trade_price_fields()
|
||||
self.targeted_qt = self._tolerance_theoretical_quantity()
|
||||
|
||||
@classmethod
|
||||
def default_price_type(cls):
|
||||
@@ -1546,12 +1552,19 @@ class SaleLine(metaclass=PoolMeta):
|
||||
unit)
|
||||
return quantity
|
||||
|
||||
def _tolerance_targeted_quantity(self):
|
||||
targeted = getattr(self, 'targeted_qt', None)
|
||||
if not self._is_empty_quantity(targeted):
|
||||
return abs(Decimal(str(targeted)))
|
||||
return self._tolerance_theoretical_quantity()
|
||||
|
||||
@fields.depends('targeted_qt', 'quantity_theorical', 'quantity')
|
||||
def get_tolerance_used(self, name):
|
||||
theoretical = self._tolerance_theoretical_quantity()
|
||||
if not theoretical:
|
||||
return Decimal(0)
|
||||
return round(
|
||||
((self._tolerance_actual_quantity() - theoretical)
|
||||
((self._tolerance_targeted_quantity() - theoretical)
|
||||
/ theoretical) * Decimal(100), 5)
|
||||
|
||||
def get_tolerance_min(self, name):
|
||||
@@ -1566,16 +1579,13 @@ class SaleLine(metaclass=PoolMeta):
|
||||
return Decimal(str(sale.tol_max or 0))
|
||||
return Decimal(str(self.tol_max or 0))
|
||||
|
||||
def get_targeted_qt(self, name):
|
||||
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()
|
||||
if self._is_empty_quantity(getattr(self, 'targeted_qt', None)):
|
||||
self.targeted_qt = theoretical
|
||||
targeted = self._tolerance_targeted_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))
|
||||
|
||||
@@ -2916,7 +2916,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
Decimal('10'))
|
||||
|
||||
def test_purchase_line_tolerance_uses_physical_lots_when_present(self):
|
||||
'purchase line tolerance ignores open lot.qt when physical lots exist'
|
||||
'purchase line tolerance uses the editable targeted quantity'
|
||||
unit = Mock()
|
||||
virtual = Mock(id=10, lot_type='virtual')
|
||||
physical = Mock(lot_type='physic')
|
||||
@@ -2925,6 +2925,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
line.unit = unit
|
||||
line.quantity_theorical = Decimal('100')
|
||||
line.quantity = Decimal('100')
|
||||
line.targeted_qt = Decimal('105')
|
||||
line.lots = [virtual, physical]
|
||||
line.inherit_tol = False
|
||||
line.tol_min = Decimal('5')
|
||||
@@ -2942,13 +2943,14 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
lot_qt_model.search.assert_not_called()
|
||||
|
||||
def test_sale_line_tolerance_uses_open_lot_qt_without_physical_lots(self):
|
||||
'sale line tolerance uses absolute lot.qt when no physical lot exists'
|
||||
'sale line tolerance uses the editable targeted quantity'
|
||||
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.targeted_qt = Decimal('95')
|
||||
line.lots = [virtual]
|
||||
line.inherit_tol = False
|
||||
line.tol_min = Decimal('5')
|
||||
@@ -2971,6 +2973,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
line = purchase_module.Line()
|
||||
line.quantity_theorical = Decimal('100')
|
||||
line.quantity = Decimal('100')
|
||||
line.targeted_qt = Decimal('111')
|
||||
line.lots = [physical]
|
||||
line.inherit_tol = False
|
||||
line.tol_min = Decimal('5')
|
||||
@@ -2987,6 +2990,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
line.unit = unit
|
||||
line.quantity_theorical = Decimal('100')
|
||||
line.quantity = Decimal('100')
|
||||
line.targeted_qt = Decimal('94')
|
||||
line.lots = [virtual]
|
||||
line.inherit_tol = False
|
||||
line.tol_min = Decimal('5')
|
||||
@@ -3001,6 +3005,22 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
with self.assertRaises(UserError):
|
||||
line.check_targeted_qt_tolerance()
|
||||
|
||||
def test_purchase_line_initial_targeted_qt_defaults_to_contract_quantity(self):
|
||||
'purchase line targeted quantity defaults to contractual quantity'
|
||||
values = {'quantity_theorical': Decimal('100')}
|
||||
|
||||
purchase_module.Line._set_initial_quantity_values(values)
|
||||
|
||||
self.assertEqual(values['targeted_qt'], Decimal('100.00000'))
|
||||
|
||||
def test_sale_line_initial_targeted_qt_defaults_to_contract_quantity(self):
|
||||
'sale line targeted quantity defaults to contractual quantity'
|
||||
values = {'quantity_theorical': Decimal('100')}
|
||||
|
||||
sale_module.SaleLine._set_initial_quantity_values(values)
|
||||
|
||||
self.assertEqual(values['targeted_qt'], Decimal('100.00000'))
|
||||
|
||||
def test_lot_context_group_defaults_to_all(self):
|
||||
'lots management opens without grouping by physical lot'
|
||||
self.assertEqual(lot_module.LotContext.default_group(), 'all')
|
||||
|
||||
Reference in New Issue
Block a user