Skip to content

Commit 57e2619

Browse files
rohitwaghchauremergify[bot]
authored andcommitted
fix: valuation rate not updating for raw materials
(cherry picked from commit 5af8378) # Conflicts: # erpnext/manufacturing/doctype/work_order/test_work_order.py (cherry picked from commit 454dd3a)
1 parent 66d0ad1 commit 57e2619

2 files changed

Lines changed: 300 additions & 1 deletion

File tree

erpnext/manufacturing/doctype/work_order/test_work_order.py

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,6 +2602,293 @@ def test_serial_no_status_for_stock_entry(self):
26022602
status = frappe.db.get_value("Serial No", row, "status")
26032603
self.assertEqual(status, "Consumed")
26042604

2605+
<<<<<<< HEAD
2606+
=======
2607+
def test_stock_reservation_for_serialized_raw_material(self):
2608+
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
2609+
make_stock_entry as make_stock_entry_test_record,
2610+
)
2611+
2612+
production_item = "Test Stock Reservation FG 1"
2613+
rm_item = "Test Stock Reservation RM 1"
2614+
source_warehouse = "Stores - _TC"
2615+
2616+
make_item(production_item, {"is_stock_item": 1})
2617+
make_item(rm_item, {"is_stock_item": 1, "has_serial_no": 1, "serial_no_series": "TST-SER-RES-.###"})
2618+
2619+
bom = make_bom(
2620+
item=production_item,
2621+
source_warehouse=source_warehouse,
2622+
raw_materials=[rm_item],
2623+
operating_cost_per_bom_quantity=100,
2624+
do_not_submit=True,
2625+
)
2626+
2627+
for row in bom.exploded_items:
2628+
make_stock_entry_test_record(
2629+
item_code=row.item_code,
2630+
target=source_warehouse,
2631+
qty=10,
2632+
basic_rate=100,
2633+
)
2634+
2635+
wo = make_wo_order_test_record(
2636+
item=production_item,
2637+
qty=10,
2638+
reserve_stock=1,
2639+
source_warehouse=source_warehouse,
2640+
)
2641+
2642+
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
2643+
2644+
wo1 = make_wo_order_test_record(
2645+
item=production_item,
2646+
qty=10,
2647+
reserve_stock=1,
2648+
source_warehouse=source_warehouse,
2649+
)
2650+
2651+
self.assertFalse(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo1.name}))
2652+
2653+
transfer_entry = frappe.get_doc(make_stock_entry(wo1.name, "Material Transfer for Manufacture", 10))
2654+
transfer_entry.save()
2655+
2656+
self.assertRaises(frappe.ValidationError, transfer_entry.submit)
2657+
2658+
def test_stock_reservation_for_batched_raw_material(self):
2659+
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
2660+
make_stock_entry as make_stock_entry_test_record,
2661+
)
2662+
2663+
production_item = "Test Stock Reservation FG 2"
2664+
rm_item = "Test Stock Reservation RM 2"
2665+
source_warehouse = "Stores - _TC"
2666+
2667+
make_item(production_item, {"is_stock_item": 1})
2668+
make_item(
2669+
rm_item,
2670+
{
2671+
"is_stock_item": 1,
2672+
"has_batch_no": 1,
2673+
"batch_number_series": "TST-BATCH-RES-.###",
2674+
"create_new_batch": 1,
2675+
},
2676+
)
2677+
2678+
bom = make_bom(
2679+
item=production_item,
2680+
source_warehouse=source_warehouse,
2681+
raw_materials=[rm_item],
2682+
operating_cost_per_bom_quantity=100,
2683+
do_not_submit=True,
2684+
)
2685+
2686+
for row in bom.exploded_items:
2687+
make_stock_entry_test_record(
2688+
item_code=row.item_code,
2689+
target=source_warehouse,
2690+
qty=10,
2691+
basic_rate=100,
2692+
)
2693+
2694+
wo = make_wo_order_test_record(
2695+
item=production_item,
2696+
qty=10,
2697+
reserve_stock=1,
2698+
source_warehouse=source_warehouse,
2699+
)
2700+
2701+
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
2702+
2703+
wo1 = make_wo_order_test_record(
2704+
item=production_item,
2705+
qty=10,
2706+
reserve_stock=1,
2707+
source_warehouse=source_warehouse,
2708+
)
2709+
2710+
self.assertFalse(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo1.name}))
2711+
2712+
transfer_entry = frappe.get_doc(make_stock_entry(wo1.name, "Material Transfer for Manufacture", 10))
2713+
transfer_entry.save()
2714+
2715+
self.assertRaises(frappe.ValidationError, transfer_entry.submit)
2716+
2717+
def test_auto_stock_reservation_for_batched_raw_material(self):
2718+
from erpnext.stock.doctype.stock_entry.stock_entry_utils import (
2719+
make_stock_entry as make_stock_entry_test_record,
2720+
)
2721+
2722+
frappe.db.set_single_value("Stock Settings", "auto_reserve_serial_and_batch", 1)
2723+
2724+
production_item = "Test Stock Reservation FG 3"
2725+
rm_item = "Test Stock Reservation RM 3"
2726+
source_warehouse = "Stores - _TC"
2727+
2728+
make_item(production_item, {"is_stock_item": 1})
2729+
make_item(
2730+
rm_item,
2731+
{
2732+
"is_stock_item": 1,
2733+
"has_batch_no": 1,
2734+
"batch_number_series": "TST-BATCH-RES-.###",
2735+
"create_new_batch": 1,
2736+
},
2737+
)
2738+
2739+
bom = make_bom(
2740+
item=production_item,
2741+
source_warehouse=source_warehouse,
2742+
raw_materials=[rm_item],
2743+
operating_cost_per_bom_quantity=100,
2744+
do_not_submit=True,
2745+
)
2746+
2747+
itemwise_batches = frappe._dict()
2748+
for row in bom.exploded_items:
2749+
se = make_stock_entry_test_record(
2750+
item_code=row.item_code,
2751+
target=source_warehouse,
2752+
qty=10,
2753+
basic_rate=100,
2754+
)
2755+
2756+
itemwise_batches[row.item_code] = get_batch_from_bundle(se.items[0].serial_and_batch_bundle)
2757+
2758+
wo = make_wo_order_test_record(
2759+
item=production_item,
2760+
qty=10,
2761+
reserve_stock=1,
2762+
source_warehouse=source_warehouse,
2763+
)
2764+
2765+
self.assertTrue(frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}))
2766+
2767+
for row in frappe.get_all("Stock Reservation Entry", filters={"voucher_no": wo.name}):
2768+
reservation_entry = frappe.get_doc("Stock Reservation Entry", row.name)
2769+
self.assertTrue(reservation_entry.has_batch_no)
2770+
self.assertTrue(reservation_entry.sb_entries)
2771+
2772+
for row in bom.exploded_items:
2773+
make_stock_entry_test_record(
2774+
item_code=row.item_code,
2775+
target=source_warehouse,
2776+
qty=10,
2777+
basic_rate=100,
2778+
)
2779+
2780+
transfer_entry = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 10))
2781+
transfer_entry.save()
2782+
transfer_entry.submit()
2783+
2784+
for row in transfer_entry.items:
2785+
batch_no = get_batch_from_bundle(row.serial_and_batch_bundle)
2786+
self.assertEqual(batch_no, itemwise_batches[row.item_code])
2787+
2788+
def test_work_order_valuation_auto_pick(self):
2789+
fg_item = "Test FG Item For Non Transfer Item Batch"
2790+
rm_item = "Test RM Item For Non Transfer Item Batch"
2791+
2792+
make_item(fg_item, {"is_stock_item": 1})
2793+
make_item(
2794+
rm_item,
2795+
{
2796+
"is_stock_item": 1,
2797+
"has_batch_no": 1,
2798+
"create_new_batch": 1,
2799+
"batch_number_series": "TST-BATCH-NTI-.###",
2800+
},
2801+
)
2802+
2803+
source_warehouse = "_Test Warehouse - _TC"
2804+
wip_warehouse = "Stores - _TC"
2805+
finished_goods_warehouse = create_warehouse("_Test Finished Goods Warehouse", company="_Test Company")
2806+
2807+
batches = make_stock_in_entries_and_get_batches(rm_item, source_warehouse, wip_warehouse)
2808+
2809+
if not frappe.db.get_value("BOM", {"item": fg_item}):
2810+
make_bom(item=fg_item, raw_materials=[rm_item])
2811+
2812+
wo = make_wo_order_test_record(
2813+
item=fg_item,
2814+
qty=5,
2815+
source_warehouse=source_warehouse,
2816+
wip_warehouse=wip_warehouse,
2817+
fg_warehouse=finished_goods_warehouse,
2818+
)
2819+
2820+
stock_entry = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 5))
2821+
stock_entry.items[0].batch_no = batches[1]
2822+
stock_entry.items[0].use_serial_batch_fields = 1
2823+
stock_entry.submit()
2824+
stock_entry.reload()
2825+
2826+
self.assertEqual(stock_entry.items[0].valuation_rate, 200)
2827+
2828+
original_value = frappe.db.get_single_value(
2829+
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward"
2830+
)
2831+
original_based_on = frappe.db.get_single_value("Stock Settings", "pick_serial_and_batch_based_on")
2832+
2833+
frappe.db.set_single_value("Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", 1)
2834+
frappe.db.set_single_value("Stock Settings", "pick_serial_and_batch_based_on", "Expiry")
2835+
2836+
stock_entry = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 5))
2837+
stock_entry.items[0].use_serial_batch_fields = 1
2838+
stock_entry.submit()
2839+
stock_entry.reload()
2840+
2841+
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
2842+
self.assertEqual(batch_no, batches[1])
2843+
self.assertEqual(stock_entry.items[0].valuation_rate, 200)
2844+
self.assertEqual(stock_entry.items[1].valuation_rate, 200)
2845+
2846+
frappe.db.set_single_value(
2847+
"Stock Settings", "auto_create_serial_and_batch_bundle_for_outward", original_value
2848+
)
2849+
frappe.db.set_single_value("Stock Settings", "pick_serial_and_batch_based_on", original_based_on)
2850+
2851+
2852+
def make_stock_in_entries_and_get_batches(rm_item, source_warehouse, wip_warehouse):
2853+
from erpnext.stock.doctype.stock_entry.test_stock_entry import (
2854+
make_stock_entry as make_stock_entry_test_record,
2855+
)
2856+
2857+
batches = []
2858+
for qty, rate in ((5, 100), (5, 200)):
2859+
stock_entry = make_stock_entry_test_record(
2860+
item_code=rm_item,
2861+
target=source_warehouse,
2862+
qty=qty,
2863+
basic_rate=rate,
2864+
)
2865+
stock_entry.submit()
2866+
stock_entry.reload()
2867+
2868+
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
2869+
batch_doc = frappe.get_doc("Batch", batch_no)
2870+
2871+
# keep early expiry date for the batch having rate 200
2872+
days = 10 if rate == 100 else 1
2873+
batch_doc.db_set("expiry_date", add_to_date(now(), days=days))
2874+
2875+
batches.append(batch_no)
2876+
2877+
stock_entry = make_stock_entry_test_record(
2878+
item_code=rm_item,
2879+
target=wip_warehouse,
2880+
qty=qty,
2881+
basic_rate=rate,
2882+
)
2883+
stock_entry.submit()
2884+
stock_entry.reload()
2885+
batch_no = get_batch_from_bundle(stock_entry.items[0].serial_and_batch_bundle)
2886+
batch_doc = frappe.get_doc("Batch", batch_no)
2887+
batch_doc.db_set("expiry_date", add_to_date(now(), days=10))
2888+
2889+
return batches
2890+
2891+
>>>>>>> 5af8378471 (fix: valuation rate not updating for raw materials)
26052892

26062893
def make_operation(**kwargs):
26072894
kwargs = frappe._dict(kwargs)

erpnext/stock/stock_ledger.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,9 +1212,21 @@ def update_rate_on_stock_entry(self, sle, outgoing_rate):
12121212
frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
12131213

12141214
# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
1215-
if not sle.dependant_sle_voucher_detail_no:
1215+
if not sle.dependant_sle_voucher_detail_no or self.is_manufacture_entry_with_sabb(sle):
12161216
self.recalculate_amounts_in_stock_entry(sle.voucher_no, sle.voucher_detail_no)
12171217

1218+
def is_manufacture_entry_with_sabb(self, sle):
1219+
if (
1220+
self.args.get("sle_id")
1221+
and sle.serial_and_batch_bundle
1222+
and sle.auto_created_serial_and_batch_bundle
1223+
):
1224+
purpose = frappe.get_cached_value("Stock Entry", sle.voucher_no, "purpose")
1225+
if purpose in ["Manufacture", "Repack"]:
1226+
return True
1227+
1228+
return False
1229+
12181230
def recalculate_amounts_in_stock_entry(self, voucher_no, voucher_detail_no):
12191231
stock_entry = frappe.get_doc("Stock Entry", voucher_no, for_update=True)
12201232
stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)

0 commit comments

Comments
 (0)