blob: 95cb92b1b365cfdf482f325bc7cf4cbb905cafcf [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
marination1087d972020-11-26 10:45:44 +053027 this.content.on('click', '.btn-edit', function() {
28 let item = unescape($(this).attr('data-item'));
29 let warehouse = unescape($(this).attr('data-warehouse'));
30 let company = unescape($(this).attr('data-company'));
31 frappe.db.get_value('Putaway Rule',
32 {'item_code': item, 'warehouse': warehouse, 'company': company}, 'name', (r) => {
marination0f3cfc52020-12-08 19:11:51 +053033 frappe.set_route("Form", "Putaway Rule", r.name);
34 });
marination1087d972020-11-26 10:45:44 +053035 });
36
Shivam Mishra5738c932019-07-16 12:52:19 +053037 function handle_move_add(element, action) {
38 let item = unescape(element.attr('data-item'));
39 let warehouse = unescape(element.attr('data-warehouse'));
40 let actual_qty = unescape(element.attr('data-actual_qty'));
41 let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry')));
42 let entry_type = action === "Move" ? "Material Transfer": null;
Shivam Mishra444091b2019-07-10 10:22:08 +053043
Shivam Mishrafd6ff622019-07-16 12:32:50 +053044 if (disable_quick_entry) {
Shivam Mishra5738c932019-07-16 12:52:19 +053045 open_stock_entry(item, warehouse, entry_type);
Shivam Mishrafd6ff622019-07-16 12:32:50 +053046 } else {
Shivam Mishra5738c932019-07-16 12:52:19 +053047 if (action === "Add") {
48 let rate = unescape($(this).attr('data-rate'));
49 erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); });
50 }
51 else {
52 erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function() { me.refresh(); });
53 }
Shivam Mishrafd6ff622019-07-16 12:32:50 +053054 }
Shivam Mishra5738c932019-07-16 12:52:19 +053055 }
Shivam Mishra38b930b2019-07-05 10:38:48 +053056
57 function open_stock_entry(item, warehouse, entry_type) {
58 frappe.model.with_doctype('Stock Entry', function() {
59 var doc = frappe.model.get_new_doc('Stock Entry');
60 if (entry_type) doc.stock_entry_type = entry_type;
61
62 var row = frappe.model.add_child(doc, 'items');
63 row.item_code = item;
64 row.s_warehouse = warehouse;
65
66 frappe.set_route('Form', doc.doctype, doc.name);
67 })
68 }
69
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053070 // more
71 this.content.find('.btn-more').on('click', function() {
marinationa5d8d322020-12-09 16:27:18 +053072 me.start += me.page_length;
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053073 me.refresh();
74 });
75
76 },
77 refresh: function() {
78 if(this.before_refresh) {
79 this.before_refresh();
80 }
81
marination1087d972020-11-26 10:45:44 +053082 let args = {
83 item_code: this.item_code,
84 warehouse: this.warehouse,
85 parent_warehouse: this.parent_warehouse,
86 item_group: this.item_group,
87 company: this.company,
88 start: this.start,
89 sort_by: this.sort_by,
90 sort_order: this.sort_order
marination0f3cfc52020-12-08 19:11:51 +053091 };
marination1087d972020-11-26 10:45:44 +053092
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053093 var me = this;
94 frappe.call({
marination1087d972020-11-26 10:45:44 +053095 method: this.method,
96 args: args,
Rushabh Mehta3d2622c2016-04-25 17:53:42 +053097 callback: function(r) {
98 me.render(r.message);
99 }
100 });
101 },
102 render: function(data) {
marination1087d972020-11-26 10:45:44 +0530103 if (this.start===0) {
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530104 this.max_count = 0;
105 this.result.empty();
106 }
107
marination0f3cfc52020-12-08 19:11:51 +0530108 let context = "";
marination1087d972020-11-26 10:45:44 +0530109 if (this.page_name === "warehouse-capacity-summary") {
marination0f3cfc52020-12-08 19:11:51 +0530110 context = this.get_capacity_dashboard_data(data);
marination1087d972020-11-26 10:45:44 +0530111 } else {
marination0f3cfc52020-12-08 19:11:51 +0530112 context = this.get_item_dashboard_data(data, this.max_count, true);
marination1087d972020-11-26 10:45:44 +0530113 }
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530114
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530115 this.max_count = this.max_count;
116
117 // show more button
marination1087d972020-11-26 10:45:44 +0530118 if (data && data.length===(this.page_length + 1)) {
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530119 this.content.find('.more').removeClass('hidden');
120
121 // remove the last element
122 data.splice(-1);
123 } else {
124 this.content.find('.more').addClass('hidden');
125 }
126
Vinayak Jethe2c8ce5a2018-01-24 13:51:26 +0530127 // If not any stock in any warehouses provide a message to end user
Stavros Anastasiadis58b58782017-10-05 16:14:50 +0300128 if (context.data.length > 0) {
marination1087d972020-11-26 10:45:44 +0530129 this.content.find('.result').css('text-align', 'unset');
130 $(frappe.render_template(this.template, context)).appendTo(this.result);
Stavros Anastasiadis58b58782017-10-05 16:14:50 +0300131 } else {
marination1087d972020-11-26 10:45:44 +0530132 var message = __("No Stock Available Currently");
133 this.content.find('.result').css('text-align', 'center');
134
marinationa97eb6a2021-02-07 22:27:40 +0530135 $(`<div class='text-muted' style='margin: 20px 5px;'>
marination1087d972020-11-26 10:45:44 +0530136 ${message} </div>`).appendTo(this.result);
Stavros Anastasiadis58b58782017-10-05 16:14:50 +0300137 }
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530138 },
marination1087d972020-11-26 10:45:44 +0530139
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530140 get_item_dashboard_data: function(data, max_count, show_item) {
141 if(!max_count) max_count = 0;
Rushabh Mehta0dcb8612016-05-31 07:22:37 +0530142 if(!data) data = [];
Vinayak Jethe549c1962018-01-24 19:47:59 +0530143
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530144 data.forEach(function(d) {
Nabin Haita6746402018-03-28 11:16:00 +0530145 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 +0530146 d.pending_qty = 0;
Nabin Hait2c7a6e62018-03-12 14:12:12 +0530147 d.total_reserved = d.reserved_qty + d.reserved_qty_for_production + d.reserved_qty_for_sub_contract;
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530148 if(d.actual_or_pending > d.actual_qty) {
149 d.pending_qty = d.actual_or_pending - d.actual_qty;
150 }
151
152 max_count = Math.max(d.actual_or_pending, d.actual_qty,
153 d.total_reserved, max_count);
154 });
Vinayak Jethe549c1962018-01-24 19:47:59 +0530155
marination1087d972020-11-26 10:45:44 +0530156 let can_write = 0;
marination0f3cfc52020-12-08 19:11:51 +0530157 if (frappe.boot.user.can_write.indexOf("Stock Entry") >= 0) {
Vinayak Jethe549c1962018-01-24 19:47:59 +0530158 can_write = 1;
159 }
160
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530161 return {
162 data: data,
163 max_count: max_count,
Vinayak Jethe549c1962018-01-24 19:47:59 +0530164 can_write:can_write,
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530165 show_item: show_item || false
marinationb8aeb9e2021-01-05 12:16:25 +0530166 };
marination1087d972020-11-26 10:45:44 +0530167 },
168
169 get_capacity_dashboard_data: function(data) {
marination0f3cfc52020-12-08 19:11:51 +0530170 if (!data) data = [];
marination1087d972020-11-26 10:45:44 +0530171
172 data.forEach(function(d) {
173 d.color = d.percent_occupied >=80 ? "#f8814f" : "#2490ef";
174 });
175
176 let can_write = 0;
marination0f3cfc52020-12-08 19:11:51 +0530177 if (frappe.boot.user.can_write.indexOf("Putaway Rule") >= 0) {
marination1087d972020-11-26 10:45:44 +0530178 can_write = 1;
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530179 }
marination1087d972020-11-26 10:45:44 +0530180
181 return {
182 data: data,
183 can_write: can_write,
marination0f3cfc52020-12-08 19:11:51 +0530184 };
Rushabh Mehta3d2622c2016-04-25 17:53:42 +0530185 }
marination0f3cfc52020-12-08 19:11:51 +0530186});
Shivam Mishra444091b2019-07-10 10:22:08 +0530187
188erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callback) {
189 var dialog = new frappe.ui.Dialog({
190 title: target ? __('Add Item') : __('Move Item'),
191 fields: [
192 {fieldname: 'item_code', label: __('Item'),
193 fieldtype: 'Link', options: 'Item', read_only: 1},
194 {fieldname: 'source', label: __('Source Warehouse'),
195 fieldtype: 'Link', options: 'Warehouse', read_only: 1},
196 {fieldname: 'target', label: __('Target Warehouse'),
197 fieldtype: 'Link', options: 'Warehouse', reqd: 1},
198 {fieldname: 'qty', label: __('Quantity'), reqd: 1,
199 fieldtype: 'Float', description: __('Available {0}', [actual_qty]) },
200 {fieldname: 'rate', label: __('Rate'), fieldtype: 'Currency', hidden: 1 },
201 ],
202 })
203 dialog.show();
204 dialog.get_field('item_code').set_input(item);
205
206 if(source) {
207 dialog.get_field('source').set_input(source);
208 } else {
209 dialog.get_field('source').df.hidden = 1;
210 dialog.get_field('source').refresh();
211 }
212
213 if(rate) {
214 dialog.get_field('rate').set_value(rate);
215 dialog.get_field('rate').df.hidden = 0;
216 dialog.get_field('rate').refresh();
217 }
218
219 if(target) {
220 dialog.get_field('target').df.read_only = 1;
221 dialog.get_field('target').value = target;
222 dialog.get_field('target').refresh();
223 }
224
225 dialog.set_primary_action(__('Submit'), function() {
226 var values = dialog.get_values();
227 if(!values) {
228 return;
229 }
230 if(source && values.qty > actual_qty) {
231 frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
232 return;
233 }
234 if(values.source === values.target) {
235 frappe.msgprint(__('Source and target warehouse must be different'));
236 }
237
238 frappe.call({
239 method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
240 args: values,
241 freeze: true,
242 callback: function(r) {
243 frappe.show_alert(__('Stock Entry {0} created',
Rushabh Mehta2cd41bc2020-12-18 13:17:58 +0530244 ['<a href="/app/stock-entry/'+r.message.name+'">' + r.message.name+ '</a>']));
Shivam Mishra444091b2019-07-10 10:22:08 +0530245 dialog.hide();
246 callback(r);
247 },
248 });
249 });
250
251 $('<p style="margin-left: 10px;"><a class="link-open text-muted small">'
252 + __("Add more items or open full form") + '</a></p>')
253 .appendTo(dialog.body)
254 .find('.link-open')
255 .on('click', function() {
256 frappe.model.with_doctype('Stock Entry', function() {
257 var doc = frappe.model.get_new_doc('Stock Entry');
258 doc.from_warehouse = dialog.get_value('source');
259 doc.to_warehouse = dialog.get_value('target');
260 var row = frappe.model.add_child(doc, 'items');
261 row.item_code = dialog.get_value('item_code');
262 row.f_warehouse = dialog.get_value('target');
263 row.t_warehouse = dialog.get_value('target');
264 row.qty = dialog.get_value('qty');
265 row.conversion_factor = 1;
266 row.transfer_qty = dialog.get_value('qty');
267 row.basic_rate = dialog.get_value('rate');
268 frappe.set_route('Form', doc.doctype, doc.name);
269 })
270 });
Shivam Mishra7339c722019-07-16 13:19:13 +0530271}