refactor: shift auto entry of is process loss check, update validations
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index a5ce8c6..dd437dd 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -379,9 +379,6 @@
 			child.bom_no = '';
 		}
 
-		if (scrap_items) {
-			set_is_process_loss(doc, cdt, cdn)
-		}
 		get_bom_material_detail(doc, cdt, cdn, scrap_items);
 	}
 
@@ -450,9 +447,10 @@
 			callback: function(r) {
 				d = locals[cdt][cdn];
 				if (d.is_process_loss) {
-					r.message.rate = 0
-					r.message.base_rate = 0
+					r.message.rate = 0;
+					r.message.base_rate = 0;
 				}
+
 				$.extend(d, r.message);
 				refresh_field("items");
 				refresh_field("scrap_items");
@@ -661,12 +659,37 @@
 	if(!cint(frm.doc.with_operations)) {
 		frm.set_value("operations", []);
 	}
+	toggle_operations(frm);
 });
 
-function set_is_process_loss(doc, cdt, cdn) {
-	const row = locals[cdt][cdn]
-	if (row.item_code === doc.item) {
-		row.is_process_loss = 1
-		frappe.msgprint(__("Item:") + ` ${row.item_code} ` + __("set as process loss."))
-	}
+frappe.ui.form.on("BOM Scrap Item", {
+	item_code(frm, cdt, cdn) {
+		const { item_code } = locals[cdt][cdn];
+		if (item_code === frm.doc.item) {
+			locals[cdt][cdn].is_process_loss = 1;
+			trigger_process_loss_qty_prompt(frm, cdt, cdn, item_code)
+		}
+	},
+});
+
+function trigger_process_loss_qty_prompt(frm, cdt, cdn, item_code) {
+	frappe.prompt(
+		{
+			fieldname: "percent",
+			fieldtype: "Percent",
+			label: __("% Finished Item Quantity"),
+			description:
+				__("Set quantity of process loss item:") +
+				` ${item_code} ` +
+				__("as a percentage of finished item quantity"),
+		},
+		(data) => {
+			const row = locals[cdt][cdn];
+			row.stock_qty = (frm.doc.quantity * data.percent) / 100;
+			row.qty = row.stock_qty / (row.conversion_factor ?? 1);
+			refresh_field("scrap_items");
+		},
+		__("Set Process Loss Item Quantity"),
+		__("Set Quantity")
+	);
 }
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index de0c521..b90d54d 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -695,11 +695,25 @@
 	def validate_scrap_items(self):
 		for item in self.scrap_items:
 			if item.item_code == self.item and not item.is_process_loss:
-				frappe.throw(_('Item:') + f' {item.item_code} ' +\
-					_('in Scrap/Loss Items table should have Is Process Loss checked.'))
+				frappe.throw(_('Scrap/Loss Item:') + f' {frappe.bold(item.item_code)} ' +\
+					_('should have') + ' ' + frappe.bold(_('Is Process Loss')) + ' ' + ('checked.'))
 			elif item.item_code != self.item and item.is_process_loss:
-				frappe.throw(_('Item:') + f' {item.item_code} ' +\
-					_('in Scrap/Loss Items table should not have Is Process Loss checked.'))
+				frappe.throw(_('Scrap/Loss Item:') + f' {frappe.bold(item.item_code)} ' +\
+					_('should not have') + ' ' + frappe.bold(_('Is Process Loss')) + ' ' + ('checked.'))
+
+			stock_uom = item.stock_uom
+			must_be_whole_number = frappe.get_value("UOM", stock_uom, "must_be_whole_number")
+			if item.is_process_loss and must_be_whole_number:
+				frappe.throw(_('Item:') + f' {frappe.bold(item.item_code)} ' +\
+					_('with Stock UOM:') + f' {frappe.bold(stock_uom)} '+\
+					_('cannot be a Scrap/Loss Item.'))
+
+			if item.is_process_loss and (item.stock_qty >= self.quantity):
+				frappe.throw(_('Scrap/Loss Item:') + f' {item.item_code} ' +\
+					_('should have') +' '+frappe.bold(_('Qty')) +\
+					' ' + _('less than finished goods') + ' ' +\
+					frappe.bold(_('Quantity.')))
+
 
 def get_bom_item_rate(args, bom_doc):
 	if bom_doc.rm_cost_as_per == 'Valuation Rate':