frappe.provide('erpnext.stock'); erpnext.stock.ItemDashboard = class ItemDashboard { constructor(opts) { $.extend(this, opts); this.make(); } make() { var me = this; this.start = 0; if (!this.sort_by) { this.sort_by = 'projected_qty'; this.sort_order = 'asc'; } this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent); this.result = this.content.find('.result'); this.content.on('click', '.btn-move', function () { handle_move_add($(this), "Move"); }); this.content.on('click', '.btn-add', function () { handle_move_add($(this), "Add"); }); this.content.on('click', '.btn-edit', function () { let item = unescape($(this).attr('data-item')); let warehouse = unescape($(this).attr('data-warehouse')); let company = unescape($(this).attr('data-company')); frappe.db.get_value('Putaway Rule', { 'item_code': item, 'warehouse': warehouse, 'company': company }, 'name', (r) => { frappe.set_route("Form", "Putaway Rule", r.name); }); }); function handle_move_add(element, action) { let item = unescape(element.attr('data-item')); let warehouse = unescape(element.attr('data-warehouse')); let actual_qty = unescape(element.attr('data-actual_qty')); let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry'))); let entry_type = action === "Move" ? "Material Transfer" : null; if (disable_quick_entry) { open_stock_entry(item, warehouse, entry_type); } else { if (action === "Add") { let rate = unescape($(this).attr('data-rate')); erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function () { me.refresh(); }); } else { erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function () { me.refresh(); }); } } } function open_stock_entry(item, warehouse, entry_type) { frappe.model.with_doctype('Stock Entry', function () { var doc = frappe.model.get_new_doc('Stock Entry'); if (entry_type) doc.stock_entry_type = entry_type; var row = frappe.model.add_child(doc, 'items'); row.item_code = item; row.s_warehouse = warehouse; frappe.set_route('Form', doc.doctype, doc.name); }); } // more this.content.find('.btn-more').on('click', function () { me.start += me.page_length; me.refresh(); }); } refresh() { if(this.before_refresh) { this.before_refresh(); } let args = { item_code: this.item_code, warehouse: this.warehouse, parent_warehouse: this.parent_warehouse, item_group: this.item_group, company: this.company, start: this.start, sort_by: this.sort_by, sort_order: this.sort_order }; var me = this; frappe.call({ method: this.method, args: args, callback: function (r) { me.render(r.message); } }); } render(data) { if (this.start===0) { this.max_count = 0; this.result.empty(); } let context = ""; if (this.page_name === "warehouse-capacity-summary") { context = this.get_capacity_dashboard_data(data); } else { context = this.get_item_dashboard_data(data, this.max_count, true); } this.max_count = this.max_count; // show more button if (data && data.length === (this.page_length + 1)) { this.content.find('.more').removeClass('hidden'); // remove the last element data.splice(-1); } else { this.content.find('.more').addClass('hidden'); } // If not any stock in any warehouses provide a message to end user if (context.data.length > 0) { this.content.find('.result').css('text-align', 'unset'); $(frappe.render_template(this.template, context)).appendTo(this.result); } else { var message = __("No Stock Available Currently"); this.content.find('.result').css('text-align', 'center'); $(`
${message}
`).appendTo(this.result); } } get_item_dashboard_data(data, max_count, show_item) { if(!max_count) max_count = 0; if(!data) data = []; data.forEach(function (d) { d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract; d.pending_qty = 0; d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract; if (d.actual_or_pending > d.actual_qty) { d.pending_qty = d.actual_or_pending - d.actual_qty; } max_count = Math.max(d.actual_or_pending, d.actual_qty, d.total_reserved, max_count); }); let can_write = 0; if (frappe.boot.user.can_write.indexOf("Stock Entry") >= 0) { can_write = 1; } return { data: data, max_count: max_count, can_write: can_write, show_item: show_item || false }; } get_capacity_dashboard_data(data) { if (!data) data = []; data.forEach(function (d) { d.color = d.percent_occupied >= 80 ? "#f8814f" : "#2490ef"; }); let can_write = 0; if (frappe.boot.user.can_write.indexOf("Putaway Rule") >= 0) { can_write = 1; } return { data: data, can_write: can_write, }; } }; erpnext.stock.move_item = function (item, source, target, actual_qty, rate, callback) { var dialog = new frappe.ui.Dialog({ title: target ? __('Add Item') : __('Move Item'), fields: [{ fieldname: 'item_code', label: __('Item'), fieldtype: 'Link', options: 'Item', read_only: 1 }, { fieldname: 'source', label: __('Source Warehouse'), fieldtype: 'Link', options: 'Warehouse', read_only: 1 }, { fieldname: 'target', label: __('Target Warehouse'), fieldtype: 'Link', options: 'Warehouse', reqd: 1, get_query() { return { filters: { is_group: 0 } } } }, { fieldname: 'qty', label: __('Quantity'), reqd: 1, fieldtype: 'Float', description: __('Available {0}', [actual_qty]) }, { fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 }, ], }); dialog.show(); dialog.get_field('item_code').set_input(item); if (source) { dialog.get_field('source').set_input(source); } else { dialog.get_field('source').df.hidden = 1; dialog.get_field('source').refresh(); } if (rate) { dialog.get_field('rate').set_value(rate); dialog.get_field('rate').df.hidden = 0; dialog.get_field('rate').refresh(); } if (target) { dialog.get_field('target').df.read_only = 1; dialog.get_field('target').value = target; dialog.get_field('target').refresh(); } dialog.set_primary_action(__('Create Stock Entry'), function () { if (source && (dialog.get_value("qty") == 0 || dialog.get_value("qty") > actual_qty)) { frappe.msgprint(__("Quantity must be greater than zero, and less or equal to {0}", [actual_qty])); return; } if (dialog.get_value("source") === dialog.get_value("target")) { frappe.msgprint(__("Source and target warehouse must be different")); return; } frappe.model.with_doctype('Stock Entry', function () { let doc = frappe.model.get_new_doc('Stock Entry'); doc.from_warehouse = dialog.get_value('source'); doc.to_warehouse = dialog.get_value('target'); doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt"; let row = frappe.model.add_child(doc, 'items'); row.item_code = dialog.get_value('item_code'); row.s_warehouse = dialog.get_value('source'); row.t_warehouse = dialog.get_value('target'); row.qty = dialog.get_value('qty'); row.conversion_factor = 1; row.transfer_qty = dialog.get_value('qty'); row.basic_rate = dialog.get_value('rate'); frappe.set_route('Form', doc.doctype, doc.name); }); }); };