fix: negative qty validation on stock reco cancellation (#27170)
* test: negative stock validation on SR cancel * fix: negative stock setting ignored in stock reco In stock reconcilation cancellation negative stock setting is ignored as `db.get_value` is returning string `'0'` which is not casted to int/bool for further logic. This causes negative qty, which evantually gets caught by reposting but by design this should stop cancellation. * test: typo and minor refactor
This commit is contained in:
parent
e11bfe7da4
commit
e7109c18db
@ -390,7 +390,7 @@ class StockReconciliation(StockController):
|
||||
sl_entries = self.merge_similar_item_serial_nos(sl_entries)
|
||||
|
||||
sl_entries.reverse()
|
||||
allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
|
||||
allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
|
||||
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@ from erpnext.stock.doctype.item.test_item import create_item
|
||||
from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
from erpnext.tests.utils import change_settings
|
||||
|
||||
|
||||
class TestStockReconciliation(unittest.TestCase):
|
||||
@ -310,6 +311,7 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
pr2.cancel()
|
||||
pr1.cancel()
|
||||
|
||||
@change_settings("Stock Settings", {"allow_negative_stock": 0})
|
||||
def test_backdated_stock_reco_future_negative_stock(self):
|
||||
"""
|
||||
Test if a backdated stock reco causes future negative stock and is blocked.
|
||||
@ -327,8 +329,6 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
create_item(item_code)
|
||||
|
||||
negative_stock_setting = frappe.db.get_single_value("Stock Settings", "allow_negative_stock")
|
||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 0)
|
||||
|
||||
pr1 = make_purchase_receipt(item_code=item_code, warehouse=warehouse, qty=10, rate=100,
|
||||
posting_date=add_days(nowdate(), -2))
|
||||
@ -348,11 +348,50 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
self.assertRaises(NegativeStockError, sr3.submit)
|
||||
|
||||
# teardown
|
||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", negative_stock_setting)
|
||||
sr3.cancel()
|
||||
dn2.cancel()
|
||||
pr1.cancel()
|
||||
|
||||
|
||||
@change_settings("Stock Settings", {"allow_negative_stock": 0})
|
||||
def test_backdated_stock_reco_cancellation_future_negative_stock(self):
|
||||
"""
|
||||
Test if a backdated stock reco cancellation that causes future negative stock is blocked.
|
||||
-------------------------------------------
|
||||
Var | Doc | Qty | Balance
|
||||
-------------------------------------------
|
||||
SR | Reco | 100 | 100 (posting date: today-1) (shouldn't be cancelled after DN)
|
||||
DN | DN | 100 | 0 (posting date: today)
|
||||
"""
|
||||
from erpnext.stock.stock_ledger import NegativeStockError
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
frappe.db.commit()
|
||||
|
||||
item_code = "Backdated-Reco-Cancellation-Item"
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
create_item(item_code)
|
||||
|
||||
|
||||
sr = create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=100, rate=100,
|
||||
posting_date=add_days(nowdate(), -1))
|
||||
|
||||
dn = create_delivery_note(item_code=item_code, warehouse=warehouse, qty=100, rate=120,
|
||||
posting_date=nowdate())
|
||||
|
||||
dn_balance = frappe.db.get_value("Stock Ledger Entry", {"voucher_no": dn.name, "is_cancelled": 0},
|
||||
"qty_after_transaction")
|
||||
self.assertEqual(dn_balance, 0)
|
||||
|
||||
# check if cancellation of stock reco is blocked
|
||||
self.assertRaises(NegativeStockError, sr.cancel)
|
||||
|
||||
repost_exists = bool(frappe.db.exists("Repost Item Valuation", {"voucher_no": sr.name}))
|
||||
self.assertFalse(repost_exists, msg="Negative stock validation not working on reco cancellation")
|
||||
|
||||
# teardown
|
||||
frappe.db.rollback()
|
||||
|
||||
|
||||
def test_valid_batch(self):
|
||||
create_batch_item_with_batch("Testing Batch Item 1", "001")
|
||||
create_batch_item_with_batch("Testing Batch Item 2", "002")
|
||||
|
@ -955,7 +955,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
|
||||
|
||||
return valuation_rate
|
||||
|
||||
def update_qty_in_future_sle(args, allow_negative_stock=None):
|
||||
def update_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
"""Recalculate Qty after Transaction in future SLEs based on current SLE."""
|
||||
datetime_limit_condition = ""
|
||||
qty_shift = args.actual_qty
|
||||
@ -1044,8 +1044,8 @@ def get_datetime_limit_condition(detail):
|
||||
)
|
||||
)"""
|
||||
|
||||
def validate_negative_qty_in_future_sle(args, allow_negative_stock=None):
|
||||
allow_negative_stock = allow_negative_stock \
|
||||
def validate_negative_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
allow_negative_stock = cint(allow_negative_stock) \
|
||||
or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock"))
|
||||
|
||||
if (args.actual_qty < 0 or args.voucher_type == "Stock Reconciliation") and not allow_negative_stock:
|
||||
|
Loading…
Reference in New Issue
Block a user