fix: non batch-wise valuation for batch item

(cherry picked from commit 11b82ba008)
This commit is contained in:
Rohit Waghchaure
2025-09-04 00:48:45 +05:30
committed by Mergify
parent eb631d6e75
commit affe09ee0b
5 changed files with 53 additions and 9 deletions

View File

@@ -1,4 +1,5 @@
import datetime
import json
from collections import defaultdict
import frappe
@@ -197,6 +198,9 @@ class DeprecatedBatchNoValuation:
@deprecated
def set_balance_value_for_non_batchwise_valuation_batches(self):
self.last_sle = self.get_last_sle_for_non_batch()
if self.last_sle and self.last_sle.stock_value:
self.stock_queue = json.loads(self.last_sle.stock_queue or "[]") or []
self.set_balance_value_from_sl_entries()
self.set_balance_value_from_bundle()
@@ -271,6 +275,7 @@ class DeprecatedBatchNoValuation:
.select(
sle.stock_value,
sle.qty_after_transaction,
sle.stock_queue,
)
.where(
(sle.item_code == self.sle.item_code)

View File

@@ -3,6 +3,7 @@
import collections
import csv
import json
from collections import Counter, defaultdict
import frappe
@@ -29,6 +30,7 @@ from erpnext.stock.serial_batch_bundle import (
get_batches_from_bundle,
)
from erpnext.stock.serial_batch_bundle import get_serial_nos as get_serial_nos_from_bundle
from erpnext.stock.valuation import FIFOValuation
class SerialNoExistsInFutureTransactionError(frappe.ValidationError):
@@ -463,6 +465,8 @@ class SerialandBatchBundle(Document):
)
def set_incoming_rate_for_outward_transaction(self, row=None, save=False, allow_negative_stock=False):
from erpnext.stock.utils import get_valuation_method
sle = self.get_sle_for_outward_transaction()
if self.has_serial_no:
@@ -479,13 +483,40 @@ class SerialandBatchBundle(Document):
warehouse=self.warehouse,
)
stock_queue = []
if hasattr(sn_obj, "stock_queue") and sn_obj.stock_queue:
stock_queue = parse_json(sn_obj.stock_queue)
val_method = get_valuation_method(self.item_code)
for d in self.entries:
available_qty = 0
if self.has_serial_no:
d.incoming_rate = abs(sn_obj.serial_no_incoming_rate.get(d.serial_no, 0.0))
else:
d.incoming_rate = abs(flt(sn_obj.batch_avg_rate.get(d.batch_no)))
actual_qty = d.qty
if (
stock_queue
and val_method == "FIFO"
and d.batch_no in sn_obj.non_batchwise_valuation_batches
):
if actual_qty < 0:
stock_queue = FIFOValuation(stock_queue)
_prev_qty, prev_stock_value = stock_queue.get_total_stock_and_value()
stock_queue.remove_stock(qty=abs(actual_qty))
_qty, stock_value = stock_queue.get_total_stock_and_value()
stock_value_difference = stock_value - prev_stock_value
d.incoming_rate = abs(flt(stock_value_difference) / abs(flt(actual_qty)))
stock_queue = stock_queue.state
else:
d.incoming_rate = abs(flt(sn_obj.batch_avg_rate.get(d.batch_no)))
stock_queue.append([d.qty, d.incoming_rate])
d.stock_queue = json.dumps(stock_queue)
else:
d.incoming_rate = abs(flt(sn_obj.batch_avg_rate.get(d.batch_no)))
available_qty = flt(sn_obj.available_qty.get(d.batch_no), d.precision("qty"))
if self.docstatus == 1:

View File

@@ -674,6 +674,7 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
for key, value in kwargs.items():
setattr(self, key, value)
self.stock_queue = []
self.batch_nos = self.get_batch_nos()
self.prepare_batches()
self.calculate_avg_rate()
@@ -770,15 +771,12 @@ class BatchNoValuation(DeprecatedBatchNoValuation):
self.non_batchwise_valuation_batches = self.batches
return
if get_valuation_method(self.sle.item_code) == "FIFO":
self.batchwise_valuation_batches = self.batches
else:
batches = frappe.get_all(
"Batch", filters={"name": ("in", self.batches), "use_batchwise_valuation": 1}, fields=["name"]
)
batches = frappe.get_all(
"Batch", filters={"name": ("in", self.batches), "use_batchwise_valuation": 1}, fields=["name"]
)
for batch in batches:
self.batchwise_valuation_batches.append(batch.name)
for batch in batches:
self.batchwise_valuation_batches.append(batch.name)
self.non_batchwise_valuation_batches = list(set(self.batches) - set(self.batchwise_valuation_batches))

View File

@@ -1042,6 +1042,15 @@ class update_entries_after:
doc.set_incoming_rate(save=True, allow_negative_stock=self.allow_negative_stock)
doc.calculate_qty_and_amount(save=True)
if stock_queue := frappe.get_all(
"Serial and Batch Entry",
filters={"parent": sle.serial_and_batch_bundle, "stock_queue": ("is", "set")},
pluck="stock_queue",
order_by="idx desc",
limit=1,
):
self.wh_data.stock_queue = json.loads(stock_queue[0]) if stock_queue else []
self.wh_data.stock_value = round_off_if_near_zero(self.wh_data.stock_value + doc.total_amount)
self.wh_data.qty_after_transaction += flt(doc.total_qty, self.flt_precision)
if flt(self.wh_data.qty_after_transaction, self.flt_precision):

View File

@@ -373,6 +373,7 @@ def get_avg_purchase_rate(serial_nos):
)
@frappe.request_cache
def get_valuation_method(item_code):
"""get valuation method from item or default"""
val_method = frappe.db.get_value("Item", item_code, "valuation_method", cache=True)