fix: incorrect scrap item qty
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 9926b15..e7eb9c6 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -2,7 +2,7 @@
 # License: GNU General Public License v3. See license.txt
 
 import frappe
-from frappe.utils import add_months, cint, flt, now, today
+from frappe.utils import add_days, add_months, cint, flt, now, today
 
 from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
 from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
@@ -12,6 +12,7 @@
 	OverProductionError,
 	StockOverProductionError,
 	close_work_order,
+	make_job_card,
 	make_stock_entry,
 	stop_unstop,
 )
@@ -804,6 +805,34 @@
 			if row.is_scrap_item:
 				self.assertEqual(row.qty, 1)
 
+		# Partial Job Card 1 with qty 10
+		wo_order = make_wo_order_test_record(item=item, company=company, planned_start_date=add_days(now(), 60), qty=20, skip_transfer=1)
+		job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name}, 'name')
+		update_job_card(job_card, 10)
+
+		stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+		for row in stock_entry.items:
+			if row.is_scrap_item:
+				self.assertEqual(row.qty, 2)
+
+		# Partial Job Card 2 with qty 10
+		operations = []
+		wo_order.load_from_db()
+		for row in wo_order.operations:
+			n_dict = row.as_dict()
+			n_dict['qty'] = 10
+			n_dict['pending_qty'] = 10
+			operations.append(n_dict)
+
+		make_job_card(wo_order.name, operations)
+		job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name, 'docstatus': 0}, 'name')
+		update_job_card(job_card, 10)
+
+		stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+		for row in stock_entry.items:
+			if row.is_scrap_item:
+				self.assertEqual(row.qty, 2)
+
 	def test_close_work_order(self):
 		items = ['Test FG Item for Closed WO', 'Test RM Item 1 for Closed WO',
 			'Test RM Item 2 for Closed WO']
@@ -883,7 +912,8 @@
 		self.assertEqual(wo1.operations[0].time_in_mins, wo2.operations[0].time_in_mins)
 
 
-def update_job_card(job_card):
+def update_job_card(job_card, jc_qty=None):
+	employee = frappe.db.get_value('Employee', {'status': 'Active'}, 'name')
 	job_card_doc = frappe.get_doc('Job Card', job_card)
 	job_card_doc.set('scrap_items', [
 		{
@@ -896,8 +926,12 @@
 		},
 	])
 
+	if jc_qty:
+		job_card_doc.for_quantity = jc_qty
+
 	job_card_doc.append('time_logs', {
 		'from_time': now(),
+		'employee': employee,
 		'time_in_mins': 60,
 		'completed_qty': job_card_doc.for_quantity
 	})
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 93e303c..8dcf48a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -8,6 +8,7 @@
 import frappe
 from frappe import _
 from frappe.model.mapper import get_mapped_doc
+from frappe.query_builder.functions import Sum
 from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate
 
 import erpnext
@@ -1275,22 +1276,29 @@
 		if not self.pro_doc:
 			self.set_work_order_details()
 
-		scrap_items = frappe.db.sql('''
-			SELECT
-				JCSI.item_code, JCSI.item_name, SUM(JCSI.stock_qty) as stock_qty, JCSI.stock_uom, JCSI.description
-			FROM
-				`tabJob Card` JC, `tabJob Card Scrap Item` JCSI
-			WHERE
-				JCSI.parent = JC.name AND JC.docstatus = 1
-				AND JCSI.item_code IS NOT NULL AND JC.work_order = %s
-			GROUP BY
-				JCSI.item_code
-		''', self.work_order, as_dict=1)
-
-		pending_qty = flt(self.pro_doc.qty) - flt(self.pro_doc.produced_qty)
-		if pending_qty <=0:
+		if not self.pro_doc.operations:
 			return []
 
+		job_card = frappe.qb.DocType('Job Card')
+		job_card_scrap_item = frappe.qb.DocType('Job Card Scrap Item')
+
+		scrap_items = (
+			frappe.qb.from_(job_card)
+			.select(
+				Sum(job_card_scrap_item.stock_qty).as_('stock_qty'),
+				job_card_scrap_item.item_code, job_card_scrap_item.item_name,
+				job_card_scrap_item.description, job_card_scrap_item.stock_uom)
+			.join(job_card_scrap_item)
+			.on(job_card_scrap_item.parent == job_card.name)
+			.where(
+				(job_card_scrap_item.item_code.isnotnull())
+				& (job_card.work_order == self.work_order)
+				& (job_card.docstatus == 1))
+			.groupby(job_card_scrap_item.item_code)
+		).run(as_dict=1)
+
+		pending_qty = flt(self.get_completed_job_card_qty()) - flt(self.pro_doc.produced_qty)
+
 		used_scrap_items = self.get_used_scrap_items()
 		for row in scrap_items:
 			row.stock_qty -= flt(used_scrap_items.get(row.item_code))
@@ -1304,6 +1312,9 @@
 
 		return scrap_items
 
+	def get_completed_job_card_qty(self):
+		return flt(min([d.completed_qty for d in self.pro_doc.operations]))
+
 	def get_used_scrap_items(self):
 		used_scrap_items = defaultdict(float)
 		data = frappe.get_all(