Merge pull request #36856 from frappe/desk_user

refactor!: Lower all perm to `Desk User`
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2c9a60c..30be903 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -40,6 +40,7 @@
       - id: flake8
         additional_dependencies: [
           'flake8-bugbear',
+          'flake8-tuple',
         ]
         args: ['--config', '.github/helper/.flake8_strict']
         exclude: ".*setup.py$"
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/mx_plan_de_cuentas.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/mx_plan_de_cuentas.json
index e98c2d6..858f05c 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/mx_plan_de_cuentas.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/mx_plan_de_cuentas.json
@@ -109,8 +109,7 @@
                     }
                 }, 
                 "INVENTARIOS": {
-                    "account_type": "Stock", 
-                    "is_group": 1
+                    "account_type": "Stock"
                 }
             }, 
             "ACTIVO LARGO PLAZO": {
@@ -398,10 +397,18 @@
                         "INGRESOS POR SERVICIOS 1": {}
                     }, 
                     "VENTAS": {
-                        "VENTAS EXPORTACION": {}, 
-                        "VENTAS INMUEBLES": {}, 
-                        "VENTAS NACIONALES": {}, 
-                        "VENTAS NACIONALES AL DETAL": {}
+                        "VENTAS EXPORTACION": {
+                            "account_type": "Income Account"
+                        }, 
+                        "VENTAS INMUEBLES": {
+                            "account_type": "Income Account"
+                        }, 
+                        "VENTAS NACIONALES": {
+                            "account_type": "Income Account"
+                        }, 
+                        "VENTAS NACIONALES AL DETAL": {
+                            "account_type": "Income Account"
+                        }
                     }
                 }
             }, 
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py
index ced04ce..e520872 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/test_exchange_rate_revaluation.py
@@ -67,7 +67,7 @@
 		si.save().submit()
 
 		err = frappe.new_doc("Exchange Rate Revaluation")
-		err.company = (self.company,)
+		err.company = self.company
 		err.posting_date = today()
 		accounts = err.get_accounts_data()
 		err.extend("accounts", accounts)
@@ -133,7 +133,7 @@
 		frappe.get_doc("Journal Entry", je).cancel()
 
 		err = frappe.new_doc("Exchange Rate Revaluation")
-		err.company = (self.company,)
+		err.company = self.company
 		err.posting_date = today()
 		err.fetch_and_calculate_accounts_data()
 		err = err.save().submit()
@@ -215,7 +215,7 @@
 		self.assertEqual(flt(acc_balance.balance_in_account_currency, precision), 5.0)  # in USD
 
 		err = frappe.new_doc("Exchange Rate Revaluation")
-		err.company = (self.company,)
+		err.company = self.company
 		err.posting_date = today()
 		err.fetch_and_calculate_accounts_data()
 		err.set_total_gain_loss()
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 032aa80..9ed3d32 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1993,10 +1993,15 @@
 		if not total_amount:
 			if party_account_currency == company_currency:
 				# for handling cases that don't have multi-currency (base field)
-				total_amount = ref_doc.get("base_grand_total") or ref_doc.get("grand_total")
+				total_amount = (
+					ref_doc.get("base_rounded_total")
+					or ref_doc.get("rounded_total")
+					or ref_doc.get("base_grand_total")
+					or ref_doc.get("grand_total")
+				)
 				exchange_rate = 1
 			else:
-				total_amount = ref_doc.get("grand_total")
+				total_amount = ref_doc.get("rounded_total") or ref_doc.get("grand_total")
 		if not exchange_rate:
 			# Get the exchange rate from the original ref doc
 			# or get it based on the posting date of the ref doc.
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index c8bf664..edfec41 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -1244,6 +1244,24 @@
 		template.allocate_payment_based_on_payment_terms = 1
 		template.save()
 
+	def test_allocation_validation_for_sales_order(self):
+		so = make_sales_order(do_not_save=True)
+		so.items[0].rate = 99.55
+		so.save().submit()
+		self.assertGreater(so.rounded_total, 0.0)
+		pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Cash - _TC")
+		pe.paid_from = "Debtors - _TC"
+		pe.paid_amount = 45.55
+		pe.references[0].allocated_amount = 45.55
+		pe.save().submit()
+		pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Cash - _TC")
+		pe.paid_from = "Debtors - _TC"
+		# No validation error should be thrown here.
+		pe.save().submit()
+
+		so.reload()
+		self.assertEqual(so.advance_paid, so.rounded_total)
+
 
 def create_payment_entry(**args):
 	payment_entry = frappe.new_doc("Payment Entry")
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 9f1224d..be19bca 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -759,21 +759,22 @@
 
 					# Amount added through landed-cost-voucher
 					if landed_cost_entries:
-						for account, amount in landed_cost_entries[(item.item_code, item.name)].items():
-							gl_entries.append(
-								self.get_gl_dict(
-									{
-										"account": account,
-										"against": item.expense_account,
-										"cost_center": item.cost_center,
-										"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
-										"credit": flt(amount["base_amount"]),
-										"credit_in_account_currency": flt(amount["amount"]),
-										"project": item.project or self.project,
-									},
-									item=item,
+						if (item.item_code, item.name) in landed_cost_entries:
+							for account, amount in landed_cost_entries[(item.item_code, item.name)].items():
+								gl_entries.append(
+									self.get_gl_dict(
+										{
+											"account": account,
+											"against": item.expense_account,
+											"cost_center": item.cost_center,
+											"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+											"credit": flt(amount["base_amount"]),
+											"credit_in_account_currency": flt(amount["amount"]),
+											"project": item.project or self.project,
+										},
+										item=item,
+									)
 								)
-							)
 
 					# sub-contracting warehouse
 					if flt(item.rm_supp_cost):
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index bf62a8f..383be97 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -156,6 +156,8 @@
 
 
 def prepare_chart_data(data, filters):
+	if not data:
+		return
 	labels_values_map = {}
 	if filters.filter_based_on not in ("Date Range", "Fiscal Year"):
 		filters_filter_based_on = "Date Range"
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..d4270a7 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.get("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/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
index 5c4be6f..510317f 100644
--- a/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
+++ b/erpnext/erpnext_integrations/workspace/erpnext_integrations/erpnext_integrations.json
@@ -1,6 +1,6 @@
 {
  "charts": [],
- "content": "[{\"id\":\"e88ADOJ7WC\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Integrations</b></span>\",\"col\":12}},{\"id\":\"G0tyx9WOfm\",\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"id\":\"nu4oSjH5Rd\",\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"id\":\"nG8cdkpzoc\",\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"id\":\"4hwuQn6E95\",\"type\":\"card\",\"data\":{\"card_name\":\"Communication Channels\",\"col\":4}},{\"id\":\"sEGAzTJRmq\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"id\":\"ZC6xu-cLBR\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
+ "content": "[{\"id\":\"e88ADOJ7WC\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Integrations</b></span>\",\"col\":12}},{\"id\":\"pZEYOOCdB0\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Browse Apps\",\"col\":3}},{\"id\":\"St7AHbhVOr\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"nu4oSjH5Rd\",\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"id\":\"G0tyx9WOfm\",\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"id\":\"nG8cdkpzoc\",\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"id\":\"4hwuQn6E95\",\"type\":\"card\",\"data\":{\"card_name\":\"Communication Channels\",\"col\":4}},{\"id\":\"sEGAzTJRmq\",\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}}]",
  "creation": "2020-08-20 19:30:48.138801",
  "custom_blocks": [],
  "docstatus": 0,
@@ -221,27 +221,9 @@
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
-  },
-  {
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Settings",
-   "link_count": 2,
-   "onboard": 0,
-   "type": "Card Break"
-  },
-  {
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Woocommerce Settings",
-   "link_count": 0,
-   "link_to": "Woocommerce Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
   }
  ],
- "modified": "2023-05-24 14:47:26.984717",
+ "modified": "2023-08-29 15:48:59.010704",
  "modified_by": "Administrator",
  "module": "ERPNext Integrations",
  "name": "ERPNext Integrations",
@@ -253,6 +235,14 @@
  "restrict_to_domain": "",
  "roles": [],
  "sequence_id": 21.0,
- "shortcuts": [],
+ "shortcuts": [
+  {
+   "color": "Grey",
+   "doc_view": "List",
+   "label": "Browse Apps",
+   "type": "URL",
+   "url": "https://frappecloud.com/marketplace"
+  }
+ ],
  "title": "ERPNext Integrations"
 }
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index 111a0861..7f0dc2d 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -6,6 +6,7 @@
 from frappe import _
 from frappe.model.document import Document
 from frappe.model.meta import get_field_precision
+from frappe.query_builder.custom import ConstantColumn
 from frappe.utils import flt
 
 import erpnext
@@ -19,19 +20,7 @@
 		self.set("items", [])
 		for pr in self.get("purchase_receipts"):
 			if pr.receipt_document_type and pr.receipt_document:
-				pr_items = frappe.db.sql(
-					"""select pr_item.item_code, pr_item.description,
-					pr_item.qty, pr_item.base_rate, pr_item.base_amount, pr_item.name,
-					pr_item.cost_center, pr_item.is_fixed_asset
-					from `tab{doctype} Item` pr_item where parent = %s
-					and exists(select name from tabItem
-						where name = pr_item.item_code and (is_stock_item = 1 or is_fixed_asset=1))
-					""".format(
-						doctype=pr.receipt_document_type
-					),
-					pr.receipt_document,
-					as_dict=True,
-				)
+				pr_items = get_pr_items(pr)
 
 				for d in pr_items:
 					item = self.append("items")
@@ -247,3 +236,30 @@
 						),
 						tuple([item.valuation_rate] + serial_nos),
 					)
+
+
+def get_pr_items(purchase_receipt):
+	item = frappe.qb.DocType("Item")
+	pr_item = frappe.qb.DocType(purchase_receipt.receipt_document_type + " Item")
+	return (
+		frappe.qb.from_(pr_item)
+		.inner_join(item)
+		.on(item.name == pr_item.item_code)
+		.select(
+			pr_item.item_code,
+			pr_item.description,
+			pr_item.qty,
+			pr_item.base_rate,
+			pr_item.base_amount,
+			pr_item.name,
+			pr_item.cost_center,
+			pr_item.is_fixed_asset,
+			ConstantColumn(purchase_receipt.receipt_document_type).as_("receipt_document_type"),
+			ConstantColumn(purchase_receipt.receipt_document).as_("receipt_document"),
+		)
+		.where(
+			(pr_item.parent == purchase_receipt.receipt_document)
+			& ((item.is_stock_item == 1) | (item.is_fixed_asset == 1))
+		)
+		.run(as_dict=True)
+	)
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 0b5dc05..60aefdd 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -470,27 +470,28 @@
 
 					# Amount added through landed-cos-voucher
 					if d.landed_cost_voucher_amount and landed_cost_entries:
-						for account, amount in landed_cost_entries[(d.item_code, d.name)].items():
-							account_currency = get_account_currency(account)
-							credit_amount = (
-								flt(amount["base_amount"])
-								if (amount["base_amount"] or account_currency != self.company_currency)
-								else flt(amount["amount"])
-							)
+						if (d.item_code, d.name) in landed_cost_entries:
+							for account, amount in landed_cost_entries[(d.item_code, d.name)].items():
+								account_currency = get_account_currency(account)
+								credit_amount = (
+									flt(amount["base_amount"])
+									if (amount["base_amount"] or account_currency != self.company_currency)
+									else flt(amount["amount"])
+								)
 
-							self.add_gl_entry(
-								gl_entries=gl_entries,
-								account=account,
-								cost_center=d.cost_center,
-								debit=0.0,
-								credit=credit_amount,
-								remarks=remarks,
-								against_account=warehouse_account_name,
-								credit_in_account_currency=flt(amount["amount"]),
-								account_currency=account_currency,
-								project=d.project,
-								item=d,
-							)
+								self.add_gl_entry(
+									gl_entries=gl_entries,
+									account=account,
+									cost_center=d.cost_center,
+									debit=0.0,
+									credit=credit_amount,
+									remarks=remarks,
+									against_account=warehouse_account_name,
+									credit_in_account_currency=flt(amount["amount"]),
+									account_currency=account_currency,
+									project=d.project,
+									item=d,
+								)
 
 					if d.rate_difference_with_purchase_invoice and stock_rbnb:
 						account_currency = get_account_currency(stock_rbnb)
diff --git a/erpnext/stock/report/stock_balance/stock_balance.js b/erpnext/stock/report/stock_balance/stock_balance.js
index 33ed955..6de5f00 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.js
+++ b/erpnext/stock/report/stock_balance/stock_balance.js
@@ -72,6 +72,14 @@
 			"options": "Warehouse Type"
 		},
 		{
+			"fieldname": "valuation_field_type",
+			"label": __("Valuation Field Type"),
+			"fieldtype": "Select",
+			"width": "80",
+			"options": "Currency\nFloat",
+			"default": "Currency"
+		},
+		{
 			"fieldname":"include_uom",
 			"label": __("Include UOM"),
 			"fieldtype": "Link",
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index d60e9b5..1dafb4d 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -446,9 +446,12 @@
 				{
 					"label": _("Valuation Rate"),
 					"fieldname": "val_rate",
-					"fieldtype": "Float",
+					"fieldtype": self.filters.valuation_field_type or "Currency",
 					"width": 90,
 					"convertible": "rate",
+					"options": "Company:company:default_currency"
+					if self.filters.valuation_field_type == "Currency"
+					else None,
 				},
 				{
 					"label": _("Reserved Stock"),
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js
index 0def161..b00b422 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.js
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.js
@@ -82,7 +82,15 @@
 			"label": __("Include UOM"),
 			"fieldtype": "Link",
 			"options": "UOM"
-		}
+		},
+		{
+			"fieldname": "valuation_field_type",
+			"label": __("Valuation Field Type"),
+			"fieldtype": "Select",
+			"width": "80",
+			"options": "Currency\nFloat",
+			"default": "Currency"
+		},
 	],
 	"formatter": function (value, row, column, data, default_formatter) {
 		value = default_formatter(value, row, column, data);
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index ed28ed3..eeef396 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -196,17 +196,21 @@
 			{
 				"label": _("Avg Rate (Balance Stock)"),
 				"fieldname": "valuation_rate",
-				"fieldtype": "Float",
+				"fieldtype": filters.valuation_field_type,
 				"width": 180,
-				"options": "Company:company:default_currency",
+				"options": "Company:company:default_currency"
+				if filters.valuation_field_type == "Currency"
+				else None,
 				"convertible": "rate",
 			},
 			{
 				"label": _("Valuation Rate"),
 				"fieldname": "in_out_rate",
-				"fieldtype": "Float",
+				"fieldtype": filters.valuation_field_type,
 				"width": 140,
-				"options": "Company:company:default_currency",
+				"options": "Company:company:default_currency"
+				if filters.valuation_field_type == "Currency"
+				else None,
 				"convertible": "rate",
 			},
 			{
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index 0b14d4d..b7b3445 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -203,7 +203,10 @@
 		{
 			"Subcontracting Order": {
 				"doctype": "Subcontracting Receipt",
-				"field_map": {"supplier_warehouse": "supplier_warehouse"},
+				"field_map": {
+					"supplier_warehouse": "supplier_warehouse",
+					"set_warehouse": "set_warehouse",
+				},
 				"validation": {
 					"docstatus": ["=", 1],
 				},
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
index 6a2983f..22fdc13 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
@@ -591,6 +591,13 @@
 				for idx, val in enumerate(sco.items):
 					val.warehouse = warehouses[idx]
 
+	warehouses = set()
+	for item in sco.items:
+		warehouses.add(item.warehouse)
+
+	if len(warehouses) == 1:
+		sco.set_warehouse = list(warehouses)[0]
+
 	if not args.do_not_save:
 		sco.insert()
 		if not args.do_not_submit:
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..8a12e3b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -8,6 +8,7 @@
 import erpnext
 from erpnext.accounts.utils import get_account_currency
 from erpnext.controllers.subcontracting_controller import SubcontractingController
+from erpnext.stock.stock_ledger import get_valuation_rate
 
 
 class SubcontractingReceipt(SubcontractingController):
@@ -36,33 +37,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 +45,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 +54,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" and not frappe.flags.in_test:
+			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 +81,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 +103,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 +144,236 @@
 				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))
+					rate = (
+						get_valuation_rate(
+							scrap_item.item_code,
+							self.set_warehouse,
+							self.doctype,
+							self.name,
+							currency=erpnext.get_company_currency(self.company),
+							company=self.company,
+						)
+						or scrap_item.rate
+					)
+					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": rate,
+							"rm_cost_per_qty": 0,
+							"service_cost_per_qty": 0,
+							"additional_cost_per_qty": 0,
+							"scrap_cost_per_qty": 0,
+							"amount": qty * 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/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index a170527..1828f696 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -23,6 +23,7 @@
 	make_subcontracted_items,
 	set_backflush_based_on,
 )
+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.purchase_receipt.test_purchase_receipt import get_gl_entries
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@@ -507,8 +508,6 @@
 		self.assertEqual(scr.supplied_items[0].rate, sr.items[0].valuation_rate)
 
 	def test_subcontracting_receipt_raw_material_rate(self):
-		from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
-
 		# Step - 1: Set Backflush Based On as "BOM"
 		set_backflush_based_on("BOM")
 
@@ -625,6 +624,77 @@
 		# ValidationError should not be raised as `Inspection Required before Purchase` is disabled
 		scr2.submit()
 
+	def test_scrap_items_for_subcontracting_receipt(self):
+		set_backflush_based_on("BOM")
+
+		fg_item = "Subcontracted Item SA1"
+
+		# Create Raw Materials
+		raw_materials = [
+			make_item(properties={"is_stock_item": 1, "valuation_rate": 100}).name,
+			make_item(properties={"is_stock_item": 1, "valuation_rate": 200}).name,
+		]
+
+		# Create Scrap Items
+		scrap_item_1 = make_item(properties={"is_stock_item": 1, "valuation_rate": 10}).name
+		scrap_item_2 = make_item(properties={"is_stock_item": 1, "valuation_rate": 20}).name
+		scrap_items = [scrap_item_1, scrap_item_2]
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 1",
+				"qty": 10,
+				"rate": 100,
+				"fg_item": fg_item,
+				"fg_item_qty": 10,
+			},
+		]
+
+		# Create BOM with Scrap Items
+		bom = make_bom(
+			item=fg_item, raw_materials=raw_materials, rate=100, currency="INR", do_not_submit=True
+		)
+		for idx, item in enumerate(bom.items):
+			item.qty = 1 * (idx + 1)
+		for idx, item in enumerate(scrap_items):
+			bom.append(
+				"scrap_items",
+				{
+					"item_code": item,
+					"stock_qty": 1 * (idx + 1),
+					"rate": 10 * (idx + 1),
+				},
+			)
+		bom.save()
+		bom.submit()
+
+		# Create PO and SCO
+		sco = get_subcontracting_order(service_items=service_items)
+
+		# Inward Raw Materials
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+
+		# Transfer RM's to Subcontractor
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
+		)
+
+		# Create Subcontracting Receipt
+		scr = make_subcontracting_receipt(sco.name)
+		scr.save()
+		scr.get_scrap_items()
+
+		# Test - 1: Scrap Items should be fetched from BOM in items table with `is_scrap_item` = 1
+		scr_scrap_items = set([item.item_code for item in scr.items if item.is_scrap_item])
+		self.assertEqual(len(scr.items), 3)  # 1 FG Item + 2 Scrap Items
+		self.assertEqual(scr_scrap_items, set(scrap_items))
+
+		scr.submit()
+
 
 def make_return_subcontracting_receipt(**args):
 	args = frappe._dict(args)
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",