diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index fb64772479..ee0752549d 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -309,9 +309,12 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex make_work_order() { var me = this; - this.frm.call({ - doc: this.frm.doc, - method: 'get_work_order_items', + me.frm.call({ + method: "erpnext.selling.doctype.sales_order.sales_order.get_work_order_items", + args: { + sales_order: this.frm.docname, + }, + freeze: true, callback: function(r) { if(!r.message) { frappe.msgprint({ @@ -321,14 +324,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex }); return; } - else if(!r.message) { - frappe.msgprint({ - title: __('Work Order not created'), - message: __('Work Order already created for all items with BOM'), - indicator: 'orange' - }); - return; - } else { + else { const fields = [{ label: 'Items', fieldtype: 'Table', @@ -429,9 +425,9 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex make_raw_material_request() { var me = this; this.frm.call({ - doc: this.frm.doc, - method: 'get_work_order_items', + method: "erpnext.selling.doctype.sales_order.sales_order.get_work_order_items", args: { + sales_order: this.frm.docname, for_raw_material_request: 1 }, callback: function(r) { @@ -450,6 +446,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } make_raw_material_request_dialog(r) { + var me = this; var fields = [ {fieldtype:'Check', fieldname:'include_exploded_items', label: __('Include Exploded Items')}, diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index ca6a51a6f3..385d0f3a58 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -6,11 +6,12 @@ import json import frappe import frappe.utils -from frappe import _ +from frappe import _, qb from frappe.contacts.doctype.address.address import get_company_address from frappe.desk.notifications import clear_doctype_notifications from frappe.model.mapper import get_mapped_doc from frappe.model.utils import get_fetch_values +from frappe.query_builder.functions import Sum from frappe.utils import add_days, cint, cstr, flt, get_link_to_form, getdate, nowdate, strip_html from erpnext.accounts.doctype.sales_invoice.sales_invoice import ( @@ -414,51 +415,6 @@ class SalesOrder(SellingController): self.indicator_color = "green" self.indicator_title = _("Paid") - @frappe.whitelist() - def get_work_order_items(self, for_raw_material_request=0): - """Returns items with BOM that already do not have a linked work order""" - items = [] - item_codes = [i.item_code for i in self.items] - product_bundle_parents = [ - pb.new_item_code - for pb in frappe.get_all( - "Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"] - ) - ] - - for table in [self.items, self.packed_items]: - for i in table: - bom = get_default_bom(i.item_code) - stock_qty = i.qty if i.doctype == "Packed Item" else i.stock_qty - - if not for_raw_material_request: - total_work_order_qty = flt( - frappe.db.sql( - """select sum(qty) from `tabWork Order` - where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2""", - (i.item_code, self.name, i.name), - )[0][0] - ) - pending_qty = stock_qty - total_work_order_qty - else: - pending_qty = stock_qty - - if pending_qty and i.item_code not in product_bundle_parents: - items.append( - dict( - name=i.name, - item_code=i.item_code, - description=i.description, - bom=bom or "", - warehouse=i.warehouse, - pending_qty=pending_qty, - required_qty=pending_qty if for_raw_material_request else 0, - sales_order_item=i.name, - ) - ) - - return items - def on_recurring(self, reference_doc, auto_repeat_doc): def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_date): delivery_date = auto_repeat_doc.get_next_schedule_date(schedule_date=ref_doc_delivery_date) @@ -1350,3 +1306,57 @@ def update_produced_qty_in_so_item(sales_order, sales_order_item): return frappe.db.set_value("Sales Order Item", sales_order_item, "produced_qty", total_produced_qty) + + +@frappe.whitelist() +def get_work_order_items(sales_order, for_raw_material_request=0): + """Returns items with BOM that already do not have a linked work order""" + if sales_order: + so = frappe.get_doc("Sales Order", sales_order) + + wo = qb.DocType("Work Order") + + items = [] + item_codes = [i.item_code for i in so.items] + product_bundle_parents = [ + pb.new_item_code + for pb in frappe.get_all( + "Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"] + ) + ] + + for table in [so.items, so.packed_items]: + for i in table: + bom = get_default_bom(i.item_code) + stock_qty = i.qty if i.doctype == "Packed Item" else i.stock_qty + + if not for_raw_material_request: + total_work_order_qty = flt( + qb.from_(wo) + .select(Sum(wo.qty)) + .where( + (wo.production_item == i.item_code) + & (wo.sales_order == so.name) * (wo.sales_order_item == i.name) + & (wo.docstatus.lte(2)) + ) + .run()[0][0] + ) + pending_qty = stock_qty - total_work_order_qty + else: + pending_qty = stock_qty + + if pending_qty and i.item_code not in product_bundle_parents: + items.append( + dict( + name=i.name, + item_code=i.item_code, + description=i.description, + bom=bom or "", + warehouse=i.warehouse, + pending_qty=pending_qty, + required_qty=pending_qty if for_raw_material_request else 0, + sales_order_item=i.name, + ) + ) + + return items