From c8410cb5ca6a03f25b06688cadb491a36c755cc0 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 7 Aug 2025 00:50:56 +0530 Subject: [PATCH] fix: zero valuation rate for the batch --- .../sales_invoice/test_sales_invoice.py | 96 ++++++++++++++++++- erpnext/stock/serial_batch_bundle.py | 9 ++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e5272f3e1a7..a3b6c42afef 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -8,7 +8,7 @@ import frappe from frappe import qb from frappe.model.dynamic_links import get_dynamic_link_map from frappe.tests import IntegrationTestCase, change_settings -from frappe.utils import add_days, flt, format_date, getdate, nowdate, today +from frappe.utils import add_days, cint, flt, format_date, getdate, nowdate, today import erpnext from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account @@ -4602,6 +4602,99 @@ class TestSalesInvoice(ERPNextTestSuite): self.assertEqual(q[0][0], 1) + def test_non_batchwise_valuation_for_moving_average(self): + from erpnext.stock.doctype.item.test_item import make_item + + item_code = "_Test Item for Non Batchwise Valuation" + make_item_for_si( + item_code, + { + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "TBATCH-TCNV.####", + "valuation_method": "Moving Average", + }, + ) + + doc = frappe.get_doc("Stock Settings") + original_value = cint(doc.do_not_use_batchwise_valuation) + + doc.db_set("do_not_use_batchwise_valuation", 1) + + se = make_stock_entry( + item_code=item_code, + qty=10, + target="_Test Warehouse - _TC", + rate=13.02, + valuation_method="Moving Average", + use_serial_batch_fields=True, + ) + + se_batch = get_batch_from_bundle(se.items[0].serial_and_batch_bundle) + + # without use serial and batch fields + si = create_sales_invoice( + item=item_code, + qty=1, + rate=120, + update_stock=1, + use_serial_batch_fields=False, + warehouse="_Test Warehouse - _TC", + ) + + si.reload() + si_batch = get_batch_from_bundle(si.items[0].serial_and_batch_bundle) + + self.assertEqual(se_batch, si_batch) + self.assertEqual(si.items[0].use_serial_batch_fields, 0) + + serial_and_batch_bundle = si.items[0].serial_and_batch_bundle + change_in_value = frappe.db.get_value( + "Stock Ledger Entry", + { + "voucher_type": "Sales Invoice", + "voucher_no": si.name, + "item_code": item_code, + "warehouse": "_Test Warehouse - _TC", + "serial_and_batch_bundle": serial_and_batch_bundle, + }, + "stock_value_difference", + ) + + self.assertEqual(change_in_value, 13.02 * -1) + + # with use serial and batch fields + si = create_sales_invoice( + item=item_code, + qty=1, + rate=120, + update_stock=1, + use_serial_batch_fields=True, + warehouse="_Test Warehouse - _TC", + ) + + si.reload() + + self.assertEqual(si.items[0].use_serial_batch_fields, 1) + + serial_and_batch_bundle = si.items[0].serial_and_batch_bundle + change_in_value = frappe.db.get_value( + "Stock Ledger Entry", + { + "voucher_type": "Sales Invoice", + "voucher_no": si.name, + "item_code": item_code, + "warehouse": "_Test Warehouse - _TC", + "serial_and_batch_bundle": serial_and_batch_bundle, + }, + "stock_value_difference", + ) + + self.assertEqual(change_in_value, 13.02 * -1) + + doc.db_set("do_not_use_batchwise_valuation", original_value) + def make_item_for_si(item_code, properties=None): from erpnext.stock.doctype.item.test_item import make_item @@ -4725,6 +4818,7 @@ def create_sales_invoice(**args): "incoming_rate": args.incoming_rate or 0, "serial_and_batch_bundle": bundle_id, "allow_zero_valuation_rate": args.allow_zero_valuation_rate or 0, + "use_serial_batch_fields": args.use_serial_batch_fields or 0, }, ) diff --git a/erpnext/stock/serial_batch_bundle.py b/erpnext/stock/serial_batch_bundle.py index 1ed0021347a..e896f0bc8fd 100644 --- a/erpnext/stock/serial_batch_bundle.py +++ b/erpnext/stock/serial_batch_bundle.py @@ -113,6 +113,7 @@ class SerialBatchBundle: "is_rejected": self.is_rejected_entry(), "is_packed": self.is_packed_entry(), "make_bundle_from_sle": 1, + "sle": self.sle, } ).make_serial_and_batch_bundle() @@ -1036,6 +1037,14 @@ class SerialBatchCreation: if not hasattr(self, "do_not_submit") or not self.do_not_submit: doc.flags.ignore_voucher_validation = True + if self.get("sle"): + doc.flags.ignore_validate = True + doc.save() + self.sle.db_set("serial_and_batch_bundle", doc.name, update_modified=False) + + if doc.flags.ignore_validate: + doc.flags.ignore_validate = False + doc.submit() else: doc.save()