blob: f64d5931aee4f39cbf8301a86acf4eb2b3105027 [file] [log] [blame]
Rushabh Mehta3d2622c2016-04-25 17:53:42 +05301frappe.provide('erpnext.stock');
2
3erpnext.stock.ItemDashboard = Class.extend({
4 init: function(opts) {
5 $.extend(this, opts);
6 this.make();
7 },
8 make: function() {
9 var me = this;
10 this.start = 0;
11 if(!this.sort_by) {
12 this.sort_by = 'projected_qty';
13 this.sort_order = 'asc';
14 }
15
16 this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent);
17 this.result = this.content.find('.result');
18
Shivam Mishra38b930b2019-07-05 10:38:48 +053019 this.content.on('click', '.btn-move', function() {
Shivam Mishra5738c932019-07-16 12:52:19 +053020 handle_move_add($(this), "Move")
Shivam Mishra38b930b2019-07-05 10:38:48 +053021 });
22
23 this.content.on('click', '.btn-add', function() {
Shivam Mishra7339c722019-07-16 13:19:13 +053024 handle_move_add($(this), "Add")
Shivam Mishra5738c932019-07-16 12:52:19 +053025 });
26
27 function handle_move_add(element, action) {
28 let item = unescape(element.attr('data-item'));
29 let warehouse = unescape(element.attr('data-warehouse'));
30 let actual_qty = unescape(element.attr('data-actual_qty'));
31 let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry')));
32 let entry_type = action === "Move" ? "Material Transfer": null;
Shivam Mishra444091b2019-07-10 10:22:08 +053033
Shivam Mishrafd6ff622019-07-16 12:32:50 +053034 if (disable_quick_entry) {
Shivam Mishra5738c932019-07-16 12:52:19 +053035 open_stock_entry(item, warehouse, entry_type);
Shivam Mishrafd6ff622019-07-16 12:32:50 +053036 } else {
Shivam Mishra5738c932019-07-16 12:52:19 +053037 if (action === "Add") {
38 let rate = unescape($(this).attr('data-rate'));
39 erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); });
40 }
41 else {
42 erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function() { me.refresh(); });
43 }
Shivam Mishrafd6ff622019-07-16 12:32:50 +053044 }
Shivam Mishra5738c932019-07-16 12:52:19 +053045 }
Shivam Mishra38b930b2019-07-05 10:38:48 +053046
47 function open_stock_entry(item, warehouse, entry_type) {
48 frappe.model.with_doctype('Stock Entry', function() {
49 var doc = frappe.model.get_new_doc('Stock Entry');
50 if (entry_type) doc.stock_entry_type = entry_type;
51
52 var row = frappe.model.add_child(doc, 'items');
53 row.item_code = item;
54 row.s_warehouse = warehouse;
55
56 frappe.set_route('Form', doc.doctype, doc.name);
57 })
58 }
59
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053060 // more
61 this.content.find('.btn-more').on('click', function() {
62 me.start += 20;
63 me.refresh();
64 });
65
66 },
67 refresh: function() {
68 if(this.before_refresh) {
69 this.before_refresh();
70 }
71
72 var me = this;
73 frappe.call({
74 method: 'erpnext.stock.dashboard.item_dashboard.get_data',
75 args: {
76 item_code: this.item_code,
77 warehouse: this.warehouse,
Rushabh Mehta057db062016-11-08 12:40:04 +053078 item_group: this.item_group,
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053079 start: this.start,
80 sort_by: this.sort_by,
81 sort_order: this.sort_order,
82 },
83 callback: function(r) {
84 me.render(r.message);
85 }
86 });
87 },
88 render: function(data) {
89 if(this.start===0) {
90 this.max_count = 0;
91 this.result.empty();
92 }
93
94 var context = this.get_item_dashboard_data(data, this.max_count, true);
95 this.max_count = this.max_count;
96
97 // show more button
Rushabh Mehtaaed79e92016-06-02 17:49:16 +053098 if(data && data.length===21) {
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053099 this.content.find('.more').removeClass('hidden');
100
101 // remove the last element
102 data.splice(-1);
103 } else {
104 this.content.find('.more').addClass('hidden');
105 }
106
Vinayak Jethe2c8ce5a2018-01-24 13:51:26 +0530107 // If not any stock in any warehouses provide a message to end user
Stavros Anastasiadis58b58782017-10-05 16:14:50 +0300108 if (context.data.length > 0) {
109 $(frappe.render_template('item_dashboard_list', context)).appendTo(this.result);
110 } else {
Suraj Shettyda6806e2020-04-08 09:32:41 +0530111 var message = __("Currently no stock available in any warehouse");
112 $(`<span class='text-muted small'> ${message} </span>`).appendTo(this.result);
Stavros Anastasiadis58b58782017-10-05 16:14:50 +0300113 }
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530114 },
115 get_item_dashboard_data: function(data, max_count, show_item) {
116 if(!max_count) max_count = 0;
Rushabh Mehta0dcb8612016-05-31 07:22:37 +0530117 if(!data) data = [];
Vinayak Jethe549c1962018-01-24 19:47:59 +0530118
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530119 data.forEach(function(d) {
Nabin Haita6746402018-03-28 11:16:00 +0530120 d.actual_or_pending = d.projected_qty + d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530121 d.pending_qty = 0;
Nabin Hait2c7a6e62018-03-12 14:12:12 +0530122 d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530123 if(d.actual_or_pending > d.actual_qty) {
124 d.pending_qty = d.actual_or_pending - d.actual_qty;
125 }
126
127 max_count = Math.max(d.actual_or_pending, d.actual_qty,
128 d.total_reserved, max_count);
129 });
Vinayak Jethe549c1962018-01-24 19:47:59 +0530130
131 var can_write = 0;
132 if(frappe.boot.user.can_write.indexOf("Stock Entry")>=0){
133 can_write = 1;
134 }
135
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530136 return {
137 data: data,
138 max_count: max_count,
Vinayak Jethe549c1962018-01-24 19:47:59 +0530139 can_write:can_write,
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530140 show_item: show_item || false
141 }
142 }
Shivam Mishra444091b2019-07-10 10:22:08 +0530143})
144
145erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) {
146 var dialog = new frappe.ui.Dialog({
147 title: target ? __('Add Item') : __('Move Item'),
148 fields: [
149 {fieldname: 'item_code', label: __('Item'),
150 fieldtype: 'Link', options: 'Item', read_only: 1},
151 {fieldname: 'source', label: __('Source Warehouse'),
152 fieldtype: 'Link', options: 'Warehouse', read_only: 1},
153 {fieldname: 'target', label: __('Target Warehouse'),
154 fieldtype: 'Link', options: 'Warehouse', reqd: 1},
155 {fieldname: 'qty', label: __('Quantity'), reqd: 1,
156 fieldtype: 'Float', description: __('Available {0}', [actual_qty]) },
157 {fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 },
158 ],
159 })
160 dialog.show();
161 dialog.get_field('item_code').set_input(item);
162
163 if(source) {
164 dialog.get_field('source').set_input(source);
165 } else {
166 dialog.get_field('source').df.hidden = 1;
167 dialog.get_field('source').refresh();
168 }
169
170 if(rate) {
171 dialog.get_field('rate').set_value(rate);
172 dialog.get_field('rate').df.hidden = 0;
173 dialog.get_field('rate').refresh();
174 }
175
176 if(target) {
177 dialog.get_field('target').df.read_only = 1;
178 dialog.get_field('target').value = target;
179 dialog.get_field('target').refresh();
180 }
181
182 dialog.set_primary_action(__('Submit'), function() {
183 var values = dialog.get_values();
184 if(!values) {
185 return;
186 }
187 if(source && values.qty > actual_qty) {
188 frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
189 return;
190 }
191 if(values.source === values.target) {
192 frappe.msgprint(__('Source and target warehouse must be different'));
193 }
194
195 frappe.call({
196 method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
197 args: values,
198 freeze: true,
199 callback: function(r) {
200 frappe.show_alert(__('Stock Entry {0} created',
Rushabh Mehta2cd41bc2020-12-18 13:17:58 +0530201 ['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>']));
Shivam Mishra444091b2019-07-10 10:22:08 +0530202 dialog.hide();
203 callback(r);
204 },
205 });
206 });
207
208 $('<p style="margin-left: 10px;"><a class="link-open text-muted small">'
209 + __("Add more items or open full form") + '</a></p>')
210 .appendTo(dialog.body)
211 .find('.link-open')
212 .on('click', function() {
213 frappe.model.with_doctype('Stock Entry', function() {
214 var doc = frappe.model.get_new_doc('Stock Entry');
215 doc.from_warehouse = dialog.get_value('source');
216 doc.to_warehouse = dialog.get_value('target');
217 var row = frappe.model.add_child(doc, 'items');
218 row.item_code = dialog.get_value('item_code');
219 row.f_warehouse = dialog.get_value('target');
220 row.t_warehouse = dialog.get_value('target');
221 row.qty = dialog.get_value('qty');
222 row.conversion_factor = 1;
223 row.transfer_qty = dialog.get_value('qty');
224 row.basic_rate = dialog.get_value('rate');
225 frappe.set_route('Form', doc.doctype, doc.name);
226 })
227 });
Shivam Mishra7339c722019-07-16 13:19:13 +0530228}