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(