diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 3a15c7de4ba..0b7c9de467a 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -404,7 +404,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( ); } } else { - if (!doc.items.every((item) => item.qty == item.sco_qty)) { + if (!doc.items.every((item) => item.qty == item.subcontracted_quantity)) { this.frm.add_custom_button( __("Subcontracting Order"), () => { diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 26c0101b49b..ee8ba35222f 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -898,7 +898,7 @@ def is_po_fully_subcontracted(po_name): query = ( frappe.qb.from_(table) .select(table.name) - .where((table.parent == po_name) & (table.qty != table.sco_qty)) + .where((table.parent == po_name) & (table.qty != table.subcontracted_quantity)) ) return not query.run(as_dict=True) @@ -945,7 +945,7 @@ def get_mapped_subcontracting_order(source_name, target_doc=None): "material_request_item": "material_request_item", }, "field_no_map": ["qty", "fg_item_qty", "amount"], - "condition": lambda item: item.qty != item.sco_qty, + "condition": lambda item: item.qty != item.subcontracted_quantity, }, }, target_doc, diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 5d8ce73e8ab..99ad609f8df 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1076,9 +1076,9 @@ class TestPurchaseOrder(FrappeTestCase): # Test - 2: Subcontracted Quantity for the PO Items of each line item should be updated accordingly po.reload() - self.assertEqual(po.items[0].sco_qty, 5) - self.assertEqual(po.items[1].sco_qty, 0) - self.assertEqual(po.items[2].sco_qty, 12.5) + self.assertEqual(po.items[0].subcontracted_quantity, 5) + self.assertEqual(po.items[1].subcontracted_quantity, 0) + self.assertEqual(po.items[2].subcontracted_quantity, 12.5) # Test - 3: Amount for both FG Item and its Service Item should be updated correctly based on change in Quantity self.assertEqual(sco.items[0].amount, 2000) @@ -1114,10 +1114,10 @@ class TestPurchaseOrder(FrappeTestCase): # Test - 8: Subcontracted Quantity for each PO Item should be subtracted if SCO gets cancelled po.reload() - self.assertEqual(po.items[2].sco_qty, 25) + self.assertEqual(po.items[2].subcontracted_quantity, 25) sco.cancel() po.reload() - self.assertEqual(po.items[2].sco_qty, 12.5) + self.assertEqual(po.items[2].subcontracted_quantity, 12.5) sco = make_subcontracting_order(po.name) sco.save() diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 1724e3cc99c..894c705dc96 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -26,7 +26,7 @@ "quantity_and_rate", "qty", "stock_uom", - "sco_qty", + "subcontracted_quantity", "col_break2", "uom", "conversion_factor", @@ -913,7 +913,7 @@ }, { "allow_on_submit": 1, - "fieldname": "sco_qty", + "fieldname": "subcontracted_quantity", "fieldtype": "Float", "label": "Subcontracted Quantity", "no_copy": 1, @@ -921,11 +921,12 @@ "read_only": 1 } ], + "grid_page_length": 50, "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-02-18 12:35:04.432636", + "modified": "2025-03-02 16:58:26.059601", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", @@ -933,6 +934,7 @@ "owner": "Administrator", "permissions": [], "quick_entry": 1, + "row_format": "Dynamic", "search_fields": "item_name", "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py index b80abda56c3..5e4ce19d340 100644 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.py @@ -80,10 +80,10 @@ class PurchaseOrderItem(Document): sales_order_item: DF.Data | None sales_order_packed_item: DF.Data | None schedule_date: DF.Date - sco_qty: DF.Float stock_qty: DF.Float stock_uom: DF.Link stock_uom_rate: DF.Currency + subcontracted_quantity: DF.Float supplier_part_no: DF.Data | None supplier_quotation: DF.Link | None supplier_quotation_item: DF.Link | None diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index b6a7f715d22..a672360046c 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -104,18 +104,18 @@ class SubcontractingController(StockController): ) if ( - self.doctype == "Subcontracting Order" and not item.sc_conversion_factor + self.doctype == "Subcontracting Order" and not item.subcontracting_conversion_factor ): # this condition will only be true if user has recently updated from develop branch service_item_qty = frappe.get_value( "Subcontracting Order Service Item", filters={"purchase_order_item": item.purchase_order_item, "parent": self.name}, fieldname=["qty"], ) - item.sc_conversion_factor = service_item_qty / item.qty + item.subcontracting_conversion_factor = service_item_qty / item.qty if self.doctype not in "Subcontracting Receipt" and item.qty > flt( - get_pending_sco_qty(self.purchase_order).get(item.purchase_order_item) - / item.sc_conversion_factor, + get_pending_subcontracted_quantity(self.purchase_order).get(item.purchase_order_item) + / item.subcontracting_conversion_factor, frappe.get_precision("Purchase Order Item", "qty"), ): frappe.throw( @@ -1132,10 +1132,14 @@ def get_item_details(items): return item_details -def get_pending_sco_qty(po_name): +def get_pending_subcontracted_quantity(po_name): table = frappe.qb.DocType("Purchase Order Item") - query = frappe.qb.from_(table).select(table.name, table.qty, table.sco_qty).where(table.parent == po_name) - return {item.name: item.qty - item.sco_qty for item in query.run(as_dict=True)} + query = ( + frappe.qb.from_(table) + .select(table.name, table.qty, table.subcontracted_quantity) + .where(table.parent == po_name) + ) + return {item.name: item.qty - item.subcontracted_quantity for item in query.run(as_dict=True)} @frappe.whitelist() diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 5d13471f541..054b482b260 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -1371,7 +1371,7 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None): }, ) - def get_max_op_qty(): + def get_max_operation_quantity(): from frappe.query_builder.functions import Sum table = frappe.qb.DocType("Job Card") @@ -1387,7 +1387,7 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None): ) return min([d.qty for d in query.run(as_dict=True)], default=0) - def get_utilised_cc(): + def get_utilised_corrective_cost(): from frappe.query_builder.functions import Sum table = frappe.qb.DocType("Stock Entry") @@ -1417,15 +1417,15 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None): ) ) ): - max_qty = get_max_op_qty() - work_order.produced_qty - remaining_cc = work_order.corrective_operation_cost - get_utilised_cc() + max_qty = get_max_operation_quantity() - work_order.produced_qty + remaining_corrective_cost = work_order.corrective_operation_cost - get_utilised_corrective_cost() stock_entry.append( "additional_costs", { "expense_account": expense_account, "description": "Corrective Operation Cost", "has_corrective_cost": 1, - "amount": remaining_cc / max_qty * flt(stock_entry.fg_completed_qty), + "amount": remaining_corrective_cost / max_qty * flt(stock_entry.fg_completed_qty), }, ) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index f292abfd50a..43d471f105e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -261,6 +261,7 @@ erpnext.patches.v14_0.show_loan_management_deprecation_warning erpnext.patches.v14_0.clear_reconciliation_values_from_singles execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True) erpnext.patches.v14_0.update_proprietorship_to_individual +erpnext.patches.v15_0.rename_subcontracting_fields [post_model_sync] erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets diff --git a/erpnext/patches/v15_0/rename_subcontracting_fields.py b/erpnext/patches/v15_0/rename_subcontracting_fields.py new file mode 100644 index 00000000000..d18d6149cac --- /dev/null +++ b/erpnext/patches/v15_0/rename_subcontracting_fields.py @@ -0,0 +1,7 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + rename_field("Purchase Order Item", "sco_qty", "subcontracted_quantity") + rename_field("Subcontracting Order Item", "sc_conversion_factor", "subcontracting_conversion_factor") diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js index e9513a47597..bf0c8dc53f8 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js @@ -16,14 +16,14 @@ frappe.ui.form.on("Subcontracting Order Item", { service_item.doctype, service_item.name, "qty", - row.qty * row.sc_conversion_factor + row.qty * row.subcontracting_conversion_factor ); frappe.model.set_value(service_item.doctype, service_item.name, "fg_item_qty", row.qty); frappe.model.set_value( service_item.doctype, service_item.name, "amount", - row.qty * row.sc_conversion_factor * service_item.rate + row.qty * row.subcontracting_conversion_factor * service_item.rate ); }, before_items_remove(frm, cdt, cdn) { diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index f6d3fa04148..d171883c408 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -119,12 +119,12 @@ class SubcontractingOrder(SubcontractingController): def on_submit(self): self.update_prevdoc_status() self.update_status() - self.update_sco_qty_in_po() + self.update_subcontracted_quantity_in_po() def on_cancel(self): self.update_prevdoc_status() self.update_status() - self.update_sco_qty_in_po(cancel=True) + self.update_subcontracted_quantity_in_po(cancel=True) def validate_purchase_order_for_subcontracting(self): if self.purchase_order: @@ -162,7 +162,7 @@ class SubcontractingOrder(SubcontractingController): item = next( item for item in self.items if item.purchase_order_item == service_item.purchase_order_item ) - service_item.qty = item.qty * item.sc_conversion_factor + service_item.qty = item.qty * item.subcontracting_conversion_factor service_item.fg_item_qty = item.qty service_item.amount = service_item.qty * service_item.rate @@ -250,7 +250,7 @@ class SubcontractingOrder(SubcontractingController): item = frappe.get_doc("Item", si.fg_item) po_item = frappe.get_doc("Purchase Order Item", si.purchase_order_item) - available_qty = po_item.qty - po_item.sco_qty + available_qty = po_item.qty - po_item.subcontracted_quantity if available_qty == 0: continue @@ -276,7 +276,7 @@ class SubcontractingOrder(SubcontractingController): "schedule_date": self.schedule_date, "description": item.description, "qty": si.fg_item_qty, - "sc_conversion_factor": conversion_factor, + "subcontracting_conversion_factor": conversion_factor, "stock_uom": item.stock_uom, "bom": bom, "purchase_order_item": si.purchase_order_item, @@ -330,10 +330,14 @@ class SubcontractingOrder(SubcontractingController): self.update_ordered_qty_for_subcontracting() self.update_reserved_qty_for_subcontracting() - def update_sco_qty_in_po(self, cancel=False): + def update_subcontracted_quantity_in_po(self, cancel=False): for service_item in self.service_items: doc = frappe.get_doc("Purchase Order Item", service_item.purchase_order_item) - doc.sco_qty = (doc.sco_qty + service_item.qty) if not cancel else (doc.sco_qty - service_item.qty) + doc.subcontracted_quantity = ( + (doc.subcontracted_quantity + service_item.qty) + if not cancel + else (doc.subcontracted_quantity - service_item.qty) + ) doc.save() diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json index 31616944fda..e85929dd2bb 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json +++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json @@ -52,7 +52,7 @@ "section_break_34", "purchase_order_item", "page_break", - "sc_conversion_factor" + "subcontracting_conversion_factor" ], "fields": [ { @@ -384,18 +384,35 @@ "search_index": 1 }, { - "fieldname": "sc_conversion_factor", + "fieldname": "references_section", + "fieldtype": "Section Break", + "label": "References" + }, + { + "fieldname": "job_card", + "fieldtype": "Link", + "label": "Job Card", + "options": "Job Card", + "read_only": 1 + }, + { + "fieldname": "column_break_nfod", + "fieldtype": "Column Break" + }, + { + "fieldname": "subcontracting_conversion_factor", "fieldtype": "Float", "hidden": 1, - "label": "SC Conversion Factor", + "label": "Subcontracting Conversion Factor", "read_only": 1 } ], + "grid_page_length": 50, "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-12-13 13:35:28.935898", + "modified": "2025-03-02 17:05:28.386492", "modified_by": "Administrator", "module": "Subcontracting", "name": "Subcontracting Order Item", @@ -403,6 +420,7 @@ "owner": "Administrator", "permissions": [], "quick_entry": 1, + "row_format": "Dynamic", "search_fields": "item_name", "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.py b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.py index d8f2e5664e7..db49fccce3c 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.py +++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.py @@ -42,10 +42,10 @@ class SubcontractingOrderItem(Document): received_qty: DF.Float returned_qty: DF.Float rm_cost_per_qty: DF.Currency - sc_conversion_factor: DF.Float schedule_date: DF.Date | None service_cost_per_qty: DF.Currency stock_uom: DF.Link + subcontracting_conversion_factor: DF.Float warehouse: DF.Link # end: auto-generated types