refactor(manufacturing): rename secondary item valuation type to "% of Component Cost" (backport #59021) (#59022)

Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
This commit is contained in:
mergify[bot]
2026-09-12 06:19:45 +00:00
committed by GitHub
parent 8672a6e604
commit d4bacb7354
18 changed files with 46 additions and 30 deletions

View File

@@ -1026,7 +1026,7 @@ frappe.tour["BOM"] = [
frappe.ui.form.on("BOM Secondary Item", { frappe.ui.form.on("BOM Secondary Item", {
valuation_type(frm, cdt, cdn) { valuation_type(frm, cdt, cdn) {
const row = locals[cdt][cdn]; const row = locals[cdt][cdn];
if (row.valuation_type !== "% of FG Cost") { if (row.valuation_type !== "% of Component Cost") {
frappe.model.set_value(cdt, cdn, "cost_allocation_per", 0); frappe.model.set_value(cdt, cdn, "cost_allocation_per", 0);
} }
if (row.valuation_type === "Valuation Rate") { if (row.valuation_type === "Valuation Rate") {

View File

@@ -1092,7 +1092,7 @@ class BOM(WebsiteGenerator):
def calculate_secondary_items_costs(self, save=False): def calculate_secondary_items_costs(self, save=False):
"""Valuation Rate and Manual rows carry their own cost, deducted from the raw """Valuation Rate and Manual rows carry their own cost, deducted from the raw
material cost; the % of FG Cost rows split the remainder by their percentage.""" material cost; the % of Component Cost rows split the remainder by their percentage."""
total_sm_cost = 0 total_sm_cost = 0
base_total_sm_cost = 0 base_total_sm_cost = 0
precision = self.precision("raw_material_cost") precision = self.precision("raw_material_cost")

View File

@@ -462,7 +462,7 @@ class TestBOM(ERPNextTestSuite):
"secondary_item_type": "Additional Finished Good", "secondary_item_type": "Additional Finished Good",
"qty": 1, "qty": 1,
"cost_allocation_per": 10, "cost_allocation_per": 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
@@ -497,7 +497,7 @@ class TestBOM(ERPNextTestSuite):
"secondary_item_type": "Scrap", "secondary_item_type": "Scrap",
"qty": 1, "qty": 1,
"cost_allocation_per": 10, "cost_allocation_per": 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
self.assertRaises(frappe.ValidationError, bom_doc.save) self.assertRaises(frappe.ValidationError, bom_doc.save)
@@ -570,7 +570,7 @@ class TestBOM(ERPNextTestSuite):
"secondary_item_type": "By-Product", "secondary_item_type": "By-Product",
"qty": 1, "qty": 1,
"cost_allocation_per": 10, "cost_allocation_per": 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom_doc.save() bom_doc.save()

View File

@@ -138,7 +138,7 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "eval:doc.valuation_type == '% of FG Cost'", "depends_on": "eval:doc.valuation_type == '% of Component Cost'",
"fieldname": "cost_allocation_per", "fieldname": "cost_allocation_per",
"fieldtype": "Percent", "fieldtype": "Percent",
"label": "Cost Allocation %", "label": "Cost Allocation %",
@@ -178,11 +178,11 @@
}, },
{ {
"default": "Valuation Rate", "default": "Valuation Rate",
"description": "Valuation Rate and Manual value this item on its own and deduct that cost from the raw material cost, like the pre-v16 scrap items. % of FG Cost allocates a percentage of the remaining raw material cost.", "description": "Valuation Rate and Manual value this item on its own and deduct that cost from the raw material cost, like the pre-v16 scrap items. % of Component Cost allocates a percentage of the remaining raw material cost.",
"fieldname": "valuation_type", "fieldname": "valuation_type",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Valuation Type", "label": "Valuation Type",
"options": "Valuation Rate\n% of FG Cost\nManual", "options": "Valuation Rate\n% of Component Cost\nManual",
"reqd": 1, "reqd": 1,
"show_description_on_click": 1 "show_description_on_click": 1
}, },

View File

@@ -32,7 +32,7 @@ class BOMSecondaryItem(Document):
stock_qty: DF.Float stock_qty: DF.Float
stock_uom: DF.Link | None stock_uom: DF.Link | None
uom: DF.Link uom: DF.Link
valuation_type: DF.Literal["Valuation Rate", "% of FG Cost", "Manual"] valuation_type: DF.Literal["Valuation Rate", "% of Component Cost", "Manual"]
# end: auto-generated types # end: auto-generated types
pass pass

View File

@@ -1303,7 +1303,7 @@ class TestJobCard(ERPNextTestSuite):
"qty": 1, "qty": 1,
"process_loss_per": 10, "process_loss_per": 10,
"cost_allocation_per": 5, "cost_allocation_per": 5,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
"secondary_item_type": "Scrap", "secondary_item_type": "Scrap",
}, },
) )
@@ -2645,7 +2645,7 @@ class TestJobCard(ERPNextTestSuite):
"secondary_item_type": "Scrap", "secondary_item_type": "Scrap",
"qty": 1, "qty": 1,
"cost_allocation_per": cost_allocation_per, "cost_allocation_per": cost_allocation_per,
"valuation_type": "% of FG Cost" if cost_allocation_per else "Valuation Rate", "valuation_type": "% of Component Cost" if cost_allocation_per else "Valuation Rate",
}, },
) )
bom_doc.save() bom_doc.save()
@@ -2701,7 +2701,7 @@ class TestJobCard(ERPNextTestSuite):
self.assertEqual(rows[bom_links[0]].qty, 2) self.assertEqual(rows[bom_links[0]].qty, 2)
self.assertEqual(rows[bom_links[0]].valuation_type, "Valuation Rate") self.assertEqual(rows[bom_links[0]].valuation_type, "Valuation Rate")
self.assertEqual(rows[bom_links[1]].qty, 3) self.assertEqual(rows[bom_links[1]].qty, 3)
self.assertEqual(rows[bom_links[1]].valuation_type, "% of FG Cost") self.assertEqual(rows[bom_links[1]].valuation_type, "% of Component Cost")
@ERPNextTestSuite.change_settings( @ERPNextTestSuite.change_settings(
"Manufacturing Settings", {"overproduction_percentage_for_work_order": 100} "Manufacturing Settings", {"overproduction_percentage_for_work_order": 100}

View File

@@ -4023,7 +4023,7 @@ def make_bom(**args):
"stock_uom": item_doc.stock_uom, "stock_uom": item_doc.stock_uom,
"qty": args.scrap_qty or 1, "qty": args.scrap_qty or 1,
"cost_allocation_per": args.scrap_cost_allocation_per or 10, "cost_allocation_per": args.scrap_cost_allocation_per or 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
"process_loss_per": args.scrap_process_loss_per or 10, "process_loss_per": args.scrap_process_loss_per or 10,
}, },
) )

View File

@@ -4789,7 +4789,7 @@ class TestWorkOrder(ERPNextTestSuite):
"item_name": scrap_item, "item_name": scrap_item,
"qty": 3, "qty": 3,
"cost_allocation_per": 25, "cost_allocation_per": 25,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
"process_loss_per": 0, "process_loss_per": 0,
}, },
) )
@@ -4838,7 +4838,7 @@ class TestWorkOrder(ERPNextTestSuite):
"item_name": scrap_item, "item_name": scrap_item,
"qty": 3, "qty": 3,
"cost_allocation_per": 25, "cost_allocation_per": 25,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
"process_loss_per": 0, "process_loss_per": 0,
}, },
) )

View File

@@ -507,3 +507,4 @@ erpnext.patches.v16_0.append_fieldname_to_pos_search_fields
erpnext.patches.v16_0.set_secondary_item_valuation_type erpnext.patches.v16_0.set_secondary_item_valuation_type
erpnext.patches.v16_0.add_transaction_roles_to_sms_settings erpnext.patches.v16_0.add_transaction_roles_to_sms_settings
erpnext.patches.v16_0.recalculate_holiday_list_totals erpnext.patches.v16_0.recalculate_holiday_list_totals
erpnext.patches.v16_0.rename_component_cost_valuation_type

View File

@@ -0,0 +1,15 @@
import frappe
DOCTYPES = ("BOM Secondary Item", "Stock Entry Detail", "Subcontracting Receipt Item")
def execute():
"""Rename the `% of FG Cost` valuation type: the percentage is of the component cost."""
for doctype in DOCTYPES:
frappe.db.set_value(
doctype,
{"valuation_type": "% of FG Cost"},
"valuation_type",
"% of Component Cost",
update_modified=False,
)

View File

@@ -310,7 +310,7 @@ frappe.ui.form.on("Stock Entry", {
frm.trigger("toggle_warehouse_fields"); frm.trigger("toggle_warehouse_fields");
// only BOM-less rows are editable, and they cannot allocate a BOM percentage; // only BOM-less rows are editable, and they cannot allocate a BOM percentage;
// read-only rows from a BOM still display their stored % of FG Cost // read-only rows from a BOM still display their stored % of Component Cost
frm.fields_dict.items.grid.update_docfield_property("valuation_type", "options", [ frm.fields_dict.items.grid.update_docfield_property("valuation_type", "options", [
"Valuation Rate", "Valuation Rate",
"Manual", "Manual",

View File

@@ -1656,7 +1656,7 @@ class StockEntry(StockController, SubcontractingInwardController):
def set_bomless_secondary_valuation_types(self): def set_bomless_secondary_valuation_types(self):
"""Secondary rows without a BOM link choose their own costing: valuation rate or manual. """Secondary rows without a BOM link choose their own costing: valuation rate or manual.
There is no percentage to allocate without a BOM row, so % of FG Cost is rejected.""" There is no percentage to allocate without a BOM row, so % of Component Cost is rejected."""
for d in self.get("items"): for d in self.get("items"):
if d.bom_secondary_item: if d.bom_secondary_item:
continue continue
@@ -1667,10 +1667,10 @@ class StockEntry(StockController, SubcontractingInwardController):
d.set_basic_rate_manually = 0 d.set_basic_rate_manually = 0
continue continue
if d.valuation_type == "% of FG Cost": if d.valuation_type == "% of Component Cost":
frappe.throw( frappe.throw(
_( _(
"Row #{0}: % of FG Cost needs a BOM secondary item. Choose Valuation Rate or Manual for {1}." "Row #{0}: % of Component Cost needs a BOM secondary item. Choose Valuation Rate or Manual for {1}."
).format(d.idx, frappe.bold(d.item_code)) ).format(d.idx, frappe.bold(d.item_code))
) )

View File

@@ -1124,7 +1124,7 @@ class TestStockEntry(ERPNextTestSuite):
"secondary_item_type": "By-Product", "secondary_item_type": "By-Product",
"qty": 1, "qty": 1,
"cost_allocation_per": 10, "cost_allocation_per": 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom_doc.save() bom_doc.save()
@@ -1208,7 +1208,7 @@ class TestStockEntry(ERPNextTestSuite):
"secondary_item_type": "By-Product", "secondary_item_type": "By-Product",
"qty": 1, "qty": 1,
"cost_allocation_per": 10, "cost_allocation_per": 10,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom_doc.save() bom_doc.save()
@@ -1422,7 +1422,7 @@ class TestStockEntry(ERPNextTestSuite):
self.assertEqual(fg_row.basic_amount, 830) self.assertEqual(fg_row.basic_amount, 830)
# there is no percentage to allocate without a BOM row # there is no percentage to allocate without a BOM row
manual_row.valuation_type = "% of FG Cost" manual_row.valuation_type = "% of Component Cost"
self.assertRaises(frappe.ValidationError, entry.save) self.assertRaises(frappe.ValidationError, entry.save)
def test_valuation_rate_lookup_without_voucher_no(self): def test_valuation_rate_lookup_without_voucher_no(self):
@@ -3348,7 +3348,7 @@ class TestStockEntry(ERPNextTestSuite):
"qty": 5, "qty": 5,
"cost_allocation_per": 25, "cost_allocation_per": 25,
"process_loss_per": 0, "process_loss_per": 0,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom.insert() bom.insert()
@@ -3410,7 +3410,7 @@ class TestStockEntry(ERPNextTestSuite):
"qty": 5, "qty": 5,
"cost_allocation_per": 0, "cost_allocation_per": 0,
"process_loss_per": 0, "process_loss_per": 0,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom.insert() bom.insert()
@@ -3497,7 +3497,7 @@ class TestStockEntry(ERPNextTestSuite):
"qty": 5, "qty": 5,
"cost_allocation_per": 25, "cost_allocation_per": 25,
"process_loss_per": 0, "process_loss_per": 0,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
}, },
) )
bom.insert() bom.insert()

View File

@@ -682,7 +682,7 @@
"fieldname": "valuation_type", "fieldname": "valuation_type",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Valuation Type", "label": "Valuation Type",
"options": "\nValuation Rate\n% of FG Cost\nManual", "options": "\nValuation Rate\n% of Component Cost\nManual",
"read_only_depends_on": "eval:!doc.secondary_item_type || doc.bom_secondary_item" "read_only_depends_on": "eval:!doc.secondary_item_type || doc.bom_secondary_item"
} }
], ],

View File

@@ -69,7 +69,7 @@ class StockEntryDetail(Document):
transferred_qty: DF.Float transferred_qty: DF.Float
secondary_item_type: DF.Literal["", "Co-Product", "By-Product", "Scrap", "Additional Finished Good"] secondary_item_type: DF.Literal["", "Co-Product", "By-Product", "Scrap", "Additional Finished Good"]
uom: DF.Link uom: DF.Link
valuation_type: DF.Literal["", "Valuation Rate", "% of FG Cost", "Manual"] valuation_type: DF.Literal["", "Valuation Rate", "% of Component Cost", "Manual"]
use_serial_batch_fields: DF.Check use_serial_batch_fields: DF.Check
valuation_rate: DF.Currency valuation_rate: DF.Currency
# end: auto-generated types # end: auto-generated types

View File

@@ -1216,7 +1216,7 @@ class TestSubcontractingReceipt(ERPNextTestSuite):
"item_code": percentage_item, "item_code": percentage_item,
"secondary_item_type": "Co-Product", "secondary_item_type": "Co-Product",
"stock_qty": 1, "stock_qty": 1,
"valuation_type": "% of FG Cost", "valuation_type": "% of Component Cost",
"cost_allocation_per": 10, "cost_allocation_per": 10,
}, },
) )

View File

@@ -623,7 +623,7 @@
"fieldname": "valuation_type", "fieldname": "valuation_type",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Valuation Type", "label": "Valuation Type",
"options": "\nValuation Rate\n% of FG Cost\nManual", "options": "\nValuation Rate\n% of Component Cost\nManual",
"read_only": 1 "read_only": 1
}, },
{ {

View File

@@ -64,7 +64,7 @@ class SubcontractingReceiptItem(Document):
subcontracting_receipt_item: DF.Data | None subcontracting_receipt_item: DF.Data | None
secondary_item_type: DF.Literal["", "Co-Product", "By-Product", "Scrap", "Additional Finished Good"] secondary_item_type: DF.Literal["", "Co-Product", "By-Product", "Scrap", "Additional Finished Good"]
use_serial_batch_fields: DF.Check use_serial_batch_fields: DF.Check
valuation_type: DF.Literal["", "Valuation Rate", "% of FG Cost", "Manual"] valuation_type: DF.Literal["", "Valuation Rate", "% of Component Cost", "Manual"]
warehouse: DF.Link | None warehouse: DF.Link | None
# end: auto-generated types # end: auto-generated types