refactor: backport old subcontracting code
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 172ac9e..306d01d 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -572,6 +572,10 @@
 	},
 
 	is_subcontracted: function(frm) {
+		if (frm.doc.is_old_subcontracting_flow) {
+			erpnext.buying.get_default_bom(frm);
+		}
+
 		frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted);
 	},
 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 5c8ab64..6281877 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -513,6 +513,10 @@
 		# because updating ordered qty in bin depends upon updated ordered qty in PO
 		if self.update_stock == 1:
 			self.update_stock_ledger()
+
+			if self.is_old_subcontracting_flow:
+				self.set_consumed_qty_in_subcontract_order()
+
 			from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
 
 			update_serial_nos_after_submit(self, "items")
@@ -1416,6 +1420,9 @@
 			self.update_stock_ledger()
 			self.delete_auto_created_batches()
 
+			if self.is_old_subcontracting_flow:
+				self.set_consumed_qty_in_subcontract_order()
+
 		self.make_gl_entries_on_cancel()
 
 		if self.update_stock == 1:
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index dd62886..387b2cb 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -616,11 +616,13 @@
    "search_index": 1
   },
   {
+   "depends_on": "eval:parent.is_old_subcontracting_flow",
    "fieldname": "bom",
    "fieldtype": "Link",
    "label": "BOM",
    "options": "BOM",
-   "read_only": 1
+   "read_only": 1,
+   "read_only_depends_on": "eval:!parent.is_old_subcontracting_flow"
   },
   {
    "default": "0",
@@ -872,7 +874,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-11-15 17:04:07.191013",
+ "modified": "2022-06-15 16:02:15.196835",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
@@ -880,5 +882,6 @@
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 6aba373..c635a7f 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -7,6 +7,19 @@
 
 frappe.ui.form.on("Purchase Order", {
 	setup: function(frm) {
+
+		if (frm.doc.is_old_subcontracting_flow) {
+			frm.set_query("reserve_warehouse", "supplied_items", function() {
+				return {
+					filters: {
+						"company": frm.doc.company,
+						"name": ['!=', frm.doc.supplier_warehouse],
+						"is_group": 0
+					}
+				}
+			});
+		}
+
 		frm.set_indicator_formatter('item_code',
 			function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
 
@@ -19,7 +32,10 @@
 
 		frm.set_query("fg_item", "items", function() {
 			return {
-				filters: {'is_sub_contracted_item': 1}
+				filters: {
+					'is_sub_contracted_item': 1,
+					'default_bom': ['!=', '']
+				}
 			}
 		});
 	},
@@ -28,6 +44,44 @@
 		erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
 	},
 
+	refresh: function(frm) {
+		if(frm.doc.is_old_subcontracting_flow)
+			frm.trigger('get_materials_from_supplier');
+	},
+
+	get_materials_from_supplier: function(frm) {
+		let po_details = [];
+
+		if (frm.doc.supplied_items && (frm.doc.per_received == 100 || frm.doc.status === 'Closed')) {
+			frm.doc.supplied_items.forEach(d => {
+				if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) {
+					po_details.push(d.name)
+				}
+			});
+		}
+
+		if (po_details && po_details.length) {
+			frm.add_custom_button(__('Return of Components'), () => {
+				frm.call({
+					method: 'erpnext.controllers.subcontracting_controller.get_materials_from_supplier',
+					freeze: true,
+					freeze_message: __('Creating Stock Entry'),
+					args: {
+						subcontract_order: frm.doc.name,
+						rm_details: po_details,
+						order_doctype: cur_frm.doc.doctype
+					},
+					callback: function(r) {
+						if (r && r.message) {
+							const doc = frappe.model.sync(r.message);
+							frappe.set_route("Form", doc[0].doctype, doc[0].name);
+						}
+					}
+				});
+			}, __('Create'));
+		}
+	},
+
 	onload: function(frm) {
 		set_schedule_date(frm);
 		if (!frm.doc.transaction_date){
@@ -67,7 +121,8 @@
 			'Purchase Receipt': 'Purchase Receipt',
 			'Purchase Invoice': 'Purchase Invoice',
 			'Payment Entry': 'Payment',
-			'Subcontracting Order': 'Subcontracting Order'
+			'Subcontracting Order': 'Subcontracting Order',
+			'Stock Entry': 'Material to Supplier'
 		}
 
 		super.setup();
@@ -138,7 +193,14 @@
 					if(flt(doc.per_received) < 100 && allow_receipt) {
 						cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
 						if (doc.is_subcontracted) {
-							cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
+							if (doc.is_old_subcontracting_flow) {
+								if (me.has_unsupplied_items()) {
+									cur_frm.add_custom_button(__('Material to Supplier'), function() { me.make_stock_entry(); }, __("Transfer"));
+								}
+							}
+							else {
+								cur_frm.add_custom_button(__('Subcontracting Order'), this.make_subcontracting_order, __('Create'));
+							}
 						}
 					}
 					if(flt(doc.per_billed) < 100)
@@ -206,6 +268,143 @@
 		set_schedule_date(this.frm);
 	}
 
+	has_unsupplied_items() {
+		return this.frm.doc['supplied_items'].some(item => item.required_qty > item.supplied_qty);
+	}
+
+	make_stock_entry() {
+		var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
+		var me = this;
+
+		if(items.length >= 1){
+			me.raw_material_data = [];
+			me.show_dialog = 1;
+			let title = __('Transfer Material to Supplier');
+			let fields = [
+			{fieldtype:'Section Break', label: __('Raw Materials')},
+			{fieldname: 'sub_con_rm_items', fieldtype: 'Table', label: __('Items'),
+				fields: [
+					{
+						fieldtype:'Data',
+						fieldname:'item_code',
+						label: __('Item'),
+						read_only:1,
+						in_list_view:1
+					},
+					{
+						fieldtype:'Data',
+						fieldname:'rm_item_code',
+						label: __('Raw Material'),
+						read_only:1,
+						in_list_view:1
+					},
+					{
+						fieldtype:'Float',
+						read_only:1,
+						fieldname:'qty',
+						label: __('Quantity'),
+						read_only:1,
+						in_list_view:1
+					},
+					{
+						fieldtype:'Data',
+						read_only:1,
+						fieldname:'warehouse',
+						label: __('Reserve Warehouse'),
+						in_list_view:1
+					},
+					{
+						fieldtype:'Float',
+						read_only:1,
+						fieldname:'rate',
+						label: __('Rate'),
+						hidden:1
+					},
+					{
+						fieldtype:'Float',
+						read_only:1,
+						fieldname:'amount',
+						label: __('Amount'),
+						hidden:1
+					},
+					{
+						fieldtype:'Link',
+						read_only:1,
+						fieldname:'uom',
+						label: __('UOM'),
+						hidden:1
+					}
+				],
+				data: me.raw_material_data,
+				get_data: function() {
+					return me.raw_material_data;
+				}
+			}
+		]
+
+		me.dialog = new frappe.ui.Dialog({
+			title: title, fields: fields
+		});
+
+		if (me.frm.doc['supplied_items']) {
+			me.frm.doc['supplied_items'].forEach((item, index) => {
+			if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) {
+					me.raw_material_data.push ({
+						'name':item.name,
+						'item_code': item.main_item_code,
+						'rm_item_code': item.rm_item_code,
+						'item_name': item.rm_item_code,
+						'qty': item.required_qty - item.supplied_qty,
+						'warehouse':item.reserve_warehouse,
+						'rate':item.rate,
+						'amount':item.amount,
+						'stock_uom':item.stock_uom
+					});
+					me.dialog.fields_dict.sub_con_rm_items.grid.refresh();
+				}
+			})
+		}
+
+		me.dialog.get_field('sub_con_rm_items').check_all_rows()
+
+		me.dialog.show()
+		this.dialog.set_primary_action(__('Transfer'), function() {
+			me.values = me.dialog.get_values();
+			if(me.values) {
+				me.values.sub_con_rm_items.map((row,i) => {
+					if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
+						let row_id = i+1;
+						frappe.throw(__("Item Code, warehouse and quantity are required on row {0}", [row_id]));
+					}
+				})
+				me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children())
+				me.dialog.hide()
+				}
+			});
+		}
+
+		me.dialog.get_close_btn().on('click', () => {
+			me.dialog.hide();
+		});
+
+	}
+
+	_make_rm_stock_entry(rm_items) {
+		frappe.call({
+			method:"erpnext.controllers.subcontracting_controller.make_rm_stock_entry",
+			args: {
+				subcontract_order: cur_frm.doc.name,
+				rm_items: rm_items,
+				order_doctype: cur_frm.doc.doctype
+			}
+			,
+			callback: function(r) {
+				var doclist = frappe.model.sync(r.message);
+				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+			}
+		});
+	}
+
 	make_inter_company_order(frm) {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
@@ -444,6 +643,20 @@
 	}
 }
 
+if (cur_frm.doc.is_old_subcontracting_flow) {
+	cur_frm.fields_dict['items'].grid.get_field('bom').get_query = function(doc, cdt, cdn) {
+		var d = locals[cdt][cdn]
+		return {
+			filters: [
+				['BOM', 'item', '=', d.item_code],
+				['BOM', 'is_active', '=', '1'],
+				['BOM', 'docstatus', '=', '1'],
+				['BOM', 'company', '=', doc.company]
+			]
+		}
+	}
+}
+
 function set_schedule_date(frm) {
 	if(frm.doc.schedule_date){
 		erpnext.utils.copy_value_in_all_rows(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
@@ -451,3 +664,9 @@
 }
 
 frappe.provide("erpnext.buying");
+
+frappe.ui.form.on("Purchase Order", "is_subcontracted", function(frm) {
+	if (frm.doc.is_old_subcontracting_flow) {
+		erpnext.buying.get_default_bom(frm);
+	}
+});
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index b622b4f..aa50487 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -453,10 +453,6 @@
    "print_hide": 1
   },
   {
-   "fieldname": "col_break_warehouse",
-   "fieldtype": "Column Break"
-  },
-  {
    "default": "0",
    "fieldname": "is_subcontracted",
    "fieldtype": "Check",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 6cf5837..6f960a2 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -24,6 +24,7 @@
 from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
 from erpnext.stock.doctype.item.item import get_item_defaults, get_last_purchase_details
 from erpnext.stock.stock_balance import get_ordered_qty, update_bin_qty
+from erpnext.stock.utils import get_bin
 
 form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
 
@@ -68,6 +69,11 @@
 		self.validate_with_previous_doc()
 		self.validate_for_subcontracting()
 		self.validate_minimum_order_qty()
+
+		if self.is_old_subcontracting_flow:
+			self.validate_bom_for_subcontracting_items()
+			self.create_raw_materials_supplied()
+
 		self.validate_fg_item_for_subcontracting()
 		self.set_received_qty_for_drop_ship_items()
 		validate_inter_company_party(
@@ -191,8 +197,17 @@
 					).format(item_code, qty, itemwise_min_order_qty.get(item_code))
 				)
 
+	def validate_bom_for_subcontracting_items(self):
+		for item in self.items:
+			if not item.bom:
+				frappe.throw(
+					_("Row #{0}: BOM is not specified for subcontracting item {0}").format(
+						item.idx, item.item_code
+					)
+				)
+
 	def validate_fg_item_for_subcontracting(self):
-		if self.is_subcontracted:
+		if self.is_subcontracted and not self.is_old_subcontracting_flow:
 			for item in self.items:
 				if not item.fg_item:
 					frappe.throw(
@@ -207,6 +222,10 @@
 								"Row #{0}: Finished Good Item {1} must be a sub-contracted item for service item {2}"
 							).format(item.idx, item.fg_item, item.item_code)
 						)
+					elif not frappe.get_value("Item", item.fg_item, "default_bom"):
+						frappe.throw(
+							_("Row #{0}: Default BOM not found for FG Item {1}").format(item.idx, item.fg_item)
+						)
 				if not item.fg_item_qty:
 					frappe.throw(
 						_("Row #{0}: Finished Good Item Qty is not specified for service item {0}").format(
@@ -305,6 +324,7 @@
 		self.set_status(update=True, status=status)
 		self.update_requested_qty()
 		self.update_ordered_qty()
+		self.update_reserved_qty_for_subcontract()
 		self.notify_update()
 		clear_doctype_notifications(self)
 
@@ -318,6 +338,7 @@
 		self.update_requested_qty()
 		self.update_ordered_qty()
 		self.validate_budget()
+		self.update_reserved_qty_for_subcontract()
 
 		frappe.get_doc("Authorization Control").validate_approving_authority(
 			self.doctype, self.company, self.base_grand_total
@@ -337,6 +358,7 @@
 		if self.has_drop_ship_item():
 			self.update_delivered_qty_in_sales_order()
 
+		self.update_reserved_qty_for_subcontract()
 		self.check_on_hold_or_closed_status()
 
 		frappe.db.set(self, "status", "Cancelled")
@@ -406,6 +428,13 @@
 			if item.delivered_by_supplier == 1:
 				item.received_qty = item.qty
 
+	def update_reserved_qty_for_subcontract(self):
+		if self.is_old_subcontracting_flow:
+			for d in self.supplied_items:
+				if d.rm_item_code:
+					stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse)
+					stock_bin.update_reserved_qty_for_sub_contracting(subcontract_doctype="Purchase Order")
+
 	def update_receiving_percentage(self):
 		total_qty, received_qty = 0.0, 0.0
 		for item in self.items:
@@ -649,4 +678,16 @@
 
 	target_doc.populate_items_table()
 
+	if target_doc.set_warehouse:
+		for item in target_doc.items:
+			item.warehouse = target_doc.set_warehouse
+	else:
+		source_doc = frappe.get_doc("Purchase Order", source_name)
+		if source_doc.set_warehouse:
+			for item in target_doc.items:
+				item.warehouse = source_doc.set_warehouse
+		else:
+			for idx, item in enumerate(target_doc.items):
+				item.warehouse = source_doc.items[idx].warehouse
+
 	return target_doc
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
index 0c38c3e..01b55c0 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
@@ -22,6 +22,6 @@
 				"label": _("Reference"),
 				"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
 			},
-			{"label": _("Sub-contracting"), "items": ["Subcontracting Order"]},
+			{"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]},
 		],
 	}
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 12eef79..4794104 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -574,18 +574,20 @@
    "read_only": 1
   },
   {
+   "depends_on": "eval:parent.is_old_subcontracting_flow",
    "fieldname": "bom",
    "fieldtype": "Link",
    "label": "BOM",
    "options": "BOM",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "read_only_depends_on": "eval:!parent.is_old_subcontracting_flow"
   },
   {
    "default": "0",
+   "depends_on": "eval:parent.is_old_subcontracting_flow",
    "fieldname": "include_exploded_items",
    "fieldtype": "Check",
-   "hidden": 1,
    "label": "Include Exploded Items",
    "print_hide": 1
   },
@@ -849,27 +851,27 @@
    "print_hide": 1
   },
   {
-   "depends_on": "eval:parent.is_subcontracted",
+   "depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow",
    "fieldname": "fg_item",
    "fieldtype": "Link",
    "label": "Finished Good Item",
-   "mandatory_depends_on": "eval:parent.is_subcontracted",
+   "mandatory_depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow",
    "options": "Item"
   },
   {
    "default": "1",
-   "depends_on": "eval:parent.is_subcontracted",
+   "depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow",
    "fieldname": "fg_item_qty",
    "fieldtype": "Float",
    "label": "Finished Good Item Qty",
-   "mandatory_depends_on": "eval:parent.is_subcontracted"
+   "mandatory_depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow"
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-04-07 14:53:16.684010",
+ "modified": "2022-06-16 06:00:01.624317",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item",
diff --git a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.js b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.js
index 57a41ad..075671f 100644
--- a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.js
+++ b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.js
@@ -27,18 +27,16 @@
 			reqd: 1
 		},
 		{
-			label: __("Subcontracting Order"),
+			label: __("Order Type"),
+			fieldname: "order_type",
+			fieldtype: "Select",
+			options: ["Purchase Order", "Subcontracting Order"],
+			default: "Subcontracting Order"
+		},
+		{
+			label: __("Subcontract Order"),
 			fieldname: "name",
-			fieldtype: "Link",
-			options: "Subcontracting Order",
-			get_query: function () {
-				return {
-					filters: {
-						docstatus: 1,
-						company: frappe.query_report.get_filter_value('company')
-					}
-				}
-			}
+			fieldtype: "Data"
 		}
 	]
 };
\ No newline at end of file
diff --git a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
index 3750daa..0213051 100644
--- a/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
+++ b/erpnext/buying/report/subcontract_order_summary/subcontract_order_summary.py
@@ -8,7 +8,7 @@
 
 def execute(filters=None):
 	columns, data = [], []
-	columns = get_columns()
+	columns = get_columns(filters)
 	data = get_data(filters)
 
 	return columns, data
@@ -20,42 +20,45 @@
 
 	if orders:
 		supplied_items = get_supplied_items(orders, report_filters)
-		sco_details = prepare_subcontracted_data(orders, supplied_items)
-		get_subcontracted_data(sco_details, data)
+		order_details = prepare_subcontracted_data(orders, supplied_items)
+		get_subcontracted_data(order_details, data)
 
 	return data
 
 
 def get_subcontracted_orders(report_filters):
 	fields = [
-		"`tabSubcontracting Order Item`.`parent` as sco_id",
-		"`tabSubcontracting Order Item`.`item_code`",
-		"`tabSubcontracting Order Item`.`item_name`",
-		"`tabSubcontracting Order Item`.`qty`",
-		"`tabSubcontracting Order Item`.`name`",
-		"`tabSubcontracting Order Item`.`received_qty`",
-		"`tabSubcontracting Order`.`status`",
+		f"`tab{report_filters.order_type} Item`.`parent` as order_id",
+		f"`tab{report_filters.order_type} Item`.`item_code`",
+		f"`tab{report_filters.order_type} Item`.`item_name`",
+		f"`tab{report_filters.order_type} Item`.`qty`",
+		f"`tab{report_filters.order_type} Item`.`name`",
+		f"`tab{report_filters.order_type} Item`.`received_qty`",
+		f"`tab{report_filters.order_type}`.`status`",
 	]
 
 	filters = get_filters(report_filters)
 
-	return frappe.get_all("Subcontracting Order", fields=fields, filters=filters) or []
+	return frappe.get_all(report_filters.order_type, fields=fields, filters=filters) or []
 
 
 def get_filters(report_filters):
 	filters = [
-		["Subcontracting Order", "docstatus", "=", 1],
+		[report_filters.order_type, "docstatus", "=", 1],
 		[
-			"Subcontracting Order",
+			report_filters.order_type,
 			"transaction_date",
 			"between",
 			(report_filters.from_date, report_filters.to_date),
 		],
 	]
 
+	if report_filters.order_type == "Purchase Order":
+		filters.append(["Purchase Order", "is_old_subcontracting_flow", "=", 1])
+
 	for field in ["name", "company"]:
 		if report_filters.get(field):
-			filters.append(["Subcontracting Order", field, "=", report_filters.get(field)])
+			filters.append([report_filters.order_type, field, "=", report_filters.get(field)])
 
 	return filters
 
@@ -70,15 +73,21 @@
 		"rm_item_code",
 		"required_qty",
 		"supplied_qty",
+		"returned_qty",
 		"total_supplied_qty",
 		"consumed_qty",
 		"reference_name",
 	]
 
-	filters = {"parent": ("in", [d.sco_id for d in orders]), "docstatus": 1}
+	filters = {"parent": ("in", [d.order_id for d in orders]), "docstatus": 1}
 
 	supplied_items = {}
-	for row in frappe.get_all("Subcontracting Order Supplied Item", fields=fields, filters=filters):
+	supplied_items_table = (
+		"Purchase Order Item Supplied"
+		if report_filters.order_type == "Purchase Order"
+		else "Subcontracting Order Supplied Item"
+	)
+	for row in frappe.get_all(supplied_items_table, fields=fields, filters=filters):
 		new_key = (row.parent, row.reference_name, row.main_item_code)
 
 		supplied_items.setdefault(new_key, []).append(row)
@@ -87,24 +96,24 @@
 
 
 def prepare_subcontracted_data(orders, supplied_items):
-	sco_details = {}
+	order_details = {}
 	for row in orders:
-		key = (row.sco_id, row.name, row.item_code)
-		if key not in sco_details:
-			sco_details.setdefault(key, frappe._dict({"sco_item": row, "supplied_items": []}))
+		key = (row.order_id, row.name, row.item_code)
+		if key not in order_details:
+			order_details.setdefault(key, frappe._dict({"order_item": row, "supplied_items": []}))
 
-		details = sco_details[key]
+		details = order_details[key]
 
 		if supplied_items.get(key):
 			for supplied_item in supplied_items[key]:
 				details["supplied_items"].append(supplied_item)
 
-	return sco_details
+	return order_details
 
 
-def get_subcontracted_data(sco_details, data):
-	for key, details in sco_details.items():
-		res = details.sco_item
+def get_subcontracted_data(order_details, data):
+	for key, details in order_details.items():
+		res = details.order_item
 		for index, row in enumerate(details.supplied_items):
 			if index != 0:
 				res = {}
@@ -113,13 +122,13 @@
 			data.append(res)
 
 
-def get_columns():
+def get_columns(filters):
 	return [
 		{
-			"label": _("Subcontracting Order"),
-			"fieldname": "sco_id",
+			"label": _("Subcontract Order"),
+			"fieldname": "order_id",
 			"fieldtype": "Link",
-			"options": "Subcontracting Order",
+			"options": filters.order_type,
 			"width": 100,
 		},
 		{"label": _("Status"), "fieldname": "status", "fieldtype": "Data", "width": 80},
@@ -142,4 +151,5 @@
 		{"label": _("Required Qty"), "fieldname": "required_qty", "fieldtype": "Float", "width": 110},
 		{"label": _("Supplied Qty"), "fieldname": "supplied_qty", "fieldtype": "Float", "width": 110},
 		{"label": _("Consumed Qty"), "fieldname": "consumed_qty", "fieldtype": "Float", "width": 120},
+		{"label": _("Returned Qty"), "fieldname": "returned_qty", "fieldtype": "Float", "width": 110},
 	]
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js
index fc58b6a..6304a09 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.js
@@ -5,6 +5,13 @@
 frappe.query_reports["Subcontracted Item To Be Received"] = {
 	"filters": [
 		{
+			label: __("Order Type"),
+			fieldname: "order_type",
+			fieldtype: "Select",
+			options: ["Purchase Order", "Subcontracting Order"],
+			default: "Subcontracting Order"
+		},
+		{
 			fieldname: "supplier",
 			label: __("Supplier"),
 			fieldtype: "Link",
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json
index fdf6cf7..f40b788 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.json
@@ -13,7 +13,7 @@
  "name": "Subcontracted Item To Be Received",
  "owner": "Administrator",
  "prepared_report": 0,
- "ref_doctype": "Purchase Order",
+ "ref_doctype": "Subcontracting Order",
  "report_name": "Subcontracted Item To Be Received",
  "report_type": "Script Report",
  "roles": [
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py
index 30f9dec..135449b 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/subcontracted_item_to_be_received.py
@@ -11,18 +11,18 @@
 		frappe.msgprint(_("To Date must be greater than From Date"))
 
 	data = []
-	columns = get_columns()
+	columns = get_columns(filters)
 	get_data(data, filters)
 	return columns, data
 
 
-def get_columns():
+def get_columns(filters):
 	return [
 		{
-			"label": _("Subcontracting Order"),
+			"label": _("Subcontract Order"),
 			"fieldtype": "Link",
-			"fieldname": "subcontracting_order",
-			"options": "Subcontracting Order",
+			"fieldname": "subcontract_order",
+			"options": filters.order_type,
 			"width": 150,
 		},
 		{"label": _("Date"), "fieldtype": "Date", "fieldname": "date", "hidden": 1, "width": 150},
@@ -57,14 +57,14 @@
 
 
 def get_data(data, filters):
-	sco = get_sco(filters)
-	sco_name = [v.name for v in sco]
-	sub_items = get_subcontracting_order_item_supplied(sco_name)
-	for item in sub_items:
-		for order in sco:
+	orders = get_subcontract_orders(filters)
+	orders_name = [order.name for order in orders]
+	subcontracted_items = get_subcontract_order_supplied_item(filters.order_type, orders_name)
+	for item in subcontracted_items:
+		for order in orders:
 			if order.name == item.parent and item.received_qty < item.qty:
 				row = {
-					"subcontracting_order": item.parent,
+					"subcontract_order": item.parent,
 					"date": order.transaction_date,
 					"supplier": order.supplier,
 					"fg_item_code": item.item_code,
@@ -76,21 +76,25 @@
 				data.append(row)
 
 
-def get_sco(filters):
+def get_subcontract_orders(filters):
 	record_filters = [
 		["supplier", "=", filters.supplier],
 		["transaction_date", "<=", filters.to_date],
 		["transaction_date", ">=", filters.from_date],
 		["docstatus", "=", 1],
 	]
+
+	if filters.order_type == "Purchase Order":
+		record_filters.append(["is_old_subcontracting_flow", "=", 1])
+
 	return frappe.get_all(
-		"Subcontracting Order", filters=record_filters, fields=["name", "transaction_date", "supplier"]
+		filters.order_type, filters=record_filters, fields=["name", "transaction_date", "supplier"]
 	)
 
 
-def get_subcontracting_order_item_supplied(sco):
+def get_subcontract_order_supplied_item(order_type, orders):
 	return frappe.get_all(
-		"Subcontracting Order Item",
-		filters=[("parent", "IN", sco)],
+		f"{order_type} Item",
+		filters=[("parent", "IN", orders)],
 		fields=["parent", "item_code", "item_name", "qty", "received_qty"],
 	)
diff --git a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
index 80fd657..c772c1a 100644
--- a/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
+++ b/erpnext/buying/report/subcontracted_item_to_be_received/test_subcontracted_item_to_be_received.py
@@ -50,6 +50,7 @@
 		col, data = execute(
 			filters=frappe._dict(
 				{
+					"order_type": "Subcontracting Order",
 					"supplier": sco.supplier,
 					"from_date": frappe.utils.get_datetime(
 						frappe.utils.add_to_date(sco.transaction_date, days=-10)
@@ -60,7 +61,7 @@
 		)
 		self.assertEqual(data[0]["pending_qty"], 5)
 		self.assertEqual(data[0]["received_qty"], 5)
-		self.assertEqual(data[0]["subcontracting_order"], sco.name)
+		self.assertEqual(data[0]["subcontract_order"], sco.name)
 		self.assertEqual(data[0]["supplier"], sco.supplier)
 
 
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js
index 0853afd..b6739fe 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.js
@@ -5,6 +5,13 @@
 frappe.query_reports["Subcontracted Raw Materials To Be Transferred"] = {
 	"filters": [
 		{
+			label: __("Order Type"),
+			fieldname: "order_type",
+			fieldtype: "Select",
+			options: ["Purchase Order", "Subcontracting Order"],
+			default: "Subcontracting Order"
+		},
+		{
 			fieldname: "supplier",
 			label: __("Supplier"),
 			fieldtype: "Link",
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json
index c7cee5e..f689fbc 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.json
@@ -13,7 +13,7 @@
  "name": "Subcontracted Raw Materials To Be Transferred",
  "owner": "Administrator",
  "prepared_report": 0,
- "ref_doctype": "Purchase Order",
+ "ref_doctype": "Subcontracting Order",
  "report_name": "Subcontracted Raw Materials To Be Transferred",
  "report_type": "Script Report",
  "roles": [
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
index a837b24..ef28eda 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/subcontracted_raw_materials_to_be_transferred.py
@@ -10,19 +10,19 @@
 	if filters.from_date >= filters.to_date:
 		frappe.msgprint(_("To Date must be greater than From Date"))
 
-	columns = get_columns()
+	columns = get_columns(filters)
 	data = get_data(filters)
 
 	return columns, data or []
 
 
-def get_columns():
+def get_columns(filters):
 	return [
 		{
-			"label": _("Purchase Order"),
+			"label": _("Subcontract Order"),
 			"fieldtype": "Link",
-			"fieldname": "purchase_order",
-			"options": "Purchase Order",
+			"fieldname": "subcontract_order",
+			"options": filters.order_type,
 			"width": 200,
 		},
 		{"label": _("Date"), "fieldtype": "Date", "fieldname": "date", "width": 150},
@@ -46,10 +46,10 @@
 
 
 def get_data(filters):
-	sco_rm_item_details = get_sco_items_to_supply(filters)
+	order_rm_item_details = get_order_items_to_supply(filters)
 
 	data = []
-	for row in sco_rm_item_details:
+	for row in order_rm_item_details:
 		transferred_qty = row.get("transferred_qty") or 0
 		if transferred_qty < row.get("reqd_qty", 0):
 			pending_qty = frappe.utils.flt(row.get("reqd_qty", 0) - transferred_qty)
@@ -59,22 +59,33 @@
 	return data
 
 
-def get_sco_items_to_supply(filters):
+def get_order_items_to_supply(filters):
+	supplied_items_table = (
+		"Purchase Order Item Supplied"
+		if filters.order_type == "Purchase Order"
+		else "Subcontracting Order Supplied Item"
+	)
+
+	record_filters = [
+		[filters.order_type, "per_received", "<", "100"],
+		[filters.order_type, "supplier", "=", filters.supplier],
+		[filters.order_type, "transaction_date", "<=", filters.to_date],
+		[filters.order_type, "transaction_date", ">=", filters.from_date],
+		[filters.order_type, "docstatus", "=", 1],
+	]
+
+	if filters.order_type == "Purchase Order":
+		record_filters.append([filters.order_type, "is_old_subcontracting_flow", "=", 1])
+
 	return frappe.db.get_all(
-		"Subcontracting Order",
+		filters.order_type,
 		fields=[
-			"name as subcontracting_order",
+			"name as subcontract_order",
 			"transaction_date as date",
 			"supplier as supplier",
-			"`tabSubcontracting Order Supplied Item`.rm_item_code as rm_item_code",
-			"`tabSubcontracting Order Supplied Item`.required_qty as reqd_qty",
-			"`tabSubcontracting Order Supplied Item`.supplied_qty as transferred_qty",
+			f"`tab{supplied_items_table}`.rm_item_code as rm_item_code",
+			f"`tab{supplied_items_table}`.required_qty as reqd_qty",
+			f"`tab{supplied_items_table}`.supplied_qty as transferred_qty",
 		],
-		filters=[
-			["Subcontracting Order", "per_received", "<", "100"],
-			["Subcontracting Order", "supplier", "=", filters.supplier],
-			["Subcontracting Order", "transaction_date", "<=", filters.to_date],
-			["Subcontracting Order", "transaction_date", ">=", filters.from_date],
-			["Subcontracting Order", "docstatus", "=", 1],
-		],
+		filters=record_filters,
 	)
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
index d29791c..1602957 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
@@ -9,14 +9,12 @@
 from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcontracted_raw_materials_to_be_transferred import (
 	execute,
 )
+from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
 from erpnext.controllers.tests.test_subcontracting_controller import (
 	get_subcontracting_order,
 	make_service_item,
 )
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
-	make_rm_stock_entry,
-)
 
 
 class TestSubcontractedItemToBeTransferred(FrappeTestCase):
@@ -45,6 +43,7 @@
 		col, data = execute(
 			filters=frappe._dict(
 				{
+					"order_type": "Subcontracting Order",
 					"supplier": sco.supplier,
 					"from_date": frappe.utils.get_datetime(
 						frappe.utils.add_to_date(sco.transaction_date, days=-10)
@@ -55,12 +54,12 @@
 		)
 		sco.reload()
 
-		sco_data = [row for row in data if row.get("subcontracting_order") == sco.name]
+		sco_data = [row for row in data if row.get("subcontract_order") == sco.name]
 		# Alphabetically sort to be certain of order
 		sco_data = sorted(sco_data, key=lambda i: i["rm_item_code"])
 
 		self.assertEqual(len(sco_data), 2)
-		self.assertEqual(sco_data[0]["subcontracting_order"], sco.name)
+		self.assertEqual(sco_data[0]["subcontract_order"], sco.name)
 
 		self.assertEqual(sco_data[0]["rm_item_code"], "_Test Item")
 		self.assertEqual(sco_data[0]["p_qty"], 8)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 7cb34fc..e83e0c2 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -2657,6 +2657,10 @@
 		parent.update_ordered_qty()
 		parent.update_ordered_and_reserved_qty()
 		parent.update_receiving_percentage()
+		if parent.is_old_subcontracting_flow:
+			parent.update_reserved_qty_for_subcontract()
+			parent.create_raw_materials_supplied()
+			parent.save()
 	else:  # Sales Order
 		parent.validate_warehouse()
 		parent.update_reserved_qty()
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index fa091df..4db8ccb 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -11,7 +11,7 @@
 from erpnext.accounts.party import get_party_details
 from erpnext.buying.utils import update_last_purchase_rate, validate_for_items
 from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
-from erpnext.controllers.stock_controller import StockController
+from erpnext.controllers.subcontracting_controller import SubcontractingController
 from erpnext.stock.get_item_details import get_conversion_factor
 from erpnext.stock.utils import get_incoming_rate
 
@@ -20,7 +20,10 @@
 	pass
 
 
-class BuyingController(StockController):
+class BuyingController(SubcontractingController):
+	def __setup__(self):
+		self.flags.ignore_permlevel_for_fields = ["buying_price_list", "price_list_currency"]
+
 	def get_feed(self):
 		if self.get("supplier_name"):
 			return _("From {0} | {1} {2}").format(self.supplier_name, self.currency, self.grand_total)
@@ -51,6 +54,8 @@
 
 			# sub-contracting
 			self.validate_for_subcontracting()
+			if self.get("is_old_subcontracting_flow"):
+				self.create_raw_materials_supplied()
 			self.set_landed_cost_voucher_amount()
 
 		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
@@ -251,9 +256,18 @@
 					)
 
 				qty_in_stock_uom = flt(item.qty * item.conversion_factor)
-				item.valuation_rate = (
-					item.base_net_amount + item.item_tax_amount + flt(item.landed_cost_voucher_amount)
-				) / qty_in_stock_uom
+				if self.get("is_old_subcontracting_flow"):
+					item.rm_supp_cost = self.get_supplied_items_cost(item.name, reset_outgoing_rate)
+					item.valuation_rate = (
+						item.base_net_amount
+						+ item.item_tax_amount
+						+ item.rm_supp_cost
+						+ flt(item.landed_cost_voucher_amount)
+					) / qty_in_stock_uom
+				else:
+					item.valuation_rate = (
+						item.base_net_amount + item.item_tax_amount + flt(item.landed_cost_voucher_amount)
+					) / qty_in_stock_uom
 			else:
 				item.valuation_rate = 0.0
 
@@ -312,6 +326,19 @@
 		if self.is_subcontracted:
 			if self.doctype in ["Purchase Receipt", "Purchase Invoice"] and not self.supplier_warehouse:
 				frappe.throw(_("Supplier Warehouse mandatory for sub-contracted {0}").format(self.doctype))
+
+			if self.get("is_old_subcontracting_flow"):
+				for item in self.get("items"):
+					if item in self.sub_contracted_items and not item.bom:
+						frappe.throw(_("Please select BOM in BOM field for Item {0}").format(item.item_code))
+
+				if self.doctype != "Purchase Order":
+					return
+
+				for row in self.get("supplied_items"):
+					if not row.reserve_warehouse:
+						msg = f"Reserved Warehouse is mandatory for the Item {frappe.bold(row.rm_item_code)} in Raw Materials supplied"
+						frappe.throw(_(msg))
 		else:
 			for item in self.get("items"):
 				if item.get("bom"):
@@ -440,7 +467,9 @@
 						sle.update(
 							{
 								"incoming_rate": incoming_rate,
-								"recalculate_rate": 1 if (self.is_subcontracted and d.fg_item) or d.from_warehouse else 0,
+								"recalculate_rate": 1
+								if (self.is_subcontracted and (d.bom or d.fg_item)) or d.from_warehouse
+								else 0,
 							}
 						)
 					sl_entries.append(sle)
@@ -468,6 +497,8 @@
 					)
 				)
 
+		if self.get("is_old_subcontracting_flow"):
+			self.make_sl_entries_for_supplier_warehouse(sl_entries)
 		self.make_sl_entries(
 			sl_entries,
 			allow_negative_stock=allow_negative_stock,
@@ -494,6 +525,8 @@
 					)
 
 				po_obj.update_ordered_qty(po_item_rows)
+				if self.get("is_old_subcontracting_flow"):
+					po_obj.update_reserved_qty_for_subcontract()
 
 	def on_submit(self):
 		if self.get("is_return"):
@@ -718,7 +751,10 @@
 		if self.doctype == "Material Request":
 			return
 
-		validate_item_type(self, "is_purchase_item", "purchase")
+		if self.get("is_old_subcontracting_flow"):
+			validate_item_type(self, "is_sub_contracted_item", "subcontracted")
+		else:
+			validate_item_type(self, "is_purchase_item", "purchase")
 
 
 def get_asset_item_details(asset_items):
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 4e0d911..2a2f8f5 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -2,6 +2,7 @@
 # For license information, please see license.txt
 
 import copy
+import json
 from collections import defaultdict
 
 import frappe
@@ -14,13 +15,40 @@
 
 
 class SubcontractingController(StockController):
+	def __init__(self, *args, **kwargs):
+		super(SubcontractingController, self).__init__(*args, **kwargs)
+		if self.get("is_old_subcontracting_flow"):
+			self.subcontract_data = frappe._dict(
+				{
+					"order_doctype": "Purchase Order",
+					"order_field": "purchase_order",
+					"rm_detail_field": "po_detail",
+					"receipt_supplied_items_field": "Purchase Receipt Item Supplied",
+					"order_supplied_items_field": "Purchase Order Item Supplied",
+				}
+			)
+		else:
+			self.subcontract_data = frappe._dict(
+				{
+					"order_doctype": "Subcontracting Order",
+					"order_field": "subcontracting_order",
+					"rm_detail_field": "sco_rm_detail",
+					"receipt_supplied_items_field": "Subcontracting Receipt Supplied Item",
+					"order_supplied_items_field": "Subcontracting Order Supplied Item",
+				}
+			)
+
 	def before_validate(self):
-		self.remove_empty_rows()
-		self.set_items_conversion_factor()
+		if self.doctype in ["Subcontracting Order", "Subcontracting Receipt"]:
+			self.remove_empty_rows()
+			self.set_items_conversion_factor()
 
 	def validate(self):
-		self.validate_items()
-		self.create_raw_materials_supplied()
+		if self.doctype in ["Subcontracting Order", "Subcontracting Receipt"]:
+			self.validate_items()
+			self.create_raw_materials_supplied()
+		else:
+			super(SubcontractingController, self).validate()
 
 	def remove_empty_rows(self):
 		for key in ["service_items", "items", "supplied_items"]:
@@ -54,7 +82,10 @@
 
 	def __get_data_before_save(self):
 		item_dict = {}
-		if self.doctype == "Subcontracting Receipt" and self._doc_before_save:
+		if (
+			self.doctype in ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"]
+			and self._doc_before_save
+		):
 			for row in self._doc_before_save.get("items"):
 				item_dict[row.name] = (row.item_code, row.qty)
 
@@ -64,7 +95,7 @@
 		self.__changed_name = []
 		self.__reference_name = []
 
-		if self.doctype == "Subcontracting Order" or self.is_new():
+		if self.doctype in ["Purchase Order", "Subcontracting Order"] or self.is_new():
 			self.set(self.raw_material_table, [])
 			return
 
@@ -93,36 +124,38 @@
 		self.alternative_item_details = frappe._dict()
 		self.__get_backflush_based_on()
 
-	def __get_subcontracting_orders(self):
-		self.subcontracting_orders = []
+	def __get_subcontract_orders(self):
+		self.subcontract_orders = []
 
-		if self.doctype == "Subcontracting Order":
+		if self.doctype in ["Purchase Order", "Subcontracting Order"]:
 			return
 
-		self.subcontracting_orders = [
-			item.subcontracting_order for item in self.items if item.subcontracting_order
+		self.subcontract_orders = [
+			item.get(self.subcontract_data.order_field)
+			for item in self.items
+			if item.get(self.subcontract_data.order_field)
 		]
 
 	def __get_pending_qty_to_receive(self):
-		"""Get qty to be received against the subcontracting order."""
+		"""Get qty to be received against the subcontract order."""
 
 		self.qty_to_be_received = defaultdict(float)
 
 		if (
-			self.doctype != "Subcontracting Order"
+			self.doctype != self.subcontract_data.order_doctype
 			and self.backflush_based_on != "BOM"
-			and self.subcontracting_orders
+			and self.subcontract_orders
 		):
 			for row in frappe.get_all(
-				"Subcontracting Order Item",
+				f"{self.subcontract_data.order_doctype} Item",
 				fields=["item_code", "(qty - received_qty) as qty", "parent", "name"],
-				filters={"docstatus": 1, "parent": ("in", self.subcontracting_orders)},
+				filters={"docstatus": 1, "parent": ("in", self.subcontract_orders)},
 			):
 
 				self.qty_to_be_received[(row.item_code, row.parent)] += row.qty
 
 	def __get_transferred_items(self):
-		fields = ["`tabStock Entry`.`subcontracting_order`"]
+		fields = [f"`tabStock Entry`.`{self.subcontract_data.order_field}`"]
 		alias_dict = {
 			"item_code": "rm_item_code",
 			"subcontracted_item": "main_item_code",
@@ -145,7 +178,7 @@
 			"s_warehouse",
 			"t_warehouse",
 			"item_group",
-			"sco_rm_detail",
+			self.subcontract_data.rm_detail_field,
 		]
 
 		if self.backflush_based_on == "BOM":
@@ -157,7 +190,7 @@
 		filters = [
 			["Stock Entry", "docstatus", "=", 1],
 			["Stock Entry", "purpose", "=", "Send to Subcontractor"],
-			["Stock Entry", "subcontracting_order", "in", self.subcontracting_orders],
+			["Stock Entry", self.subcontract_data.order_field, "in", self.subcontract_orders],
 		]
 
 		return frappe.get_all("Stock Entry", fields=fields, filters=filters)
@@ -168,21 +201,21 @@
 
 	def __get_received_items(self, doctype):
 		fields = []
-		self.sco_field = "subcontracting_order"
-
-		for field in ["name", self.sco_field, "parent"]:
+		for field in ["name", self.subcontract_data.order_field, "parent"]:
 			fields.append(f"`tab{doctype} Item`.`{field}`")
 
 		filters = [
 			[doctype, "docstatus", "=", 1],
-			[f"{doctype} Item", self.sco_field, "in", self.subcontracting_orders],
+			[f"{doctype} Item", self.subcontract_data.order_field, "in", self.subcontract_orders],
 		]
+		if doctype == "Purchase Invoice":
+			filters.append(["Purchase Invoice", "update_stock", "=", 1])
 
 		return frappe.get_all(f"{doctype}", fields=fields, filters=filters)
 
-	def __get_consumed_items(self, doctype, scr_items):
+	def __get_consumed_items(self, doctype, receipt_items):
 		return frappe.get_all(
-			"Subcontracting Receipt Supplied Item",
+			self.subcontract_data.receipt_supplied_items_field,
 			fields=[
 				"serial_no",
 				"rm_item_code",
@@ -191,26 +224,26 @@
 				"consumed_qty",
 				"main_item_code",
 			],
-			filters={"docstatus": 1, "reference_name": ("in", list(scr_items)), "parenttype": doctype},
+			filters={"docstatus": 1, "reference_name": ("in", list(receipt_items)), "parenttype": doctype},
 		)
 
 	def __update_consumed_materials(self, doctype, return_consumed_items=False):
 		"""Deduct the consumed materials from the available materials."""
 
-		scr_items = self.__get_received_items(doctype)
-		if not scr_items:
+		receipt_items = self.__get_received_items(doctype)
+		if not receipt_items:
 			return ([], {}) if return_consumed_items else None
 
-		scr_items = {
-			item.name: item.get(self.get("sco_field") or "subcontracting_order") for item in scr_items
+		receipt_items = {
+			item.name: item.get(self.subcontract_data.order_field) for item in receipt_items
 		}
-		consumed_materials = self.__get_consumed_items(doctype, scr_items.keys())
+		consumed_materials = self.__get_consumed_items(doctype, receipt_items.keys())
 
 		if return_consumed_items:
-			return (consumed_materials, scr_items)
+			return (consumed_materials, receipt_items)
 
 		for row in consumed_materials:
-			key = (row.rm_item_code, row.main_item_code, scr_items.get(row.reference_name))
+			key = (row.rm_item_code, row.main_item_code, receipt_items.get(row.reference_name))
 			if not self.available_materials.get(key):
 				continue
 
@@ -226,16 +259,16 @@
 	def get_available_materials(self):
 		"""Get the available raw materials which has been transferred to the supplier.
 		available_materials = {
-		        (item_code, subcontracted_item, subcontracting_order): {
+		        (item_code, subcontracted_item, subcontract_order): {
 		                'qty': 1, 'serial_no': [ABC], 'batch_no': {'batch1': 1}, 'data': item_details
 		        }
 		}
 		"""
-		if not self.subcontracting_orders:
+		if not self.subcontract_orders:
 			return
 
 		for row in self.__get_transferred_items():
-			key = (row.rm_item_code, row.main_item_code, row.subcontracting_order)
+			key = (row.rm_item_code, row.main_item_code, row.get(self.subcontract_data.order_field))
 
 			if key not in self.available_materials:
 				self.available_materials.setdefault(
@@ -246,14 +279,16 @@
 							"serial_no": [],
 							"batch_no": defaultdict(float),
 							"item_details": row,
-							"sco_rm_details": [],
+							f"{self.subcontract_data.rm_detail_field}s": [],
 						}
 					),
 				)
 
 			details = self.available_materials[key]
 			details.qty += row.qty
-			details.sco_rm_details.append(row.sco_rm_detail)
+			details[f"{self.subcontract_data.rm_detail_field}s"].append(
+				row.get(self.subcontract_data.rm_detail_field)
+			)
 
 			if row.serial_no:
 				details.serial_no.extend(get_serial_nos(row.serial_no))
@@ -264,7 +299,11 @@
 			self.__set_alternative_item_details(row)
 
 		self.__transferred_items = copy.deepcopy(self.available_materials)
-		self.__update_consumed_materials("Subcontracting Receipt")
+		if self.get("is_old_subcontracting_flow"):
+			for doctype in ["Purchase Receipt", "Purchase Invoice"]:
+				self.__update_consumed_materials(doctype)
+		else:
+			self.__update_consumed_materials("Subcontracting Receipt")
 
 	def __remove_changed_rows(self):
 		if not self.__changed_name:
@@ -317,7 +356,7 @@
 		)
 
 	def __update_reserve_warehouse(self, row, item):
-		if self.doctype == "Subcontracting Order":
+		if self.doctype == self.subcontract_data.order_doctype:
 			row.reserve_warehouse = self.set_reserve_warehouse or item.warehouse
 
 	def __set_alternative_item(self, bom_item):
@@ -325,7 +364,7 @@
 			bom_item.update(self.alternative_item_details[bom_item.rm_item_code])
 
 	def __set_serial_nos(self, item_row, rm_obj):
-		key = (rm_obj.rm_item_code, item_row.item_code, item_row.subcontracting_order)
+		key = (rm_obj.rm_item_code, item_row.item_code, item_row.get(self.subcontract_data.order_field))
 		if self.available_materials.get(key) and self.available_materials[key]["serial_no"]:
 			used_serial_nos = self.available_materials[key]["serial_no"][0 : cint(rm_obj.consumed_qty)]
 			rm_obj.serial_no = "\n".join(used_serial_nos)
@@ -340,7 +379,7 @@
 				"consumed_qty": qty,
 				"batch_no": batch_no,
 				"required_qty": qty,
-				"subcontracting_order": item_row.subcontracting_order,
+				self.subcontract_data.order_field: item_row.get(self.subcontract_data.order_field),
 			}
 		)
 
@@ -351,7 +390,7 @@
 		rm_obj.consumed_qty = consumed_qty
 
 	def __set_batch_nos(self, bom_item, item_row, rm_obj, qty):
-		key = (rm_obj.rm_item_code, item_row.item_code, item_row.subcontracting_order)
+		key = (rm_obj.rm_item_code, item_row.item_code, item_row.get(self.subcontract_data.order_field))
 
 		if self.available_materials.get(key) and self.available_materials[key]["batch_no"]:
 			new_rm_obj = None
@@ -397,16 +436,18 @@
 			)
 			rm_obj.rate = get_incoming_rate(args)
 
-		if self.doctype == "Subcontracting Order":
+		if self.doctype == self.subcontract_data.order_doctype:
 			rm_obj.required_qty = qty
 			rm_obj.amount = rm_obj.required_qty * rm_obj.rate
 		else:
 			rm_obj.consumed_qty = 0
-			rm_obj.subcontracting_order = item_row.subcontracting_order
+			setattr(
+				rm_obj, self.subcontract_data.order_field, item_row.get(self.subcontract_data.order_field)
+			)
 			self.__set_batch_nos(bom_item, item_row, rm_obj, qty)
 
 	def __get_qty_based_on_material_transfer(self, item_row, transfer_item):
-		key = (item_row.item_code, item_row.subcontracting_order)
+		key = (item_row.item_code, item_row.get(self.subcontract_data.order_field))
 
 		if self.qty_to_be_received == item_row.qty:
 			return transfer_item.qty
@@ -427,13 +468,13 @@
 
 		has_supplied_items = True if self.get(self.raw_material_table) else False
 		for row in self.items:
-			if self.doctype != "Subcontracting Order" and (
+			if self.doctype != self.subcontract_data.order_doctype and (
 				(self.__changed_name and row.name not in self.__changed_name)
 				or (has_supplied_items and not self.__changed_name)
 			):
 				continue
 
-			if self.doctype == "Subcontracting Order" or self.backflush_based_on == "BOM":
+			if self.doctype == self.subcontract_data.order_doctype or self.backflush_based_on == "BOM":
 				for bom_item in self.__get_materials_from_bom(
 					row.item_code, row.bom, row.get("include_exploded_items")
 				):
@@ -445,17 +486,22 @@
 
 			elif self.backflush_based_on != "BOM":
 				for key, transfer_item in self.available_materials.items():
-					if (key[1], key[2]) == (row.item_code, row.subcontracting_order) and transfer_item.qty > 0:
+					if (key[1], key[2]) == (
+						row.item_code,
+						row.get(self.subcontract_data.order_field),
+					) and transfer_item.qty > 0:
 						qty = self.__get_qty_based_on_material_transfer(row, transfer_item) or 0
 						transfer_item.qty -= qty
 						self.__add_supplied_item(row, transfer_item.get("item_details"), qty)
 
 				if self.qty_to_be_received:
-					self.qty_to_be_received[(row.item_code, row.subcontracting_order)] -= row.qty
+					self.qty_to_be_received[
+						(row.item_code, row.get(self.subcontract_data.order_field))
+					] -= row.qty
 
 	def __prepare_supplied_items(self):
 		self.initialized_fields()
-		self.__get_subcontracting_orders()
+		self.__get_subcontract_orders()
 		self.__get_pending_qty_to_receive()
 		self.get_available_materials()
 		self.__remove_changed_rows()
@@ -465,8 +511,10 @@
 		if row.get("batch_no") and row.get("batch_no") not in self.__transferred_items.get(key).get(
 			"batch_no"
 		):
-			link = get_link_to_form("Subcontracting Order", row.subcontracting_order)
-			msg = f'The Batch No {frappe.bold(row.get("batch_no"))} has not supplied against the Subcontracting Order {link}'
+			link = get_link_to_form(
+				self.subcontract_data.order_doctype, row.get(self.subcontract_data.order_field)
+			)
+			msg = f'The Batch No {frappe.bold(row.get("batch_no"))} has not supplied against the {self.subcontract_data.order_doctype} {link}'
 			frappe.throw(_(msg), title=_("Incorrect Batch Consumed"))
 
 	def __validate_serial_no(self, row, key):
@@ -476,16 +524,18 @@
 
 			if incorrect_sn:
 				incorrect_sn = "\n".join(incorrect_sn)
-				link = get_link_to_form("Subcontracting Order", row.subcontracting_order)
-				msg = f"The Serial Nos {incorrect_sn} has not supplied against the Subcontracting Order {link}"
+				link = get_link_to_form(
+					self.subcontract_data.order_doctype, row.get(self.subcontract_data.order_field)
+				)
+				msg = f"The Serial Nos {incorrect_sn} has not supplied against the {self.subcontract_data.order_doctype} {link}"
 				frappe.throw(_(msg), title=_("Incorrect Serial Number Consumed"))
 
 	def __validate_supplied_items(self):
-		if self.doctype != "Subcontracting Receipt":
+		if self.doctype not in ["Purchase Invoice", "Purchase Receipt", "Subcontracting Receipt"]:
 			return
 
 		for row in self.get(self.raw_material_table):
-			key = (row.rm_item_code, row.main_item_code, row.subcontracting_order)
+			key = (row.rm_item_code, row.main_item_code, row.get(self.subcontract_data.order_field))
 			if not self.__transferred_items or not self.__transferred_items.get(key):
 				return
 
@@ -493,6 +543,9 @@
 			self.__validate_serial_no(row, key)
 
 	def set_materials_for_subcontracted_items(self, raw_material_table):
+		if self.doctype == "Purchase Invoice" and not self.update_stock:
+			return
+
 		self.raw_material_table = raw_material_table
 		self.__identify_change_in_item_table()
 		self.__prepare_supplied_items()
@@ -501,16 +554,16 @@
 	def create_raw_materials_supplied(self, raw_material_table="supplied_items"):
 		self.set_materials_for_subcontracted_items(raw_material_table)
 
-		if self.doctype == "Subcontracting Receipt":
+		if self.doctype in ["Subcontracting Receipt", "Purchase Receipt", "Purchase Invoice"]:
 			for item in self.get("items"):
 				item.rm_supp_cost = 0.0
 
-	def __update_consumed_qty_in_sco(self, itemwise_consumed_qty):
+	def __update_consumed_qty_in_subcontract_order(self, itemwise_consumed_qty):
 		fields = ["main_item_code", "rm_item_code", "parent", "supplied_qty", "name"]
-		filters = {"docstatus": 1, "parent": ("in", self.subcontracting_orders)}
+		filters = {"docstatus": 1, "parent": ("in", self.subcontract_orders)}
 
 		for row in frappe.get_all(
-			"Subcontracting Order Supplied Item", fields=fields, filters=filters, order_by="idx"
+			self.subcontract_data.order_supplied_items_field, fields=fields, filters=filters, order_by="idx"
 		):
 			key = (row.rm_item_code, row.main_item_code, row.parent)
 			consumed_qty = itemwise_consumed_qty.get(key, 0)
@@ -520,22 +573,31 @@
 
 			itemwise_consumed_qty[key] -= consumed_qty
 			frappe.db.set_value(
-				"Subcontracting Order Supplied Item", row.name, "consumed_qty", consumed_qty
+				self.subcontract_data.order_supplied_items_field, row.name, "consumed_qty", consumed_qty
 			)
 
-	def set_consumed_qty_in_sco(self):
-		# Update consumed qty back in the subcontracting order
-		self.__get_subcontracting_orders()
-		itemwise_consumed_qty = defaultdict(float)
-		consumed_items, scr_items = self.__update_consumed_materials(
-			"Subcontracting Receipt", return_consumed_items=True
-		)
+	def set_consumed_qty_in_subcontract_order(self):
+		# Update consumed qty back in the subcontract order
+		if self.doctype in ["Subcontracting Order", "Subcontracting Receipt"] or self.get(
+			"is_old_subcontracting_flow"
+		):
+			self.__get_subcontract_orders()
+			itemwise_consumed_qty = defaultdict(float)
+			if self.get("is_old_subcontracting_flow"):
+				doctypes = ["Purchase Receipt", "Purchase Invoice"]
+			else:
+				doctypes = ["Subcontracting Receipt"]
 
-		for row in consumed_items:
-			key = (row.rm_item_code, row.main_item_code, scr_items.get(row.reference_name))
-			itemwise_consumed_qty[key] += row.consumed_qty
+			for doctype in doctypes:
+				consumed_items, receipt_items = self.__update_consumed_materials(
+					doctype, return_consumed_items=True
+				)
 
-		self.__update_consumed_qty_in_sco(itemwise_consumed_qty)
+				for row in consumed_items:
+					key = (row.rm_item_code, row.main_item_code, receipt_items.get(row.reference_name))
+					itemwise_consumed_qty[key] += row.consumed_qty
+
+			self.__update_consumed_qty_in_subcontract_order(itemwise_consumed_qty)
 
 	def update_ordered_and_reserved_qty(self):
 		sco_map = {}
@@ -618,10 +680,30 @@
 			via_landed_cost_voucher=via_landed_cost_voucher,
 		)
 
-	def get_supplied_items_cost(self, item_row_id):
+	def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
 		supplied_items_cost = 0.0
 		for item in self.get("supplied_items"):
 			if item.reference_name == item_row_id:
+				if (
+					self.get("is_old_subcontracting_flow")
+					and reset_outgoing_rate
+					and frappe.get_cached_value("Item", item.rm_item_code, "is_stock_item")
+				):
+					rate = get_incoming_rate(
+						{
+							"item_code": item.rm_item_code,
+							"warehouse": self.supplier_warehouse,
+							"posting_date": self.posting_date,
+							"posting_time": self.posting_time,
+							"qty": -1 * item.consumed_qty,
+							"serial_no": item.serial_no,
+							"batch_no": item.batch_no,
+						}
+					)
+
+					if rate > 0:
+						item.rate = rate
+
 				item.amount = flt(flt(item.consumed_qty) * flt(item.rate), item.precision("amount"))
 				supplied_items_cost += item.amount
 
@@ -631,13 +713,25 @@
 		if self.doctype == "Subcontracting Order":
 			self.update_status()
 		elif self.doctype == "Subcontracting Receipt":
-			self.__get_subcontracting_orders
+			self.__get_subcontract_orders
 
-			if self.subcontracting_orders:
-				for sco in set(self.subcontracting_orders):
+			if self.subcontract_orders:
+				for sco in set(self.subcontract_orders):
 					sco_doc = frappe.get_doc("Subcontracting Order", sco)
 					sco_doc.update_status()
 
+	@frappe.whitelist()
+	def get_current_stock(self):
+		if self.doctype in ["Purchase Receipt", "Subcontracting Receipt"]:
+			for item in self.get("supplied_items"):
+				if self.supplier_warehouse:
+					actual_qty = frappe.db.get_value(
+						"Bin",
+						{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
+						"actual_qty",
+					)
+					item.current_stock = flt(actual_qty) or 0
+
 	@property
 	def sub_contracted_items(self):
 		if not hasattr(self, "_sub_contracted_items"):
@@ -650,3 +744,159 @@
 				self._sub_contracted_items = [item.name for item in items]
 
 		return self._sub_contracted_items
+
+
+def get_item_details(items):
+	item = frappe.qb.DocType("Item")
+	item_list = (
+		frappe.qb.from_(item)
+		.select(item.item_code, item.description, item.allow_alternative_item)
+		.where(item.name.isin(items))
+		.run(as_dict=True)
+	)
+
+	item_details = {}
+	for item in item_list:
+		item_details[item.item_code] = item
+
+	return item_details
+
+
+@frappe.whitelist()
+def make_rm_stock_entry(subcontract_order, rm_items, order_doctype="Subcontracting Order"):
+	rm_items_list = rm_items
+
+	if isinstance(rm_items, str):
+		rm_items_list = json.loads(rm_items)
+	elif not rm_items:
+		frappe.throw(_("No Items available for transfer"))
+
+	if rm_items_list:
+		fg_items = list(set(item["item_code"] for item in rm_items_list))
+	else:
+		frappe.throw(_("No Items selected for transfer"))
+
+	if subcontract_order:
+		subcontract_order = frappe.get_doc(order_doctype, subcontract_order)
+
+	if fg_items:
+		items = tuple(set(item["rm_item_code"] for item in rm_items_list))
+		item_wh = get_item_details(items)
+
+		stock_entry = frappe.new_doc("Stock Entry")
+		stock_entry.purpose = "Send to Subcontractor"
+		if order_doctype == "Purchase Order":
+			stock_entry.purchase_order = subcontract_order.name
+		else:
+			stock_entry.subcontracting_order = subcontract_order.name
+		stock_entry.supplier = subcontract_order.supplier
+		stock_entry.supplier_name = subcontract_order.supplier_name
+		stock_entry.supplier_address = subcontract_order.supplier_address
+		stock_entry.address_display = subcontract_order.address_display
+		stock_entry.company = subcontract_order.company
+		stock_entry.to_warehouse = subcontract_order.supplier_warehouse
+		stock_entry.set_stock_entry_type()
+
+		if order_doctype == "Purchase Order":
+			rm_detail_field = "po_detail"
+		else:
+			rm_detail_field = "sco_rm_detail"
+
+		for item_code in fg_items:
+			for rm_item_data in rm_items_list:
+				if rm_item_data["item_code"] == item_code:
+					rm_item_code = rm_item_data["rm_item_code"]
+					items_dict = {
+						rm_item_code: {
+							rm_detail_field: rm_item_data.get("name"),
+							"item_name": rm_item_data["item_name"],
+							"description": item_wh.get(rm_item_code, {}).get("description", ""),
+							"qty": rm_item_data["qty"],
+							"from_warehouse": rm_item_data["warehouse"],
+							"stock_uom": rm_item_data["stock_uom"],
+							"serial_no": rm_item_data.get("serial_no"),
+							"batch_no": rm_item_data.get("batch_no"),
+							"main_item_code": rm_item_data["item_code"],
+							"allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"),
+						}
+					}
+					stock_entry.add_to_stock_entry_detail(items_dict)
+		return stock_entry.as_dict()
+	else:
+		frappe.throw(_("No Items selected for transfer"))
+	return subcontract_order.name
+
+
+def add_items_in_ste(
+	ste_doc, row, qty, rm_details, rm_detail_field="sco_rm_detail", batch_no=None
+):
+	item = ste_doc.append("items", row.item_details)
+
+	rm_detail = list(set(row.get(f"{rm_detail_field}s")).intersection(rm_details))
+	item.update(
+		{
+			"qty": qty,
+			"batch_no": batch_no,
+			"basic_rate": row.item_details["rate"],
+			rm_detail_field: rm_detail[0] if rm_detail else "",
+			"s_warehouse": row.item_details["t_warehouse"],
+			"t_warehouse": row.item_details["s_warehouse"],
+			"item_code": row.item_details["rm_item_code"],
+			"subcontracted_item": row.item_details["main_item_code"],
+			"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
+		}
+	)
+
+
+def make_return_stock_entry_for_subcontract(
+	available_materials, order_doc, rm_details, order_doctype="Subcontracting Order"
+):
+	ste_doc = frappe.new_doc("Stock Entry")
+	ste_doc.purpose = "Material Transfer"
+
+	if order_doctype == "Purchase Order":
+		ste_doc.purchase_order = order_doc.name
+		rm_detail_field = "po_detail"
+	else:
+		ste_doc.subcontracting_order = order_doc.name
+		rm_detail_field = "sco_rm_detail"
+	ste_doc.company = order_doc.company
+	ste_doc.is_return = 1
+
+	for key, value in available_materials.items():
+		if not value.qty:
+			continue
+
+		if value.batch_no:
+			for batch_no, qty in value.batch_no.items():
+				if qty > 0:
+					add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field, batch_no)
+		else:
+			add_items_in_ste(ste_doc, value, value.qty, rm_details, rm_detail_field)
+
+	ste_doc.set_stock_entry_type()
+	ste_doc.calculate_rate_and_amount()
+
+	return ste_doc
+
+
+@frappe.whitelist()
+def get_materials_from_supplier(
+	subcontract_order, rm_details, order_doctype="Subcontracting Order"
+):
+	if isinstance(rm_details, str):
+		rm_details = json.loads(rm_details)
+
+	doc = frappe.get_cached_doc(order_doctype, subcontract_order)
+	doc.initialized_fields()
+	doc.subcontract_orders = [doc.name]
+	doc.get_available_materials()
+
+	if not doc.available_materials:
+		frappe.throw(
+			_("Materials are already received against the {0} {1}").format(order_doctype, subcontract_order)
+		)
+
+	return make_return_stock_entry_for_subcontract(
+		doc.available_materials, doc, rm_details, order_doctype
+	)
diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py
index 4ef3d64..4fab805 100644
--- a/erpnext/controllers/tests/test_subcontracting_controller.py
+++ b/erpnext/controllers/tests/test_subcontracting_controller.py
@@ -9,13 +9,15 @@
 from frappe.utils import cint
 
 from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.controllers.subcontracting_controller import (
+	get_materials_from_supplier,
+	make_rm_stock_entry,
+)
 from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
-	get_materials_from_supplier,
-	make_rm_stock_entry,
 	make_subcontracting_receipt,
 )
 
diff --git a/erpnext/patches/v13_0/add_bin_unique_constraint.py b/erpnext/patches/v13_0/add_bin_unique_constraint.py
index 38a8500..7ad2bec 100644
--- a/erpnext/patches/v13_0/add_bin_unique_constraint.py
+++ b/erpnext/patches/v13_0/add_bin_unique_constraint.py
@@ -64,4 +64,8 @@
 		bin.update(qty_dict)
 		bin.update_reserved_qty_for_production()
 		bin.update_reserved_qty_for_sub_contracting()
+		if frappe.db.count(
+			"Purchase Order", {"status": ["!=", "Completed"], "is_old_subcontracting_flow": 1}
+		):
+			bin.update_reserved_qty_for_sub_contracting(subcontract_doctype="Purchase Order")
 		bin.db_update()
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 91e0771..09779d8 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -83,9 +83,17 @@
 
 		this.frm.set_query("item_code", "items", function() {
 			if (me.frm.doc.is_subcontracted) {
+				var filters = {'supplier': me.frm.doc.supplier};
+				if (me.frm.doc.is_old_subcontracting_flow) {
+					filters["is_sub_contracted_item"] = 1;
+				}
+				else {
+					filters["is_stock_item"] = 0;
+				}
+
 				return{
 					query: "erpnext.controllers.queries.item_query",
-					filters:{ 'supplier': me.frm.doc.supplier, 'is_stock_item': 0 }
+					filters: filters
 				}
 			}
 			else {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index de93c82..d86ff1c 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -471,7 +471,8 @@
 							cost_center: item.cost_center,
 							tax_category: me.frm.doc.tax_category,
 							item_tax_template: item.item_tax_template,
-							child_docname: item.name
+							child_docname: item.name,
+							is_old_subcontracting_flow: me.frm.doc.is_old_subcontracting_flow,
 						}
 					},
 
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 01710f1..68b3e2e 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -486,7 +486,11 @@
 				filters = {"is_sales_item": 1};
 			} else if (frm.doc.doctype == 'Purchase Order') {
 				if (frm.doc.is_subcontracted) {
-					filters = {"is_sub_contracted_item": 1};
+					if (frm.doc.is_old_subcontracting_flow) {
+						filters = {"is_sub_contracted_item": 1};
+					} else {
+						filters = {"is_stock_item": 0};
+					}
 				} else {
 					filters = {"is_purchase_item": 1};
 				}
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 448b049..548df31 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -40,23 +40,37 @@
 		self.db_set("reserved_qty_for_production", flt(self.reserved_qty_for_production))
 		self.db_set("projected_qty", self.projected_qty)
 
-	def update_reserved_qty_for_sub_contracting(self):
+	def update_reserved_qty_for_sub_contracting(self, subcontract_doctype="Subcontracting Order"):
 		# reserved qty
 
-		sco = frappe.qb.DocType("Subcontracting Order")
-		supplied_item = frappe.qb.DocType("Subcontracting Order Supplied Item")
+		subcontract_order = frappe.qb.DocType(subcontract_doctype)
+		supplied_item = frappe.qb.DocType(
+			"Purchase Order Item Supplied"
+			if subcontract_doctype == "Purchase Order"
+			else "Subcontracting Order Supplied Item"
+		)
+
+		conditions = (
+			(supplied_item.rm_item_code == self.item_code)
+			& (subcontract_order.name == supplied_item.parent)
+			& (subcontract_order.per_received < 100)
+			& (supplied_item.reserve_warehouse == self.warehouse)
+			& (
+				(
+					(subcontract_order.is_old_subcontracting_flow == 1)
+					& (subcontract_order.status != "Closed")
+					& (subcontract_order.docstatus == 1)
+				)
+				if subcontract_doctype == "Purchase Order"
+				else (subcontract_order.docstatus == 1)
+			)
+		)
 
 		reserved_qty_for_sub_contract = (
-			frappe.qb.from_(sco)
+			frappe.qb.from_(subcontract_order)
 			.from_(supplied_item)
 			.select(Sum(Coalesce(supplied_item.required_qty, 0)))
-			.where(
-				(supplied_item.rm_item_code == self.item_code)
-				& (sco.name == supplied_item.parent)
-				& (sco.docstatus == 1)
-				& (sco.per_received < 100)
-				& (supplied_item.reserve_warehouse == self.warehouse)
-			)
+			.where(conditions)
 		).run()[0][0] or 0.0
 
 		se = frappe.qb.DocType("Stock Entry")
@@ -69,23 +83,34 @@
 		else:
 			qty_field = se_item.transfer_qty
 
+		conditions = (
+			(se.docstatus == 1)
+			& (se.purpose == "Send to Subcontractor")
+			& ((se_item.item_code == self.item_code) | (se_item.original_item == self.item_code))
+			& (se.name == se_item.parent)
+			& (subcontract_order.docstatus == 1)
+			& (subcontract_order.per_received < 100)
+			& (
+				(
+					(Coalesce(se.purchase_order, "") != "")
+					& (subcontract_order.name == se.purchase_order)
+					& (subcontract_order.is_old_subcontracting_flow == 1)
+					& (subcontract_order.status != "Closed")
+				)
+				if subcontract_doctype == "Purchase Order"
+				else (
+					(Coalesce(se.subcontracting_order, "") != "")
+					& (subcontract_order.name == se.subcontracting_order)
+				)
+			)
+		)
+
 		materials_transferred = (
 			frappe.qb.from_(se)
 			.from_(se_item)
-			.from_(sco)
-			.select(
-				Sum(Case().when(se.is_return == 1, se_item.transfer_qty * -1).else_(se_item.transfer_qty))
-			)
-			.where(
-				(se.docstatus == 1)
-				& (se.purpose == "Send to Subcontractor")
-				& (Coalesce(se.subcontracting_order, "") != "")
-				& ((se_item.item_code == self.item_code) | (se_item.original_item == self.item_code))
-				& (se.name == se_item.parent)
-				& (sco.name == se.subcontracting_order)
-				& (sco.docstatus == 1)
-				& (sco.per_received < 100)
-			)
+			.from_(subcontract_order)
+			.select(Sum(qty_field))
+			.where(conditions)
 		).run()[0][0] or 0.0
 
 		if reserved_qty_for_sub_contract > materials_transferred:
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
index 49530b4..1996418 100644
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
@@ -5,6 +5,7 @@
 from frappe.tests.utils import FrappeTestCase
 from frappe.utils import flt
 
+from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
 from erpnext.controllers.tests.test_subcontracting_controller import (
 	get_subcontracting_order,
 	make_service_item,
@@ -21,7 +22,6 @@
 	create_stock_reconciliation,
 )
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
-	make_rm_stock_entry,
 	make_subcontracting_receipt,
 )
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 74db616..e6fcb78 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -296,6 +296,10 @@
 frappe.provide("erpnext.buying");
 
 frappe.ui.form.on("Purchase Receipt", "is_subcontracted", function(frm) {
+	if (frm.doc.is_old_subcontracting_flow) {
+		erpnext.buying.get_default_bom(frm);
+	}
+
 	frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted);
 });
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index ff4e0a1..cef9ddd 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -123,6 +123,7 @@
 		if getdate(self.posting_date) > getdate(nowdate()):
 			throw(_("Posting Date cannot be future date"))
 
+		self.get_current_stock()
 		self.reset_default_field_value("set_warehouse", "items", "warehouse")
 		self.reset_default_field_value("rejected_warehouse", "items", "rejected_warehouse")
 		self.reset_default_field_value("set_from_warehouse", "items", "from_warehouse")
@@ -234,6 +235,7 @@
 
 		self.make_gl_entries()
 		self.repost_future_sle_and_gle()
+		self.set_consumed_qty_in_subcontract_order()
 
 	def check_next_docstatus(self):
 		submit_rv = frappe.db.sql(
@@ -269,6 +271,7 @@
 		self.repost_future_sle_and_gle()
 		self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
 		self.delete_auto_created_batches()
+		self.set_consumed_qty_in_subcontract_order()
 
 	def get_gl_entries(self, warehouse_account=None):
 		from erpnext.accounts.general_ledger import process_gl_map
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 625a303..f0de04b 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -642,13 +642,15 @@
    "print_hide": 1
   },
   {
+   "depends_on": "eval:parent.is_old_subcontracting_flow",
    "fieldname": "bom",
    "fieldtype": "Link",
    "label": "BOM",
    "no_copy": 1,
    "options": "BOM",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "read_only_depends_on": "eval:!parent.is_old_subcontracting_flow"
   },
   {
    "default": "0",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index a838236..1c514a9 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -615,8 +615,15 @@
 		if (frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(frm, frm.doc.purpose);
 	},
 
+	purchase_order: (frm) => {
+		if (frm.doc.purchase_order) {
+			frm.set_value("subcontracting_order", "");
+		}
+	},
+
 	subcontracting_order: (frm) => {
 		if (frm.doc.subcontracting_order) {
+			frm.set_value("purchase_order", "");
 			erpnext.utils.map_current_doc({
 				method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontracting_order',
 				source_name: frm.doc.subcontracting_order,
@@ -624,9 +631,6 @@
 				freeze: true,
 			});
 		}
-		else {
-			frm.set_value("items", []);
-		}
 	},
 });
 
@@ -790,6 +794,16 @@
 			return erpnext.queries.item({is_stock_item: 1});
 		};
 
+		this.frm.set_query("purchase_order", function() {
+			return {
+				"filters": {
+					"docstatus": 1,
+					"is_old_subcontracting_flow": 1,
+					"company": me.frm.doc.company
+				}
+			};
+		});
+
 		this.frm.set_query("subcontracting_order", function() {
 			return {
 				"filters": {
@@ -814,7 +828,12 @@
 			}
 		}
 
-		this.frm.add_fetch("subcontracting_order", "supplier", "supplier");
+		if (me.frm.doc.purchase_order) {
+			this.frm.add_fetch("purchase_order", "supplier", "supplier");
+		}
+		else {
+			this.frm.add_fetch("subcontracting_order", "supplier", "supplier");
+		}
 
 		frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier' }
 		this.frm.set_query("supplier_address", erpnext.queries.address_query)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index 86f1b6a..abe98e2 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -148,11 +148,11 @@
    "search_index": 1
   },
   {
+    "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"",
     "fieldname": "purchase_order",
     "fieldtype": "Link",
     "label": "Purchase Order",
-    "options": "Purchase Order",
-    "read_only": 1
+    "options": "Purchase Order"
   },
   {
     "depends_on": "eval:doc.purpose==\"Send to Subcontractor\"",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 6599edd..d3f15e7 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -62,6 +62,27 @@
 
 
 class StockEntry(StockController):
+	def __init__(self, *args, **kwargs):
+		super(StockEntry, self).__init__(*args, **kwargs)
+		if self.purchase_order:
+			self.subcontract_data = frappe._dict(
+				{
+					"order_doctype": "Purchase Order",
+					"order_field": "purchase_order",
+					"rm_detail_field": "po_detail",
+					"order_supplied_items_field": "Purchase Order Item Supplied",
+				}
+			)
+		else:
+			self.subcontract_data = frappe._dict(
+				{
+					"order_doctype": "Subcontracting Order",
+					"order_field": "subcontracting_order",
+					"rm_detail_field": "sco_rm_detail",
+					"order_supplied_items_field": "Subcontracting Order Supplied Item",
+				}
+			)
+
 	def get_feed(self):
 		return self.stock_entry_type
 
@@ -134,8 +155,8 @@
 
 		update_serial_nos_after_submit(self, "items")
 		self.update_work_order()
-		self.validate_subcontracting_order()
-		self.update_subcontracting_order_supplied_items()
+		self.validate_subcontract_order()
+		self.update_subcontract_order_supplied_items()
 		self.update_subcontracting_order_status()
 
 		self.make_gl_entries()
@@ -155,7 +176,7 @@
 			self.set_material_request_transfer_status("Completed")
 
 	def on_cancel(self):
-		self.update_subcontracting_order_supplied_items()
+		self.update_subcontract_order_supplied_items()
 		self.update_subcontracting_order_status()
 
 		if self.work_order and self.purpose == "Material Consumption for Manufacture":
@@ -809,8 +830,8 @@
 
 					serial_nos.append(sn)
 
-	def validate_subcontracting_order(self):
-		"""Throw exception if more raw material is transferred against Subcontracting Order than in
+	def validate_subcontract_order(self):
+		"""Throw exception if more raw material is transferred against Subcontract Order than in
 		the raw materials supplied table"""
 		backflush_raw_materials_based_on = frappe.db.get_single_value(
 			"Buying Settings", "backflush_raw_materials_of_subcontract_based_on"
@@ -818,28 +839,29 @@
 
 		qty_allowance = flt(frappe.db.get_single_value("Buying Settings", "over_transfer_allowance"))
 
-		if not (self.purpose == "Send to Subcontractor" and self.subcontracting_order):
+		if not (self.purpose == "Send to Subcontractor" and self.get(self.subcontract_data.order_field)):
 			return
 
 		if backflush_raw_materials_based_on == "BOM":
-			subcontracting_order = frappe.get_doc("Subcontracting Order", self.subcontracting_order)
+			subcontract_order = frappe.get_doc(
+				self.subcontract_data.order_doctype, self.get(self.subcontract_data.order_field)
+			)
 			for se_item in self.items:
 				item_code = se_item.original_item or se_item.item_code
 				precision = cint(frappe.db.get_default("float_precision")) or 3
 				required_qty = sum(
-					[
-						flt(d.required_qty)
-						for d in subcontracting_order.supplied_items
-						if d.rm_item_code == item_code
-					]
+					[flt(d.required_qty) for d in subcontract_order.supplied_items if d.rm_item_code == item_code]
 				)
 
 				total_allowed = required_qty + (required_qty * (qty_allowance / 100))
 
 				if not required_qty:
 					bom_no = frappe.db.get_value(
-						"Subcontracting Order Item",
-						{"parent": self.subcontracting_order, "item_code": se_item.subcontracted_item},
+						f"{self.subcontract_data.order_doctype} Item",
+						{
+							"parent": self.get(self.subcontract_data.order_field),
+							"item_code": se_item.subcontracted_item,
+						},
 						"bom",
 					)
 
@@ -851,7 +873,7 @@
 						required_qty = sum(
 							[
 								flt(d.required_qty)
-								for d in subcontracting_order.supplied_items
+								for d in subcontract_order.supplied_items
 								if d.rm_item_code == original_item_code
 							]
 						)
@@ -860,43 +882,57 @@
 
 				if not required_qty:
 					frappe.throw(
-						_("Item {0} not found in 'Raw Materials Supplied' table in Subcontracting Order {1}").format(
-							se_item.item_code, self.subcontracting_order
+						_("Item {0} not found in 'Raw Materials Supplied' table in {1} {2}").format(
+							se_item.item_code,
+							self.subcontract_data.order_doctype,
+							self.get(self.subcontract_data.order_field),
 						)
 					)
 
 				parent = frappe.qb.DocType("Stock Entry")
 				child = frappe.qb.DocType("Stock Entry Detail")
 
+				conditions = (
+					(parent.docstatus == 1)
+					& (child.item_code == se_item.item_code)
+					& (
+						(parent.purchase_order == self.purchase_order)
+						if self.subcontract_data.order_doctype == "Purchase Order"
+						else (parent.subcontracting_order == self.subcontracting_order)
+					)
+				)
+
 				total_supplied = (
 					frappe.qb.from_(parent)
 					.inner_join(child)
 					.on(parent.name == child.parent)
 					.select(Sum(child.transfer_qty))
-					.where(parent.docstatus == 1)
-					.where(parent.subcontracting_order == self.subcontracting_order)
-					.where(child.item_code == se_item.item_code)
+					.where(conditions)
 				).run()[0][0]
 
 				if flt(total_supplied, precision) > flt(total_allowed, precision):
 					frappe.throw(
-						_(
-							"Row {0}# Item {1} cannot be transferred more than {2} against Subcontracting Order {3}"
-						).format(
-							se_item.idx, se_item.item_code, total_allowed, self.subcontracting_order
+						_("Row {0}# Item {1} cannot be transferred more than {2} against {3} {4}").format(
+							se_item.idx,
+							se_item.item_code,
+							total_allowed,
+							self.subcontract_data.order_doctype,
+							self.get(self.subcontract_data.order_field),
 						)
 					)
-				elif not se_item.sco_rm_detail:
+				elif not se_item.get(self.subcontract_data.rm_detail_field):
 					filters = {
-						"parent": self.subcontracting_order,
+						"parent": self.get(self.subcontract_data.order_field),
 						"docstatus": 1,
 						"rm_item_code": se_item.item_code,
 						"main_item_code": se_item.subcontracted_item,
 					}
 
-					sco_rm_detail = frappe.db.get_value("Subcontracting Order Supplied Item", filters, "name")
-					if sco_rm_detail:
-						se_item.db_set("sco_rm_detail", sco_rm_detail)
+					order_rm_detail = frappe.db.get_value(
+						self.subcontract_data.order_supplied_items_field, filters, "name"
+					)
+					if order_rm_detail:
+						se_item.db_set(self.subcontract_data.rm_detail_field, order_rm_detail)
 		elif backflush_raw_materials_based_on == "Material Transferred for Subcontract":
 			for row in self.items:
 				if not row.subcontracted_item:
@@ -905,17 +941,19 @@
 							row.idx, frappe.bold(row.item_code)
 						)
 					)
-				elif not row.sco_rm_detail:
+				elif not row.get(self.subcontract_data.rm_detail_field):
 					filters = {
-						"parent": self.subcontracting_order,
+						"parent": self.get(self.subcontract_data.order_field),
 						"docstatus": 1,
 						"rm_item_code": row.item_code,
 						"main_item_code": row.subcontracted_item,
 					}
 
-					sco_rm_detail = frappe.db.get_value("Subcontracting Order Supplied Item", filters, "name")
-					if sco_rm_detail:
-						row.db_set("sco_rm_detail", sco_rm_detail)
+					order_rm_detail = frappe.db.get_value(
+						self.subcontract_data.order_supplied_items_field, filters, "name"
+					)
+					if order_rm_detail:
+						row.db_set(self.subcontract_data.rm_detail_field, order_rm_detail)
 
 	def validate_bom(self):
 		for d in self.get("items"):
@@ -1263,12 +1301,12 @@
 
 		if (
 			self.purpose == "Send to Subcontractor"
-			and self.get("subcontracting_order")
+			and self.get(self.subcontract_data.order_field)
 			and args.get("item_code")
 		):
 			subcontract_items = frappe.get_all(
-				"Subcontracting Order Supplied Item",
-				{"parent": self.subcontracting_order, "rm_item_code": args.get("item_code")},
+				self.subcontract_data.order_supplied_items_field,
+				{"parent": self.get(self.subcontract_data.order_field), "rm_item_code": args.get("item_code")},
 				"main_item_code",
 			)
 
@@ -1362,18 +1400,18 @@
 
 					item_dict = self.get_bom_raw_materials(self.fg_completed_qty)
 
-					# Get SCO Supplied Items Details
-					if self.subcontracting_order and self.purpose == "Send to Subcontractor":
-						# Get SCO Supplied Items Details
-						parent = frappe.qb.DocType("Subcontracting Order")
-						child = frappe.qb.DocType("Subcontracting Order Supplied Item")
+					# Get Subcontract Order Supplied Items Details
+					if self.get(self.subcontract_data.order_field) and self.purpose == "Send to Subcontractor":
+						# Get Subcontract Order Supplied Items Details
+						parent = frappe.qb.DocType(self.subcontract_data.order_doctype)
+						child = frappe.qb.DocType(self.subcontract_data.order_supplied_items_field)
 
 						item_wh = (
 							frappe.qb.from_(parent)
 							.inner_join(child)
 							.on(parent.name == child.parent)
 							.select(child.rm_item_code, child.reserve_warehouse)
-							.where(parent.name == self.subcontracting_order)
+							.where(parent.name == self.get(self.subcontract_data.order_field))
 						).run(as_list=True)
 
 						item_wh = frappe._dict(item_wh)
@@ -1381,8 +1419,8 @@
 					for item in item_dict.values():
 						if self.pro_doc and cint(self.pro_doc.from_wip_warehouse):
 							item["from_warehouse"] = self.pro_doc.wip_warehouse
-						# Get Reserve Warehouse from SCO
-						if self.subcontracting_order and self.purpose == "Send to Subcontractor":
+						# Get Reserve Warehouse from Subcontract Order
+						if self.get(self.subcontract_data.order_field) and self.purpose == "Send to Subcontractor":
 							item["from_warehouse"] = item_wh.get(item.item_code)
 						item["to_warehouse"] = self.to_warehouse if self.purpose == "Send to Subcontractor" else ""
 
@@ -1519,7 +1557,9 @@
 			fetch_qty_in_stock_uom=False,
 		)
 
-		used_alternative_items = get_used_alternative_items(work_order=self.work_order)
+		used_alternative_items = get_used_alternative_items(
+			subcontract_order_field=self.subcontract_data.order_field, work_order=self.work_order
+		)
 		for item in item_dict.values():
 			# if source warehouse presents in BOM set from_warehouse as bom source_warehouse
 			if item["allow_alternative_item"]:
@@ -1925,7 +1965,7 @@
 			se_child.is_process_loss = item_row.get("is_process_loss", 0)
 
 			for field in [
-				"sco_rm_detail",
+				self.subcontract_data.rm_detail_field,
 				"original_item",
 				"expense_account",
 				"description",
@@ -1999,33 +2039,37 @@
 					else:
 						frappe.throw(_("Batch {0} of Item {1} is disabled.").format(item.batch_no, item.item_code))
 
-	def update_subcontracting_order_supplied_items(self):
-		if self.subcontracting_order and (
-			self.purpose in ["Send to Subcontractor", "Material Transfer"]
+	def update_subcontract_order_supplied_items(self):
+		if self.get(self.subcontract_data.order_field) and (
+			self.purpose in ["Send to Subcontractor", "Material Transfer"] or self.is_return
 		):
 
-			# Get SCO Supplied Items Details
-			sco_supplied_items = frappe.db.get_all(
-				"Subcontracting Order Supplied Item",
-				filters={"parent": self.subcontracting_order},
+			# Get Subcontract Order Supplied Items Details
+			order_supplied_items = frappe.db.get_all(
+				self.subcontract_data.order_supplied_items_field,
+				filters={"parent": self.get(self.subcontract_data.order_field)},
 				fields=["name", "rm_item_code", "reserve_warehouse"],
 			)
 
-			# Get Items Supplied in Stock Entries against SCO
-			supplied_items = get_supplied_items(self.subcontracting_order)
+			# Get Items Supplied in Stock Entries against Subcontract Order
+			supplied_items = get_supplied_items(
+				self.get(self.subcontract_data.order_field),
+				self.subcontract_data.rm_detail_field,
+				self.subcontract_data.order_field,
+			)
 
-			for row in sco_supplied_items:
+			for row in order_supplied_items:
 				key, item = row.name, {}
 				if not supplied_items.get(key):
-					# no stock transferred against SCO Supplied Items row
+					# no stock transferred against Subcontract Order Supplied Items row
 					item = {"supplied_qty": 0, "returned_qty": 0, "total_supplied_qty": 0}
 				else:
 					item = supplied_items.get(key)
 
-				frappe.db.set_value("Subcontracting Order Supplied Item", row.name, item)
+				frappe.db.set_value(self.subcontract_data.order_supplied_items_field, row.name, item)
 
 			# RM Item-Reserve Warehouse Dict
-			item_wh = {x.get("rm_item_code"): x.get("reserve_warehouse") for x in sco_supplied_items}
+			item_wh = {x.get("rm_item_code"): x.get("reserve_warehouse") for x in order_supplied_items}
 
 			for d in self.get("items"):
 				# Update reserved sub contracted quantity in bin based on Supplied Item Details and
@@ -2382,13 +2426,13 @@
 	return operating_cost_per_unit
 
 
-def get_used_alternative_items(subcontracting_order=None, work_order=None):
+def get_used_alternative_items(
+	subcontract_order=None, subcontract_order_field="subcontracting_order", work_order=None
+):
 	cond = ""
 
-	if subcontracting_order:
-		cond = "and ste.purpose = 'Send to Subcontractor' and ste.subcontracting_order = '{0}'".format(
-			subcontracting_order
-		)
+	if subcontract_order:
+		cond = f"and ste.purpose = 'Send to Subcontractor' and ste.{subcontract_order_field} = '{subcontract_order}'"
 	elif work_order:
 		cond = "and ste.purpose = 'Material Transfer for Manufacture' and ste.work_order = '{0}'".format(
 			work_order
@@ -2524,25 +2568,27 @@
 	return sample_quantity
 
 
-def get_supplied_items(subcontracting_order):
+def get_supplied_items(
+	subcontract_order, rm_detail_field="sco_rm_detail", subcontract_order_field="subcontracting_order"
+):
 	fields = [
 		"`tabStock Entry Detail`.`transfer_qty`",
 		"`tabStock Entry`.`is_return`",
-		"`tabStock Entry Detail`.`sco_rm_detail`",
+		f"`tabStock Entry Detail`.`{rm_detail_field}`",
 		"`tabStock Entry Detail`.`item_code`",
 	]
 
 	filters = [
 		["Stock Entry", "docstatus", "=", 1],
-		["Stock Entry", "subcontracting_order", "=", subcontracting_order],
+		["Stock Entry", subcontract_order_field, "=", subcontract_order],
 	]
 
 	supplied_item_details = {}
 	for row in frappe.get_all("Stock Entry", fields=fields, filters=filters):
-		if not row.sco_rm_detail:
+		if not row.get(rm_detail_field):
 			continue
 
-		key = row.sco_rm_detail
+		key = row.get(rm_detail_field)
 		if key not in supplied_item_details:
 			supplied_item_details.setdefault(
 				key, frappe._dict({"supplied_qty": 0, "returned_qty": 0, "total_supplied_qty": 0})
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index e701c14..c23548c 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -240,8 +240,13 @@
 		throw(_("Item {0} is a template, please select one of its variants").format(item.name))
 
 	elif args.transaction_type == "buying" and args.doctype != "Material Request":
-		if args.get("is_subcontracted") and item.is_stock_item:
-			throw(_("Item {0} must be a Non-Stock Item").format(item.name))
+		if args.get("is_subcontracted"):
+			if args.get("is_old_subcontracting_flow"):
+				if item.is_sub_contracted_item != 1:
+					throw(_("Item {0} must be a Sub-contracted Item").format(item.name))
+			else:
+				if item.is_stock_item:
+					throw(_("Item {0} must be a Non-Stock Item").format(item.name))
 
 
 def get_basic_details(args, item, overwrite_warehouse=True):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 9293dde..8d82c73 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -738,6 +738,13 @@
 				"Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate
 			)
 
+		# Recalculate subcontracted item's rate in case of subcontracted purchase receipt/invoice
+		if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_subcontracted"):
+			doc = frappe.get_doc(sle.voucher_type, sle.voucher_no)
+			doc.update_valuation_rate(reset_outgoing_rate=False)
+			for d in doc.items + doc.supplied_items:
+				d.db_update()
+
 	def update_rate_on_subcontracting_receipt(self, sle, outgoing_rate):
 		if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
 			frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "rate", outgoing_rate)
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
index c9e4577..dbd337a 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
@@ -24,7 +24,8 @@
 			return {
 				filters: {
 					docstatus: 1,
-					is_subcontracted: 1
+					is_subcontracted: 1,
+					is_old_subcontracting_flow: 0
 				}
 			};
 		});
@@ -115,10 +116,14 @@
 		if (sco_rm_details && sco_rm_details.length) {
 			frm.add_custom_button(__('Return of Components'), () => {
 				frm.call({
-					method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.get_materials_from_supplier',
+					method: 'erpnext.controllers.subcontracting_controller.get_materials_from_supplier',
 					freeze: true,
 					freeze_message: __('Creating Stock Entry'),
-					args: { subcontracting_order: frm.doc.name, sco_rm_details: sco_rm_details },
+					args: {
+						subcontract_order: frm.doc.name,
+						rm_details: sco_rm_details,
+						order_doctype: cur_frm.doc.doctype
+					},
 					callback: function (r) {
 						if (r && r.message) {
 							const doc = frappe.model.sync(r.message);
@@ -306,10 +311,11 @@
 
 	make_rm_stock_entry(rm_items) {
 		frappe.call({
-			method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_rm_stock_entry',
+			method: 'erpnext.controllers.subcontracting_controller.make_rm_stock_entry',
 			args: {
-				subcontracting_order: cur_frm.doc.name,
-				rm_items: rm_items
+				subcontract_order: cur_frm.doc.name,
+				rm_items: rm_items,
+				order_doctype: cur_frm.doc.doctype
 			},
 			callback: (r) => {
 				var doclist = frappe.model.sync(r.message);
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index d12c9e8..3655910 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -1,8 +1,6 @@
 # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-import json
-
 import frappe
 from frappe import _
 from frappe.model.mapper import get_mapped_doc
@@ -42,6 +40,9 @@
 			if not po.is_subcontracted:
 				frappe.throw(_("Please select a valid Purchase Order that is configured for Subcontracting."))
 
+			if po.is_old_subcontracting_flow:
+				frappe.throw(_("Please select a valid Purchase Order that has Service Items."))
+
 			if po.docstatus != 1:
 				msg = f"Please submit Purchase Order {po.name} before proceeding."
 				frappe.throw(_(msg))
@@ -227,143 +228,6 @@
 	return target_doc
 
 
-def get_item_details(items):
-	item = frappe.qb.DocType("Item")
-	item_list = (
-		frappe.qb.from_(item)
-		.select(item.item_code, item.description, item.allow_alternative_item)
-		.where(item.name.isin(items))
-		.run(as_dict=True)
-	)
-
-	item_details = {}
-	for item in item_list:
-		item_details[item.item_code] = item
-
-	return item_details
-
-
-@frappe.whitelist()
-def make_rm_stock_entry(subcontracting_order, rm_items):
-	rm_items_list = rm_items
-
-	if isinstance(rm_items, str):
-		rm_items_list = json.loads(rm_items)
-	elif not rm_items:
-		frappe.throw(_("No Items available for transfer"))
-
-	if rm_items_list:
-		fg_items = list(set(item["item_code"] for item in rm_items_list))
-	else:
-		frappe.throw(_("No Items selected for transfer"))
-
-	if subcontracting_order:
-		subcontracting_order = frappe.get_doc("Subcontracting Order", subcontracting_order)
-
-	if fg_items:
-		items = tuple(set(item["rm_item_code"] for item in rm_items_list))
-		item_wh = get_item_details(items)
-
-		stock_entry = frappe.new_doc("Stock Entry")
-		stock_entry.purpose = "Send to Subcontractor"
-		stock_entry.subcontracting_order = subcontracting_order.name
-		stock_entry.supplier = subcontracting_order.supplier
-		stock_entry.supplier_name = subcontracting_order.supplier_name
-		stock_entry.supplier_address = subcontracting_order.supplier_address
-		stock_entry.address_display = subcontracting_order.address_display
-		stock_entry.company = subcontracting_order.company
-		stock_entry.to_warehouse = subcontracting_order.supplier_warehouse
-		stock_entry.set_stock_entry_type()
-
-		for item_code in fg_items:
-			for rm_item_data in rm_items_list:
-				if rm_item_data["item_code"] == item_code:
-					rm_item_code = rm_item_data["rm_item_code"]
-					items_dict = {
-						rm_item_code: {
-							"sco_rm_detail": rm_item_data.get("name"),
-							"item_name": rm_item_data["item_name"],
-							"description": item_wh.get(rm_item_code, {}).get("description", ""),
-							"qty": rm_item_data["qty"],
-							"from_warehouse": rm_item_data["warehouse"],
-							"stock_uom": rm_item_data["stock_uom"],
-							"serial_no": rm_item_data.get("serial_no"),
-							"batch_no": rm_item_data.get("batch_no"),
-							"main_item_code": rm_item_data["item_code"],
-							"allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"),
-						}
-					}
-					stock_entry.add_to_stock_entry_detail(items_dict)
-		return stock_entry.as_dict()
-	else:
-		frappe.throw(_("No Items selected for transfer"))
-	return subcontracting_order.name
-
-
-def add_items_in_ste(ste_doc, row, qty, sco_rm_details, batch_no=None):
-	item = ste_doc.append("items", row.item_details)
-
-	sco_rm_detail = list(set(row.sco_rm_details).intersection(sco_rm_details))
-	item.update(
-		{
-			"qty": qty,
-			"batch_no": batch_no,
-			"basic_rate": row.item_details["rate"],
-			"sco_rm_detail": sco_rm_detail[0] if sco_rm_detail else "",
-			"s_warehouse": row.item_details["t_warehouse"],
-			"t_warehouse": row.item_details["s_warehouse"],
-			"item_code": row.item_details["rm_item_code"],
-			"subcontracted_item": row.item_details["main_item_code"],
-			"serial_no": "\n".join(row.serial_no) if row.serial_no else "",
-		}
-	)
-
-
-def make_return_stock_entry_for_subcontract(available_materials, sco_doc, sco_rm_details):
-	ste_doc = frappe.new_doc("Stock Entry")
-	ste_doc.purpose = "Material Transfer"
-
-	ste_doc.subcontracting_order = sco_doc.name
-	ste_doc.company = sco_doc.company
-	ste_doc.is_return = 1
-
-	for key, value in available_materials.items():
-		if not value.qty:
-			continue
-
-		if value.batch_no:
-			for batch_no, qty in value.batch_no.items():
-				if qty > 0:
-					add_items_in_ste(ste_doc, value, value.qty, sco_rm_details, batch_no)
-		else:
-			add_items_in_ste(ste_doc, value, value.qty, sco_rm_details)
-
-	ste_doc.set_stock_entry_type()
-	ste_doc.calculate_rate_and_amount()
-
-	return ste_doc
-
-
-@frappe.whitelist()
-def get_materials_from_supplier(subcontracting_order, sco_rm_details):
-	if isinstance(sco_rm_details, str):
-		sco_rm_details = json.loads(sco_rm_details)
-
-	doc = frappe.get_cached_doc("Subcontracting Order", subcontracting_order)
-	doc.initialized_fields()
-	doc.subcontracting_orders = [doc.name]
-	doc.get_available_materials()
-
-	if not doc.available_materials:
-		frappe.throw(
-			_("Materials are already received against the Subcontracting Order {0}").format(
-				subcontracting_order
-			)
-		)
-
-	return make_return_stock_entry_for_subcontract(doc.available_materials, doc, sco_rm_details)
-
-
 @frappe.whitelist()
 def update_subcontracting_order_status(sco):
 	if isinstance(sco, str):
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
index 1454f1a..e579834 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
@@ -7,6 +7,7 @@
 from frappe.tests.utils import FrappeTestCase
 
 from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_subcontracting_order
+from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
 from erpnext.controllers.tests.test_subcontracting_controller import (
 	get_rm_items,
 	get_subcontracting_order,
@@ -22,7 +23,6 @@
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
-	make_rm_stock_entry,
 	make_subcontracting_receipt,
 )
 
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 5ee49d8..0c4ec6f 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -3,7 +3,7 @@
 
 import frappe
 from frappe import _
-from frappe.utils import cint, flt, getdate, nowdate
+from frappe.utils import cint, getdate, nowdate
 
 from erpnext.controllers.subcontracting_controller import SubcontractingController
 
@@ -78,7 +78,7 @@
 		self.update_status_updater_args()
 		self.update_prevdoc_status()
 		self.set_subcontracting_order_status()
-		self.set_consumed_qty_in_sco()
+		self.set_consumed_qty_in_subcontract_order()
 		self.update_stock_ledger()
 
 		from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
@@ -97,7 +97,7 @@
 		self.make_gl_entries_on_cancel()
 		self.repost_future_sle_and_gle()
 		self.delete_auto_created_batches()
-		self.set_consumed_qty_in_sco()
+		self.set_consumed_qty_in_subcontract_order()
 		self.set_subcontracting_order_status()
 		self.update_status()
 
@@ -162,17 +162,6 @@
 				if not item.expense_account:
 					item.expense_account = expense_account
 
-	@frappe.whitelist()
-	def get_current_stock(self):
-		for item in self.get("supplied_items"):
-			if self.supplier_warehouse:
-				actual_qty = frappe.db.get_value(
-					"Bin",
-					{"item_code": item.rm_item_code, "warehouse": self.supplier_warehouse},
-					"actual_qty",
-				)
-				item.current_stock = flt(actual_qty) or 0
-
 	def update_status(self, status=None, update_modified=False):
 		if self.docstatus >= 1 and not status:
 			if self.docstatus == 1:
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index 156a271..763e768 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -119,7 +119,7 @@
 		        receive more than the required qty in the SCO.
 		Expected Result: Error Raised for Over Receipt against SCO.
 		"""
-		from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
+		from erpnext.controllers.subcontracting_controller import (
 			make_rm_stock_entry as make_subcontract_transfer_entry,
 		)
 		from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
@@ -188,8 +188,8 @@
 		self.assertRaises(frappe.ValidationError, scr2.submit)
 
 	def test_subcontracted_scr_for_multi_transfer_batches(self):
+		from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
 		from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
-			make_rm_stock_entry,
 			make_subcontracting_receipt,
 		)