mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-04 05:58:27 +00:00
* fix: negative stock balance (#44990)
(cherry picked from commit 7c4aecf834)
# Conflicts:
# erpnext/stock/deprecated_serial_batch.py
* chore: fix conflicts
---------
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -181,6 +181,9 @@ class DeprecatedBatchNoValuation:
|
|||||||
stock_value_change = self.batch_avg_rate[batch_no] * ledger.qty
|
stock_value_change = self.batch_avg_rate[batch_no] * ledger.qty
|
||||||
self.stock_value_change += stock_value_change
|
self.stock_value_change += stock_value_change
|
||||||
|
|
||||||
|
self.non_batchwise_balance_value[batch_no] -= stock_value_change
|
||||||
|
self.non_batchwise_balance_qty[batch_no] -= ledger.qty
|
||||||
|
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
"Serial and Batch Entry",
|
"Serial and Batch Entry",
|
||||||
ledger.name,
|
ledger.name,
|
||||||
@@ -220,7 +223,6 @@ class DeprecatedBatchNoValuation:
|
|||||||
.select(
|
.select(
|
||||||
sle.batch_no,
|
sle.batch_no,
|
||||||
Sum(sle.actual_qty).as_("batch_qty"),
|
Sum(sle.actual_qty).as_("batch_qty"),
|
||||||
Sum(sle.stock_value_difference).as_("batch_value"),
|
|
||||||
)
|
)
|
||||||
.where(
|
.where(
|
||||||
(sle.item_code == self.sle.item_code)
|
(sle.item_code == self.sle.item_code)
|
||||||
@@ -237,11 +239,59 @@ class DeprecatedBatchNoValuation:
|
|||||||
if self.sle.name:
|
if self.sle.name:
|
||||||
query = query.where(sle.name != self.sle.name)
|
query = query.where(sle.name != self.sle.name)
|
||||||
|
|
||||||
for d in query.run(as_dict=True):
|
batch_data = query.run(as_dict=True)
|
||||||
self.non_batchwise_balance_value[d.batch_no] += flt(d.batch_value)
|
for d in batch_data:
|
||||||
self.non_batchwise_balance_qty[d.batch_no] += flt(d.batch_qty)
|
|
||||||
self.available_qty[d.batch_no] += flt(d.batch_qty)
|
self.available_qty[d.batch_no] += flt(d.batch_qty)
|
||||||
|
|
||||||
|
last_sle = self.get_last_sle_for_non_batch()
|
||||||
|
for d in batch_data:
|
||||||
|
self.non_batchwise_balance_value[d.batch_no] += flt(last_sle.stock_value)
|
||||||
|
self.non_batchwise_balance_qty[d.batch_no] += flt(last_sle.qty_after_transaction)
|
||||||
|
|
||||||
|
def get_last_sle_for_non_batch(self):
|
||||||
|
from erpnext.stock.utils import get_combine_datetime
|
||||||
|
|
||||||
|
sle = frappe.qb.DocType("Stock Ledger Entry")
|
||||||
|
batch = frappe.qb.DocType("Batch")
|
||||||
|
|
||||||
|
posting_datetime = get_combine_datetime(self.sle.posting_date, self.sle.posting_time)
|
||||||
|
if not self.sle.creation:
|
||||||
|
posting_datetime = posting_datetime + datetime.timedelta(milliseconds=1)
|
||||||
|
|
||||||
|
timestamp_condition = sle.posting_datetime < posting_datetime
|
||||||
|
|
||||||
|
if self.sle.creation:
|
||||||
|
timestamp_condition |= (sle.posting_datetime == posting_datetime) & (
|
||||||
|
sle.creation < self.sle.creation
|
||||||
|
)
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(sle)
|
||||||
|
.inner_join(batch)
|
||||||
|
.on(sle.batch_no == batch.name)
|
||||||
|
.select(
|
||||||
|
sle.stock_value,
|
||||||
|
sle.qty_after_transaction,
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
(sle.item_code == self.sle.item_code)
|
||||||
|
& (sle.warehouse == self.sle.warehouse)
|
||||||
|
& (sle.batch_no.isnotnull())
|
||||||
|
& (batch.use_batchwise_valuation == 0)
|
||||||
|
& (sle.is_cancelled == 0)
|
||||||
|
)
|
||||||
|
.where(timestamp_condition)
|
||||||
|
.orderby(sle.posting_datetime, order=Order.desc)
|
||||||
|
.orderby(sle.creation, order=Order.desc)
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.sle.name:
|
||||||
|
query = query.where(sle.name != self.sle.name)
|
||||||
|
|
||||||
|
data = query.run(as_dict=True)
|
||||||
|
return data[0] if data else {}
|
||||||
|
|
||||||
@deprecated
|
@deprecated
|
||||||
def set_balance_value_from_bundle(self) -> None:
|
def set_balance_value_from_bundle(self) -> None:
|
||||||
bundle = frappe.qb.DocType("Serial and Batch Bundle")
|
bundle = frappe.qb.DocType("Serial and Batch Bundle")
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
for qty, valuation in {10: 100, 20: 200}.items():
|
for qty, valuation in {10: 100, 20: 200}.items():
|
||||||
stock_queue.append([qty, valuation])
|
stock_queue.append([qty, valuation])
|
||||||
qty_after_transaction += qty
|
qty_after_transaction += qty
|
||||||
balance_value += qty_after_transaction * valuation
|
balance_value += qty * valuation
|
||||||
|
|
||||||
doc = frappe.get_doc(
|
doc = frappe.get_doc(
|
||||||
{
|
{
|
||||||
@@ -177,6 +177,7 @@ class TestSerialandBatchBundle(FrappeTestCase):
|
|||||||
"incoming_rate": valuation,
|
"incoming_rate": valuation,
|
||||||
"qty_after_transaction": qty_after_transaction,
|
"qty_after_transaction": qty_after_transaction,
|
||||||
"stock_value_difference": valuation * qty,
|
"stock_value_difference": valuation * qty,
|
||||||
|
"stock_value": balance_value,
|
||||||
"balance_value": balance_value,
|
"balance_value": balance_value,
|
||||||
"valuation_rate": balance_value / qty_after_transaction,
|
"valuation_rate": balance_value / qty_after_transaction,
|
||||||
"actual_qty": qty,
|
"actual_qty": qty,
|
||||||
|
|||||||
Reference in New Issue
Block a user