refactor: code cleanup
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index b1a585d..2c7b2eb 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -36,33 +36,6 @@
 			),
 		)
 
-	def update_status_updater_args(self):
-		if cint(self.is_return):
-			self.status_updater.extend(
-				[
-					{
-						"source_dt": "Subcontracting Receipt Item",
-						"target_dt": "Subcontracting Order Item",
-						"join_field": "subcontracting_order_item",
-						"target_field": "returned_qty",
-						"source_field": "-1 * qty",
-						"extra_cond": """ and exists (select name from `tabSubcontracting Receipt`
-						where name=`tabSubcontracting Receipt Item`.parent and is_return=1)""",
-					},
-					{
-						"source_dt": "Subcontracting Receipt Item",
-						"target_dt": "Subcontracting Receipt Item",
-						"join_field": "subcontracting_receipt_item",
-						"target_field": "returned_qty",
-						"target_parent_dt": "Subcontracting Receipt",
-						"target_parent_field": "per_returned",
-						"target_ref_field": "received_qty",
-						"source_field": "-1 * received_qty",
-						"percent_join_field_parent": "return_against",
-					},
-				]
-			)
-
 	def before_validate(self):
 		super(SubcontractingReceipt, self).before_validate()
 		self.validate_items_qty()
@@ -71,16 +44,18 @@
 		self.set_items_expense_account()
 
 	def validate(self):
-		if (
-			frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
-			== "BOM"
-		):
-			self.supplied_items = []
+		self.reset_supplied_items()
 		super(SubcontractingReceipt, self).validate()
+
+		if self.is_new() and self.get("_action") == "save":
+			self.get_scrap_items()
+
 		self.set_missing_values()
 		self.validate_posting_time()
-		self.validate_accepted_warehouse()
-		self.validate_rejected_warehouse()
+
+		if self.get("_action") == "submit":
+			self.validate_accepted_warehouse()
+			self.validate_rejected_warehouse()
 
 		if getdate(self.posting_date) > getdate(nowdate()):
 			frappe.throw(_("Posting Date cannot be future date"))
@@ -89,11 +64,6 @@
 		self.reset_default_field_value("rejected_warehouse", "items", "rejected_warehouse")
 		self.get_current_stock()
 
-	def on_update(self):
-		for table_field in ["items", "supplied_items"]:
-			if self.get(table_field):
-				self.set_serial_and_batch_bundle(table_field)
-
 	def on_submit(self):
 		self.validate_available_qty_for_consumption()
 		self.update_status_updater_args()
@@ -105,6 +75,11 @@
 		self.repost_future_sle_and_gle()
 		self.update_status()
 
+	def on_update(self):
+		for table_field in ["items", "supplied_items"]:
+			if self.get(table_field):
+				self.set_serial_and_batch_bundle(table_field)
+
 	def on_cancel(self):
 		self.ignore_linked_doctypes = (
 			"GL Entry",
@@ -122,107 +97,6 @@
 		self.set_subcontracting_order_status()
 		self.update_status()
 
-	@frappe.whitelist()
-	def set_missing_values(self):
-		self.calculate_additional_costs()
-		self.calculate_supplied_items_qty_and_amount()
-		self.calculate_items_qty_and_amount()
-
-	def validate_accepted_warehouse(self):
-		for item in self.get("items"):
-			if flt(item.qty) and not item.warehouse:
-				if self.set_warehouse:
-					item.warehouse = self.set_warehouse
-				else:
-					frappe.throw(
-						_("Row #{0}: Accepted Warehouse is mandatory for the accepted Item {1}").format(
-							item.idx, item.item_code
-						)
-					)
-
-			if item.get("warehouse") and (item.get("warehouse") == item.get("rejected_warehouse")):
-				frappe.throw(
-					_("Row #{0}: Accepted Warehouse and Rejected Warehouse cannot be same").format(item.idx)
-				)
-
-	def set_available_qty_for_consumption(self):
-		supplied_items_details = {}
-
-		sco_supplied_item = frappe.qb.DocType("Subcontracting Order Supplied Item")
-		for item in self.get("items"):
-			supplied_items = (
-				frappe.qb.from_(sco_supplied_item)
-				.select(
-					sco_supplied_item.rm_item_code,
-					sco_supplied_item.reference_name,
-					(sco_supplied_item.total_supplied_qty - sco_supplied_item.consumed_qty).as_("available_qty"),
-				)
-				.where(
-					(sco_supplied_item.parent == item.subcontracting_order)
-					& (sco_supplied_item.main_item_code == item.item_code)
-					& (sco_supplied_item.reference_name == item.subcontracting_order_item)
-				)
-			).run(as_dict=True)
-
-			if supplied_items:
-				supplied_items_details[item.name] = {}
-
-				for supplied_item in supplied_items:
-					supplied_items_details[item.name][supplied_item.rm_item_code] = supplied_item.available_qty
-		else:
-			for item in self.get("supplied_items"):
-				item.available_qty_for_consumption = supplied_items_details.get(item.reference_name, {}).get(
-					item.rm_item_code, 0
-				)
-
-	def calculate_supplied_items_qty_and_amount(self):
-		for item in self.get("supplied_items") or []:
-			item.amount = item.rate * item.consumed_qty
-
-		self.set_available_qty_for_consumption()
-
-	def calculate_items_qty_and_amount(self):
-		rm_supp_cost = {}
-		for item in self.get("supplied_items") or []:
-			if item.reference_name in rm_supp_cost:
-				rm_supp_cost[item.reference_name] += item.amount
-			else:
-				rm_supp_cost[item.reference_name] = item.amount
-
-		total_qty = total_amount = 0
-		for item in self.items:
-			if item.qty and item.name in rm_supp_cost:
-				item.rm_supp_cost = rm_supp_cost[item.name]
-				item.rm_cost_per_qty = item.rm_supp_cost / item.qty
-				rm_supp_cost.pop(item.name)
-
-			if item.recalculate_rate:
-				item.rate = (
-					flt(item.rm_cost_per_qty) + flt(item.service_cost_per_qty) + flt(item.additional_cost_per_qty)
-				)
-
-			item.received_qty = flt(item.qty) + flt(item.rejected_qty)
-			item.amount = flt(item.qty) * flt(item.rate)
-			total_qty += flt(item.qty)
-			total_amount += item.amount
-		else:
-			self.total_qty = total_qty
-			self.total = total_amount
-
-	def validate_available_qty_for_consumption(self):
-		for item in self.get("supplied_items"):
-			precision = item.precision("consumed_qty")
-			if (
-				item.available_qty_for_consumption
-				and flt(item.available_qty_for_consumption, precision) - flt(item.consumed_qty, precision) < 0
-			):
-				msg = f"""Row {item.idx}: Consumed Qty {flt(item.consumed_qty, precision)}
-					must be less than or equal to Available Qty For Consumption
-					{flt(item.available_qty_for_consumption, precision)}
-					in Consumed Items Table."""
-
-				frappe.throw(_(msg))
-
 	def validate_items_qty(self):
 		for item in self.items:
 			if not (item.qty or item.rejected_qty):
@@ -264,6 +138,167 @@
 				if not item.expense_account:
 					item.expense_account = expense_account
 
+	def reset_supplied_items(self):
+		if (
+			frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
+			== "BOM"
+		):
+			self.supplied_items = []
+
+	def get_scrap_items(self):
+		if (
+			frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
+			== "BOM"
+		):
+			for item in list(self.items):
+				if item.bom and not item.is_scrap_item:
+					bom = frappe.get_doc("BOM", item.bom)
+					for scrap_item in bom.scrap_items:
+						qty = flt(item.received_qty) * (flt(scrap_item.stock_qty) / flt(bom.quantity))
+						self.append(
+							"items",
+							{
+								"item_code": scrap_item.item_code,
+								"item_name": scrap_item.item_name,
+								"qty": qty,
+								"stock_uom": scrap_item.stock_uom,
+								"rate": scrap_item.rate,
+								"amount": qty * scrap_item.rate,
+								"is_scrap_item": 1,
+								"warehouse": self.set_warehouse,
+								"rejected_warehouse": self.rejected_warehouse,
+								"service_cost_per_qty": 0,
+							},
+						)
+
+	@frappe.whitelist()
+	def set_missing_values(self):
+		self.calculate_additional_costs()
+		self.calculate_supplied_items_qty_and_amount()
+		self.calculate_items_qty_and_amount()
+
+	def calculate_supplied_items_qty_and_amount(self):
+		for item in self.get("supplied_items") or []:
+			item.amount = item.rate * item.consumed_qty
+
+		self.set_available_qty_for_consumption()
+
+	def set_available_qty_for_consumption(self):
+		supplied_items_details = {}
+
+		sco_supplied_item = frappe.qb.DocType("Subcontracting Order Supplied Item")
+		for item in self.get("items"):
+			supplied_items = (
+				frappe.qb.from_(sco_supplied_item)
+				.select(
+					sco_supplied_item.rm_item_code,
+					sco_supplied_item.reference_name,
+					(sco_supplied_item.total_supplied_qty - sco_supplied_item.consumed_qty).as_("available_qty"),
+				)
+				.where(
+					(sco_supplied_item.parent == item.subcontracting_order)
+					& (sco_supplied_item.main_item_code == item.item_code)
+					& (sco_supplied_item.reference_name == item.subcontracting_order_item)
+				)
+			).run(as_dict=True)
+
+			if supplied_items:
+				supplied_items_details[item.name] = {}
+
+				for supplied_item in supplied_items:
+					supplied_items_details[item.name][supplied_item.rm_item_code] = supplied_item.available_qty
+		else:
+			for item in self.get("supplied_items"):
+				item.available_qty_for_consumption = supplied_items_details.get(item.reference_name, {}).get(
+					item.rm_item_code, 0
+				)
+
+	def calculate_items_qty_and_amount(self):
+		rm_supp_cost = {}
+		for item in self.get("supplied_items") or []:
+			if item.reference_name in rm_supp_cost:
+				rm_supp_cost[item.reference_name] += item.amount
+			else:
+				rm_supp_cost[item.reference_name] = item.amount
+
+		total_qty = total_amount = 0
+		for item in self.items:
+			if item.qty and item.name in rm_supp_cost:
+				item.rm_supp_cost = rm_supp_cost[item.name]
+				item.rm_cost_per_qty = item.rm_supp_cost / item.qty
+				rm_supp_cost.pop(item.name)
+
+			if item.recalculate_rate:
+				item.rate = (
+					flt(item.rm_cost_per_qty) + flt(item.service_cost_per_qty) + flt(item.additional_cost_per_qty)
+				)
+
+			item.received_qty = flt(item.qty) + flt(item.rejected_qty)
+			item.amount = flt(item.qty) * flt(item.rate)
+			total_qty += flt(item.qty)
+			total_amount += item.amount
+		else:
+			self.total_qty = total_qty
+			self.total = total_amount
+
+	def validate_accepted_warehouse(self):
+		for item in self.get("items"):
+			if flt(item.qty) and not item.warehouse:
+				if self.set_warehouse:
+					item.warehouse = self.set_warehouse
+				else:
+					frappe.throw(
+						_("Row #{0}: Accepted Warehouse is mandatory for the accepted Item {1}").format(
+							item.idx, item.item_code
+						)
+					)
+
+			if item.get("warehouse") and (item.get("warehouse") == item.get("rejected_warehouse")):
+				frappe.throw(
+					_("Row #{0}: Accepted Warehouse and Rejected Warehouse cannot be same").format(item.idx)
+				)
+
+	def validate_available_qty_for_consumption(self):
+		for item in self.get("supplied_items"):
+			precision = item.precision("consumed_qty")
+			if (
+				item.available_qty_for_consumption
+				and flt(item.available_qty_for_consumption, precision) - flt(item.consumed_qty, precision) < 0
+			):
+				msg = f"""Row {item.idx}: Consumed Qty {flt(item.consumed_qty, precision)}
+					must be less than or equal to Available Qty For Consumption
+					{flt(item.available_qty_for_consumption, precision)}
+					in Consumed Items Table."""
+
+				frappe.throw(_(msg))
+
+	def update_status_updater_args(self):
+		if cint(self.is_return):
+			self.status_updater.extend(
+				[
+					{
+						"source_dt": "Subcontracting Receipt Item",
+						"target_dt": "Subcontracting Order Item",
+						"join_field": "subcontracting_order_item",
+						"target_field": "returned_qty",
+						"source_field": "-1 * qty",
+						"extra_cond": """ and exists (select name from `tabSubcontracting Receipt`
+						where name=`tabSubcontracting Receipt Item`.parent and is_return=1)""",
+					},
+					{
+						"source_dt": "Subcontracting Receipt Item",
+						"target_dt": "Subcontracting Receipt Item",
+						"join_field": "subcontracting_receipt_item",
+						"target_field": "returned_qty",
+						"target_parent_dt": "Subcontracting Receipt",
+						"target_parent_field": "per_returned",
+						"target_ref_field": "received_qty",
+						"source_field": "-1 * received_qty",
+						"percent_join_field_parent": "return_against",
+					},
+				]
+			)
+
 	def update_status(self, status=None, update_modified=False):
 		if not status:
 			if self.docstatus == 0: