feat: get RM costs from consumption entry in manufacture SE (#39822) (cherry picked from commit 39067c761427e49c3c5aff5895faaee20de3f672) Co-authored-by: s-aga-r <sagarsharma.s312@gmail.com>
This commit is contained in:
parent
43fce29a04
commit
2d5f186812
@ -7,6 +7,7 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"raw_materials_consumption_section",
|
"raw_materials_consumption_section",
|
||||||
"material_consumption",
|
"material_consumption",
|
||||||
|
"get_rm_cost_from_consumption_entry",
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"backflush_raw_materials_based_on",
|
"backflush_raw_materials_based_on",
|
||||||
"capacity_planning",
|
"capacity_planning",
|
||||||
@ -202,13 +203,20 @@
|
|||||||
"fieldname": "set_op_cost_and_scrape_from_sub_assemblies",
|
"fieldname": "set_op_cost_and_scrape_from_sub_assemblies",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Set Operating Cost / Scrape Items From Sub-assemblies"
|
"label": "Set Operating Cost / Scrape Items From Sub-assemblies"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "eval: doc.material_consumption",
|
||||||
|
"fieldname": "get_rm_cost_from_consumption_entry",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Get Raw Materials Cost from Consumption Entry"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-wrench",
|
"icon": "icon-wrench",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-12-28 16:37:44.874096",
|
"modified": "2024-02-08 19:00:37.561244",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Manufacturing Settings",
|
"name": "Manufacturing Settings",
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class ManufacturingSettings(Document):
|
|||||||
default_scrap_warehouse: DF.Link | None
|
default_scrap_warehouse: DF.Link | None
|
||||||
default_wip_warehouse: DF.Link | None
|
default_wip_warehouse: DF.Link | None
|
||||||
disable_capacity_planning: DF.Check
|
disable_capacity_planning: DF.Check
|
||||||
|
get_rm_cost_from_consumption_entry: DF.Check
|
||||||
job_card_excess_transfer: DF.Check
|
job_card_excess_transfer: DF.Check
|
||||||
make_serial_no_batch_from_work_order: DF.Check
|
make_serial_no_batch_from_work_order: DF.Check
|
||||||
material_consumption: DF.Check
|
material_consumption: DF.Check
|
||||||
|
|||||||
@ -1775,6 +1775,52 @@ class TestWorkOrder(FrappeTestCase):
|
|||||||
"Manufacturing Settings", "set_op_cost_and_scrape_from_sub_assemblies", 0
|
"Manufacturing Settings", "set_op_cost_and_scrape_from_sub_assemblies", 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@change_settings(
|
||||||
|
"Manufacturing Settings", {"material_consumption": 1, "get_rm_cost_from_consumption_entry": 1}
|
||||||
|
)
|
||||||
|
def test_get_rm_cost_from_consumption_entry(self):
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import (
|
||||||
|
make_stock_entry as make_stock_entry_test_record,
|
||||||
|
)
|
||||||
|
|
||||||
|
rm = make_item(properties={"is_stock_item": 1}).name
|
||||||
|
fg = make_item(properties={"is_stock_item": 1}).name
|
||||||
|
|
||||||
|
make_stock_entry_test_record(
|
||||||
|
purpose="Material Receipt",
|
||||||
|
item_code=rm,
|
||||||
|
target="Stores - _TC",
|
||||||
|
qty=10,
|
||||||
|
basic_rate=100,
|
||||||
|
)
|
||||||
|
make_stock_entry_test_record(
|
||||||
|
purpose="Material Receipt",
|
||||||
|
item_code=rm,
|
||||||
|
target="Stores - _TC",
|
||||||
|
qty=10,
|
||||||
|
basic_rate=200,
|
||||||
|
)
|
||||||
|
|
||||||
|
bom = make_bom(item=fg, raw_materials=[rm], rate=150).name
|
||||||
|
wo = make_wo_order_test_record(
|
||||||
|
production_item=fg,
|
||||||
|
bom_no=bom,
|
||||||
|
qty=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
mte = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", 10))
|
||||||
|
mte.items[0].s_warehouse = "Stores - _TC"
|
||||||
|
mte.insert().submit()
|
||||||
|
|
||||||
|
mce = frappe.get_doc(make_stock_entry(wo.name, "Material Consumption for Manufacture", 10))
|
||||||
|
mce.insert().submit()
|
||||||
|
|
||||||
|
me = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 10))
|
||||||
|
me.insert().submit()
|
||||||
|
|
||||||
|
valuation_rate = sum([item.valuation_rate * item.transfer_qty for item in mce.items]) / 10
|
||||||
|
self.assertEqual(me.items[0].valuation_rate, valuation_rate)
|
||||||
|
|
||||||
|
|
||||||
def prepare_boms_for_sub_assembly_test():
|
def prepare_boms_for_sub_assembly_test():
|
||||||
if not frappe.db.exists("BOM", {"item": "Test Final SF Item 1"}):
|
if not frappe.db.exists("BOM", {"item": "Test Final SF Item 1"}):
|
||||||
|
|||||||
@ -899,14 +899,62 @@ class StockEntry(StockController):
|
|||||||
return flt(outgoing_items_cost / total_fg_qty)
|
return flt(outgoing_items_cost / total_fg_qty)
|
||||||
|
|
||||||
def get_basic_rate_for_manufactured_item(self, finished_item_qty, outgoing_items_cost=0) -> float:
|
def get_basic_rate_for_manufactured_item(self, finished_item_qty, outgoing_items_cost=0) -> float:
|
||||||
|
settings = frappe.get_single("Manufacturing Settings")
|
||||||
scrap_items_cost = sum([flt(d.basic_amount) for d in self.get("items") if d.is_scrap_item])
|
scrap_items_cost = sum([flt(d.basic_amount) for d in self.get("items") if d.is_scrap_item])
|
||||||
|
|
||||||
# Get raw materials cost from BOM if multiple material consumption entries
|
if settings.material_consumption:
|
||||||
if not outgoing_items_cost and frappe.db.get_single_value(
|
if settings.get_rm_cost_from_consumption_entry and self.work_order:
|
||||||
"Manufacturing Settings", "material_consumption", cache=True
|
|
||||||
):
|
# Validate only if Material Consumption Entry exists for the Work Order.
|
||||||
bom_items = self.get_bom_raw_materials(finished_item_qty)
|
if frappe.db.exists(
|
||||||
outgoing_items_cost = sum([flt(row.qty) * flt(row.rate) for row in bom_items.values()])
|
"Stock Entry",
|
||||||
|
{
|
||||||
|
"docstatus": 1,
|
||||||
|
"work_order": self.work_order,
|
||||||
|
"purpose": "Material Consumption for Manufacture",
|
||||||
|
},
|
||||||
|
):
|
||||||
|
for item in self.items:
|
||||||
|
if not item.is_finished_item and not item.is_scrap_item:
|
||||||
|
label = frappe.get_meta(settings.doctype).get_label("get_rm_cost_from_consumption_entry")
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Row {0}: As {1} is enabled, raw materials cannot be added to {2} entry. Use {3} entry to consume raw materials."
|
||||||
|
).format(
|
||||||
|
item.idx,
|
||||||
|
frappe.bold(label),
|
||||||
|
frappe.bold("Manufacture"),
|
||||||
|
frappe.bold("Material Consumption for Manufacture"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if frappe.db.exists(
|
||||||
|
"Stock Entry", {"docstatus": 1, "work_order": self.work_order, "purpose": "Manufacture"}
|
||||||
|
):
|
||||||
|
frappe.throw(
|
||||||
|
_("Only one {0} entry can be created against the Work Order {1}").format(
|
||||||
|
frappe.bold("Manufacture"), frappe.bold(self.work_order)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
SE = frappe.qb.DocType("Stock Entry")
|
||||||
|
SE_ITEM = frappe.qb.DocType("Stock Entry Detail")
|
||||||
|
|
||||||
|
outgoing_items_cost = (
|
||||||
|
frappe.qb.from_(SE)
|
||||||
|
.left_join(SE_ITEM)
|
||||||
|
.on(SE.name == SE_ITEM.parent)
|
||||||
|
.select(Sum(SE_ITEM.valuation_rate * SE_ITEM.transfer_qty))
|
||||||
|
.where(
|
||||||
|
(SE.docstatus == 1)
|
||||||
|
& (SE.work_order == self.work_order)
|
||||||
|
& (SE.purpose == "Material Consumption for Manufacture")
|
||||||
|
)
|
||||||
|
).run()[0][0] or 0
|
||||||
|
|
||||||
|
elif not outgoing_items_cost:
|
||||||
|
bom_items = self.get_bom_raw_materials(finished_item_qty)
|
||||||
|
outgoing_items_cost = sum([flt(row.qty) * flt(row.rate) for row in bom_items.values()])
|
||||||
|
|
||||||
return flt((outgoing_items_cost - scrap_items_cost) / finished_item_qty)
|
return flt((outgoing_items_cost - scrap_items_cost) / finished_item_qty)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user