Merge pull request #24921 from Anurag810/item-dashboard-fixes

fix: precision and formatted document for stock level in item dashboard.
This commit is contained in:
Marica 2021-04-09 12:43:06 +05:30 committed by GitHub
commit c6b3766fb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 66 deletions

View File

@ -1,14 +1,14 @@
frappe.provide('erpnext.stock'); frappe.provide('erpnext.stock');
erpnext.stock.ItemDashboard = Class.extend({ erpnext.stock.ItemDashboard = Class.extend({
init: function(opts) { init: function (opts) {
$.extend(this, opts); $.extend(this, opts);
this.make(); this.make();
}, },
make: function() { make: function () {
var me = this; var me = this;
this.start = 0; this.start = 0;
if(!this.sort_by) { if (!this.sort_by) {
this.sort_by = 'projected_qty'; this.sort_by = 'projected_qty';
this.sort_order = 'asc'; this.sort_order = 'asc';
} }
@ -16,20 +16,23 @@ erpnext.stock.ItemDashboard = Class.extend({
this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent); this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent);
this.result = this.content.find('.result'); this.result = this.content.find('.result');
this.content.on('click', '.btn-move', function() { this.content.on('click', '.btn-move', function () {
handle_move_add($(this), "Move") handle_move_add($(this), "Move");
}); });
this.content.on('click', '.btn-add', function() { this.content.on('click', '.btn-add', function () {
handle_move_add($(this), "Add") handle_move_add($(this), "Add");
}); });
this.content.on('click', '.btn-edit', function() { this.content.on('click', '.btn-edit', function () {
let item = unescape($(this).attr('data-item')); let item = unescape($(this).attr('data-item'));
let warehouse = unescape($(this).attr('data-warehouse')); let warehouse = unescape($(this).attr('data-warehouse'));
let company = unescape($(this).attr('data-company')); let company = unescape($(this).attr('data-company'));
frappe.db.get_value('Putaway Rule', frappe.db.get_value('Putaway Rule', {
{'item_code': item, 'warehouse': warehouse, 'company': company}, 'name', (r) => { 'item_code': item,
'warehouse': warehouse,
'company': company
}, 'name', (r) => {
frappe.set_route("Form", "Putaway Rule", r.name); frappe.set_route("Form", "Putaway Rule", r.name);
}); });
}); });
@ -39,23 +42,26 @@ erpnext.stock.ItemDashboard = Class.extend({
let warehouse = unescape(element.attr('data-warehouse')); let warehouse = unescape(element.attr('data-warehouse'));
let actual_qty = unescape(element.attr('data-actual_qty')); let actual_qty = unescape(element.attr('data-actual_qty'));
let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry'))); let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry')));
let entry_type = action === "Move" ? "Material Transfer": null; let entry_type = action === "Move" ? "Material Transfer" : null;
if (disable_quick_entry) { if (disable_quick_entry) {
open_stock_entry(item, warehouse, entry_type); open_stock_entry(item, warehouse, entry_type);
} else { } else {
if (action === "Add") { if (action === "Add") {
let rate = unescape($(this).attr('data-rate')); let rate = unescape($(this).attr('data-rate'));
erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); }); 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(); }); } else {
erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function () {
me.refresh();
});
} }
} }
} }
function open_stock_entry(item, warehouse, entry_type) { function open_stock_entry(item, warehouse, entry_type) {
frappe.model.with_doctype('Stock Entry', function() { frappe.model.with_doctype('Stock Entry', function () {
var doc = frappe.model.get_new_doc('Stock Entry'); var doc = frappe.model.get_new_doc('Stock Entry');
if (entry_type) doc.stock_entry_type = entry_type; if (entry_type) doc.stock_entry_type = entry_type;
@ -64,18 +70,18 @@ erpnext.stock.ItemDashboard = Class.extend({
row.s_warehouse = warehouse; row.s_warehouse = warehouse;
frappe.set_route('Form', doc.doctype, doc.name); frappe.set_route('Form', doc.doctype, doc.name);
}) });
} }
// more // more
this.content.find('.btn-more').on('click', function() { this.content.find('.btn-more').on('click', function () {
me.start += me.page_length; me.start += me.page_length;
me.refresh(); me.refresh();
}); });
}, },
refresh: function() { refresh: function () {
if(this.before_refresh) { if (this.before_refresh) {
this.before_refresh(); this.before_refresh();
} }
@ -94,13 +100,13 @@ erpnext.stock.ItemDashboard = Class.extend({
frappe.call({ frappe.call({
method: this.method, method: this.method,
args: args, args: args,
callback: function(r) { callback: function (r) {
me.render(r.message); me.render(r.message);
} }
}); });
}, },
render: function(data) { render: function (data) {
if (this.start===0) { if (this.start === 0) {
this.max_count = 0; this.max_count = 0;
this.result.empty(); this.result.empty();
} }
@ -115,7 +121,7 @@ erpnext.stock.ItemDashboard = Class.extend({
this.max_count = this.max_count; this.max_count = this.max_count;
// show more button // show more button
if (data && data.length===(this.page_length + 1)) { if (data && data.length === (this.page_length + 1)) {
this.content.find('.more').removeClass('hidden'); this.content.find('.more').removeClass('hidden');
// remove the last element // remove the last element
@ -137,15 +143,15 @@ erpnext.stock.ItemDashboard = Class.extend({
} }
}, },
get_item_dashboard_data: function(data, max_count, show_item) { get_item_dashboard_data: function (data, max_count, show_item) {
if(!max_count) max_count = 0; if (!max_count) max_count = 0;
if(!data) data = []; if (!data) data = [];
data.forEach(function(d) { 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.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.pending_qty = 0;
d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract; 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) { if (d.actual_or_pending > d.actual_qty) {
d.pending_qty = d.actual_or_pending - d.actual_qty; d.pending_qty = d.actual_or_pending - d.actual_qty;
} }
@ -161,16 +167,16 @@ erpnext.stock.ItemDashboard = Class.extend({
return { return {
data: data, data: data,
max_count: max_count, max_count: max_count,
can_write:can_write, can_write: can_write,
show_item: show_item || false show_item: show_item || false
}; };
}, },
get_capacity_dashboard_data: function(data) { get_capacity_dashboard_data: function (data) {
if (!data) data = []; if (!data) data = [];
data.forEach(function(d) { data.forEach(function (d) {
d.color = d.percent_occupied >=80 ? "#f8814f" : "#2490ef"; d.color = d.percent_occupied >= 80 ? "#f8814f" : "#2490ef";
}); });
let can_write = 0; let can_write = 0;
@ -185,53 +191,77 @@ erpnext.stock.ItemDashboard = Class.extend({
} }
}); });
erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) { erpnext.stock.move_item = function (item, source, target, actual_qty, rate, callback) {
var dialog = new frappe.ui.Dialog({ var dialog = new frappe.ui.Dialog({
title: target ? __('Add Item') : __('Move Item'), title: target ? __('Add Item') : __('Move Item'),
fields: [ fields: [{
{fieldname: 'item_code', label: __('Item'), fieldname: 'item_code',
fieldtype: 'Link', options: 'Item', read_only: 1}, label: __('Item'),
{fieldname: 'source', label: __('Source Warehouse'), fieldtype: 'Link',
fieldtype: 'Link', options: 'Warehouse', read_only: 1}, options: 'Item',
{fieldname: 'target', label: __('Target Warehouse'), read_only: 1
fieldtype: 'Link', options: 'Warehouse', reqd: 1}, },
{fieldname: 'qty', label: __('Quantity'), reqd: 1, {
fieldtype: 'Float', description: __('Available {0}', [actual_qty]) }, fieldname: 'source',
{fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 }, label: __('Source Warehouse'),
fieldtype: 'Link',
options: 'Warehouse',
read_only: 1
},
{
fieldname: 'target',
label: __('Target Warehouse'),
fieldtype: 'Link',
options: 'Warehouse',
reqd: 1
},
{
fieldname: 'qty',
label: __('Quantity'),
reqd: 1,
fieldtype: 'Float',
description: __('Available {0}', [actual_qty])
},
{
fieldname: 'rate',
label: __('Rate'),
fieldtype: 'Currency',
hidden: 1
},
], ],
}) });
dialog.show(); dialog.show();
dialog.get_field('item_code').set_input(item); dialog.get_field('item_code').set_input(item);
if(source) { if (source) {
dialog.get_field('source').set_input(source); dialog.get_field('source').set_input(source);
} else { } else {
dialog.get_field('source').df.hidden = 1; dialog.get_field('source').df.hidden = 1;
dialog.get_field('source').refresh(); dialog.get_field('source').refresh();
} }
if(rate) { if (rate) {
dialog.get_field('rate').set_value(rate); dialog.get_field('rate').set_value(rate);
dialog.get_field('rate').df.hidden = 0; dialog.get_field('rate').df.hidden = 0;
dialog.get_field('rate').refresh(); dialog.get_field('rate').refresh();
} }
if(target) { if (target) {
dialog.get_field('target').df.read_only = 1; dialog.get_field('target').df.read_only = 1;
dialog.get_field('target').value = target; dialog.get_field('target').value = target;
dialog.get_field('target').refresh(); dialog.get_field('target').refresh();
} }
dialog.set_primary_action(__('Submit'), function() { dialog.set_primary_action(__('Submit'), function () {
var values = dialog.get_values(); var values = dialog.get_values();
if(!values) { if (!values) {
return; return;
} }
if(source && values.qty > actual_qty) { if (source && values.qty > actual_qty) {
frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty])); frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
return; return;
} }
if(values.source === values.target) { if (values.source === values.target) {
frappe.msgprint(__('Source and target warehouse must be different')); frappe.msgprint(__('Source and target warehouse must be different'));
} }
@ -239,21 +269,21 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
args: values, args: values,
freeze: true, freeze: true,
callback: function(r) { callback: function (r) {
frappe.show_alert(__('Stock Entry {0} created', frappe.show_alert(__('Stock Entry {0} created',
['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>'])); ['<a href="/app/stock-entry/' + r.message.name + '">' + r.message.name + '</a>']));
dialog.hide(); dialog.hide();
callback(r); callback(r);
}, },
}); });
}); });
$('<p style="margin-left: 10px;"><a class="link-open text-muted small">' $('<p style="margin-left: 10px;"><a class="link-open text-muted small">' +
+ __("Add more items or open full form") + '</a></p>') __("Add more items or open full form") + '</a></p>')
.appendTo(dialog.body) .appendTo(dialog.body)
.find('.link-open') .find('.link-open')
.on('click', function() { .on('click', function () {
frappe.model.with_doctype('Stock Entry', function() { frappe.model.with_doctype('Stock Entry', function () {
var doc = frappe.model.get_new_doc('Stock Entry'); var doc = frappe.model.get_new_doc('Stock Entry');
doc.from_warehouse = dialog.get_value('source'); doc.from_warehouse = dialog.get_value('source');
doc.to_warehouse = dialog.get_value('target'); doc.to_warehouse = dialog.get_value('target');
@ -266,6 +296,6 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb
row.transfer_qty = dialog.get_value('qty'); row.transfer_qty = dialog.get_value('qty');
row.basic_rate = dialog.get_value('rate'); row.basic_rate = dialog.get_value('rate');
frappe.set_route('Form', doc.doctype, doc.name); frappe.set_route('Form', doc.doctype, doc.name);
})
}); });
} });
};

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.model.db_query import DatabaseQuery from frappe.model.db_query import DatabaseQuery
from frappe.utils import flt, cint
@frappe.whitelist() @frappe.whitelist()
def get_data(item_code=None, warehouse=None, item_group=None, def get_data(item_code=None, warehouse=None, item_group=None,
@ -42,11 +43,20 @@ def get_data(item_code=None, warehouse=None, item_group=None,
limit_start=start, limit_start=start,
limit_page_length='21') limit_page_length='21')
precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
for item in items: for item in items:
item.update({ item.update({
'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name'), 'item_name': frappe.get_cached_value(
'disable_quick_entry': frappe.get_cached_value("Item", item.item_code, 'has_batch_no') "Item", item.item_code, 'item_name'),
or frappe.get_cached_value("Item", item.item_code, 'has_serial_no'), 'disable_quick_entry': frappe.get_cached_value(
"Item", item.item_code, 'has_batch_no')
or frappe.get_cached_value(
"Item", item.item_code, 'has_serial_no'),
'projected_qty': flt(item.projected_qty, precision),
'reserved_qty': flt(item.reserved_qty, precision),
'reserved_qty_for_production': flt(item.reserved_qty_for_production, precision),
'reserved_qty_for_sub_contract': flt(item.reserved_qty_for_sub_contract, precision),
'actual_qty': flt(item.actual_qty, precision),
}) })
return items return items