Merge branch 'develop' into fixed-negative-stock-error
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 38bf0a5..cc06bd7 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -1662,6 +1662,48 @@
self.assertRaises(BatchExpiredError, se.save)
+ def test_negative_stock_reco(self):
+ from erpnext.controllers.stock_controller import BatchExpiredError
+ from erpnext.stock.doctype.batch.test_batch import make_new_batch
+
+ frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 0)
+
+ item_code = "Test Negative Item - 001"
+ item_doc = create_item(item_code=item_code, is_stock_item=1, valuation_rate=10)
+
+ make_stock_entry(
+ item_code=item_code,
+ posting_date=add_days(today(), -3),
+ posting_time="00:00:00",
+ purpose="Material Receipt",
+ qty=10,
+ to_warehouse="_Test Warehouse - _TC",
+ do_not_save=True,
+ )
+
+ make_stock_entry(
+ item_code=item_code,
+ posting_date=today(),
+ posting_time="00:00:00",
+ purpose="Material Receipt",
+ qty=8,
+ from_warehouse="_Test Warehouse - _TC",
+ do_not_save=True,
+ )
+
+ sr_doc = create_stock_reconciliation(
+ purpose="Stock Reconciliation",
+ posting_date=add_days(today(), -3),
+ posting_time="00:00:00",
+ item_code=item_code,
+ warehouse="_Test Warehouse - _TC",
+ valuation_rate=10,
+ qty=7,
+ do_not_submit=True,
+ )
+
+ self.assertRaises(frappe.ValidationError, sr_doc.submit)
+
def make_serialized_item(**args):
args = frappe._dict(args)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index d8b12ed..08fc6fb 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -1050,7 +1050,7 @@
frappe.db.set_value("Bin", bin_name, updated_values, update_modified=True)
-def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False):
+def get_previous_sle_of_current_voucher(args, operator="<", exclude_current_voucher=False):
"""get stock ledger entries filtered by specific posting datetime conditions"""
args["time_format"] = "%H:%i:%s"
@@ -1076,13 +1076,13 @@
posting_date < %(posting_date)s or
(
posting_date = %(posting_date)s and
- time_format(posting_time, %(time_format)s) < time_format(%(posting_time)s, %(time_format)s)
+ time_format(posting_time, %(time_format)s) {operator} time_format(%(posting_time)s, %(time_format)s)
)
)
order by timestamp(posting_date, posting_time) desc, creation desc
limit 1
for update""".format(
- voucher_condition=voucher_condition
+ operator=operator, voucher_condition=voucher_condition
),
args,
as_dict=1,
@@ -1375,7 +1375,7 @@
stock_reco_qty_shift = flt(args.actual_qty)
else:
# reco is being submitted
- last_balance = get_previous_sle_of_current_voucher(args, exclude_current_voucher=True).get(
+ last_balance = get_previous_sle_of_current_voucher(args, "<=", exclude_current_voucher=True).get(
"qty_after_transaction"
)