From 7871dddca4fbf124362443d9b616bb47f50e9cbb Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Fri, 17 May 2024 21:04:04 +0200 Subject: [PATCH] fix: Sales order js controller issues --- .../doctype/sales_order/sales_order.js | 897 ++++++++++-------- 1 file changed, 494 insertions(+), 403 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 18178ca547..6c8b21b330 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -8,59 +8,60 @@ erpnext.accounts.taxes.setup_tax_validations("Sales Order"); erpnext.sales_common.setup_selling_controller(); frappe.ui.form.on("Sales Order", { - setup: function(frm) { + setup: function (frm) { frm.custom_make_buttons = { - 'Delivery Note': 'Delivery Note', - 'Pick List': 'Pick List', - 'Sales Invoice': 'Sales Invoice', - 'Material Request': 'Material Request', - 'Purchase Order': 'Purchase Order', - 'Project': 'Project', - 'Payment Entry': "Payment", - 'Work Order': "Work Order" - } - frm.add_fetch('customer', 'tax_id', 'tax_id'); + "Delivery Note": "Delivery Note", + "Pick List": "Pick List", + "Sales Invoice": "Sales Invoice", + "Material Request": "Material Request", + "Purchase Order": "Purchase Order", + Project: "Project", + "Payment Entry": "Payment", + "Work Order": "Work Order", + }; + frm.add_fetch("customer", "tax_id", "tax_id"); // formatter for material request item - frm.set_indicator_formatter('item_code', - function(doc) { return (doc.stock_qty<=doc.delivered_qty) ? "green" : "orange" }) + frm.set_indicator_formatter("item_code", function (doc) { + return doc.stock_qty <= doc.delivered_qty ? "green" : "orange"; + }); - frm.set_query('company_address', function(doc) { - if(!doc.company) { - frappe.throw(__('Please set Company')); + frm.set_query("company_address", function (doc) { + if (!doc.company) { + frappe.throw(__("Please set Company")); } return { - query: 'frappe.contacts.doctype.address.address.address_query', + query: "frappe.contacts.doctype.address.address.address_query", filters: { - link_doctype: 'Company', - link_name: doc.company - } + link_doctype: "Company", + link_name: doc.company, + }, }; - }) + }); - frm.set_query("bom_no", "items", function(doc, cdt, cdn) { + frm.set_query("bom_no", "items", function (doc, cdt, cdn) { var row = locals[cdt][cdn]; return { filters: { - "item": row.item_code - } - } + item: row.item_code, + }, + }; }); let item_booking_field = frm.get_docfield("items", "item_booking"); if (item_booking_field) { - item_booking_field.get_route_options_for_new_doc = function(row) { + item_booking_field.get_route_options_for_new_doc = function (row) { return { - "item": row.doc.item_code, - "starts_on": row.doc.delivery_date, - "ends_on": row.doc.delivery_date - } + item: row.doc.item_code, + starts_on: row.doc.delivery_date, + ends_on: row.doc.delivery_date, + }; }; } - frm.set_df_property('packed_items', 'cannot_add_rows', true); - frm.set_df_property('packed_items', 'cannot_delete_rows', true); + frm.set_df_property("packed_items", "cannot_add_rows", true); + frm.set_df_property("packed_items", "cannot_delete_rows", true); }, refresh: function (frm) { @@ -77,8 +78,8 @@ frappe.ui.form.on("Sales Order", { child_docname: "items", child_doctype: "Sales Order Detail", cannot_add_row: false, - has_reserved_stock: frm.doc.__onload && frm.doc.__onload.has_reserved_stock - }) + has_reserved_stock: frm.doc.__onload && frm.doc.__onload.has_reserved_stock, + }); }); // Stock Reservation > Reserve button should only be visible if the SO has unreserved stock and no Pick List is created against the SO. @@ -206,34 +207,25 @@ frappe.ui.form.on("Sales Order", { } else { frm.set_value("company_address", ""); } - ], - get_query_filters: { - company: frm.doc.company, - is_internal_supplier: 1, - docstatus: 1, - status: ['!=', 'Completed'] - } + }, }); - }, __('Get items from')); + } }, - onload: function(frm) { - if (!frm.doc.transaction_date){ - frm.set_value('transaction_date', frappe.datetime.get_today()) + + onload: function (frm) { + if (!frm.doc.transaction_date) { + frm.set_value("transaction_date", frappe.datetime.get_today()); } - erpnext.queries.setup_queries(frm, "Warehouse", function() { + erpnext.queries.setup_queries(frm, "Warehouse", function () { return { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ] + filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]], }; }); - frm.set_query('warehouse', 'items', function(doc, cdt, cdn) { - let row = locals[cdt][cdn]; + frm.set_query("warehouse", "items", function (doc, cdt, cdn) { + let row = locals[cdt][cdn]; let query = { - filters: [ - ["Warehouse", "company", "in", ["", cstr(frm.doc.company)]], - ] + filters: [["Warehouse", "company", "in", ["", cstr(frm.doc.company)]]], }; if (row.item_code) { query.query = "erpnext.controllers.queries.warehouse_query"; @@ -244,25 +236,30 @@ frappe.ui.form.on("Sales Order", { // On cancel and amending a sales order with advance payment, reset advance paid amount if (frm.is_new()) { - frm.set_value("advance_paid", 0) + frm.set_value("advance_paid", 0); } - frm.ignore_doctypes_on_cancel_all = ['Purchase Order']; + frm.ignore_doctypes_on_cancel_all = ["Purchase Order"]; }, - delivery_date: function(frm) { - $.each(frm.doc.items || [], function(i, d) { - if(!d.delivery_date) d.delivery_date = frm.doc.delivery_date; + delivery_date: function (frm) { + $.each(frm.doc.items || [], function (i, d) { + if (!d.delivery_date) d.delivery_date = frm.doc.delivery_date; }); refresh_field("items"); if (frm.doc.items?.length && frm.doc.delivery_date) { // @dokos - frappe.confirm(__("Update delivery date for all items?"), () => { - for (const d of (frm.doc.items || [])) { - frappe.model.set_value(d.doctype, d.name, "delivery_date", frm.doc.delivery_date); - } - }, null, { title: __("Delivery Date") }); + frappe.confirm( + __("Update delivery date for all items?"), + () => { + for (const d of frm.doc.items || []) { + frappe.model.set_value(d.doctype, d.name, "delivery_date", frm.doc.delivery_date); + } + }, + null, + { title: __("Delivery Date") } + ); } }, @@ -279,9 +276,7 @@ frappe.ui.form.on("Sales Order", { default: frm.doc.set_warehouse, get_query: () => { return { - filters: [ - ["Warehouse", "is_group", "!=", 1] - ] + filters: [["Warehouse", "is_group", "!=", 1]], }; }, onchange: () => { @@ -293,7 +288,7 @@ frappe.ui.form.on("Sales Order", { } }, }, - {fieldtype: "Column Break"}, + { fieldtype: "Column Break" }, { fieldname: "add_item", fieldtype: "Link", @@ -303,19 +298,24 @@ frappe.ui.form.on("Sales Order", { return { query: "erpnext.controllers.queries.get_filtered_child_rows", filters: { - "parenttype": frm.doc.doctype, - "parent": frm.doc.name, - "reserve_stock": 1, - } - } + parenttype: frm.doc.doctype, + parent: frm.doc.name, + reserve_stock: 1, + }, + }; }, onchange: () => { let sales_order_item = dialog.get_value("add_item"); if (sales_order_item) { - frm.doc.items.forEach(item => { + frm.doc.items.forEach((item) => { if (item.name === sales_order_item) { - let unreserved_qty = (flt(item.stock_qty) - (item.stock_reserved_qty ? flt(item.stock_reserved_qty) : (flt(item.delivered_qty) * flt(item.conversion_factor)))) / flt(item.conversion_factor); + let unreserved_qty = + (flt(item.stock_qty) - + (item.stock_reserved_qty + ? flt(item.stock_reserved_qty) + : flt(item.delivered_qty) * flt(item.conversion_factor))) / + flt(item.conversion_factor); if (unreserved_qty > 0) { dialog.fields_dict.items.df.data.forEach((row) => { @@ -326,10 +326,10 @@ frappe.ui.form.on("Sales Order", { } dialog.fields_dict.items.df.data.push({ - 'sales_order_item': item.name, - 'item_code': item.item_code, - 'warehouse': dialog.get_value("set_warehouse") || item.warehouse, - 'qty_to_reserve': Math.max(unreserved_qty, 0) + sales_order_item: item.name, + item_code: item.item_code, + warehouse: dialog.get_value("set_warehouse") || item.warehouse, + qty_to_reserve: Math.max(unreserved_qty, 0), }); dialog.fields_dict.items.grid.refresh(); dialog.set_value("add_item", undefined); @@ -338,7 +338,7 @@ frappe.ui.form.on("Sales Order", { } }, }, - {fieldtype: "Section Break"}, + { fieldtype: "Section Break" }, { fieldname: "items", fieldtype: "Table", @@ -359,25 +359,26 @@ frappe.ui.form.on("Sales Order", { return { query: "erpnext.controllers.queries.get_filtered_child_rows", filters: { - "parenttype": frm.doc.doctype, - "parent": frm.doc.name, - "reserve_stock": 1, - } - } + parenttype: frm.doc.doctype, + parent: frm.doc.name, + reserve_stock: 1, + }, + }; }, onchange: (event) => { if (event) { let name = $(event.currentTarget).closest(".grid-row").attr("data-name"); - let item_row = dialog.fields_dict.items.grid.grid_rows_by_docname[name].doc; + let item_row = + dialog.fields_dict.items.grid.grid_rows_by_docname[name].doc; - frm.doc.items.forEach(item => { + frm.doc.items.forEach((item) => { if (item.name === item_row.sales_order_item) { item_row.item_code = item.item_code; } }); dialog.fields_dict.items.grid.refresh(); } - } + }, }, { fieldname: "item_code", @@ -397,9 +398,7 @@ frappe.ui.form.on("Sales Order", { in_list_view: 1, get_query: () => { return { - filters: [ - ["Warehouse", "is_group", "!=", 1] - ] + filters: [["Warehouse", "is_group", "!=", 1]], }; }, }, @@ -408,8 +407,8 @@ frappe.ui.form.on("Sales Order", { fieldtype: "Float", label: __("Qty"), reqd: 1, - in_list_view: 1 - } + in_list_view: 1, + }, ], }, ], @@ -423,14 +422,14 @@ frappe.ui.form.on("Sales Order", { method: "create_stock_reservation_entries", args: { items_details: data.items, - notify: true + notify: true, }, freeze: true, freeze_message: __("Reserving Stock..."), callback: (r) => { frm.doc.__onload.has_unreserved_stock = false; frm.reload_doc(); - } + }, }); dialog.hide(); @@ -440,9 +439,14 @@ frappe.ui.form.on("Sales Order", { }, }); - frm.doc.items.forEach(item => { + frm.doc.items.forEach((item) => { if (item.reserve_stock) { - let unreserved_qty = (flt(item.stock_qty) - (item.stock_reserved_qty ? flt(item.stock_reserved_qty) : (flt(item.delivered_qty) * flt(item.conversion_factor)))) / flt(item.conversion_factor); + let unreserved_qty = + (flt(item.stock_qty) - + (item.stock_reserved_qty + ? flt(item.stock_reserved_qty) + : flt(item.delivered_qty) * flt(item.conversion_factor))) / + flt(item.conversion_factor); if (unreserved_qty > 0) { dialog.fields_dict.items.df.data.push({ @@ -508,10 +512,10 @@ frappe.ui.form.on("Sales Order", { label: __("Qty"), reqd: 1, read_only: 1, - in_list_view: 1 - } - ] - } + in_list_view: 1, + }, + ], + }, ], primary_action_label: __("Unreserve Stock"), primary_action: () => { @@ -522,14 +526,14 @@ frappe.ui.form.on("Sales Order", { doc: frm.doc, method: "cancel_stock_reservation_entries", args: { - sre_list: data.sr_entries.map(item => item.sre), + sre_list: data.sr_entries.map((item) => item.sre), }, freeze: true, - freeze_message: __('Unreserving Stock...'), + freeze_message: __("Unreserving Stock..."), callback: (r) => { frm.doc.__onload.has_reserved_stock = false; frm.reload_doc(); - } + }, }); dialog.hide(); @@ -539,35 +543,39 @@ frappe.ui.form.on("Sales Order", { }, }); - frappe.call({ - method: 'erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry.get_stock_reservation_entries_for_voucher', - args: { - voucher_type: frm.doctype, - voucher_no: frm.docname, - }, - callback: (r) => { - if (!r.exc && r.message) { - r.message.forEach(sre => { - if (flt(sre.reserved_qty) > flt(sre.delivered_qty)) { - dialog.fields_dict.sr_entries.df.data.push({ - 'sre': sre.name, - 'item_code': sre.item_code, - 'warehouse': sre.warehouse, - 'qty': (flt(sre.reserved_qty) - flt(sre.delivered_qty)) - }); - } - }); - } - } - }).then(r => { - dialog.fields_dict.sr_entries.grid.refresh(); - dialog.show(); - }); + frappe + .call({ + method: "erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry.get_stock_reservation_entries_for_voucher", + args: { + voucher_type: frm.doctype, + voucher_no: frm.docname, + }, + callback: (r) => { + if (!r.exc && r.message) { + r.message.forEach((sre) => { + if (flt(sre.reserved_qty) > flt(sre.delivered_qty)) { + dialog.fields_dict.sr_entries.df.data.push({ + sre: sre.name, + item_code: sre.item_code, + warehouse: sre.warehouse, + qty: flt(sre.reserved_qty) - flt(sre.delivered_qty), + }); + } + }); + } + }, + }) + .then((r) => { + dialog.fields_dict.sr_entries.grid.refresh(); + dialog.show(); + }); }, show_reserved_stock(frm) { // Get the latest modified date from the items table. - var to_date = moment(new Date(Math.max(...frm.doc.items.map(e => new Date(e.modified))))).format('YYYY-MM-DD'); + var to_date = moment(new Date(Math.max(...frm.doc.items.map((e) => new Date(e.modified))))).format( + "YYYY-MM-DD" + ); frappe.route_options = { company: frm.doc.company, @@ -575,32 +583,36 @@ frappe.ui.form.on("Sales Order", { to_date: to_date, voucher_type: frm.doc.doctype, voucher_no: frm.doc.name, - } + }; frappe.set_route("query-report", "Reserved Stock"); }, add_header_for_recurring_sales(frm) { // @dokos - if (!frm.__islocal && frm.doc.items.filter(f => f.is_recurring_item).length) { + if (!frm.__islocal && frm.doc.items.filter((f) => f.is_recurring_item).length) { if (frm.doc.docstatus == 0) { - frm.dashboard.clear_headline() + frm.dashboard.clear_headline(); frm.dashboard.set_headline_alert( - __("This order contains some recurring items.
A subscription will be automatically generated on submission if a recurring period is set."), + __( + "This order contains some recurring items.
A subscription will be automatically generated on submission if a recurring period is set." + ), "orange" - ) + ); } else if (frm.doc.subscription) { - frm.dashboard.clear_headline() + frm.dashboard.clear_headline(); frm.dashboard.set_headline_alert( - __("This order contains some recurring items and is linked to subscription {0}", [frm.doc.subscription]), + __("This order contains some recurring items and is linked to subscription {0}", [ + frm.doc.subscription, + ]), "green" - ) + ); } } - } + }, }); frappe.ui.form.on("Sales Order Item", { - item_code: function(frm,cdt,cdn) { + item_code: function (frm, cdt, cdn) { var row = locals[cdt][cdn]; if (frm.doc.delivery_date) { row.delivery_date = frm.doc.delivery_date; @@ -609,15 +621,15 @@ frappe.ui.form.on("Sales Order Item", { frm.script_manager.copy_from_first_row("items", row, ["delivery_date"]); } }, - delivery_date: function(frm, cdt, cdn) { - if(!frm.doc.delivery_date) { + delivery_date: function (frm, cdt, cdn) { + if (!frm.doc.delivery_date) { erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "items", "delivery_date"); } }, - items_add: function(frm, cdt, cdn) { + items_add: function (frm, cdt, cdn) { // @dokos const row = frappe.get_doc(cdt, cdn); - if(frm.doc.delivery_date && !row.delivery_date) { + if (frm.doc.delivery_date && !row.delivery_date) { frappe.model.set_value(row.doctype, row.name, "delivery_date", frm.doc.delivery_date); } }, @@ -633,38 +645,54 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex super.refresh(); let allow_delivery = false; - if(doc.docstatus==1) { - - if(this.frm.has_perm("submit")) { - if(doc.status === 'On Hold') { - // un-hold - this.frm.add_custom_button(__('Resume'), function() { - me.frm.cscript.update_status('Resume', 'Draft') - }, __("Status")); + if (doc.docstatus == 1) { + if (this.frm.has_perm("submit")) { + if (doc.status === "On Hold") { + // un-hold + this.frm.add_custom_button( + __("Resume"), + function () { + me.frm.cscript.update_status("Resume", "Draft"); + }, + __("Status") + ); - if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { - // close - this.frm.add_custom_button(__('Close'), () => this.close_sales_order(), __("Status")) - } + if (flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { + // close + this.frm.add_custom_button(__("Close"), () => this.close_sales_order(), __("Status")); + } + } else if (doc.status === "Closed") { + // un-close + this.frm.add_custom_button( + __("Re-open"), + function () { + me.frm.cscript.update_status("Re-open", "Draft"); + }, + __("Status") + ); } - else if(doc.status === 'Closed') { - // un-close - this.frm.add_custom_button(__('Re-open'), function() { - me.frm.cscript.update_status('Re-open', 'Draft') - }, __("Status")); - } } - if(doc.status !== 'Closed') { - if(doc.status !== 'On Hold') { - allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty)) - && !this.frm.doc.skip_delivery_note + if (doc.status !== "Closed") { + if (doc.status !== "On Hold") { + allow_delivery = + this.frm.doc.items.some( + (item) => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty) + ) && !this.frm.doc.skip_delivery_note; if (this.frm.has_perm("submit")) { - if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { + if (flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed, 2) < 100) { // hold - this.frm.add_custom_button(__('Hold'), () => this.hold_sales_order(), __("Status")) + this.frm.add_custom_button( + __("Hold"), + () => this.hold_sales_order(), + __("Status") + ); // close - this.frm.add_custom_button(__('Close'), () => this.close_sales_order(), __("Status")) + this.frm.add_custom_button( + __("Close"), + () => this.close_sales_order(), + __("Status") + ); } } @@ -684,7 +712,8 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex const order_is_a_sale = ["Sales", "Shopping Cart"].indexOf(doc.order_type) !== -1; const order_is_maintenance = ["Maintenance"].indexOf(doc.order_type) !== -1; // order type has been customised then show all the action buttons - const order_is_a_custom_sale = ["Sales", "Shopping Cart", "Maintenance"].indexOf(doc.order_type) === -1; + const order_is_a_custom_sale = + ["Sales", "Shopping Cart", "Maintenance"].indexOf(doc.order_type) === -1; // delivery note if ( @@ -777,12 +806,18 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex let me = this; let internal = me.frm.doc.is_internal_customer; if (internal) { - let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Order" : - "Inter Company Purchase Order"; - - me.frm.add_custom_button(button_label, function() { - me.make_inter_company_order(); - }, __('Create')); + let button_label = + me.frm.doc.company === me.frm.doc.represents_company + ? "Internal Purchase Order" + : "Inter Company Purchase Order"; + + me.frm.add_custom_button( + button_label, + function () { + me.make_inter_company_order(); + }, + __("Create") + ); } } } @@ -807,7 +842,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex ); } } - this.frm.page.set_inner_btn_group_as_primary(__('Create')); + this.frm.page.set_inner_btn_group_as_primary(__("Create")); } } @@ -825,14 +860,14 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex fieldname: "party_name", fieldtype: "Link", options: "Customer", - default: me.frm.doc.customer || undefined - } + default: me.frm.doc.customer || undefined, + }, ], get_query_filters: { company: me.frm.doc.company, docstatus: 1, - status: ["!=", "Lost"] - } + status: ["!=", "Lost"], + }, }); }, __("Get Items From") @@ -845,8 +880,8 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex create_pick_list() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.create_pick_list", - frm: this.frm - }) + frm: this.frm, + }); } make_work_order() { @@ -857,86 +892,99 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex sales_order: this.frm.docname, }, freeze: true, - callback: function(r) { - if(!r.message) { + callback: function (r) { + if (!r.message) { frappe.msgprint({ - title: __('Work Order not created'), - message: __('No Items with Bill of Materials to Manufacture'), - indicator: 'orange' + title: __("Work Order not created"), + message: __("No Items with Bill of Materials to Manufacture"), + indicator: "orange", }); return; - } - else { - const fields = [{ - label: 'Items', - fieldtype: 'Table', - fieldname: 'items', - description: __('Select BOM and Qty for Production'), - fields: [{ - fieldtype: 'Read Only', - fieldname: 'item_code', - label: __('Item Code'), - in_list_view: 1 - }, { - fieldtype: 'Link', - fieldname: 'bom', - options: 'BOM', - reqd: 1, - label: __('Select BOM'), - in_list_view: 1, - get_query: function (doc) { - return { filters: { item: doc.item_code } }; - } - }, { - fieldtype: 'Float', - fieldname: 'pending_qty', - reqd: 1, - label: __('Qty'), - in_list_view: 1 - }, { - fieldtype: 'Data', - fieldname: 'sales_order_item', - reqd: 1, - label: __('Sales Order Item'), - hidden: 1 - }], - data: r.message, - get_data: () => { - return r.message - } - }] + } else { + const fields = [ + { + label: "Items", + fieldtype: "Table", + fieldname: "items", + description: __("Select BOM and Qty for Production"), + fields: [ + { + fieldtype: "Read Only", + fieldname: "item_code", + label: __("Item Code"), + in_list_view: 1, + }, + { + fieldtype: "Link", + fieldname: "bom", + options: "BOM", + reqd: 1, + label: __("Select BOM"), + in_list_view: 1, + get_query: function (doc) { + return { filters: { item: doc.item_code } }; + }, + }, + { + fieldtype: "Float", + fieldname: "pending_qty", + reqd: 1, + label: __("Qty"), + in_list_view: 1, + }, + { + fieldtype: "Data", + fieldname: "sales_order_item", + reqd: 1, + label: __("Sales Order Item"), + hidden: 1, + }, + ], + data: r.message, + get_data: () => { + return r.message; + }, + }, + ]; var d = new frappe.ui.Dialog({ - title: __('Select Items to Manufacture'), + title: __("Select Items to Manufacture"), fields: fields, - primary_action: function() { - var data = {items: d.fields_dict.items.grid.get_selected_children()}; + primary_action: function () { + var data = { items: d.fields_dict.items.grid.get_selected_children() }; me.frm.call({ - method: 'make_work_orders', + method: "make_work_orders", args: { items: data, company: me.frm.doc.company, sales_order: me.frm.docname, - project: me.frm.project + project: me.frm.project, }, freeze: true, - callback: function(r) { - if(r.message) { + callback: function (r) { + if (r.message) { frappe.msgprint({ - message: __('Work Orders Created: {0}', [r.message.map(function(d) { - return repl('%(name)s', {name:d}) - }).join(', ')]), - indicator: 'green' - }) + message: __("Work Orders Created: {0}", [ + r.message + .map(function (d) { + return repl( + '%(name)s', + { name: d } + ); + }) + .join(", "), + ]), + indicator: "green", + }); } d.hide(); - } + }, }); }, - primary_action_label: __('Create') + primary_action_label: __("Create"), }); d.show(); } - } + }, }); } @@ -951,17 +999,19 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex make_material_request() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request", - frm: this.frm - }) + frm: this.frm, + }); } skip_delivery_note() { this.toggle_delivery_date(); } - toggle_delivery_date() { - this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", - (this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note)); + toggle_delivery_date() { + this.frm.fields_dict.items.grid.toggle_reqd( + "delivery_date", + this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note + ); } make_raw_material_request() { @@ -970,104 +1020,135 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex method: "erpnext.selling.doctype.sales_order.sales_order.get_work_order_items", args: { sales_order: this.frm.docname, - for_raw_material_request: 1 + for_raw_material_request: 1, }, - callback: function(r) { - if(!r.message) { + callback: function (r) { + if (!r.message) { frappe.msgprint({ - message: __('No Items with Bill of Materials.'), - indicator: 'orange' + message: __("No Items with Bill of Materials."), + indicator: "orange", }); return; - } - else { + } else { me.make_raw_material_request_dialog(r); } - } + }, }); } make_raw_material_request_dialog(r) { var me = this; var fields = [ - {fieldtype:'Check', fieldname:'include_exploded_items', - label: __('Include Exploded Items')}, - {fieldtype:'Check', fieldname:'ignore_existing_ordered_qty', - label: __('Ignore Existing Ordered Qty')}, + { fieldtype: "Check", fieldname: "include_exploded_items", label: __("Include Exploded Items") }, + { + fieldtype: "Check", + fieldname: "ignore_existing_ordered_qty", + label: __("Ignore Existing Ordered Qty"), + }, { - fieldtype:'Table', fieldname: 'items', - description: __('Select BOM, Qty and For Warehouse'), + fieldtype: "Table", + fieldname: "items", + description: __("Select BOM, Qty and For Warehouse"), fields: [ - {fieldtype:'Read Only', fieldname:'item_code', - label: __('Item Code'), in_list_view:1}, - {fieldtype:'Link', fieldname:'warehouse', options: 'Warehouse', - label: __('For Warehouse'), in_list_view:1}, - {fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1, - label: __('BOM'), in_list_view:1, get_query: function(doc) { - return {filters: {item: doc.item_code}}; - } + { + fieldtype: "Read Only", + fieldname: "item_code", + label: __("Item Code"), + in_list_view: 1, + }, + { + fieldtype: "Link", + fieldname: "warehouse", + options: "Warehouse", + label: __("For Warehouse"), + in_list_view: 1, + }, + { + fieldtype: "Link", + fieldname: "bom", + options: "BOM", + reqd: 1, + label: __("BOM"), + in_list_view: 1, + get_query: function (doc) { + return { filters: { item: doc.item_code } }; + }, + }, + { + fieldtype: "Float", + fieldname: "required_qty", + reqd: 1, + label: __("Qty"), + in_list_view: 1, }, - {fieldtype:'Float', fieldname:'required_qty', reqd: 1, - label: __('Qty'), in_list_view:1}, ], data: r.message, - get_data: function() { - return r.message - } - } - ] + get_data: function () { + return r.message; + }, + }, + ]; var d = new frappe.ui.Dialog({ title: __("Items for Raw Material Request"), fields: fields, - primary_action: function() { + primary_action: function () { var data = d.get_values(); me.frm.call({ - method: 'erpnext.selling.doctype.sales_order.sales_order.make_raw_material_request', + method: "erpnext.selling.doctype.sales_order.sales_order.make_raw_material_request", args: { items: data, company: me.frm.doc.company, sales_order: me.frm.docname, - project: me.frm.project + project: me.frm.project, }, freeze: true, - callback: function(r) { - if(r.message) { - frappe.msgprint(__('Material Request {0} submitted.', - ['' + r.message.name+ ''])); + callback: function (r) { + if (r.message) { + frappe.msgprint( + __("Material Request {0} submitted.", [ + '' + + r.message.name + + "", + ]) + ); } d.hide(); me.frm.reload_doc(); - } + }, }); }, - primary_action_label: __('Create') + primary_action_label: __("Create"), }); d.show(); } - make_delivery_note_based_on_delivery_date(for_reserved_stock=false) { + make_delivery_note_based_on_delivery_date(for_reserved_stock = false) { var me = this; - var delivery_dates = this.frm.doc.items.map(i => i.delivery_date); - delivery_dates = [ ...new Set(delivery_dates) ]; + var delivery_dates = this.frm.doc.items.map((i) => i.delivery_date); + delivery_dates = [...new Set(delivery_dates)]; var today = new Date(); var item_grid = this.frm.fields_dict["items"].grid; - if(!item_grid.get_selected().length && delivery_dates.length > 1) { + if (!item_grid.get_selected().length && delivery_dates.length > 1) { var dialog = new frappe.ui.Dialog({ title: __("Select Items based on Delivery Date"), - fields: [{fieldtype: "HTML", fieldname: "dates_html"}] + fields: [{ fieldtype: "HTML", fieldname: "dates_html" }], }); var html = $(`
- ${__('Delivery Date')} + ${__("Delivery Date")}
- ${delivery_dates.map(date => ` + ${delivery_dates + .map( + (date) => `
- `).join("")} + ` + ) + .join("")}
`); var wrapper = dialog.fields_dict.dates_html.$wrapper; wrapper.html(html); - dialog.set_primary_action(__("Select"), function() { - var dates = wrapper.find('input[type=checkbox]:checked') - .map((i, el) => $(el).attr('data-date')).toArray(); + dialog.set_primary_action(__("Select"), function () { + var dates = wrapper + .find("input[type=checkbox]:checked") + .map((i, el) => $(el).attr("data-date")) + .toArray(); - if(!dates) return; + if (!dates) return; me.make_delivery_note(dates, for_reserved_stock); dialog.hide(); @@ -1102,61 +1187,64 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex } } - make_delivery_note(delivery_dates, for_reserved_stock=false) { + make_delivery_note(delivery_dates, for_reserved_stock = false) { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note", frm: this.frm, args: { delivery_dates, - for_reserved_stock: for_reserved_stock + for_reserved_stock: for_reserved_stock, }, freeze: true, - freeze_message: __("Creating Delivery Note ...") - }) + freeze_message: __("Creating Delivery Note ..."), + }); } make_sales_invoice() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice", - frm: this.frm - }) + frm: this.frm, + }); } make_maintenance_schedule() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule", - frm: this.frm - }) + frm: this.frm, + }); } make_project() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_project", - frm: this.frm - }) + frm: this.frm, + }); } make_inter_company_order() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_inter_company_purchase_order", - frm: this.frm + frm: this.frm, }); } make_maintenance_visit() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit", - frm: this.frm - }) + frm: this.frm, + }); } - make_purchase_order(){ - let pending_items = this.frm.doc.items.some((item) =>{ + make_purchase_order() { + let pending_items = this.frm.doc.items.some((item) => { let pending_qty = flt(item.stock_qty) - flt(item.ordered_qty); return item.item_code && pending_qty > 0; // @dokos - }) - if(!pending_items){ - frappe.throw({message: __("Purchase Order already created for all Sales Order items"), title: __("Note")}); + }); + if (!pending_items) { + frappe.throw({ + message: __("Purchase Order already created for all Sales Order items"), + title: __("Note"), + }); } var me = this; @@ -1165,88 +1253,95 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex size: "large", fields: [ { - "fieldtype": "Check", - "label": __("Against Default Supplier"), - "fieldname": "against_default_supplier", - "default": 0 + fieldtype: "Check", + label: __("Against Default Supplier"), + fieldname: "against_default_supplier", + default: 0, }, { - fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items', + fieldname: "items_for_po", + fieldtype: "Table", + label: "Select Items", fields: [ { - fieldtype:'Data', - fieldname:'item_code', - label: __('Item'), - read_only:1, - in_list_view:1 + fieldtype: "Data", + fieldname: "item_code", + label: __("Item"), + read_only: 1, + in_list_view: 1, }, { - fieldtype:'Data', - fieldname:'item_name', - label: __('Item name'), - read_only:1, - in_list_view:1 + fieldtype: "Data", + fieldname: "item_name", + label: __("Item name"), + read_only: 1, + in_list_view: 1, }, { - fieldtype:'Float', - fieldname:'pending_qty', - label: __('Pending Qty'), + fieldtype: "Float", + fieldname: "pending_qty", + label: __("Pending Qty"), read_only: 1, - in_list_view:1 + in_list_view: 1, }, { - fieldtype:'Link', - read_only:1, - fieldname:'uom', - label: __('UOM'), - in_list_view:1, + fieldtype: "Link", + read_only: 1, + fieldname: "uom", + label: __("UOM"), + in_list_view: 1, }, { - fieldtype:'Data', - fieldname:'supplier', - label: __('Supplier'), - read_only:1, - in_list_view:1 + fieldtype: "Data", + fieldname: "supplier", + label: __("Supplier"), + read_only: 1, + in_list_view: 1, }, - ] - } + ], + }, ], - primary_action_label: __('Create Purchase Order'), - primary_action (args) { + primary_action_label: __("Create Purchase Order"), + primary_action(args) { if (!args) return; let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children(); - if(selected_items.length == 0) { - frappe.throw({message: 'Please select Items from the Table', title: __('Items Required'), indicator:'blue'}) + if (selected_items.length == 0) { + frappe.throw({ + message: "Please select Items from the Table", + title: __("Items Required"), + indicator: "blue", + }); } dialog.hide(); - var method = args.against_default_supplier ? "make_purchase_order_for_default_supplier" : "make_purchase_order" + var method = args.against_default_supplier + ? "make_purchase_order_for_default_supplier" + : "make_purchase_order"; return frappe.call({ method: "erpnext.selling.doctype.sales_order.sales_order." + method, freeze_message: __("Creating Purchase Order ..."), args: { - "source_name": me.frm.doc.name, - "selected_items": selected_items + source_name: me.frm.doc.name, + selected_items: selected_items, }, freeze: true, - callback: function(r) { - if(!r.exc) { + callback: function (r) { + if (!r.exc) { if (!args.against_default_supplier) { frappe.model.sync(r.message); frappe.set_route("Form", r.message.doctype, r.message.name); - } - else { + } else { frappe.route_options = { - "sales_order": me.frm.doc.name - } + sales_order: me.frm.doc.name, + }; frappe.set_route("List", "Purchase Order"); } } - } - }) - } + }, + }); + }, }); dialog.fields_dict["against_default_supplier"].df.onchange = () => set_po_items_data(dialog); @@ -1256,27 +1351,28 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex var items_for_po = dialog.get_value("items_for_po"); if (against_default_supplier) { - let items_with_supplier = items_for_po.filter((item) => item.supplier) + let items_with_supplier = items_for_po.filter((item) => item.supplier); dialog.fields_dict["items_for_po"].df.data = items_with_supplier; dialog.get_field("items_for_po").refresh(); } else { let po_items = []; - me.frm.doc.items.forEach(d => { - if (!d.item_code) { // @dokos - return + me.frm.doc.items.forEach((d) => { + if (!d.item_code) { + // @dokos + return; } let ordered_qty = me.get_ordered_qty(d, me.frm.doc); let pending_qty = (flt(d.stock_qty) - ordered_qty) / flt(d.conversion_factor); if (pending_qty > 0) { po_items.push({ - "doctype": "Sales Order Item", - "name": d.name, - "item_name": d.item_name, - "item_code": d.item_code, - "pending_qty": pending_qty, - "uom": d.uom, - "supplier": d.supplier + doctype: "Sales Order Item", + name: d.name, + item_name: d.item_name, + item_code: d.item_code, + pending_qty: pending_qty, + uom: d.uom, + supplier: d.supplier, }); } }); @@ -1289,7 +1385,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex set_po_items_data(dialog); dialog.get_field("items_for_po").grid.only_sortable(); dialog.get_field("items_for_po").refresh(); - dialog.wrapper.find('.grid-heading-row .grid-row-check').click(); + dialog.wrapper.find(".grid-heading-row .grid-row-check").click(); dialog.show(); } @@ -1297,72 +1393,67 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex let ordered_qty = item.ordered_qty; if (so.packed_items && so.packed_items.length) { // calculate ordered qty based on packed items in case of product bundle - let packed_items = so.packed_items.filter( - (pi) => pi.parent_detail_docname == item.name - ); + let packed_items = so.packed_items.filter((pi) => pi.parent_detail_docname == item.name); if (packed_items && packed_items.length) { - ordered_qty = packed_items.reduce( - (sum, pi) => sum + flt(pi.ordered_qty), - 0 - ); + ordered_qty = packed_items.reduce((sum, pi) => sum + flt(pi.ordered_qty), 0); ordered_qty = ordered_qty / packed_items.length; } } return ordered_qty; } - hold_sales_order(){ + hold_sales_order() { var me = this; var d = new frappe.ui.Dialog({ - title: __('Reason for Hold'), + title: __("Reason for Hold"), fields: [ { - "fieldname": "reason_for_hold", - "fieldtype": "Text", - "reqd": 1, - } + fieldname: "reason_for_hold", + fieldtype: "Text", + reqd: 1, + }, ], - primary_action: function() { + primary_action: function () { var data = d.get_values(); frappe.call({ method: "frappe.desk.form.utils.add_comment", args: { reference_doctype: me.frm.doctype, reference_name: me.frm.docname, - content: __('Reason for hold:') + ' ' + data.reason_for_hold, + content: __("Reason for hold:") + " " + data.reason_for_hold, comment_email: frappe.session.user, - comment_by: frappe.session.user_fullname + comment_by: frappe.session.user_fullname, }, - callback: function(r) { - if(!r.exc) { - me.update_status('Hold', 'On Hold') + callback: function (r) { + if (!r.exc) { + me.update_status("Hold", "On Hold"); d.hide(); } - } + }, }); - } + }, }); d.show(); } - close_sales_order(){ - this.frm.cscript.update_status("Close", "Closed") + close_sales_order() { + this.frm.cscript.update_status("Close", "Closed"); } - update_status(label, status){ + update_status(label, status) { var doc = this.frm.doc; var me = this; frappe.ui.form.is_saving = true; frappe.call({ method: "erpnext.selling.doctype.sales_order.sales_order.update_status", - args: {status: status, name: doc.name}, - callback: function(r){ + args: { status: status, name: doc.name }, + callback: function (r) { me.frm.reload_doc(); }, - always: function() { + always: function () { frappe.ui.form.is_saving = false; - } + }, }); } }; -extend_cscript(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm})); +extend_cscript(cur_frm.cscript, new erpnext.selling.SalesOrderController({ frm: cur_frm })); -- GitLab