feat: validate negative stock for inventory dimension (backport #37373) (#37383)

* feat: validate negative stock for inventory dimension (#37373)

* feat: validate negative stock for inventory dimension

* test: test case for validate negative stock for inv dimension

(cherry picked from commit 1480acabb0)

# Conflicts:
#	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
#	erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
#	erpnext/stock/stock_ledger.py

* chore: fix conflicts

* chore: fix conflicts

* chore: fix conflicts

* chore: fix linter issue

* chore: fix linter issue

* chore: fix linter issue

* chore: fix linter issue

* chore: fix linter issue

---------

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
mergify[bot]
2023-10-16 19:15:18 +05:30
committed by GitHub
parent 6e3e4c8ade
commit 27a1e3bf83
8 changed files with 218 additions and 11 deletions

View File

@@ -24,6 +24,7 @@ from frappe.utils import (
import erpnext
from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
get_sre_reserved_qty_for_item_and_warehouse as get_reserved_stock,
)
@@ -711,10 +712,17 @@ class update_entries_after(object):
):
sle.outgoing_rate = get_incoming_rate_for_inter_company_transfer(sle)
dimensions = get_inventory_dimensions()
has_dimensions = False
if dimensions:
for dimension in dimensions:
if sle.get(dimension.get("fieldname")):
has_dimensions = True
if sle.serial_and_batch_bundle:
self.calculate_valuation_for_serial_batch_bundle(sle)
else:
if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no:
if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no and not has_dimensions:
# assert
self.wh_data.valuation_rate = sle.valuation_rate
self.wh_data.qty_after_transaction = sle.qty_after_transaction
@@ -1297,7 +1305,7 @@ def get_previous_sle_of_current_voucher(args, operator="<", exclude_current_vouc
return sle[0] if sle else frappe._dict()
def get_previous_sle(args, for_update=False):
def get_previous_sle(args, for_update=False, extra_cond=None):
"""
get the last sle on or before the current time-bucket,
to get actual qty before transaction, this function
@@ -1312,7 +1320,9 @@ def get_previous_sle(args, for_update=False):
}
"""
args["name"] = args.get("sle", None) or ""
sle = get_stock_ledger_entries(args, "<=", "desc", "limit 1", for_update=for_update)
sle = get_stock_ledger_entries(
args, "<=", "desc", "limit 1", for_update=for_update, extra_cond=extra_cond
)
return sle and sle[0] or {}
@@ -1324,6 +1334,7 @@ def get_stock_ledger_entries(
for_update=False,
debug=False,
check_serial_no=True,
extra_cond=None,
):
"""get stock ledger entries filtered by specific posting datetime conditions"""
conditions = " and timestamp(posting_date, posting_time) {0} timestamp(%(posting_date)s, %(posting_time)s)".format(
@@ -1361,6 +1372,9 @@ def get_stock_ledger_entries(
if operator in (">", "<=") and previous_sle.get("name"):
conditions += " and name!=%(name)s"
if extra_cond:
conditions += f"{extra_cond}"
return frappe.db.sql(
"""
select *, timestamp(posting_date, posting_time) as "timestamp"