diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 9fb9dfe58ab..92327243834 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -1442,7 +1442,7 @@ class StockController(AccountsController): elif self.doctype == "Stock Entry" and row.t_warehouse: qi_required = True # inward stock needs inspection - if row.get("type") or row.get("is_legacy_scrap_item"): + if row.get("secondary_item_type") or row.get("is_legacy_scrap_item"): continue if qi_required: # validate row only if inspection is required on item level diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 0ab520d8548..d7cc6b427d0 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -150,7 +150,7 @@ class SubcontractingController(StockController): ).format(item.idx, get_link_to_form("Item", item.item_code)) ) - if not item.get("type") and not item.get("is_legacy_scrap_item"): + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item"): if not is_sub_contracted_item: frappe.throw( _("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name) @@ -1243,10 +1243,10 @@ class SubcontractingController(StockController): total_amt = sum( flt(item.amount) for item in self.get("items") - if not item.get("type") and not item.get("is_legacy_scrap_item") + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item") ) for item in self.items: - if not item.get("type") and not item.get("is_legacy_scrap_item"): + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item"): item.additional_cost_per_qty = ( (item.amount * self.total_additional_costs) / total_amt ) / item.qty @@ -1254,15 +1254,15 @@ class SubcontractingController(StockController): total_qty = sum( flt(item.qty) for item in self.get("items") - if not item.get("type") and not item.get("is_legacy_scrap_item") + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item") ) additional_cost_per_qty = self.total_additional_costs / total_qty for item in self.items: - if not item.get("type") and not item.get("is_legacy_scrap_item"): + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item"): item.additional_cost_per_qty = additional_cost_per_qty else: for item in self.items: - if not item.get("type") and not item.get("is_legacy_scrap_item"): + if not item.get("secondary_item_type") and not item.get("is_legacy_scrap_item"): item.additional_cost_per_qty = 0 @frappe.whitelist() diff --git a/erpnext/controllers/subcontracting_inward_controller.py b/erpnext/controllers/subcontracting_inward_controller.py index e331ccfe26c..d1c36b61d32 100644 --- a/erpnext/controllers/subcontracting_inward_controller.py +++ b/erpnext/controllers/subcontracting_inward_controller.py @@ -241,7 +241,7 @@ class SubcontractingInwardController: item for item in self.get("items") if not item.is_finished_item - and not item.type + and not item.secondary_item_type and not item.is_legacy_scrap_item and frappe.get_cached_value("Item", item.item_code, "is_customer_provided_item") ] @@ -372,7 +372,7 @@ class SubcontractingInwardController: if self.purpose in ["Subcontracting Delivery", "Subcontracting Return", "Manufacture"]: for item in self.items: if ( - item.is_finished_item or item.type or item.is_legacy_scrap_item + item.is_finished_item or item.secondary_item_type or item.is_legacy_scrap_item ) and item.valuation_rate == 0: item.allow_zero_valuation_rate = 1 @@ -472,7 +472,7 @@ class SubcontractingInwardController: self.validate_delivery_on_save() else: for item in self.items: - if not item.type and not item.is_legacy_scrap_item: + if not item.secondary_item_type and not item.is_legacy_scrap_item: delivered_qty, returned_qty = frappe.get_value( "Subcontracting Inward Order Item", item.scio_detail, @@ -543,7 +543,7 @@ class SubcontractingInwardController: bold( frappe.get_cached_value( "Subcontracting Inward Order Item" - if not item.type and not item.is_legacy_scrap_item + if not item.secondary_item_type and not item.is_legacy_scrap_item else "Subcontracting Inward Order Secondary Item", item.scio_detail, "stock_uom", @@ -595,7 +595,7 @@ class SubcontractingInwardController: ) for item in [item for item in self.items if not item.is_finished_item]: - if item.type or item.is_legacy_scrap_item: + if item.secondary_item_type or item.is_legacy_scrap_item: scio_secondary_item = frappe.get_value( "Subcontracting Inward Order Secondary Item", { @@ -655,7 +655,7 @@ class SubcontractingInwardController: for item in self.items: doctype = ( "Subcontracting Inward Order Item" - if not item.type and not item.is_legacy_scrap_item + if not item.secondary_item_type and not item.is_legacy_scrap_item else "Subcontracting Inward Order Secondary Item" ) qty_map[doctype][item.scio_detail] += ( @@ -781,7 +781,7 @@ class SubcontractingInwardController: items = [ item for item in self.items - if not item.is_finished_item and not item.type and not item.is_legacy_scrap_item + if not item.is_finished_item and not item.secondary_item_type and not item.is_legacy_scrap_item ] item_code_wh = frappe._dict( { @@ -884,7 +884,9 @@ class SubcontractingInwardController: def update_inward_order_secondary_items(self): if (scio := self.subcontracting_inward_order) and self.purpose == "Manufacture": - secondary_items_list = [item for item in self.items if item.type or item.is_legacy_scrap_item] + secondary_items_list = [ + item for item in self.items if item.secondary_item_type or item.is_legacy_scrap_item + ] secondary_items = defaultdict(float) for item in secondary_items_list: @@ -958,7 +960,7 @@ class SubcontractingInwardController: stock_uom=secondary_item.stock_uom, warehouse=secondary_item.t_warehouse, produced_qty=secondary_item.transfer_qty, - type=secondary_item.type, + secondary_item_type=secondary_item.secondary_item_type, delivered_qty=0, reference_name=frappe.get_value( "Work Order", self.work_order, "subcontracting_inward_order_item" diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index bbec18036fe..f5e943823cf 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -338,14 +338,14 @@ class BOM(WebsiteGenerator): if not item.qty: frappe.throw( _("Row #{0}: Quantity should be greater than 0 for {1} Item {2}").format( - item.idx, item.type, get_link_to_form("Item", item.item_code) + item.idx, item.secondary_item_type, get_link_to_form("Item", item.item_code) ) ) if item.process_loss_per >= 100: frappe.throw( _("Row #{0}: Process Loss Percentage should be less than 100% for {1} Item {2}").format( - item.idx, item.type, get_link_to_form("Item", item.item_code) + item.idx, item.secondary_item_type, get_link_to_form("Item", item.item_code) ) ) @@ -1285,7 +1285,9 @@ class BOM(WebsiteGenerator): frappe.throw(msg, title=_("Invalid Process Loss Configuration")) def has_scrap_items(self): - return any(d.get("type") == "Scrap" or d.get("is_legacy") for d in self.get("secondary_items")) + return any( + d.get("secondary_item_type") == "Scrap" or d.get("is_legacy") for d in self.get("secondary_items") + ) def get_bom_item_rate(args, bom_doc): @@ -1453,7 +1455,7 @@ def get_bom_items_as_dict( query = query.format( table="BOM Secondary Item", where_conditions=")", - select_columns=", item.description, bom_item.cost_allocation_per, bom_item.process_loss_per, bom_item.type, bom_item.name, bom_item.is_legacy", + select_columns=", item.description, bom_item.cost_allocation_per, bom_item.process_loss_per, bom_item.secondary_item_type, bom_item.name, bom_item.is_legacy", is_stock_item=is_stock_item, qty_field="stock_qty", group_by_cond=group_by_cond, diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json index 7c5c41fec19..2386fd0f38b 100644 --- a/erpnext/manufacturing/doctype/bom/test_records.json +++ b/erpnext/manufacturing/doctype/bom/test_records.json @@ -45,7 +45,7 @@ "stock_qty": 1.0, "rate": 2000.0, "stock_uom": "_Test UOM", - "type": "Scrap", + "secondary_item_type": "Scrap", "is_legacy": 1 } ], diff --git a/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.json b/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.json index 39fa55123f4..18615cb193b 100644 --- a/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.json +++ b/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.json @@ -6,7 +6,7 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "type", + "secondary_item_type", "rate", "column_break_gres", "is_legacy", @@ -35,7 +35,7 @@ "fields": [ { "depends_on": "eval:!doc.is_legacy", - "fieldname": "type", + "fieldname": "secondary_item_type", "fieldtype": "Select", "in_list_view": 1, "label": "Type", @@ -218,7 +218,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-03-11 12:12:29.208031", + "modified": "2026-06-01 10:00:00.000000", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Secondary Item", diff --git a/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.py b/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.py index 87748fe2269..577eb0bd6e2 100644 --- a/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.py +++ b/erpnext/manufacturing/doctype/bom_secondary_item/bom_secondary_item.py @@ -32,7 +32,7 @@ class BOMSecondaryItem(Document): rate: DF.Currency stock_qty: DF.Float stock_uom: DF.Link | None - 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 # end: auto-generated types diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index 12dad352dc2..d1dc17e26eb 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -295,7 +295,7 @@ class JobCard(Document): "stock_qty": values.qty, "item_name": values.item_name, "stock_uom": values.stock_uom, - "type": values.type, + "secondary_item_type": values.secondary_item_type, "bom_secondary_item": values.name, } @@ -1532,7 +1532,7 @@ class JobCard(Document): add_additional_cost(ste.stock_entry, wo_doc, self) ManufactureStockEntry(ste.stock_entry).add_secondary_items_from_job_card() for row in ste.stock_entry.items: - if (row.type or row.is_legacy_scrap_item) and not row.t_warehouse: + if (row.secondary_item_type or row.is_legacy_scrap_item) and not row.t_warehouse: row.t_warehouse = self.target_warehouse if auto_submit: diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py index feeb758c8e7..e7316259d01 100644 --- a/erpnext/manufacturing/doctype/job_card/test_job_card.py +++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py @@ -913,7 +913,7 @@ class TestJobCard(ERPNextTestSuite): "qty": 1, "process_loss_per": 10, "cost_allocation_per": 5, - "type": "Scrap", + "secondary_item_type": "Scrap", }, ) if submit: @@ -996,7 +996,8 @@ class TestJobCard(ERPNextTestSuite): }, ) job_card.append( - "secondary_items", {"item_code": scrap_extra.name, "stock_qty": 5, "type": "Co-Product"} + "secondary_items", + {"item_code": scrap_extra.name, "stock_qty": 5, "secondary_item_type": "Co-Product"}, ) job_card.submit() @@ -1015,7 +1016,7 @@ class TestJobCard(ERPNextTestSuite): self.assertEqual(manufacturing_entry.items[2].qty, 9) self.assertEqual(flt(manufacturing_entry.items[2].basic_rate, 3), 5.556) self.assertEqual(manufacturing_entry.items[3].item_code, scrap_extra.name) - self.assertEqual(manufacturing_entry.items[3].type, "Co-Product") + self.assertEqual(manufacturing_entry.items[3].secondary_item_type, "Co-Product") self.assertEqual(manufacturing_entry.items[3].qty, 5) self.assertEqual(manufacturing_entry.items[3].basic_rate, 0) @@ -1060,7 +1061,9 @@ class TestJobCard(ERPNextTestSuite): ) job_card = frappe.get_last_doc("Job Card", {"work_order": self.work_order.name}) - job_card.append("secondary_items", {"item_code": "_Test Item", "stock_qty": 2, "type": "Scrap"}) + job_card.append( + "secondary_items", {"item_code": "_Test Item", "stock_qty": 2, "secondary_item_type": "Scrap"} + ) job_card.append( "time_logs", { diff --git a/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.json b/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.json index d9ac0e08ced..d367d7e308c 100644 --- a/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.json +++ b/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.json @@ -5,7 +5,7 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "type", + "secondary_item_type", "description", "column_break_3", "item_code", @@ -69,7 +69,7 @@ "read_only": 1 }, { - "fieldname": "type", + "fieldname": "secondary_item_type", "fieldtype": "Select", "in_list_view": 1, "label": "Type", @@ -87,7 +87,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-03-06 13:51:00.492621", + "modified": "2026-06-01 10:00:00.000000", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card Secondary Item", diff --git a/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.py b/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.py index 3a71ab9d755..db61f3cad48 100644 --- a/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.py +++ b/erpnext/manufacturing/doctype/job_card_secondary_item/job_card_secondary_item.py @@ -22,7 +22,7 @@ class JobCardSecondaryItem(Document): parenttype: DF.Data stock_qty: DF.Float stock_uom: DF.Link | None - type: DF.Literal["Co-Product", "By-Product", "Scrap", "Additional Finished Good"] + secondary_item_type: DF.Literal["Co-Product", "By-Product", "Scrap", "Additional Finished Good"] # end: auto-generated types pass diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index 19b04032a3b..e985abf8f12 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -2903,7 +2903,7 @@ def make_bom(**args): bom.append( "secondary_items", { - "type": "Scrap", + "secondary_item_type": "Scrap", "item_code": item, "item_name": item, "uom": item_doc.stock_uom, diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 2257363fd7f..e945bcdf4dc 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -1096,7 +1096,7 @@ class TestWorkOrder(ERPNextTestSuite): stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10)) for row in stock_entry.items: - if row.type or row.is_legacy_scrap_item: + if row.secondary_item_type or row.is_legacy_scrap_item: self.assertEqual(row.qty, 1) # Partial Job Card 1 with qty 10 @@ -1108,7 +1108,7 @@ class TestWorkOrder(ERPNextTestSuite): stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10)) for row in stock_entry.items: - if row.type or row.is_legacy_scrap_item: + if row.secondary_item_type or row.is_legacy_scrap_item: self.assertEqual(row.qty, 2) # Partial Job Card 2 with qty 10 @@ -2193,7 +2193,7 @@ class TestWorkOrder(ERPNextTestSuite): self.assertTrue(se_doc.additional_costs) secondary_items = [] for item in se_doc.items: - if item.type or item.is_legacy_scrap_item: + if item.secondary_item_type or item.is_legacy_scrap_item: secondary_items.append(item.item_code) self.assertEqual( @@ -2658,7 +2658,7 @@ class TestWorkOrder(ERPNextTestSuite): # Secondary/Scrap item: should be taken from scrap warehouse in disassembly scrap_row = next((i for i in stock_entry.items if i.item_code == scrap_item), None) self.assertIsNotNone(scrap_row) - self.assertEqual(scrap_row.type, "Scrap") + self.assertEqual(scrap_row.secondary_item_type, "Scrap") self.assertTrue(scrap_row.s_warehouse) self.assertFalse(scrap_row.t_warehouse) self.assertEqual(scrap_row.s_warehouse, wo.scrap_warehouse) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index b17841bade5..ffae51a893d 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -483,3 +483,4 @@ erpnext.patches.v16_0.packed_item_inv_dimen erpnext.patches.v16_0.set_not_applicable_on_german_item_tax_templates erpnext.patches.v16_0.clear_procedures_from_receivable_report erpnext.patches.v16_0.migrate_address_contact_custom_fields +erpnext.patches.v16_0.rename_secondary_item_type_field diff --git a/erpnext/patches/v16_0/co_by_product_patch.py b/erpnext/patches/v16_0/co_by_product_patch.py index 63f43e85b9e..5baca92b31a 100644 --- a/erpnext/patches/v16_0/co_by_product_patch.py +++ b/erpnext/patches/v16_0/co_by_product_patch.py @@ -41,7 +41,7 @@ def insert_into_bom(): "conversion_factor": 1, "qty": item.stock_qty, "is_legacy": 1, - "type": "Scrap", + "secondary_item_type": "Scrap", } ) secondary_item.insert() @@ -49,7 +49,14 @@ def insert_into_bom(): def insert_into_job_card(): fields = ["item_code", "item_name", "description", "stock_qty", "stock_uom"] - bulk_insert("Job Card", "Job Card Scrap Item", "Job Card Secondary Item", fields, ["type"], ["Scrap"]) + bulk_insert( + "Job Card", + "Job Card Scrap Item", + "Job Card Secondary Item", + fields, + ["secondary_item_type"], + ["Scrap"], + ) def insert_into_subcontracting_inward(): @@ -67,7 +74,7 @@ def insert_into_subcontracting_inward(): "Subcontracting Inward Order Scrap Item", "Subcontracting Inward Order Secondary Item", fields, - ["type"], + ["secondary_item_type"], ["Scrap"], ) diff --git a/erpnext/patches/v16_0/rename_secondary_item_type_field.py b/erpnext/patches/v16_0/rename_secondary_item_type_field.py new file mode 100644 index 00000000000..41b264b7ccb --- /dev/null +++ b/erpnext/patches/v16_0/rename_secondary_item_type_field.py @@ -0,0 +1,18 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + doctypes = [ + "BOM Secondary Item", + "Job Card Secondary Item", + "Stock Entry Detail", + "Subcontracting Inward Order Secondary Item", + "Subcontracting Receipt Item", + ] + + for doctype in doctypes: + if not frappe.db.has_column(doctype, "type"): + continue + + rename_field(doctype, "type", "secondary_item_type") diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index ba02499faae..01c15b5193c 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -572,7 +572,7 @@ class StockEntry(StockController, SubcontractingInwardController): if self.bom_no: d.basic_rate *= frappe.get_value("BOM", self.bom_no, "cost_allocation_per") / 100 - elif d.type and d.bom_secondary_item: + elif d.secondary_item_type and d.bom_secondary_item: cost_allocation_per = frappe.get_value( "BOM Secondary Item", d.bom_secondary_item, "cost_allocation_per" ) @@ -693,7 +693,7 @@ class StockEntry(StockController, SubcontractingInwardController): def _validate_no_raw_materials_in_manufacture_entry(self, settings): for item in self.items: - if not item.is_finished_item and not item.type and not item.is_legacy_scrap_item: + if not item.is_finished_item and not item.secondary_item_type and not item.is_legacy_scrap_item: label = frappe.get_meta(settings.doctype).get_label("get_rm_cost_from_consumption_entry") frappe.throw( _( @@ -835,7 +835,7 @@ class StockEntry(StockController, SubcontractingInwardController): d.is_finished_item = 1 else: d.is_finished_item = 0 - d.type = "" + d.secondary_item_type = "" def get_finished_item(self): finished_item = None diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_handler/disassemble.py b/erpnext/stock/doctype/stock_entry/stock_entry_handler/disassemble.py index a4b2671d484..767afab2fb7 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry_handler/disassemble.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry_handler/disassemble.py @@ -135,7 +135,7 @@ class DisassembleStockEntry(BaseStockEntry): "s_warehouse": s_warehouse, "t_warehouse": t_warehouse, "is_finished_item": source_row.is_finished_item, - "type": source_row.type, + "secondary_item_type": source_row.secondary_item_type, "is_legacy_scrap_item": source_row.is_legacy_scrap_item, "bom_secondary_item": source_row.bom_secondary_item, "bom_no": source_row.bom_no, @@ -185,7 +185,7 @@ class DisassembleStockEntry(BaseStockEntry): "conversion_factor", "item_group", "description", - "type", + "secondary_item_type", ] for field in fields: item_args[field] = row.get(field) @@ -235,7 +235,7 @@ class DisassembleStockEntry(BaseStockEntry): SED.basic_rate, SED.conversion_factor, SED.is_finished_item, - SED.type, + SED.secondary_item_type, SED.is_legacy_scrap_item, SED.bom_secondary_item, SED.batch_no, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_handler/manufacturing.py b/erpnext/stock/doctype/stock_entry/stock_entry_handler/manufacturing.py index acbba110342..652e8e09ba5 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry_handler/manufacturing.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry_handler/manufacturing.py @@ -25,7 +25,7 @@ class BaseManufactureStockEntry(BaseStockEntry): and self.doc.from_warehouse and not row.is_finished_item and not row.is_legacy_scrap_item - and not row.type + and not row.secondary_item_type ): row.s_warehouse = self.doc.from_warehouse row.t_warehouse = None @@ -33,7 +33,7 @@ class BaseManufactureStockEntry(BaseStockEntry): elif ( not row.t_warehouse and self.doc.to_warehouse - and (row.is_finished_item or row.is_legacy_scrap_item or row.type) + and (row.is_finished_item or row.is_legacy_scrap_item or row.secondary_item_type) ): row.t_warehouse = self.doc.to_warehouse row.s_warehouse = None @@ -83,10 +83,10 @@ class BaseManufactureStockEntry(BaseStockEntry): for row in secondary_items: item_args = self.get_item_dict(row) item_args["is_legacy_scrap_item"] = bool(row.get("is_legacy")) - item_args["type"] = row.type + item_args["secondary_item_type"] = row.secondary_item_type item_args["bom_secondary_item"] = row.name - if row.type == "Scrap" and self.wo_doc and self.wo_doc.get("scrap_warehouse"): + if row.secondary_item_type == "Scrap" and self.wo_doc and self.wo_doc.get("scrap_warehouse"): item_args["t_warehouse"] = self.wo_doc.scrap_warehouse else: item_args["t_warehouse"] = self.doc.to_warehouse @@ -591,7 +591,7 @@ class ManufactureStockEntry(BaseManufactureStockEntry): row.s_warehouse = None row.t_warehouse = row.warehouse or self.doc.to_warehouse row.is_legacy_scrap_item = row.is_legacy - row.type = row.get("type") + row.secondary_item_type = row.get("secondary_item_type") self.doc.append("items", row) @@ -633,7 +633,7 @@ class ManufactureStockEntry(BaseManufactureStockEntry): .select(sed.item_code, sed.qty) .where( (se.work_order == self.doc.work_order) - & ((sed.type.isnotnull()) | (sed.is_legacy_scrap_item == 1)) + & ((sed.secondary_item_type.isnotnull()) | (sed.is_legacy_scrap_item == 1)) & (se.docstatus == 1) & (se.purpose.isin(["Repack", "Manufacture"])) ) @@ -832,7 +832,7 @@ def _add_bom_table_specific_fields(query, doctype, table_name): doctype.cost_allocation_per, doctype.uom, doctype.process_loss_per, - doctype.type, + doctype.secondary_item_type, doctype.is_legacy, doctype.conversion_factor, ) @@ -891,7 +891,7 @@ def get_secondary_items_from_job_card(work_order, jc_name=None): job_card_secondary_item.item_name, job_card_secondary_item.description, job_card_secondary_item.stock_uom, - job_card_secondary_item.type, + job_card_secondary_item.secondary_item_type, job_card_secondary_item.bom_secondary_item, ) .join(job_card_secondary_item) @@ -901,7 +901,7 @@ def get_secondary_items_from_job_card(work_order, jc_name=None): & (job_card.work_order == work_order) & (job_card.docstatus == 1) ) - .groupby(job_card_secondary_item.item_code, job_card_secondary_item.type) + .groupby(job_card_secondary_item.item_code, job_card_secondary_item.secondary_item_type) .orderby(job_card_secondary_item.idx) ) diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index bb40f47765a..c30d1f76de3 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -908,7 +908,9 @@ class TestStockEntry(ERPNextTestSuite): if d.s_warehouse: rm_cost += d.amount fg_cost = next(filter(lambda x: x.item_code == "_Test FG Item", s.get("items"))).amount - secondary_item_cost = next(filter(lambda x: x.type or x.is_legacy_scrap_item, s.get("items"))).amount + secondary_item_cost = next( + filter(lambda x: x.secondary_item_type or x.is_legacy_scrap_item, s.get("items")) + ).amount self.assertEqual(fg_cost, flt(rm_cost - secondary_item_cost, 2)) @@ -1027,7 +1029,7 @@ class TestStockEntry(ERPNextTestSuite): basic_rate=row.basic_rate or 100, ) - if row.type or row.is_legacy_scrap_item: + if row.secondary_item_type or row.is_legacy_scrap_item: row.item_code = secondary_item row.uom = frappe.db.get_value("Item", secondary_item, "stock_uom") row.stock_uom = frappe.db.get_value("Item", secondary_item, "stock_uom") @@ -1035,10 +1037,16 @@ class TestStockEntry(ERPNextTestSuite): stock_entry.inspection_required = 1 stock_entry.save() - self.assertTrue([row.item_code for row in stock_entry.items if row.type or row.is_legacy_scrap_item]) + self.assertTrue( + [ + row.item_code + for row in stock_entry.items + if row.secondary_item_type or row.is_legacy_scrap_item + ] + ) for row in stock_entry.items: - if not row.type and not row.is_legacy_scrap_item: + if not row.secondary_item_type and not row.is_legacy_scrap_item: qc = frappe.get_doc( { "doctype": "Quality Inspection", @@ -1058,7 +1066,7 @@ class TestStockEntry(ERPNextTestSuite): stock_entry.reload() stock_entry.submit() for row in stock_entry.items: - if row.type or row.is_legacy_scrap_item: + if row.secondary_item_type or row.is_legacy_scrap_item: self.assertFalse(row.quality_inspection) else: self.assertTrue(row.quality_inspection) diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json index b446aa1e51e..c21d9ec91cb 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json @@ -19,7 +19,7 @@ "col_break2", "is_finished_item", "is_legacy_scrap_item", - "type", + "secondary_item_type", "quality_inspection", "subcontracted_item", "against_fg", @@ -559,7 +559,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.is_legacy_scrap_item && !doc.type", + "depends_on": "eval:!doc.is_legacy_scrap_item && !doc.secondary_item_type", "fieldname": "is_finished_item", "fieldtype": "Check", "label": "Is Finished Item", @@ -653,7 +653,7 @@ }, { "depends_on": "eval:parent.purpose == \"Manufacture\" && doc.t_warehouse && !doc.is_finished_item && !doc.is_legacy_scrap_item", - "fieldname": "type", + "fieldname": "secondary_item_type", "fieldtype": "Select", "label": "Type", "options": "\nCo-Product\nBy-Product\nScrap\nAdditional Finished Good" @@ -679,7 +679,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-04-27 11:40:38.294196", + "modified": "2026-06-01 10:00:00.000000", "modified_by": "Administrator", "module": "Stock", "name": "Stock Entry Detail", diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py index 5b933427ee4..a09daf35634 100644 --- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py +++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.py @@ -83,7 +83,7 @@ class StockEntryDetail(Document): t_warehouse: DF.Link | None transfer_qty: DF.Float transferred_qty: DF.Float - 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 use_serial_batch_fields: DF.Check valuation_rate: DF.Currency diff --git a/erpnext/subcontracting/doctype/subcontracting_inward_order/subcontracting_inward_order.py b/erpnext/subcontracting/doctype/subcontracting_inward_order/subcontracting_inward_order.py index d1cd27f4a11..77d7530b3c7 100644 --- a/erpnext/subcontracting/doctype/subcontracting_inward_order/subcontracting_inward_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_inward_order/subcontracting_inward_order.py @@ -499,7 +499,7 @@ class SubcontractingInwardOrder(SubcontractingController): "s_warehouse": secondary_item.warehouse, "stock_uom": secondary_item.stock_uom, "scio_detail": secondary_item.name, - "type": secondary_item.type, + "secondary_item_type": secondary_item.secondary_item_type, } } diff --git a/erpnext/subcontracting/doctype/subcontracting_inward_order/test_subcontracting_inward_order.py b/erpnext/subcontracting/doctype/subcontracting_inward_order/test_subcontracting_inward_order.py index 9a45a49be5e..a8aeca2f423 100644 --- a/erpnext/subcontracting/doctype/subcontracting_inward_order/test_subcontracting_inward_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_inward_order/test_subcontracting_inward_order.py @@ -328,7 +328,7 @@ class IntegrationTestSubcontractingInwardOrder(ERPNextTestSuite): def test_secondary_items_delivery(self): new_bom = frappe.copy_doc(frappe.get_doc("BOM", "BOM-Basic FG Item-001")) new_bom.secondary_items.append( - frappe.new_doc("BOM Secondary Item", item_code="Basic RM 2", qty=1, type="Scrap") + frappe.new_doc("BOM Secondary Item", item_code="Basic RM 2", qty=1, secondary_item_type="Scrap") ) new_bom.submit() sc_bom = frappe.get_doc("Subcontracting BOM", "SB-0001") diff --git a/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.json b/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.json index 94a640b41ce..01e4c63ad2f 100644 --- a/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.json @@ -7,7 +7,7 @@ "engine": "InnoDB", "field_order": [ "column_break_rptg", - "type", + "secondary_item_type", "reference_name", "column_break_jkzt", "item_code", @@ -97,7 +97,7 @@ "fieldtype": "Column Break" }, { - "fieldname": "type", + "fieldname": "secondary_item_type", "fieldtype": "Select", "label": "Type", "no_copy": 1, @@ -114,7 +114,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2026-02-27 15:15:40.009957", + "modified": "2026-06-01 10:00:00.000000", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Inward Order Secondary Item", diff --git a/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.py b/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.py index 767f216921a..9fcc8b20135 100644 --- a/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.py +++ b/erpnext/subcontracting/doctype/subcontracting_inward_order_secondary_item/subcontracting_inward_order_secondary_item.py @@ -23,7 +23,7 @@ class SubcontractingInwardOrderSecondaryItem(Document): produced_qty: DF.Float reference_name: DF.Data stock_uom: DF.Link - type: DF.Literal["Co-Product", "By-Product", "Scrap", "Additional Finished Good"] + secondary_item_type: DF.Literal["Co-Product", "By-Product", "Scrap", "Additional Finished Good"] warehouse: DF.Link # end: auto-generated types diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 26ad0039070..536ee67d237 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -420,7 +420,7 @@ class SubcontractingReceipt(SubcontractingController): self.append( "items", { - "type": secondary_item.type, + "secondary_item_type": secondary_item.secondary_item_type, "is_legacy_scrap_item": secondary_item.is_legacy, "reference_name": item.name, "item_code": secondary_item.item_code, @@ -448,7 +448,7 @@ class SubcontractingReceipt(SubcontractingController): def remove_secondary_items(self): for item in list(self.items): - if item.type or item.is_legacy_scrap_item: + if item.secondary_item_type or item.is_legacy_scrap_item: self.remove(item) else: item.secondary_items_cost_per_qty = 0 @@ -508,7 +508,7 @@ class SubcontractingReceipt(SubcontractingController): secondary_items_cost_map = {} for item in self.get("items") or []: - if item.type or item.is_legacy_scrap_item: + if item.secondary_item_type or item.is_legacy_scrap_item: qty = ( flt(item.qty) if item.is_legacy_scrap_item @@ -523,7 +523,7 @@ class SubcontractingReceipt(SubcontractingController): total_qty = total_amount = 0 for item in self.get("items") or []: - if not item.type and not item.is_legacy_scrap_item: + if not item.secondary_item_type and not item.is_legacy_scrap_item: if item.qty: if item.name in rm_cost_map: item.rm_supp_cost = rm_cost_map[item.name] @@ -567,7 +567,7 @@ class SubcontractingReceipt(SubcontractingController): def validate_secondary_items(self): for item in self.items: - if item.type or item.is_legacy_scrap_item: + if item.secondary_item_type or item.is_legacy_scrap_item: if not item.qty: frappe.throw( _("Row #{0}: Secondary Item Qty cannot be zero").format(item.idx), diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index 95264201c44..a1d126fb7b5 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -1220,7 +1220,7 @@ class TestSubcontractingReceipt(ERPNextTestSuite): scr.get_secondary_items() scr_secondary_items = set( - [item.item_code for item in scr.items if item.type or item.is_legacy_scrap_item] + [item.item_code for item in scr.items if item.secondary_item_type or item.is_legacy_scrap_item] ) self.assertEqual(len(scr.items), 3) # 1 FG Item + 2 Scrap Items self.assertEqual(scr_secondary_items, set(secondary_items)) diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json index b6d07f66b98..71f262d7663 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json @@ -9,7 +9,7 @@ "field_order": [ "item_code", "is_legacy_scrap_item", - "type", + "secondary_item_type", "column_break_2", "item_name", "section_break_4", @@ -162,12 +162,12 @@ "label": "Accepted Qty", "no_copy": 1, "print_width": "100px", - "read_only_depends_on": "eval:doc.type || doc.is_legacy_scrap_item", + "read_only_depends_on": "eval:doc.secondary_item_type || doc.is_legacy_scrap_item", "width": "100px" }, { "columns": 1, - "depends_on": "eval:!parent.is_return && !doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!parent.is_return && !doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "rejected_qty", "fieldtype": "Float", "in_list_view": 1, @@ -175,7 +175,7 @@ "no_copy": 1, "print_hide": 1, "print_width": "100px", - "read_only_depends_on": "eval:doc.type || doc.is_legacy_scrap_item", + "read_only_depends_on": "eval:doc.secondary_item_type || doc.is_legacy_scrap_item", "width": "100px" }, { @@ -234,7 +234,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "rm_cost_per_qty", "fieldtype": "Currency", "label": "Raw Material Cost Per Qty", @@ -244,7 +244,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "service_cost_per_qty", "fieldtype": "Currency", "label": "Service Cost Per Qty", @@ -254,7 +254,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "additional_cost_per_qty", "fieldtype": "Currency", "label": "Additional Cost Per Qty", @@ -278,7 +278,7 @@ "width": "100px" }, { - "depends_on": "eval: !parent.is_return && !doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval: !parent.is_return && !doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "rejected_warehouse", "fieldtype": "Link", "ignore_user_permissions": 1, @@ -290,7 +290,7 @@ "width": "100px" }, { - "depends_on": "eval:!doc.__islocal && !doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.__islocal && !doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "quality_inspection", "fieldtype": "Link", "label": "Quality Inspection", @@ -372,7 +372,7 @@ "no_copy": 1, "options": "BOM", "print_hide": 1, - "read_only_depends_on": "eval:doc.type || doc.is_legacy_scrap_item" + "read_only_depends_on": "eval:doc.secondary_item_type || doc.is_legacy_scrap_item" }, { "fetch_from": "item_code.brand", @@ -499,7 +499,7 @@ "print_hide": 1 }, { - "depends_on": "eval:(doc.use_serial_batch_fields === 0 || doc.docstatus === 1) && !doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:(doc.use_serial_batch_fields === 0 || doc.docstatus === 1) && !doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "rejected_serial_and_batch_bundle", "fieldtype": "Link", "label": "Rejected Serial and Batch Bundle", @@ -564,7 +564,7 @@ "label": "Add Serial / Batch Bundle" }, { - "depends_on": "eval:doc.use_serial_batch_fields === 0 && !doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:doc.use_serial_batch_fields === 0 && !doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "add_serial_batch_for_rejected_qty", "fieldtype": "Button", "label": "Add Serial / Batch No (Rejected Qty)" @@ -578,7 +578,7 @@ "search_index": 1 }, { - "depends_on": "eval:!doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "landed_cost_voucher_amount", "fieldtype": "Currency", "label": "Landed Cost Voucher Amount", @@ -596,7 +596,7 @@ "options": "Account" }, { - "fieldname": "type", + "fieldname": "secondary_item_type", "fieldtype": "Select", "label": "Type", "no_copy": 1, @@ -606,7 +606,7 @@ }, { "default": "0", - "depends_on": "eval:!doc.type && !doc.is_legacy_scrap_item", + "depends_on": "eval:!doc.secondary_item_type && !doc.is_legacy_scrap_item", "fieldname": "secondary_items_cost_per_qty", "fieldtype": "Currency", "label": "Secondary Items Cost Per Qty", @@ -635,7 +635,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2026-03-09 15:11:16.977539", + "modified": "2026-06-01 10:00:00.000000", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Receipt Item", diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py index c6233b841a2..47cfd9a1648 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.py @@ -62,7 +62,7 @@ class SubcontractingReceiptItem(Document): subcontracting_order: DF.Link | None subcontracting_order_item: DF.Data | None subcontracting_receipt_item: DF.Data | None - 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 warehouse: DF.Link | None # end: auto-generated types