diff --git a/modules/purchase_trade/lot.py b/modules/purchase_trade/lot.py index 4318f9a..c90e379 100755 --- a/modules/purchase_trade/lot.py +++ b/modules/purchase_trade/lot.py @@ -1393,8 +1393,10 @@ class LotQt( l.sale_line = ll.sale_line Lot.save([l]) #ll.lot_gross_quantity -= qt - ll.lot_quantity -= qt - ll.lot_qt -= float(qt) + ll.lot_quantity = ( + Decimal(str(ll.lot_quantity or 0)) - qt) + if ll.lot_qt is not None: + ll.lot_qt -= float(qt) Lot.save([ll]) else: #Increase forecasted virtual part matched diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 90e6bdf..17a0a83 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -3488,6 +3488,65 @@ class PurchaseTradeTestCase(ModuleTestCase): with self.assertRaises(UserError): wizard.transition_matching() + def test_physical_purchase_matching_keeps_empty_sale_lot_qt(self): + 'physical purchase matching does not fail when sale lot_qt is empty' + physical_lot = Mock( + id=101, + lot_type='physic', + sale_line=None) + physical_lot.get_current_quantity_converted.return_value = ( + Decimal('10')) + physical_lot.getVlot_p.return_value = Mock() + physical_lot.updateVirtualPart.return_value = True + sale_virtual_lot = Mock( + sale_line=Mock(), + lot_quantity=Decimal('9'), + lot_qt=None) + sale_virtual_lot.getVlot_s.return_value = sale_virtual_lot + sale_lqt = Mock( + lot_p=None, + lot_s=sale_virtual_lot, + lot_quantity=Decimal('9'), + lot_unit=None) + + class LotQtMock: + def __call__(self, _id): + return sale_lqt + + @staticmethod + def search(_domain): + return [] + + @staticmethod + def save(_records): + return None + + class LotMock: + def __call__(self, _id): + return physical_lot + + @staticmethod + def save(_records): + return None + + pool = Mock() + pool.get.side_effect = ( + lambda name: LotQtMock() if name == 'lot.qt' else LotMock()) + purchase_match = Mock( + lot_id=101, + lot_r_id=None, + lot_matched_qt=Decimal('1')) + sale_match = Mock( + lot_r_id=2, + lot_matched_qt=Decimal('1')) + + with patch.object(lot_module, 'Pool', return_value=pool), \ + patch.object(lot_module.LotQt, 'search', return_value=[]): + lot_module.LotQt.match_lots([purchase_match], [sale_match]) + + self.assertIsNone(sale_virtual_lot.lot_qt) + self.assertEqual(sale_virtual_lot.lot_quantity, Decimal('8')) + def test_purchase_tolerance_used_is_weighted_line_average(self): 'purchase tolerance gauge averages line gauges by theoretical quantity' unit = Mock()