fix: valuation rate not updating for raw materials

(cherry picked from commit 5af8378471)

# Conflicts:
#	erpnext/manufacturing/doctype/work_order/test_work_order.py
(cherry picked from commit 454dd3a2f1)
This commit is contained in:
Rohit Waghchaure
2025-03-27 17:33:43 +05:30
committed by Mergify
parent 66d0ad1bc6
commit 57e2619cf1
2 changed files with 300 additions and 1 deletions

View File

@@ -2602,6 +2602,293 @@ class TestWorkOrder(FrappeTestCase):
status = frappe.db.get_value("Serial No", row, "status")
self.assertEqual(status, "Consumed")
<<<<<<< HEAD
=======
def test_stock_reservation_for_serialized_raw_material(self):
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
make_stock_entry as make_stock_entry_test_record,
)
production_item = "Test Stock Reservation FG 1"
rm_item = "Test Stock Reservation RM 1"
source_warehouse = "Stores - _TC"
make_item(production_item, {"is_stock_item": 1})
make_item(rm_item, {"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "TST-SER-RES-.###"})
bom = make_bom(
item=production_item,
source_warehouse=source_warehouse,
raw_materials=[rm_item],
operating_cost_per_bom_quantity=100,
do_not_submit=True,
)
for row in bom.exploded_items:
make_stock_entry_test_record(
item_code=row.item_code,
target=source_warehouse,
qty=10,
basic_rate=100,
)
wo = make_wo_order_test_record(
item=production_item,
qty=10,
reserve_stock=1,
source_warehouse=source_warehouse,
)
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
wo1 = make_wo_order_test_record(
item=production_item,
qty=10,
reserve_stock=1,
source_warehouse=source_warehouse,
)
self.assertFalse(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo1.name}))
transfer_entry = frappe.get_doc(make_stock_entry(wo1.name, "Material Transfer for Manufacture", 10))
transfer_entry.save()
self.assertRaises(frappe.ValidationError, transfer_entry.submit)
def test_stock_reservation_for_batched_raw_material(self):
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
make_stock_entry as make_stock_entry_test_record,
)
production_item = "Test Stock Reservation FG 2"
rm_item = "Test Stock Reservation RM 2"
source_warehouse = "Stores - _TC"
make_item(production_item, {"is_stock_item": 1})
make_item(
rm_item,
{
"is_stock_item": 1,
"has_batch_no": 1,
"batch_number_series": "TST-BATCH-RES-.###",
"create_new_batch": 1,
},
)
bom = make_bom(
item=production_item,
source_warehouse=source_warehouse,
raw_materials=[rm_item],
operating_cost_per_bom_quantity=100,
do_not_submit=True,
)
for row in bom.exploded_items:
make_stock_entry_test_record(
item_code=row.item_code,
target=source_warehouse,
qty=10,
basic_rate=100,
)
wo = make_wo_order_test_record(
item=production_item,
qty=10,
reserve_stock=1,
source_warehouse=source_warehouse,
)
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
wo1 = make_wo_order_test_record(
item=production_item,
qty=10,
reserve_stock=1,
source_warehouse=source_warehouse,
)
self.assertFalse(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo1.name}))
transfer_entry = frappe.get_doc(make_stock_entry(wo1.name, "Material Transfer for Manufacture", 10))
transfer_entry.save()
self.assertRaises(frappe.ValidationError, transfer_entry.submit)
def test_auto_stock_reservation_for_batched_raw_material(self):
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
make_stock_entry as make_stock_entry_test_record,
)
frappe.db.set_single_value("Stock Settings", "auto_reserve_serial_and_batch", 1)
production_item = "Test Stock Reservation FG 3"
rm_item = "Test Stock Reservation RM 3"
source_warehouse = "Stores - _TC"
make_item(production_item, {"is_stock_item": 1})
make_item(
rm_item,
{
"is_stock_item": 1,
"has_batch_no": 1,
"batch_number_series": "TST-BATCH-RES-.###",
"create_new_batch": 1,
},
)
bom = make_bom(
item=production_item,
source_warehouse=source_warehouse,
raw_materials=[rm_item],
operating_cost_per_bom_quantity=100,
do_not_submit=True,
)
itemwise_batches = frappe._dict()
for row in bom.exploded_items:
se = make_stock_entry_test_record(
item_code=row.item_code,
target=source_warehouse,
qty=10,
basic_rate=100,
)
itemwise_batches[row.item_code] = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
wo = make_wo_order_test_record(
item=production_item,
qty=10,
reserve_stock=1,
source_warehouse=source_warehouse,
)
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
for row in frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}):
reservation_entry = frappe.get_doc("Stock Reservation Entry", row.name)
self.assertTrue(reservation_entry.has_batch_no)
self.assertTrue(reservation_entry.sb_entries)
for row in bom.exploded_items:
make_stock_entry_test_record(
item_code=row.item_code,
target=source_warehouse,
qty=10,
basic_rate=100,
)
transfer_entry = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 10))
transfer_entry.save()
transfer_entry.submit()
for row in transfer_entry.items:
batch_no = get_batch_from_bundle(row.serial_and_batch_bundle)
self.assertEqual(batch_no, itemwise_batches[row.item_code])
def test_work_order_valuation_auto_pick(self):
fg_item = "Test FG Item For Non Transfer Item Batch"
rm_item = "Test RM Item For Non Transfer Item Batch"
make_item(fg_item, {"is_stock_item": 1})
make_item(
rm_item,
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"batch_number_series": "TST-BATCH-NTI-.###",
},
)
source_warehouse = "_Test Warehouse - _TC"
wip_warehouse = "Stores - _TC"
finished_goods_warehouse = create_warehouse("_Test Finished Goods Warehouse", company="_Test Company")
batches = make_stock_in_entries_and_get_batches(rm_item, source_warehouse, wip_warehouse)
if not frappe.db.get_value("BOM", {"item": fg_item}):
make_bom(item=fg_item, raw_materials=[rm_item])
wo = make_wo_order_test_record(
item=fg_item,
qty=5,
source_warehouse=source_warehouse,
wip_warehouse=wip_warehouse,
fg_warehouse=finished_goods_warehouse,
)
stock_entry = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 5))
stock_entry.items[0].batch_no = batches[1]
stock_entry.items[0].use_serial_batch_fields = 1
stock_entry.submit()
stock_entry.reload()
self.assertEqual(stock_entry.items[0].valuation_rate, 200)
original_value = frappe.db.get_single_value(
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward"
)
original_based_on = frappe.db.get_single_value("Stock Settings", "pick_serial_and_batch_based_on")
frappe.db.set_single_value("Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1)
frappe.db.set_single_value("Stock Settings", "pick_serial_and_batch_based_on", "Expiry")
stock_entry = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 5))
stock_entry.items[0].use_serial_batch_fields = 1
stock_entry.submit()
stock_entry.reload()
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
self.assertEqual(batch_no, batches[1])
self.assertEqual(stock_entry.items[0].valuation_rate, 200)
self.assertEqual(stock_entry.items[1].valuation_rate, 200)
frappe.db.set_single_value(
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", original_value
)
frappe.db.set_single_value("Stock Settings", "pick_serial_and_batch_based_on", original_based_on)
def make_stock_in_entries_and_get_batches(rm_item, source_warehouse, wip_warehouse):
from erpnext.stock.doctype.stock_entry.test_stock_entry import (
make_stock_entry as make_stock_entry_test_record,
)
batches = []
for qty, rate in ((5, 100), (5, 200)):
stock_entry = make_stock_entry_test_record(
item_code=rm_item,
target=source_warehouse,
qty=qty,
basic_rate=rate,
)
stock_entry.submit()
stock_entry.reload()
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
batch_doc = frappe.get_doc("Batch", batch_no)
# keep early expiry date for the batch having rate 200
days = 10 if rate == 100 else 1
batch_doc.db_set("expiry_date", add_to_date(now(), days=days))
batches.append(batch_no)
stock_entry = make_stock_entry_test_record(
item_code=rm_item,
target=wip_warehouse,
qty=qty,
basic_rate=rate,
)
stock_entry.submit()
stock_entry.reload()
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
batch_doc = frappe.get_doc("Batch", batch_no)
batch_doc.db_set("expiry_date", add_to_date(now(), days=10))
return batches
>>>>>>> 5af8378471 (fix: valuation rate not updating for raw materials)
def make_operation(**kwargs):
kwargs = frappe._dict(kwargs)

View File

@@ -1212,9 +1212,21 @@ class update_entries_after:
frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
if not sle.dependant_sle_voucher_detail_no:
if not sle.dependant_sle_voucher_detail_no or self.is_manufacture_entry_with_sabb(sle):
self.recalculate_amounts_in_stock_entry(sle.voucher_no, sle.voucher_detail_no)
def is_manufacture_entry_with_sabb(self, sle):
if (
self.args.get("sle_id")
and sle.serial_and_batch_bundle
and sle.auto_created_serial_and_batch_bundle
):
purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose")
if purpose in ["Manufacture", "Repack"]:
return True
return False
def recalculate_amounts_in_stock_entry(self, voucher_no, voucher_detail_no):
stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True)
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)