Merge branch 'develop' into SCR-SCRAP-ITEMS
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index b396b27..b1ce539 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -436,24 +436,6 @@
 
 			# validate rate with ref PR
 
-	def validate_rejected_warehouse(self):
-		for item in self.get("items"):
-			if flt(item.rejected_qty) and not item.rejected_warehouse:
-				if self.rejected_warehouse:
-					item.rejected_warehouse = self.rejected_warehouse
-
-				if not item.rejected_warehouse:
-					frappe.throw(
-						_("Row #{0}: Rejected Warehouse is mandatory for the rejected Item {1}").format(
-							item.idx, item.item_code
-						)
-					)
-
-			if item.get("rejected_warehouse") and (item.get("rejected_warehouse") == item.get("warehouse")):
-				frappe.throw(
-					_("Row #{0}: Accepted Warehouse and Rejected Warehouse cannot be same").format(item.idx)
-				)
-
 	# validate accepted and rejected qty
 	def validate_accepted_rejected_qty(self):
 		for d in self.get("items"):
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 6633f4f..913c80b 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -55,6 +55,23 @@
 		else:
 			super(SubcontractingController, self).validate()
 
+	def validate_rejected_warehouse(self):
+		for item in self.get("items"):
+			if flt(item.rejected_qty) and not item.rejected_warehouse:
+				if self.rejected_warehouse:
+					item.rejected_warehouse = self.rejected_warehouse
+				else:
+					frappe.throw(
+						_("Row #{0}: Rejected Warehouse is mandatory for the rejected Item {1}").format(
+							item.idx, item.item_code
+						)
+					)
+
+			if item.get("rejected_warehouse") and (item.get("rejected_warehouse") == item.get("warehouse")):
+				frappe.throw(
+					_("Row #{0}: Accepted Warehouse and Rejected Warehouse cannot be same").format(item.idx)
+				)
+
 	def remove_empty_rows(self):
 		for key in ["service_items", "items", "supplied_items"]:
 			if self.get(key):
@@ -80,23 +97,27 @@
 			if not is_stock_item:
 				frappe.throw(_("Row {0}: Item {1} must be a stock item.").format(item.idx, item.item_name))
 
-			if not is_sub_contracted_item:
-				frappe.throw(
-					_("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name)
-				)
+			if not item.is_scrap_item:
+				if not is_sub_contracted_item:
+					frappe.throw(
+						_("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name)
+					)
 
-			if item.bom:
-				bom = frappe.get_doc("BOM", item.bom)
-				if not bom.is_active:
-					frappe.throw(
-						_("Row {0}: Please select an active BOM for Item {1}.").format(item.idx, item.item_name)
-					)
-				if bom.item != item.item_code:
-					frappe.throw(
-						_("Row {0}: Please select an valid BOM for Item {1}.").format(item.idx, item.item_name)
-					)
+				if item.bom:
+					is_active, bom_item = frappe.get_value("BOM", item.bom, ["is_active", "item"])
+
+					if not is_active:
+						frappe.throw(
+							_("Row {0}: Please select an active BOM for Item {1}.").format(item.idx, item.item_name)
+						)
+					if bom_item != item.item_code:
+						frappe.throw(
+							_("Row {0}: Please select an valid BOM for Item {1}.").format(item.idx, item.item_name)
+						)
+				else:
+					frappe.throw(_("Row {0}: Please select a BOM for Item {1}.").format(item.idx, item.item_name))
 			else:
-				frappe.throw(_("Row {0}: Please select a BOM for Item {1}.").format(item.idx, item.item_name))
+				item.bom = None
 
 	def __get_data_before_save(self):
 		item_dict = {}
@@ -874,19 +895,24 @@
 
 		if self.total_additional_costs:
 			if self.distribute_additional_costs_based_on == "Amount":
-				total_amt = sum(flt(item.amount) for item in self.get("items"))
+				total_amt = sum(
+					flt(item.amount) for item in self.get("items") if not item.get("is_scrap_item")
+				)
 				for item in self.items:
-					item.additional_cost_per_qty = (
-						(item.amount * self.total_additional_costs) / total_amt
-					) / item.qty
+					if not item.get("is_scrap_item"):
+						item.additional_cost_per_qty = (
+							(item.amount * self.total_additional_costs) / total_amt
+						) / item.qty
 			else:
-				total_qty = sum(flt(item.qty) for item in self.get("items"))
+				total_qty = sum(flt(item.qty) for item in self.get("items") if not item.get("is_scrap_item"))
 				additional_cost_per_qty = self.total_additional_costs / total_qty
 				for item in self.items:
-					item.additional_cost_per_qty = additional_cost_per_qty
+					if not item.get("is_scrap_item"):
+						item.additional_cost_per_qty = additional_cost_per_qty
 		else:
 			for item in self.items:
-				item.additional_cost_per_qty = 0
+				if not item.get("is_scrap_item"):
+					item.additional_cost_per_qty = 0
 
 	@frappe.whitelist()
 	def get_current_stock(self):
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index e374077..acf9553 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -22,7 +22,7 @@
 						to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
 						company: frm.doc.company,
 						show_cancelled_entries: frm.doc.docstatus === 2
-					};
+					}
 					frappe.set_route('query-report', 'Stock Ledger');
 				}, __('View'));
 
@@ -34,7 +34,7 @@
 						company: frm.doc.company,
 						group_by: 'Group by Voucher (Consolidated)',
 						show_cancelled_entries: frm.doc.docstatus === 2
-					};
+					}
 					frappe.set_route('query-report', 'General Ledger');
 				}, __('View'));
 		}
@@ -94,7 +94,7 @@
 					company: frm.doc.company,
 					is_group: 0
 				}
-			};
+			}
 		});
 
 		frm.set_query('rejected_warehouse', () => {
@@ -103,7 +103,7 @@
 					company: frm.doc.company,
 					is_group: 0
 				}
-			};
+			}
 		});
 
 		frm.set_query('supplier_warehouse', () => {
@@ -112,7 +112,7 @@
 					company: frm.doc.company,
 					is_group: 0
 				}
-			};
+			}
 		});
 
 		frm.set_query('warehouse', 'items', () => ({
@@ -129,10 +129,12 @@
 			}
 		}));
 
-		frm.set_query('expense_account', 'items', () => ({
+		frm.set_query('expense_account', 'items', () => {
+			return {
 				query: 'erpnext.controllers.queries.get_expense_account',
 				filters: { 'company': frm.doc.company }
-			}));
+			}
+		});
 
 		frm.set_query('batch_no', 'items', (doc, cdt, cdn) => {
 			var row = locals[cdt][cdn];
@@ -140,7 +142,7 @@
 				filters: {
 					item: row.item_code
 				}
-			};
+			}
 		});
 
 		frm.set_query('batch_no', 'supplied_items', (doc, cdt, cdn) => {
@@ -149,7 +151,7 @@
 				filters: {
 					item: row.rm_item_code
 				}
-			};
+			}
 		});
 
 		frm.set_query('serial_and_batch_bundle', 'supplied_items', (doc, cdt, cdn) => {
@@ -171,7 +173,7 @@
 					'item_code': row.doc.rm_item_code,
 					'voucher_type': frm.doc.doctype,
 				}
-			};
+			}
 		}
 
 		let batch_no_field = frm.get_docfield('items', 'batch_no');
@@ -180,7 +182,7 @@
 				return {
 					'item': row.doc.item_code
 				}
-			};
+			}
 		}
 	},
 
@@ -190,15 +192,37 @@
 			transaction_controller.setup_quality_inspection();
 		}
 	},
+
+	get_scrap_items: (frm) => {
+		frappe.call({
+			doc: frm.doc,
+			method: 'get_scrap_items',
+			args: {
+				recalculate_rate: true
+			},
+			freeze: true,
+			freeze_message: __('Getting Scrap Items'),
+			callback: (r) => {
+				if (!r.exc) {
+					frm.refresh();
+				}
+			}
+		});
+	},
 });
 
 frappe.ui.form.on('Landed Cost Taxes and Charges', {
 	amount: (frm, cdt, cdn) => {
+		set_missing_values(frm);
 		frm.events.set_base_amount(frm, cdt, cdn);
 	},
 
 	expense_account: (frm, cdt, cdn) => {
 		frm.events.set_account_currency(frm, cdt, cdn);
+	},
+
+	additional_costs_remove: (frm) => {
+		set_missing_values(frm);
 	}
 });
 
@@ -214,6 +238,16 @@
 	rate(frm) {
 		set_missing_values(frm);
 	},
+
+	recalculate_rate(frm) {
+		if (frm.doc.recalculate_rate) {
+			set_missing_values(frm);
+		}
+	},
+
+	items_remove: (frm) => {
+		set_missing_values(frm);
+	},
 });
 
 frappe.ui.form.on('Subcontracting Receipt Supplied Item', {
@@ -225,7 +259,7 @@
 let set_warehouse_in_children = (child_table, warehouse_field, warehouse) => {
 	let transaction_controller = new erpnext.TransactionController();
 	transaction_controller.autofill_warehouse(child_table, warehouse_field, warehouse);
-};
+}
 
 let set_missing_values = (frm) => {
 	frappe.call({
@@ -235,4 +269,4 @@
 			if (!r.exc) frm.refresh();
 		},
 	});
-};
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
index 4b3cc83..8be1c1b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.json
@@ -40,6 +40,7 @@
   "col_break_warehouse",
   "supplier_warehouse",
   "items_section",
+  "get_scrap_items",
   "items",
   "section_break0",
   "total_qty",
@@ -285,7 +286,7 @@
    "reqd": 1
   },
   {
-   "depends_on": "supplied_items",
+   "depends_on": "eval: (!doc.__islocal && doc.docstatus == 0 && doc.supplied_items)",
    "fieldname": "get_current_stock",
    "fieldtype": "Button",
    "label": "Get Current Stock",
@@ -626,12 +627,19 @@
    "fieldtype": "Check",
    "label": "Edit Posting Date and Time",
    "print_hide": 1
+  },
+  {
+   "depends_on": "eval: (!doc.__islocal && doc.docstatus == 0)",
+   "fieldname": "get_scrap_items",
+   "fieldtype": "Button",
+   "label": "Get Scrap Items",
+   "options": "get_scrap_items"
   }
  ],
  "in_create": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-07-06 18:43:16.171842",
+ "modified": "2023-08-26 10:52:04.050829",
  "modified_by": "Administrator",
  "module": "Subcontracting",
  "name": "Subcontracting Receipt",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index afe1b60..c601ddb 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,15 +44,8 @@
 		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 = []
-		super(SubcontractingReceipt, self).validate()
-		self.set_missing_values()
+		self.reset_supplied_items()
 		self.validate_posting_time()
-		self.validate_rejected_warehouse()
 
 		if not self.get("is_return"):
 			self.validate_inspection()
@@ -87,15 +53,22 @@
 		if getdate(self.posting_date) > getdate(nowdate()):
 			frappe.throw(_("Posting Date cannot be future date"))
 
+		super(SubcontractingReceipt, self).validate()
+
+		if self.is_new() and self.get("_action") == "save":
+			self.get_scrap_items()
+
+		self.set_missing_values()
+
+		if self.get("_action") == "submit":
+			self.validate_scrap_items()
+			self.validate_accepted_warehouse()
+			self.validate_rejected_warehouse()
+
 		self.reset_default_field_value("set_warehouse", "items", "warehouse")
 		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()
@@ -107,6 +80,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",
@@ -124,108 +102,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 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 = item.qty + flt(item.rejected_qty)
-			item.amount = item.qty * item.rate
-			total_qty += item.qty
-			total_amount += item.amount
-		else:
-			self.total_qty = total_qty
-			self.total = total_amount
-
-	def validate_rejected_warehouse(self):
-		for item in self.items:
-			if flt(item.rejected_qty) and not item.rejected_warehouse:
-				if self.rejected_warehouse:
-					item.rejected_warehouse = self.rejected_warehouse
-
-				if not item.rejected_warehouse:
-					frappe.throw(
-						_("Row #{0}: Rejected Warehouse is mandatory for the rejected Item {1}").format(
-							item.idx, item.item_code
-						)
-					)
-
-			if item.get("rejected_warehouse") and (item.get("rejected_warehouse") == item.get("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 validate_items_qty(self):
 		for item in self.items:
 			if not (item.qty or item.rejected_qty):
@@ -267,6 +143,225 @@
 				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 = []
+
+	@frappe.whitelist()
+	def get_scrap_items(self, recalculate_rate=False):
+		self.remove_scrap_items()
+
+		for item in list(self.items):
+			if item.bom:
+				bom = frappe.get_doc("BOM", item.bom)
+				for scrap_item in bom.scrap_items:
+					qty = flt(item.qty) * (flt(scrap_item.stock_qty) / flt(bom.quantity))
+					self.append(
+						"items",
+						{
+							"is_scrap_item": 1,
+							"reference_name": item.name,
+							"item_code": scrap_item.item_code,
+							"item_name": scrap_item.item_name,
+							"qty": qty,
+							"stock_uom": scrap_item.stock_uom,
+							"recalculate_rate": 0,
+							"rate": scrap_item.rate,
+							"rm_cost_per_qty": 0,
+							"service_cost_per_qty": 0,
+							"additional_cost_per_qty": 0,
+							"scrap_cost_per_qty": 0,
+							"amount": qty * scrap_item.rate,
+							"warehouse": self.set_warehouse,
+							"rejected_warehouse": self.rejected_warehouse,
+						},
+					)
+
+		if recalculate_rate:
+			self.calculate_additional_costs()
+			self.calculate_items_qty_and_amount()
+
+	def remove_scrap_items(self, recalculate_rate=False):
+		for item in list(self.items):
+			if item.is_scrap_item:
+				self.remove(item)
+			else:
+				item.scrap_cost_per_qty = 0
+
+		if recalculate_rate:
+			self.calculate_items_qty_and_amount()
+
+	@frappe.whitelist()
+	def set_missing_values(self):
+		self.set_available_qty_for_consumption()
+		self.calculate_additional_costs()
+		self.calculate_items_qty_and_amount()
+
+	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_cost_map = {}
+		for item in self.get("supplied_items") or []:
+			item.amount = flt(item.consumed_qty) * flt(item.rate)
+
+			if item.reference_name in rm_cost_map:
+				rm_cost_map[item.reference_name] += item.amount
+			else:
+				rm_cost_map[item.reference_name] = item.amount
+
+		scrap_cost_map = {}
+		for item in self.get("items") or []:
+			if item.is_scrap_item:
+				item.amount = flt(item.qty) * flt(item.rate)
+
+				if item.reference_name in scrap_cost_map:
+					scrap_cost_map[item.reference_name] += item.amount
+				else:
+					scrap_cost_map[item.reference_name] = item.amount
+
+		total_qty = total_amount = 0
+		for item in self.get("items") or []:
+			if not item.is_scrap_item:
+				if item.qty:
+					if item.name in rm_cost_map:
+						item.rm_supp_cost = rm_cost_map[item.name]
+						item.rm_cost_per_qty = item.rm_supp_cost / item.qty
+						rm_cost_map.pop(item.name)
+
+					if item.name in scrap_cost_map:
+						item.scrap_cost_per_qty = scrap_cost_map[item.name] / item.qty
+						scrap_cost_map.pop(item.name)
+					else:
+						item.scrap_cost_per_qty = 0
+
+				if item.recalculate_rate:
+					item.rate = (
+						flt(item.rm_cost_per_qty)
+						+ flt(item.service_cost_per_qty)
+						+ flt(item.additional_cost_per_qty)
+						- flt(item.scrap_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_scrap_items(self):
+		for item in self.items:
+			if item.is_scrap_item:
+				if not item.qty:
+					frappe.throw(
+						_("Row #{0}: Scrap Item Qty cannot be zero").format(item.idx),
+					)
+
+				if item.rejected_qty:
+					frappe.throw(
+						_("Row #{0}: Rejected Qty cannot be set for Scrap Item {1}.").format(
+							item.idx, frappe.bold(item.item_code)
+						),
+					)
+
+				if not item.reference_name:
+					frappe.throw(
+						_("Row #{0}: Finished Good reference is mandatory for Scrap Item {1}.").format(
+							item.idx, frappe.bold(item.item_code)
+						),
+					)
+
+	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:
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
index d728780..c036390 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -10,6 +10,7 @@
   "item_code",
   "column_break_2",
   "item_name",
+  "is_scrap_item",
   "section_break_4",
   "description",
   "brand",
@@ -24,8 +25,6 @@
   "col_break2",
   "stock_uom",
   "conversion_factor",
-  "tracking_section",
-  "col_break_tracking_section",
   "rate_and_amount",
   "rate",
   "amount",
@@ -34,18 +33,20 @@
   "rm_cost_per_qty",
   "service_cost_per_qty",
   "additional_cost_per_qty",
+  "scrap_cost_per_qty",
   "rm_supp_cost",
   "warehouse_and_reference",
   "warehouse",
-  "rejected_warehouse",
   "subcontracting_order",
-  "column_break_40",
-  "schedule_date",
-  "quality_inspection",
   "subcontracting_order_item",
   "subcontracting_receipt_item",
-  "section_break_45",
+  "column_break_40",
+  "rejected_warehouse",
   "bom",
+  "quality_inspection",
+  "schedule_date",
+  "reference_name",
+  "section_break_45",
   "serial_and_batch_bundle",
   "serial_no",
   "col_break5",
@@ -85,12 +86,13 @@
    "fieldtype": "Column Break"
   },
   {
+   "fetch_from": "item_code.item_name",
+   "fetch_if_empty": 1,
    "fieldname": "item_name",
    "fieldtype": "Data",
    "in_global_search": 1,
    "label": "Item Name",
-   "print_hide": 1,
-   "reqd": 1
+   "print_hide": 1
   },
   {
    "collapsible": 1,
@@ -99,11 +101,12 @@
    "label": "Description"
   },
   {
+   "fetch_from": "item_code.description",
+   "fetch_if_empty": 1,
    "fieldname": "description",
    "fieldtype": "Text Editor",
    "label": "Description",
    "print_width": "300px",
-   "reqd": 1,
    "width": "300px"
   },
   {
@@ -157,6 +160,7 @@
    "no_copy": 1,
    "print_hide": 1,
    "print_width": "100px",
+   "read_only_depends_on": "eval: doc.is_scrap_item",
    "width": "100px"
   },
   {
@@ -214,6 +218,8 @@
    "fieldtype": "Column Break"
   },
   {
+   "default": "0",
+   "depends_on": "eval: !doc.is_scrap_item",
    "fieldname": "rm_cost_per_qty",
    "fieldtype": "Currency",
    "label": "Raw Material Cost Per Qty",
@@ -221,6 +227,8 @@
    "read_only": 1
   },
   {
+   "default": "0",
+   "depends_on": "eval: !doc.is_scrap_item",
    "fieldname": "service_cost_per_qty",
    "fieldtype": "Currency",
    "label": "Service Cost Per Qty",
@@ -229,6 +237,7 @@
   },
   {
    "default": "0",
+   "depends_on": "eval: !doc.is_scrap_item",
    "fieldname": "additional_cost_per_qty",
    "fieldtype": "Currency",
    "label": "Additional Cost Per Qty",
@@ -260,6 +269,7 @@
    "options": "Warehouse",
    "print_hide": 1,
    "print_width": "100px",
+   "read_only_depends_on": "eval: doc.is_scrap_item",
    "width": "100px"
   },
   {
@@ -295,7 +305,8 @@
   },
   {
    "fieldname": "section_break_45",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "label": "Serial and Batch Details"
   },
   {
    "depends_on": "eval:!doc.is_fixed_asset",
@@ -321,7 +332,8 @@
    "fieldtype": "Small Text",
    "label": "Rejected Serial No",
    "no_copy": 1,
-   "print_hide": 1
+   "print_hide": 1,
+   "read_only": 1
   },
   {
    "fieldname": "subcontracting_order_item",
@@ -345,7 +357,8 @@
    "label": "BOM",
    "no_copy": 1,
    "options": "BOM",
-   "print_hide": 1
+   "print_hide": 1,
+   "read_only_depends_on": "eval: doc.is_scrap_item"
   },
   {
    "fetch_from": "item_code.brand",
@@ -411,14 +424,6 @@
    "fieldtype": "Column Break"
   },
   {
-   "fieldname": "tracking_section",
-   "fieldtype": "Section Break"
-  },
-  {
-   "fieldname": "col_break_tracking_section",
-   "fieldtype": "Column Break"
-  },
-  {
    "fieldname": "accounting_dimensions_section",
    "fieldtype": "Section Break",
    "label": "Accounting Dimensions"
@@ -456,6 +461,7 @@
    "print_hide": 1
   },
   {
+   "default": "0",
    "depends_on": "returned_qty",
    "fieldname": "returned_qty",
    "fieldtype": "Float",
@@ -471,9 +477,11 @@
   },
   {
    "default": "1",
+   "depends_on": "eval: !doc.is_scrap_item",
    "fieldname": "recalculate_rate",
    "fieldtype": "Check",
-   "label": "Recalculate Rate"
+   "label": "Recalculate Rate",
+   "read_only_depends_on": "eval: doc.is_scrap_item"
   },
   {
    "fieldname": "serial_and_batch_bundle",
@@ -490,12 +498,40 @@
    "no_copy": 1,
    "options": "Serial and Batch Bundle",
    "print_hide": 1
+  },
+  {
+   "default": "0",
+   "depends_on": "eval: !doc.bom",
+   "fieldname": "is_scrap_item",
+   "fieldtype": "Check",
+   "label": "Is Scrap Item",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only_depends_on": "eval: doc.bom"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval: !doc.is_scrap_item",
+   "fieldname": "scrap_cost_per_qty",
+   "fieldtype": "Float",
+   "label": "Scrap Cost Per Qty",
+   "no_copy": 1,
+   "non_negative": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "reference_name",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Reference Name",
+   "no_copy": 1,
+   "read_only": 1
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-07-06 18:43:45.599761",
+ "modified": "2023-08-25 20:09:03.069417",
  "modified_by": "Administrator",
  "module": "Subcontracting",
  "name": "Subcontracting Receipt Item",