fix: incorrect current qty for the batch in stock reco (#42434)
(cherry picked from commit 9cd3374101)
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -2188,6 +2188,8 @@ def get_stock_ledgers_for_serial_nos(kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def get_stock_ledgers_batches(kwargs):
|
def get_stock_ledgers_batches(kwargs):
|
||||||
|
from erpnext.stock.utils import get_combine_datetime
|
||||||
|
|
||||||
stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
|
stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
|
||||||
batch_table = frappe.qb.DocType("Batch")
|
batch_table = frappe.qb.DocType("Batch")
|
||||||
|
|
||||||
@@ -2214,6 +2216,19 @@ def get_stock_ledgers_batches(kwargs):
|
|||||||
else:
|
else:
|
||||||
query = query.where(stock_ledger_entry[field] == kwargs.get(field))
|
query = query.where(stock_ledger_entry[field] == kwargs.get(field))
|
||||||
|
|
||||||
|
if kwargs.get("posting_date"):
|
||||||
|
if kwargs.get("posting_time") is None:
|
||||||
|
kwargs.posting_time = nowtime()
|
||||||
|
|
||||||
|
timestamp_condition = stock_ledger_entry.posting_datetime <= get_combine_datetime(
|
||||||
|
kwargs.posting_date, kwargs.posting_time
|
||||||
|
)
|
||||||
|
|
||||||
|
query = query.where(timestamp_condition)
|
||||||
|
|
||||||
|
if kwargs.get("ignore_voucher_nos"):
|
||||||
|
query = query.where(stock_ledger_entry.voucher_no.notin(kwargs.get("ignore_voucher_nos")))
|
||||||
|
|
||||||
if kwargs.based_on == "LIFO":
|
if kwargs.based_on == "LIFO":
|
||||||
query = query.orderby(batch_table.creation, order=frappe.qb.desc)
|
query = query.orderby(batch_table.creation, order=frappe.qb.desc)
|
||||||
elif kwargs.based_on == "Expiry":
|
elif kwargs.based_on == "Expiry":
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle impor
|
|||||||
get_available_serial_nos,
|
get_available_serial_nos,
|
||||||
)
|
)
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
from erpnext.stock.utils import get_stock_balance
|
from erpnext.stock.utils import get_incoming_rate, get_stock_balance
|
||||||
|
|
||||||
|
|
||||||
class OpeningEntryAccountError(frappe.ValidationError):
|
class OpeningEntryAccountError(frappe.ValidationError):
|
||||||
@@ -952,14 +952,21 @@ class StockReconciliation(StockController):
|
|||||||
precesion = row.precision("current_qty")
|
precesion = row.precision("current_qty")
|
||||||
if flt(current_qty, precesion) != flt(row.current_qty, precesion):
|
if flt(current_qty, precesion) != flt(row.current_qty, precesion):
|
||||||
if not row.serial_no:
|
if not row.serial_no:
|
||||||
val_rate = get_valuation_rate(
|
val_rate = get_incoming_rate(
|
||||||
row.item_code,
|
frappe._dict(
|
||||||
row.warehouse,
|
{
|
||||||
self.doctype,
|
"item_code": row.item_code,
|
||||||
self.name,
|
"warehouse": row.warehouse,
|
||||||
company=self.company,
|
"qty": current_qty * -1,
|
||||||
batch_no=row.batch_no,
|
"serial_and_batch_bundle": row.current_serial_and_batch_bundle,
|
||||||
serial_and_batch_bundle=row.current_serial_and_batch_bundle,
|
"batch_no": row.batch_no,
|
||||||
|
"voucher_type": self.doctype,
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"company": self.company,
|
||||||
|
"posting_date": self.posting_date,
|
||||||
|
"posting_time": self.posting_time,
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
row.current_valuation_rate = val_rate
|
row.current_valuation_rate = val_rate
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# ERPNext - web based ERP (http://erpnext.com)
|
# ERPNext - web based ERP (http://erpnext.com)
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
@@ -1182,6 +1183,98 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin):
|
|||||||
self.assertAlmostEqual(row.incoming_rate, 1000.00)
|
self.assertAlmostEqual(row.incoming_rate, 1000.00)
|
||||||
self.assertEqual(row.serial_no, serial_nos[row.idx - 1])
|
self.assertEqual(row.serial_no, serial_nos[row.idx - 1])
|
||||||
|
|
||||||
|
def test_stock_reco_with_legacy_batch(self):
|
||||||
|
from erpnext.stock.doctype.batch.batch import get_batch_qty
|
||||||
|
|
||||||
|
batch_item_code = self.make_item(
|
||||||
|
"Test Batch Item Legacy Batch 1",
|
||||||
|
{
|
||||||
|
"is_stock_item": 1,
|
||||||
|
"has_batch_no": 1,
|
||||||
|
"create_new_batch": 1,
|
||||||
|
"batch_number_series": "BH1-NRALL-S-.###",
|
||||||
|
},
|
||||||
|
).name
|
||||||
|
|
||||||
|
warehouse = "_Test Warehouse - _TC"
|
||||||
|
|
||||||
|
frappe.flags.ignore_serial_batch_bundle_validation = True
|
||||||
|
frappe.flags.use_serial_and_batch_fields = True
|
||||||
|
|
||||||
|
batch_id = "BH1-NRALL-S-0001"
|
||||||
|
if not frappe.db.exists("Batch", batch_id):
|
||||||
|
batch_doc = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Batch",
|
||||||
|
"batch_id": batch_id,
|
||||||
|
"item": batch_item_code,
|
||||||
|
"use_batchwise_valuation": 0,
|
||||||
|
}
|
||||||
|
).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
self.assertTrue(batch_doc.use_batchwise_valuation)
|
||||||
|
|
||||||
|
stock_queue = []
|
||||||
|
qty_after_transaction = 0
|
||||||
|
balance_value = 0
|
||||||
|
i = 0
|
||||||
|
for qty, valuation in {10: 100, 20: 200}.items():
|
||||||
|
i += 1
|
||||||
|
stock_queue.append([qty, valuation])
|
||||||
|
qty_after_transaction += qty
|
||||||
|
balance_value += qty_after_transaction * valuation
|
||||||
|
|
||||||
|
doc = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Stock Ledger Entry",
|
||||||
|
"posting_date": add_days(nowdate(), -2 * i),
|
||||||
|
"posting_time": nowtime(),
|
||||||
|
"batch_no": batch_id,
|
||||||
|
"incoming_rate": valuation,
|
||||||
|
"qty_after_transaction": qty_after_transaction,
|
||||||
|
"stock_value_difference": valuation * qty,
|
||||||
|
"balance_value": balance_value,
|
||||||
|
"valuation_rate": balance_value / qty_after_transaction,
|
||||||
|
"actual_qty": qty,
|
||||||
|
"item_code": batch_item_code,
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"stock_queue": json.dumps(stock_queue),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
doc.flags.ignore_permissions = True
|
||||||
|
doc.flags.ignore_mandatory = True
|
||||||
|
doc.flags.ignore_links = True
|
||||||
|
doc.flags.ignore_validate = True
|
||||||
|
doc.submit()
|
||||||
|
doc.reload()
|
||||||
|
|
||||||
|
frappe.flags.ignore_serial_batch_bundle_validation = False
|
||||||
|
frappe.flags.use_serial_and_batch_fields = False
|
||||||
|
|
||||||
|
batch_doc = frappe.get_doc("Batch", batch_id)
|
||||||
|
|
||||||
|
qty = get_batch_qty(batch_id, warehouse, batch_item_code)
|
||||||
|
self.assertEqual(qty, 30)
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(
|
||||||
|
item_code=batch_item_code,
|
||||||
|
posting_date=add_days(nowdate(), -3),
|
||||||
|
posting_time=nowtime(),
|
||||||
|
warehouse=warehouse,
|
||||||
|
qty=100,
|
||||||
|
rate=1000,
|
||||||
|
reconcile_all_serial_batch=0,
|
||||||
|
batch_no=batch_id,
|
||||||
|
use_serial_batch_fields=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(sr.items[0].current_qty, 20)
|
||||||
|
self.assertEqual(sr.items[0].qty, 100)
|
||||||
|
|
||||||
|
qty = get_batch_qty(batch_id, warehouse, batch_item_code)
|
||||||
|
self.assertEqual(qty, 110)
|
||||||
|
|
||||||
|
|
||||||
def create_batch_item_with_batch(item_name, batch_id):
|
def create_batch_item_with_batch(item_name, batch_id):
|
||||||
batch_item_doc = create_item(item_name, is_stock_item=1)
|
batch_item_doc = create_item(item_name, is_stock_item=1)
|
||||||
|
|||||||
Reference in New Issue
Block a user