Bug quantity/th qt
This commit is contained in:
@@ -1147,6 +1147,25 @@ class Line(metaclass=PoolMeta):
|
||||
line.quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sync_quantity_counter_from_theorical(cls, line):
|
||||
if cls._has_physical_lot(line):
|
||||
return False
|
||||
quantity = getattr(line, 'quantity_theorical', None)
|
||||
if cls._is_empty_quantity(quantity):
|
||||
quantity = Decimal(0)
|
||||
else:
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
current = getattr(line, 'quantity', None)
|
||||
try:
|
||||
current = Decimal(str(current or 0)).quantize(Decimal("0.00001"))
|
||||
except Exception:
|
||||
current = Decimal(0)
|
||||
if current == quantity:
|
||||
return False
|
||||
line.quantity = quantity
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _set_initial_quantity_values(cls, values):
|
||||
if 'quantity_theorical' not in values:
|
||||
@@ -1356,7 +1375,7 @@ class Line(metaclass=PoolMeta):
|
||||
'quantity_theorical', 'quantity', 'lots',
|
||||
methods=['_recompute_trade_price_fields'])
|
||||
def on_change_quantity_theorical(self):
|
||||
if self._sync_initial_quantity_from_theorical(self):
|
||||
if self._sync_quantity_counter_from_theorical(self):
|
||||
self._recompute_trade_price_fields()
|
||||
|
||||
@classmethod
|
||||
@@ -1632,7 +1651,7 @@ class Line(metaclass=PoolMeta):
|
||||
lines = sum(args[::2], [])
|
||||
for line in lines:
|
||||
if line.id in old_values:
|
||||
if cls._sync_initial_quantity_from_theorical(line):
|
||||
if cls._sync_quantity_counter_from_theorical(line):
|
||||
cls.save([line])
|
||||
new = Decimal(line.quantity_theorical or 0)
|
||||
virtual_lots = [lot for lot in (line.lots or []) if lot.lot_type == 'virtual']
|
||||
|
||||
@@ -1106,6 +1106,25 @@ class SaleLine(metaclass=PoolMeta):
|
||||
line.quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sync_quantity_counter_from_theorical(cls, line):
|
||||
if cls._has_physical_lot(line):
|
||||
return False
|
||||
quantity = getattr(line, 'quantity_theorical', None)
|
||||
if cls._is_empty_quantity(quantity):
|
||||
quantity = Decimal(0)
|
||||
else:
|
||||
quantity = Decimal(str(quantity)).quantize(Decimal("0.00001"))
|
||||
current = getattr(line, 'quantity', None)
|
||||
try:
|
||||
current = Decimal(str(current or 0)).quantize(Decimal("0.00001"))
|
||||
except Exception:
|
||||
current = Decimal(0)
|
||||
if current == quantity:
|
||||
return False
|
||||
line.quantity = quantity
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _set_initial_quantity_values(cls, values):
|
||||
if 'quantity_theorical' not in values:
|
||||
@@ -1343,7 +1362,7 @@ class SaleLine(metaclass=PoolMeta):
|
||||
'quantity_theorical', 'quantity', 'lots',
|
||||
methods=['_recompute_trade_price_fields'])
|
||||
def on_change_quantity_theorical(self):
|
||||
if self._sync_initial_quantity_from_theorical(self):
|
||||
if self._sync_quantity_counter_from_theorical(self):
|
||||
self._recompute_trade_price_fields()
|
||||
|
||||
@classmethod
|
||||
@@ -1746,7 +1765,7 @@ class SaleLine(metaclass=PoolMeta):
|
||||
for line in lines:
|
||||
if line.id not in old_values:
|
||||
continue
|
||||
if cls._sync_initial_quantity_from_theorical(line):
|
||||
if cls._sync_quantity_counter_from_theorical(line):
|
||||
cls.save([line])
|
||||
if old_values[line.id] is None:
|
||||
continue
|
||||
|
||||
@@ -1503,7 +1503,9 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'sale line write increases virtual lot and open lot.qt when contractual qty grows'
|
||||
SaleLine = Pool().get('sale.line')
|
||||
line = Mock(id=1, quantity_theorical=Decimal('10'))
|
||||
line.quantity = Decimal('10')
|
||||
line.unit = Mock()
|
||||
line.fees = []
|
||||
vlot = Mock(id=99, lot_type='virtual')
|
||||
vlot.get_current_quantity_converted.return_value = Decimal('10')
|
||||
line.lots = [vlot]
|
||||
@@ -1517,7 +1519,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'trytond.modules.purchase_trade.sale.Pool'
|
||||
) as PoolMock, patch(
|
||||
'trytond.modules.purchase_trade.sale.super'
|
||||
) as super_mock:
|
||||
) as super_mock, patch.object(SaleLine, 'save'):
|
||||
PoolMock.return_value.get.side_effect = lambda name: {
|
||||
'lot.lot': lot_model,
|
||||
'lot.qt': lotqt_model,
|
||||
@@ -1543,6 +1545,8 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'sale line write blocks contractual qty decrease when open lot.qt is insufficient'
|
||||
SaleLine = Pool().get('sale.line')
|
||||
line = Mock(id=2, quantity_theorical=Decimal('10'))
|
||||
line.quantity = Decimal('10')
|
||||
line.fees = []
|
||||
vlot = Mock(id=100, lot_type='virtual')
|
||||
vlot.get_current_quantity_converted.return_value = Decimal('10')
|
||||
line.lots = [vlot]
|
||||
@@ -1557,7 +1561,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'trytond.modules.purchase_trade.sale.Pool'
|
||||
) as PoolMock, patch(
|
||||
'trytond.modules.purchase_trade.sale.super'
|
||||
) as super_mock:
|
||||
) as super_mock, patch.object(SaleLine, 'save'):
|
||||
PoolMock.return_value.get.side_effect = lambda name: {
|
||||
'lot.lot': lot_model,
|
||||
'lot.qt': lotqt_model,
|
||||
@@ -1578,7 +1582,9 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'purchase line write keeps open lot.qt net of existing physical lots'
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
line = Mock(id=4, quantity_theorical=Decimal('10000'))
|
||||
line.quantity = Decimal('10000')
|
||||
line.unit = Mock()
|
||||
line.fees = []
|
||||
vlot = Mock(id=102, lot_type='virtual')
|
||||
vlot.get_current_quantity_converted.return_value = Decimal('10000')
|
||||
physical = Mock(lot_type='physic')
|
||||
@@ -1594,7 +1600,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'trytond.modules.purchase_trade.purchase.Pool'
|
||||
) as PoolMock, patch(
|
||||
'trytond.modules.purchase_trade.purchase.super'
|
||||
) as super_mock:
|
||||
) as super_mock, patch.object(PurchaseLine, 'save'):
|
||||
PoolMock.return_value.get.side_effect = lambda name: {
|
||||
'lot.lot': lot_model,
|
||||
'lot.qt': lotqt_model,
|
||||
@@ -1612,15 +1618,65 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
[line], {'quantity_theorical': Decimal('20000')})
|
||||
|
||||
self.assertEqual(lqt.lot_quantity, Decimal('10000'))
|
||||
self.assertEqual(line.quantity, Decimal('10000'))
|
||||
vlot.set_current_quantity.assert_not_called()
|
||||
lot_model.save.assert_not_called()
|
||||
lotqt_model.save.assert_not_called()
|
||||
|
||||
def test_purchase_line_write_syncs_quantity_without_physical_lots(self):
|
||||
'purchase line write keeps quantity equal to contractual qty without physical lots'
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
line = Mock(id=6, quantity_theorical=Decimal('1500'))
|
||||
line.quantity = Decimal('1500')
|
||||
line.unit = Mock()
|
||||
line.fees = []
|
||||
vlot = Mock(id=104, lot_type='virtual')
|
||||
vlot.get_current_quantity_converted.return_value = Decimal('1500')
|
||||
line.lots = [vlot]
|
||||
free_lqt = Mock(lot_quantity=Decimal('50'))
|
||||
allocated_lqts = [
|
||||
Mock(lot_quantity=Decimal('400')),
|
||||
Mock(lot_quantity=Decimal('500')),
|
||||
Mock(lot_quantity=Decimal('550')),
|
||||
]
|
||||
|
||||
lot_model = Mock()
|
||||
lotqt_model = Mock()
|
||||
lotqt_model.search.side_effect = [[free_lqt], allocated_lqts]
|
||||
|
||||
with patch(
|
||||
'trytond.modules.purchase_trade.purchase.Pool'
|
||||
) as PoolMock, patch(
|
||||
'trytond.modules.purchase_trade.purchase.super'
|
||||
) as super_mock, patch.object(PurchaseLine, 'save') as save:
|
||||
PoolMock.return_value.get.side_effect = lambda name: {
|
||||
'lot.lot': lot_model,
|
||||
'lot.qt': lotqt_model,
|
||||
}[name]
|
||||
|
||||
def fake_super_write(*args):
|
||||
for records, values in zip(args[::2], args[1::2]):
|
||||
if 'quantity_theorical' in values:
|
||||
for record in records:
|
||||
record.quantity_theorical = values['quantity_theorical']
|
||||
|
||||
super_mock.return_value.write.side_effect = fake_super_write
|
||||
|
||||
PurchaseLine.write(
|
||||
[line], {'quantity_theorical': Decimal('2000')})
|
||||
|
||||
self.assertEqual(line.quantity, Decimal('2000.00000'))
|
||||
self.assertEqual(free_lqt.lot_quantity, Decimal('550.00000'))
|
||||
vlot.set_current_quantity.assert_called_once_with(
|
||||
Decimal('2000.00000'), Decimal('2000.00000'), 1)
|
||||
save.assert_called()
|
||||
|
||||
def test_purchase_line_write_syncs_virtual_fee_quantity(self):
|
||||
'purchase line write updates fee quantity when only virtual lot exists'
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
fee = Mock()
|
||||
line = Mock(id=5, quantity_theorical=Decimal('20000'))
|
||||
line.quantity = Decimal('20000')
|
||||
line.unit = Mock()
|
||||
line.fees = [fee]
|
||||
vlot = Mock(id=103, lot_type='virtual')
|
||||
@@ -1636,7 +1692,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'trytond.modules.purchase_trade.purchase.Pool'
|
||||
) as PoolMock, patch(
|
||||
'trytond.modules.purchase_trade.purchase.super'
|
||||
) as super_mock:
|
||||
) as super_mock, patch.object(PurchaseLine, 'save'):
|
||||
PoolMock.return_value.get.side_effect = lambda name: {
|
||||
'lot.lot': lot_model,
|
||||
'lot.qt': lotqt_model,
|
||||
@@ -1661,6 +1717,7 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'purchase line write does not re-add quantity when initializing contractual qty'
|
||||
PurchaseLine = Pool().get('purchase.line')
|
||||
line = Mock(id=3, quantity_theorical=None)
|
||||
line.quantity = Decimal('10')
|
||||
vlot = Mock(id=101, lot_type='virtual')
|
||||
vlot.get_current_quantity_converted.return_value = Decimal('10')
|
||||
line.lots = [vlot]
|
||||
|
||||
Reference in New Issue
Block a user