Add constraint delete matched contracts
This commit is contained in:
@@ -366,12 +366,31 @@ class Purchase(metaclass=PoolMeta):
|
|||||||
def default_tol_min(cls):
|
def default_tol_min(cls):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_tol_max(cls):
|
def default_tol_max(cls):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@property
|
@staticmethod
|
||||||
def report_terms(self):
|
def _has_matched_physical_lots(purchase):
|
||||||
|
for line in purchase.lines or []:
|
||||||
|
for lot in line.lots or []:
|
||||||
|
if (
|
||||||
|
getattr(lot, 'lot_type', None) == 'physic'
|
||||||
|
and getattr(lot, 'line', None)
|
||||||
|
and getattr(lot, 'sale_line', None)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, purchases):
|
||||||
|
for purchase in purchases:
|
||||||
|
if cls._has_matched_physical_lots(purchase):
|
||||||
|
raise UserError(
|
||||||
|
"You cannot delete a purchase matched to a sale")
|
||||||
|
super().delete(purchases)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_terms(self):
|
||||||
if self.lines:
|
if self.lines:
|
||||||
return self.lines[0].note
|
return self.lines[0].note
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -334,6 +334,25 @@ class Sale(metaclass=PoolMeta):
|
|||||||
def default_tol_max(cls):
|
def default_tol_max(cls):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _has_matched_physical_lots(sale):
|
||||||
|
for line in sale.lines or []:
|
||||||
|
for lot in line.lots or []:
|
||||||
|
if (
|
||||||
|
getattr(lot, 'lot_type', None) == 'physic'
|
||||||
|
and getattr(lot, 'line', None)
|
||||||
|
and getattr(lot, 'sale_line', None)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, sales):
|
||||||
|
for sale in sales:
|
||||||
|
if cls._has_matched_physical_lots(sale):
|
||||||
|
raise UserError(
|
||||||
|
"You cannot delete a sale matched to a purchase")
|
||||||
|
super().delete(sales)
|
||||||
|
|
||||||
def _get_report_lines(self):
|
def _get_report_lines(self):
|
||||||
return [line for line in self.lines if getattr(line, 'type', None) == 'line']
|
return [line for line in self.lines if getattr(line, 'type', None) == 'line']
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,42 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
PurchaseLine.default_pricing_rule(), 'Default pricing rule')
|
PurchaseLine.default_pricing_rule(), 'Default pricing rule')
|
||||||
|
|
||||||
|
def test_purchase_delete_blocks_matched_physical_contract(self):
|
||||||
|
'purchase delete stops when a physical lot already links purchase and sale'
|
||||||
|
Purchase = Pool().get('purchase.purchase')
|
||||||
|
matched_lot = Mock(lot_type='physic', line=Mock(), sale_line=Mock())
|
||||||
|
purchase = Mock(lines=[Mock(lots=[matched_lot])])
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
Purchase.delete([purchase])
|
||||||
|
|
||||||
|
def test_purchase_delete_delegates_when_no_matched_physical_lot(self):
|
||||||
|
'purchase delete keeps default flow when no matched physical lot exists'
|
||||||
|
Purchase = Pool().get('purchase.purchase')
|
||||||
|
purchase = Mock(lines=[Mock(lots=[Mock(lot_type='virtual')])])
|
||||||
|
|
||||||
|
with patch('trytond.modules.purchase_trade.purchase.super') as super_mock:
|
||||||
|
Purchase.delete([purchase])
|
||||||
|
super_mock.return_value.delete.assert_called_once_with([purchase])
|
||||||
|
|
||||||
|
def test_sale_delete_blocks_matched_physical_contract(self):
|
||||||
|
'sale delete stops when a physical lot already links sale and purchase'
|
||||||
|
Sale = Pool().get('sale.sale')
|
||||||
|
matched_lot = Mock(lot_type='physic', line=Mock(), sale_line=Mock())
|
||||||
|
sale = Mock(lines=[Mock(lots=[matched_lot])])
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
Sale.delete([sale])
|
||||||
|
|
||||||
|
def test_sale_delete_delegates_when_no_matched_physical_lot(self):
|
||||||
|
'sale delete keeps default flow when no matched physical lot exists'
|
||||||
|
Sale = Pool().get('sale.sale')
|
||||||
|
sale = Mock(lines=[Mock(lots=[Mock(lot_type='virtual')])])
|
||||||
|
|
||||||
|
with patch('trytond.modules.purchase_trade.sale.super') as super_mock:
|
||||||
|
Sale.delete([sale])
|
||||||
|
super_mock.return_value.delete.assert_called_once_with([sale])
|
||||||
|
|
||||||
def test_component_quota_uses_quantity_fallback_when_theoretical_is_missing(self):
|
def test_component_quota_uses_quantity_fallback_when_theoretical_is_missing(self):
|
||||||
'component quota does not crash when theoretical quantity is still empty'
|
'component quota does not crash when theoretical quantity is still empty'
|
||||||
SaleComponent = Pool().get('pricing.component')
|
SaleComponent = Pool().get('pricing.component')
|
||||||
|
|||||||
Reference in New Issue
Block a user