mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-04 12:49:10 +00:00
fix: incorrect available qty for backdated stock reco with batch (#37858)
* fix: incorrect available qty for backdated stock reco with batch * test: added test case
This commit is contained in:
@@ -203,6 +203,11 @@ def make_entry(args, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||
sle.allow_negative_stock = allow_negative_stock
|
||||
sle.via_landed_cost_voucher = via_landed_cost_voucher
|
||||
sle.submit()
|
||||
|
||||
# Added to handle the case when the stock ledger entry is created from the repostig
|
||||
if args.get("creation_time") and args.get("voucher_type") == "Stock Reconciliation":
|
||||
sle.db_set("creation", args.get("creation_time"))
|
||||
|
||||
return sle
|
||||
|
||||
|
||||
@@ -689,9 +694,11 @@ class update_entries_after(object):
|
||||
|
||||
if (
|
||||
sle.voucher_type == "Stock Reconciliation"
|
||||
and (sle.batch_no or (sle.has_batch_no and sle.serial_and_batch_bundle))
|
||||
and (
|
||||
sle.batch_no or (sle.has_batch_no and sle.serial_and_batch_bundle and not sle.has_serial_no)
|
||||
)
|
||||
and sle.voucher_detail_no
|
||||
and sle.actual_qty < 0
|
||||
and not self.args.get("sle_id")
|
||||
):
|
||||
self.reset_actual_qty_for_stock_reco(sle)
|
||||
|
||||
@@ -754,27 +761,22 @@ class update_entries_after(object):
|
||||
self.update_outgoing_rate_on_transaction(sle)
|
||||
|
||||
def reset_actual_qty_for_stock_reco(self, sle):
|
||||
if sle.serial_and_batch_bundle:
|
||||
current_qty = frappe.get_cached_value(
|
||||
"Serial and Batch Bundle", sle.serial_and_batch_bundle, "total_qty"
|
||||
doc = frappe.get_cached_doc("Stock Reconciliation", sle.voucher_no)
|
||||
doc.recalculate_current_qty(sle.voucher_detail_no, sle.creation, sle.actual_qty > 0)
|
||||
|
||||
if sle.actual_qty < 0:
|
||||
sle.actual_qty = (
|
||||
flt(frappe.db.get_value("Stock Reconciliation Item", sle.voucher_detail_no, "current_qty"))
|
||||
* -1
|
||||
)
|
||||
|
||||
if current_qty is not None:
|
||||
current_qty = abs(current_qty)
|
||||
else:
|
||||
current_qty = frappe.get_cached_value(
|
||||
"Stock Reconciliation Item", sle.voucher_detail_no, "current_qty"
|
||||
)
|
||||
|
||||
if current_qty:
|
||||
sle.actual_qty = current_qty * -1
|
||||
elif current_qty == 0:
|
||||
sle.is_cancelled = 1
|
||||
if abs(sle.actual_qty) == 0.0:
|
||||
sle.is_cancelled = 1
|
||||
|
||||
def calculate_valuation_for_serial_batch_bundle(self, sle):
|
||||
doc = frappe.get_cached_doc("Serial and Batch Bundle", sle.serial_and_batch_bundle)
|
||||
|
||||
doc.set_incoming_rate(save=True)
|
||||
doc.set_incoming_rate(save=True, allow_negative_stock=self.allow_negative_stock)
|
||||
doc.calculate_qty_and_amount(save=True)
|
||||
|
||||
self.wh_data.stock_value = round_off_if_near_zero(self.wh_data.stock_value + doc.total_amount)
|
||||
@@ -1461,6 +1463,7 @@ def get_valuation_rate(
|
||||
currency=None,
|
||||
company=None,
|
||||
raise_error_if_no_rate=True,
|
||||
batch_no=None,
|
||||
serial_and_batch_bundle=None,
|
||||
):
|
||||
|
||||
@@ -1469,6 +1472,25 @@ def get_valuation_rate(
|
||||
if not company:
|
||||
company = frappe.get_cached_value("Warehouse", warehouse, "company")
|
||||
|
||||
if warehouse and batch_no and frappe.db.get_value("Batch", batch_no, "use_batchwise_valuation"):
|
||||
table = frappe.qb.DocType("Stock Ledger Entry")
|
||||
query = (
|
||||
frappe.qb.from_(table)
|
||||
.select(Sum(table.stock_value_difference) / Sum(table.actual_qty))
|
||||
.where(
|
||||
(table.item_code == item_code)
|
||||
& (table.warehouse == warehouse)
|
||||
& (table.batch_no == batch_no)
|
||||
& (table.is_cancelled == 0)
|
||||
& (table.voucher_no != voucher_no)
|
||||
& (table.voucher_type != voucher_type)
|
||||
)
|
||||
)
|
||||
|
||||
last_valuation_rate = query.run()
|
||||
if last_valuation_rate:
|
||||
return flt(last_valuation_rate[0][0])
|
||||
|
||||
# Get moving average rate of a specific batch number
|
||||
if warehouse and serial_and_batch_bundle:
|
||||
batch_obj = BatchNoValuation(
|
||||
@@ -1563,8 +1585,6 @@ def update_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
next_stock_reco_detail = get_next_stock_reco(args)
|
||||
if next_stock_reco_detail:
|
||||
detail = next_stock_reco_detail[0]
|
||||
if detail.batch_no or (detail.serial_and_batch_bundle and detail.has_batch_no):
|
||||
regenerate_sle_for_batch_stock_reco(detail)
|
||||
|
||||
# add condition to update SLEs before this date & time
|
||||
datetime_limit_condition = get_datetime_limit_condition(detail)
|
||||
@@ -1593,16 +1613,6 @@ def update_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
validate_negative_qty_in_future_sle(args, allow_negative_stock)
|
||||
|
||||
|
||||
def regenerate_sle_for_batch_stock_reco(detail):
|
||||
doc = frappe.get_cached_doc("Stock Reconciliation", detail.voucher_no)
|
||||
doc.recalculate_current_qty(detail.item_code, detail.batch_no)
|
||||
|
||||
if not frappe.db.exists(
|
||||
"Repost Item Valuation", {"voucher_no": doc.name, "status": "Queued", "docstatus": "1"}
|
||||
):
|
||||
doc.repost_future_sle_and_gle(force=True)
|
||||
|
||||
|
||||
def get_stock_reco_qty_shift(args):
|
||||
stock_reco_qty_shift = 0
|
||||
if args.get("is_cancelled"):
|
||||
|
||||
Reference in New Issue
Block a user