check qt create contract & matching

This commit is contained in:
2026-05-11 20:42:26 +02:00
parent 09c78395f1
commit c017aac9a7
3 changed files with 61 additions and 0 deletions

View File

@@ -1025,6 +1025,24 @@ class LotQt(
logger.info("MATCH_LOTS:%s",lot_s)
LotQt = Pool().get('lot.qt')
Lot = Pool().get('lot.lot')
for lp in lot_p:
qt_p = Decimal(str(lp.lot_matched_qt or 0))
if qt_p <= 0:
continue
lqt = LotQt(lp.lot_r_id)
available = Decimal(str(lqt.lot_quantity or 0))
if qt_p > available:
raise UserError(
"Quantity to match exceeds the available purchase quantity.")
for ls in lot_s:
qt_s = Decimal(str(ls.lot_matched_qt or 0))
if qt_s <= 0:
continue
lqt = LotQt(ls.lot_r_id)
available = abs(Decimal(str(lqt.lot_quantity or 0)))
if qt_s > available:
raise UserError(
"Quantity to match exceeds the available sale quantity.")
for lp in lot_p:
qt_p = lp.lot_matched_qt
if qt_p == 0:

View File

@@ -37,6 +37,7 @@ class ContractFactory:
created = []
sources = cls._get_sources(ct, type_)
cls._validate_requested_quantity(contracts, sources, ct)
base_contract = cls._get_base_contract(sources, ct, type_)
for c in contracts:
@@ -251,6 +252,18 @@ class ContractFactory:
if getattr(line.unit, 'id', None) != getattr(first_line.unit, 'id', None):
raise UserError('Selected lots must share the same unit.')
@classmethod
def _validate_requested_quantity(cls, contracts, sources, ct):
if not getattr(ct, 'matched', False) or not sources:
return
available = sum(source['quantity'] for source in sources)
requested = sum(
cls._normalize_quantity(contract.quantity)
for contract in contracts)
if requested > available:
raise UserError(
'The requested quantity exceeds the selected open quantity.')
@classmethod
def _get_line_sources(cls, contract_detail, sources, ct):
if not ct.matched or len(sources) <= 1:

View File

@@ -2348,6 +2348,36 @@ class PurchaseTradeTestCase(ModuleTestCase):
with self.assertRaises(UserError):
ContractFactory._get_line_sources(contract_detail, sources, ct)
def test_contract_factory_rejects_total_above_selected_open_quantity(self):
'matched create contracts cannot consume more than selected open quantity'
contracts = [
Mock(quantity=Decimal('100')),
Mock(quantity=Decimal('100')),
]
ct = Mock(matched=True)
sources = [
{'lot': Mock(), 'trade_line': Mock(), 'quantity': Decimal('100')},
]
with self.assertRaises(UserError):
ContractFactory._validate_requested_quantity(contracts, sources, ct)
def test_lot_matching_rejects_purchase_quantity_above_available(self):
'apply matching cannot consume more than available purchase quantity'
class LotQtMock:
def __call__(self, _id):
return Mock(lot_quantity=Decimal('100'))
pool = Mock()
pool.get.side_effect = (
lambda name: LotQtMock() if name == 'lot.qt' else Mock())
purchase_lot = Mock(
lot_matched_qt=Decimal('101'), lot_r_id=1)
with patch.object(lot_module, 'Pool', return_value=pool):
with self.assertRaises(UserError):
lot_module.LotQt.match_lots([purchase_lot], [])
def test_contract_detail_defaults_sale_locations_from_dropship_purchase(self):
'create contracts copies supplier-to-customer locations from purchase to sale'
supplier = Mock(id=1, type='supplier')