mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-07 15:12:51 +00:00
[refacator] added dashboard in item
This commit is contained in:
0
erpnext/stock/dashboard/__init__.py
Normal file
0
erpnext/stock/dashboard/__init__.py
Normal file
7
erpnext/stock/dashboard/item_dashboard.html
Normal file
7
erpnext/stock/dashboard/item_dashboard.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<div>
|
||||
<div class="result">
|
||||
</div>
|
||||
<div class="more hidden" style="padding: 15px;">
|
||||
<a class="btn btn-default btn-xs btn-more">More</a>
|
||||
</div>
|
||||
</div>
|
||||
162
erpnext/stock/dashboard/item_dashboard.js
Normal file
162
erpnext/stock/dashboard/item_dashboard.js
Normal file
@@ -0,0 +1,162 @@
|
||||
frappe.provide('erpnext.stock');
|
||||
|
||||
erpnext.stock.ItemDashboard = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
this.make();
|
||||
},
|
||||
make: function() {
|
||||
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');
|
||||
|
||||
// move
|
||||
this.content.on('click', '.btn-move', function() {
|
||||
erpnext.stock.move_item($(this).attr('data-item'), $(this).attr('data-warehouse'),
|
||||
null, $(this).attr('data-actual_qty'), null, function() { me.refresh(); });
|
||||
});
|
||||
|
||||
this.content.on('click', '.btn-add', function() {
|
||||
erpnext.stock.move_item($(this).attr('data-item'), null, $(this).attr('data-warehouse'),
|
||||
$(this).attr('data-actual_qty'), $(this).attr('data-rate'),
|
||||
function() { me.refresh(); });
|
||||
});
|
||||
|
||||
// more
|
||||
this.content.find('.btn-more').on('click', function() {
|
||||
me.start += 20;
|
||||
me.refresh();
|
||||
});
|
||||
|
||||
},
|
||||
refresh: function() {
|
||||
if(this.before_refresh) {
|
||||
this.before_refresh();
|
||||
}
|
||||
|
||||
var me = this;
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.dashboard.item_dashboard.get_data',
|
||||
args: {
|
||||
item_code: this.item_code,
|
||||
warehouse: this.warehouse,
|
||||
start: this.start,
|
||||
sort_by: this.sort_by,
|
||||
sort_order: this.sort_order,
|
||||
},
|
||||
callback: function(r) {
|
||||
me.render(r.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
render: function(data) {
|
||||
if(this.start===0) {
|
||||
this.max_count = 0;
|
||||
this.result.empty();
|
||||
}
|
||||
|
||||
var context = this.get_item_dashboard_data(data, this.max_count, true);
|
||||
this.max_count = this.max_count;
|
||||
|
||||
// show more button
|
||||
if(data.length===21) {
|
||||
this.content.find('.more').removeClass('hidden');
|
||||
|
||||
// remove the last element
|
||||
data.splice(-1);
|
||||
} else {
|
||||
this.content.find('.more').addClass('hidden');
|
||||
}
|
||||
|
||||
$(frappe.render_template('item_dashboard_list', context)).appendTo(this.result);
|
||||
|
||||
},
|
||||
get_item_dashboard_data: function(data, max_count, show_item) {
|
||||
if(!max_count) max_count = 0;
|
||||
data.forEach(function(d) {
|
||||
d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production;
|
||||
d.pending_qty = 0;
|
||||
d.total_reserved = d.reserved_qty + d.reserved_qty_for_production;
|
||||
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);
|
||||
});
|
||||
return {
|
||||
data: data,
|
||||
max_count: max_count,
|
||||
show_item: show_item || false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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},
|
||||
{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(__('Submit'), function() {
|
||||
values = dialog.get_values();
|
||||
if(!values) {
|
||||
return;
|
||||
}
|
||||
if(source && values.qty > actual_qty) {
|
||||
frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
|
||||
return;
|
||||
}
|
||||
if(values.source === values.target) {
|
||||
frappe.msgprint(__('Source and target warehouse must be different'));
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
|
||||
args: values,
|
||||
callback: function(r) {
|
||||
frappe.show_alert(__('Stock Entry {0} created',
|
||||
['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
|
||||
dialog.hide();
|
||||
callback(r);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
14
erpnext/stock/dashboard/item_dashboard.py
Normal file
14
erpnext/stock/dashboard/item_dashboard.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_data(item_code=None, warehouse=None, start=0, sort_by='actual_qty', sort_order='desc'):
|
||||
filters = {}
|
||||
if item_code:
|
||||
filters['item_code'] = item_code
|
||||
if warehouse:
|
||||
filters['warehouse'] = warehouse
|
||||
return frappe.get_list("Bin", filters=filters, fields=['item_code', 'warehouse',
|
||||
'projected_qty', 'reserved_qty', 'reserved_qty_for_production', 'actual_qty', 'valuation_rate'],
|
||||
order_by='{0} {1}'.format(sort_by, sort_order), start=start, page_length = 21)
|
||||
55
erpnext/stock/dashboard/item_dashboard_list.html
Normal file
55
erpnext/stock/dashboard/item_dashboard_list.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% for d in data %}
|
||||
<div class="dashboard-list-item">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 small" style="margin-top: 8px;">
|
||||
<a data-type="warehouse" data-name="{{ d.warehouse }}">{{ d.warehouse }}</a>
|
||||
</div>
|
||||
<div class="col-sm-3 small" style="margin-top: 8px;">
|
||||
{% if show_item %}
|
||||
<a data-type="item"
|
||||
data-name="{{ d.item_code }}">{{ d.item_code }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-sm-4 small">
|
||||
<span class="inline-graph">
|
||||
<span class="inline-graph-half" title="{{ __("Reserved Qty") }}">
|
||||
<span class="inline-graph-count">{{ d.total_reserved }}</span>
|
||||
<span class="inline-graph-bar">
|
||||
<span class="inline-graph-bar-inner"
|
||||
style="width: {{ cint(Math.abs(d.total_reserved)/max_count * 100) || 5 }}%">
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="inline-graph-half" title="{{ __("Acutal Qty {0} / Waiting Qty {1}", [d.actual_qty, d.pending_qty]) }}">
|
||||
<span class="inline-graph-count">
|
||||
{{ d.actual_qty }} {{ (d.pending_qty > 0) ? ("(" + d.pending_qty+ ")") : "" }}
|
||||
</span>
|
||||
<span class="inline-graph-bar">
|
||||
<span class="inline-graph-bar-inner dark"
|
||||
style="width: {{ cint(d.actual_qty/max_count * 100) }}%">
|
||||
</span>
|
||||
{% if d.pending_qty > 0 %}
|
||||
<span class="inline-graph-bar-inner" title="{{ __("Projected Qty") }}"
|
||||
style="width: {{ cint(d.pending_qty/max_count * 100) }}%">
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-sm-2 text-right" style="margin-top: 8px;">
|
||||
{% if d.actual_qty %}
|
||||
<button class="btn btn-default btn-xs btn-move"
|
||||
data-warehouse="{{ d.warehouse }}"
|
||||
data-actual_qty="{{ d.actual_qty }}"
|
||||
data-item="{{ d.item_code }}">{{ __("Move") }}</a>
|
||||
{% endif %}
|
||||
<button style="margin-left: 7px;" class="btn btn-default btn-xs btn-add"
|
||||
data-warehouse="{{ d.warehouse }}"
|
||||
data-actual_qty="{{ d.actual_qty }}"
|
||||
data-item="{{ d.item_code }}"
|
||||
data-rate="{{ d.valuation_rate }}">{{ __("Add") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
Reference in New Issue
Block a user