39e0191a499fcc6b44864a996a1fb3c84a8d5e02
[kivitendo-erp.git] / js / kivi.Order.js
1 namespace('kivi.Order', function(ns) {
2   ns.check_cv = function() {
3     if ($('#type').val() == 'sales_order') {
4       if ($('#order_customer_id').val() === '') {
5         alert(kivi.t8('Please select a customer.'));
6         return false;
7       }
8     } else  {
9       if ($('#order_vendor_id').val() === '') {
10         alert(kivi.t8('Please select a vendor.'));
11         return false;
12       }
13     }
14     return true;
15   };
16
17   ns.check_save_duplicate_parts = function() {
18     var id_arr = $('[name="order.orderitems[].parts_id"]').map(function() {return this.value;}).get();
19
20     var i, obj = {}, pos = [];
21
22     for (i = 0; i < id_arr.length; i++) {
23       var id = id_arr[i];
24       if (obj.hasOwnProperty(id)) {
25         pos.push(i + 1);
26       }
27       obj[id] = 0;
28     }
29
30     if (pos.length > 0) {
31       return confirm(kivi.t8("There are duplicate parts at positions") + "\n"
32                      + pos.join(', ') + "\n"
33                      + kivi.t8("Do you really want to save?"));
34     }
35     return true;
36   };
37
38   ns.save = function(warn_on_duplicates) {
39     if (!ns.check_cv()) return;
40     if (warn_on_duplicates && !ns.check_save_duplicate_parts()) return;
41
42     var data = $('#order_form').serializeArray();
43     data.push({ name: 'action', value: 'Order/save' });
44
45     $.post("controller.pl", data, kivi.eval_json_result);
46   };
47
48   ns.save_and_delivery_order = function(warn_on_duplicates) {
49     if (!ns.check_cv()) return;
50     if (warn_on_duplicates && !ns.check_save_duplicate_parts()) return;
51
52     var data = $('#order_form').serializeArray();
53     data.push({ name: 'action', value: 'Order/save_and_delivery_order' });
54
55     $.post("controller.pl", data, kivi.eval_json_result);
56   };
57
58   ns.save_and_invoice = function(warn_on_duplicates) {
59     if (!ns.check_cv()) return;
60     if (warn_on_duplicates && !ns.check_save_duplicate_parts()) return;
61
62     var data = $('#order_form').serializeArray();
63     data.push({ name: 'action', value: 'Order/save_and_invoice' });
64
65     $.post("controller.pl", data, kivi.eval_json_result);
66   };
67
68   ns.delete_order = function() {
69     var data = $('#order_form').serializeArray();
70     data.push({ name: 'action', value: 'Order/delete' });
71
72     $.post("controller.pl", data, kivi.eval_json_result);
73   };
74
75   ns.show_print_options = function() {
76     if (!ns.check_cv()) return;
77
78     kivi.popup_dialog({
79       id: 'print_options',
80       dialog: {
81         title: kivi.t8('Print options'),
82         width:  800,
83         height: 300
84       }
85     });
86   };
87
88   ns.print = function() {
89     $('#print_options').dialog('close');
90
91     var data = $('#order_form').serializeArray();
92     data = data.concat($('#print_options_form').serializeArray());
93     data.push({ name: 'action', value: 'Order/print' });
94
95     $.post("controller.pl", data, kivi.eval_json_result);
96   };
97
98   ns.download_pdf = function(pdf_filename, key) {
99     var data = [];
100     data.push({ name: 'action', value: 'Order/download_pdf' });
101     data.push({ name: 'type', value: $('#type').val() });
102     data.push({ name: 'pdf_filename', value: pdf_filename });
103     data.push({ name: 'key', value: key });
104     $.download("controller.pl", data);
105   };
106
107   ns.email = function() {
108     if (!ns.check_cv()) return;
109     var data = $('#order_form').serializeArray();
110     data.push({ name: 'action', value: 'Order/show_email_dialog' });
111
112     $.post("controller.pl", data, kivi.eval_json_result);
113   };
114
115   var email_dialog;
116
117   ns.setup_send_email_dialog = function() {
118     kivi.SalesPurchase.show_all_print_options_elements();
119     kivi.SalesPurchase.show_print_options_elements([ 'sendmode', 'media', 'copies', 'remove_draft' ], false);
120
121     $('#print_options_form table').first().remove().appendTo('#email_form_print_options');
122
123     var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
124     $('#email_form_' + to_focus).focus();
125   };
126
127   ns.finish_send_email_dialog = function() {
128     kivi.SalesPurchase.show_all_print_options_elements();
129
130     $('#email_form_print_options table').first().remove().prependTo('#print_options_form');
131     return true;
132   };
133
134   ns.show_email_dialog = function(html) {
135     var id            = 'send_email_dialog';
136     var dialog_params = {
137       id:     id,
138       width:  800,
139       height: 600,
140       title:  kivi.t8('Send email'),
141       modal:  true,
142       beforeClose: kivi.Order.finish_send_email_dialog,
143       close: function(event, ui) {
144         email_dialog.remove();
145       }
146     };
147
148     $('#' + id).remove();
149
150     email_dialog = $('<div style="display:none" id="' + id + '"></div>').appendTo('body');
151     email_dialog.html(html);
152     email_dialog.dialog(dialog_params);
153
154     kivi.Order.setup_send_email_dialog();
155
156     $('.cancel').click(ns.close_email_dialog);
157
158     return true;
159   };
160
161   ns.send_email = function() {
162     var data = $('#order_form').serializeArray();
163     data = data.concat($('[name^="email_form."]').serializeArray());
164     data = data.concat($('[name^="print_options."]').serializeArray());
165     data.push({ name: 'action', value: 'Order/send_email' });
166     $.post("controller.pl", data, kivi.eval_json_result);
167   };
168
169   ns.close_email_dialog = function() {
170     email_dialog.dialog("close");
171   };
172
173   ns.reload_cv_dependant_selections = function() {
174     var data = $('#order_form').serializeArray();
175     data.push({ name: 'action', value: 'Order/customer_vendor_changed' });
176
177     $.post("controller.pl", data, kivi.eval_json_result);
178   };
179
180   ns.reformat_number = function(event) {
181     $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
182   };
183
184   ns.recalc_amounts_and_taxes = function() {
185     var data = $('#order_form').serializeArray();
186     data.push({ name: 'action', value: 'Order/recalc_amounts_and_taxes' });
187
188     $.post("controller.pl", data, kivi.eval_json_result);
189   };
190
191   ns.unit_change = function(event) {
192     var row = $(event.target).parents("tbody").first();
193     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
194     var sellprice_dom = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
195     var select_elt = $(row).find('[name="order.orderitems[].unit"]');
196
197     var oldval = $(select_elt).data('oldval');
198     $(select_elt).data('oldval', $(select_elt).val());
199
200     var data = $('#order_form').serializeArray();
201     data.push({ name: 'action', value: 'Order/unit_changed' });
202     data.push({ name: 'item_id', value: item_id_dom.val() });
203     data.push({ name: 'old_unit', value: oldval });
204     data.push({ name: 'sellprice_dom_id', value: sellprice_dom.attr('id') });
205
206     $.post("controller.pl", data, kivi.eval_json_result);
207   };
208
209   ns.update_sellprice = function(item_id, price_str) {
210     var row = $('#item_' + item_id).parents("tbody").first();
211     var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
212     var html_elt  = $(row).find('[name="sellprice_text"]');
213     price_elt.val(price_str);
214     html_elt.html(price_str);
215   };
216
217   ns.load_second_row = function(row) {
218     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
219     var div_elt = $(row).find('[name="second_row"]');
220
221     if ($(div_elt).data('loaded') == 1) {
222       return;
223     }
224     var data = $('#order_form').serializeArray();
225     data.push({ name: 'action', value: 'Order/load_second_rows' });
226     data.push({ name: 'item_ids[]', value: item_id_dom.val() });
227
228     $.post("controller.pl", data, kivi.eval_json_result);
229   };
230
231   ns.load_all_second_rows = function() {
232     var rows = $('.row_entry').filter(function(idx, elt) {
233       return $(elt).find('[name="second_row"]').data('loaded') != 1;
234     });
235
236     var item_ids = $.map(rows, function(elt) {
237       var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
238       return { name: 'item_ids[]', value: item_id };
239     });
240
241     if (item_ids.length == 0) {
242       return;
243     }
244
245     var data = $('#order_form').serializeArray();
246     data.push({ name: 'action', value: 'Order/load_second_rows' });
247     data = data.concat(item_ids);
248
249     $.post("controller.pl", data, kivi.eval_json_result);
250   };
251
252   ns.hide_second_row = function(row) {
253     $(row).children().not(':first').hide();
254     $(row).data('expanded', 0);
255     var elt = $(row).find('.expand');
256     elt.attr('src', "image/expand.svg");
257     elt.attr('alt', kivi.t8('Show details'));
258     elt.attr('title', kivi.t8('Show details'));
259   };
260
261   ns.show_second_row = function(row) {
262     $(row).children().not(':first').show();
263     $(row).data('expanded', 1);
264     var elt = $(row).find('.expand');
265     elt.attr('src', "image/collapse.svg");
266     elt.attr('alt', kivi.t8('Hide details'));
267     elt.attr('title', kivi.t8('Hide details'));
268   };
269
270   ns.toggle_second_row = function(row) {
271     if ($(row).data('expanded') == 1) {
272       ns.hide_second_row(row);
273     } else {
274       ns.show_second_row(row);
275     }
276   };
277
278   ns.init_row_handlers = function() {
279     kivi.run_once_for('.recalc', 'on_change_recalc', function(elt) {
280       $(elt).change(ns.recalc_amounts_and_taxes);
281     });
282
283     kivi.run_once_for('.reformat_number', 'on_change_reformat', function(elt) {
284       $(elt).change(ns.reformat_number);
285     });
286
287     kivi.run_once_for('.unitselect', 'on_change_unit_with_oldval', function(elt) {
288       $(elt).data('oldval', $(elt).val());
289       $(elt).change(ns.unit_change);
290     });
291
292     kivi.run_once_for('.row_entry', 'on_kbd_click_show_hide', function(elt) {
293       $(elt).keydown(function(event) {
294         if(event.keyCode == 40 && event.shiftKey === true) {
295           // shift arrow down
296           event.preventDefault();
297           var row = $(event.target).parents(".row_entry").first();
298           ns.load_second_row(row);
299           ns.show_second_row(row);
300           return false;
301         }
302         if(event.keyCode == 38 && event.shiftKey === true) {
303           // shift arrow up
304           event.preventDefault();
305           var row = $(event.target).parents(".row_entry").first();
306           ns.hide_second_row(row);
307           return false;
308         }
309       });
310     });
311
312     kivi.run_once_for('.expand', 'expand_second_row', function(elt) {
313       $(elt).click(function(event) {
314         event.preventDefault();
315         var row = $(event.target).parents(".row_entry").first();
316         ns.load_second_row(row);
317         ns.toggle_second_row(row);
318         return false;
319       })
320     });
321
322   };
323
324   ns.redisplay_line_values = function(is_sales, data) {
325     $('.row_entry').each(function(idx, elt) {
326       $(elt).find('[name="linetotal"]').html(data[idx][0]);
327       if (is_sales && $(elt).find('[name="second_row"]').data('loaded') == 1) {
328         var mt = data[idx][1];
329         var mp = data[idx][2];
330         var h  = '<span';
331         if (mt[0] === '-') h += ' class="plus0"';
332         h += '>' + mt + '&nbsp;&nbsp;' + mp + '%';
333         h += '</span>';
334         $(elt).find('[name="linemargin"]').html(h);
335       }
336     });
337   };
338
339   ns.renumber_positions = function() {
340     $('.row_entry [name="position"]').each(function(idx, elt) {
341       $(elt).html(idx+1);
342     });
343   };
344
345   ns.reorder_items = function(order_by) {
346     var dir = $('#' + order_by + '_header_id a img').attr("data-sort-dir");
347     $('#row_table_id thead a img').remove();
348
349     var src;
350     if (dir == "1") {
351       dir = "0";
352       src = "image/up.png";
353     } else {
354       dir = "1";
355       src = "image/down.png";
356     }
357
358     $('#' + order_by + '_header_id a').append('<img border=0 data-sort-dir=' + dir + ' src=' + src + ' alt="' + kivi.t8('sort items') + '">');
359
360     var data = $('#order_form').serializeArray();
361     data.push({ name: 'action', value: 'Order/reorder_items' });
362     data.push({ name: 'order_by', value: order_by });
363     data.push({ name: 'sort_dir', value: dir });
364
365     $.post("controller.pl", data, kivi.eval_json_result);
366   };
367
368   ns.redisplay_items = function(data) {
369     var old_rows = $('.row_entry').detach();
370     var new_rows = [];
371     $(data).each(function(idx, elt) {
372       new_rows.push(old_rows[elt.old_pos - 1]);
373     });
374     $(new_rows).appendTo($('#row_table_id'));
375     ns.renumber_positions();
376   };
377
378   ns.add_item = function() {
379     if ($('#add_item_parts_id').val() === '') return;
380     if (!ns.check_cv()) return;
381
382     $('#row_table_id thead a img').remove();
383
384     var data = $('#order_form').serializeArray();
385     data.push({ name: 'action', value: 'Order/add_item' });
386
387     $.post("controller.pl", data, kivi.eval_json_result);
388   };
389
390   ns.show_multi_items_dialog = function() {
391     if (!ns.check_cv()) return;
392
393     $('#row_table_id thead a img').remove();
394
395     kivi.popup_dialog({
396       url: 'controller.pl?action=Order/show_multi_items_dialog',
397       data: { type: $('#type').val(),
398               callback: 'Order/add_multi_items',
399               callback_data_id: 'order_form' },
400       id: 'jq_multi_items_dialog',
401       dialog: {
402         title: kivi.t8('Add multiple items'),
403         width:  800,
404         height: 500
405       }
406     });
407     return true;
408   };
409
410   ns.close_multi_items_dialog = function() {
411     $('#jq_multi_items_dialog').dialog('close');
412   };
413
414   ns.delete_order_item_row = function(clicked) {
415     var row = $(clicked).parents("tbody").first();
416     $(row).remove();
417
418     ns.renumber_positions();
419     ns.recalc_amounts_and_taxes();
420   };
421
422   ns.row_table_scroll_down = function() {
423     $('#row_table_scroll_id').scrollTop($('#row_table_scroll_id')[0].scrollHeight);
424   };
425
426   ns.show_longdescription_dialog = function(clicked) {
427     var row = $(clicked).parents("tbody").first();
428     var position = $(row).find('[name="position"]').html();
429     var partnumber = $(row).find('[name="partnumber"]').html();
430     var description_elt = $(row).find('[name="order.orderitems[].description"]');
431     var description = description_elt.val();
432     var longdescription_elt = $(row).find('[name="order.orderitems[].longdescription"]');
433     var longdescription;
434
435     if (!longdescription_elt.length) {
436       var data = [];
437       data.push({ name: 'action', value: 'Order/get_item_longdescription' });
438       data.push({ name: 'type', value: $('#type').val() });
439       data.push({ name: 'item_id', value: $(row).find('[name="order.orderitems[+].id"]').val() });
440       data.push({ name: 'parts_id', value: $(row).find('[name="order.orderitems[].parts_id"]').val() });
441       $.ajax({
442         url: 'controller.pl',
443         data: data,
444         method: "GET",
445         async: false,
446         dataType: 'text',
447         success: function(val){
448           longdescription = val;
449         }
450       });
451     } else {
452       longdescription = longdescription_elt.val();
453     }
454
455     var params = { runningnumber: position,
456                    partnumber: partnumber,
457                    description: description,
458                    default_longdescription: longdescription,
459                    set_function: function(val){
460                      longdescription_elt.remove();
461                      $('<input type="hidden" name="order.orderitems[].longdescription">').insertAfter(description_elt).val(val);
462                    }
463                  };
464
465     kivi.SalesPurchase.edit_longdescription_with_params(params);
466   };
467
468   ns.price_chooser_item_row = function(clicked) {
469     var row = $(clicked).parents("tbody").first();
470     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
471
472     var data = $('#order_form').serializeArray();
473     data.push({ name: 'action', value: 'Order/price_popup' });
474     data.push({ name: 'item_id', value: item_id_dom.val() });
475
476     $.post("controller.pl", data, kivi.eval_json_result);
477   };
478
479   ns.update_price_source = function(item_id, source, descr, price_str, price_editable) {
480     var row = $('#item_' + item_id).parents("tbody").first();
481     var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]');
482     var button_elt = $(row).find('[name="price_chooser_button"]');
483
484     button_elt.val(button_elt.val().replace(/.*\|/, descr + " |"));
485     source_elt.val(source);
486
487     var editable_div_elt = $(row).find('[name="editable_price"]');
488     var not_editable_div_elt = $(row).find('[name="not_editable_price"]');
489     if (price_editable == 1 && source === '') {
490       // editable
491       $(editable_div_elt).show();
492       $(not_editable_div_elt).hide();
493       $(editable_div_elt).find(':input').prop("disabled", false);
494       $(not_editable_div_elt).find(':input').prop("disabled", true);
495     } else {
496       // not editable
497       $(editable_div_elt).hide();
498       $(not_editable_div_elt).show();
499       $(editable_div_elt).find(':input').prop("disabled", true);
500       $(not_editable_div_elt).find(':input').prop("disabled", false);
501     }
502
503     if (price_str) {
504       var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
505       var html_elt  = $(row).find('[name="sellprice_text"]');
506       price_elt.val(price_str);
507       html_elt.html(price_str);
508       ns.recalc_amounts_and_taxes();
509     }
510
511     kivi.io.close_dialog();
512   };
513
514   ns.update_discount_source = function(item_id, source, descr, discount_str, price_editable) {
515     var row = $('#item_' + item_id).parents("tbody").first();
516     var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]');
517     var button_elt = $(row).find('[name="price_chooser_button"]');
518
519     button_elt.val(button_elt.val().replace(/\|.*/, "| " + descr));
520     source_elt.val(source);
521
522     var editable_div_elt = $(row).find('[name="editable_discount"]');
523     var not_editable_div_elt = $(row).find('[name="not_editable_discount"]');
524     if (price_editable == 1 && source === '') {
525       // editable
526       $(editable_div_elt).show();
527       $(not_editable_div_elt).hide();
528       $(editable_div_elt).find(':input').prop("disabled", false);
529       $(not_editable_div_elt).find(':input').prop("disabled", true);
530     } else {
531       // not editable
532       $(editable_div_elt).hide();
533       $(not_editable_div_elt).show();
534       $(editable_div_elt).find(':input').prop("disabled", true);
535       $(not_editable_div_elt).find(':input').prop("disabled", false);
536     }
537
538     if (discount_str) {
539       var discount_elt = $(row).find('[name="order.orderitems[].discount_as_percent"]');
540       var html_elt     = $(row).find('[name="discount_text"]');
541       discount_elt.val(discount_str);
542       html_elt.html(discount_str);
543       ns.recalc_amounts_and_taxes();
544     }
545
546     kivi.io.close_dialog();
547   };
548
549   ns.show_periodic_invoices_config_dialog = function() {
550     if ($('#type').val() !== 'sales_order') return;
551
552     kivi.popup_dialog({
553       url: 'controller.pl?action=Order/show_periodic_invoices_config_dialog',
554       data: { type       : $('#type').val(),
555               id         : $('#id').val(),
556               config     : $('#order_periodic_invoices_config').val(),
557               customer_id: $('#order_customer_id').val(),
558               transdate  : $('#order_transdate').val(),
559               language_id: $('#language_id').val()
560             },
561       id: 'jq_periodic_invoices_config_dialog',
562       load: kivi.reinit_widgets,
563       dialog: {
564         title: kivi.t8('Edit the configuration for periodic invoices'),
565         width:  800,
566         height: 650
567       }
568     });
569     return true;
570   };
571
572   ns.close_periodic_invoices_config_dialog = function() {
573     $('#jq_periodic_invoices_config_dialog').dialog('close');
574   };
575
576   ns.assign_periodic_invoices_config = function() {
577     var data = $('[name="Form"]').serializeArray();
578     data.push({ name: 'type',   value: $('#type').val() });
579     data.push({ name: 'action', value: 'Order/assign_periodic_invoices_config' });
580     $.post("controller.pl", data, kivi.eval_json_result);
581   };
582
583   ns.check_save_active_periodic_invoices = function() {
584     var type = $('#type').val();
585     if (type !== 'sales_order') return true;
586
587     var active = false;
588     $.ajax({
589       url: 'controller.pl',
590       data: { action: 'Order/get_has_active_periodic_invoices',
591               type  : type,
592               id    : $('#id').val(),
593               config: $('#order_periodic_invoices_config').val(),
594       },
595       method: "GET",
596       async: false,
597       dataType: 'text',
598       success: function(val){
599         active = val;
600       }
601     });
602
603     if (active == 1) {
604       return confirm(kivi.t8('This sales order has an active configuration for periodic invoices. If you save then all subsequently created invoices will contain those changes as well, but not those that have already been created. Do you want to continue?'));
605     }
606
607     return true;
608   };
609
610 });
611
612 $(function(){
613   if ($('#type').val() == 'sales_order') {
614     $('#order_customer_id').change(kivi.Order.reload_cv_dependant_selections);
615   } else {
616     $('#order_vendor_id').change(kivi.Order.reload_cv_dependant_selections);
617   }
618
619   if ($('#type').val() == 'sales_order') {
620     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
621   } else {
622     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) });
623   }
624   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
625   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
626
627   $('.add_item_input').keydown(function(event) {
628     if(event.keyCode == 13) {
629       event.preventDefault();
630       kivi.Order.add_item();
631       return false;
632     }
633   });
634
635   kivi.Order.init_row_handlers();
636
637   $('#row_table_id').on('sortstop', function(event, ui) {
638     $('#row_table_id thead a img').remove();
639     kivi.Order.renumber_positions();
640   });
641
642   $('#expand_all').on('click', function(event) {
643     event.preventDefault();
644     if ($('#expand_all').data('expanded') == 1) {
645       $('#expand_all').data('expanded', 0);
646       $('#expand_all').attr('src', 'image/expand.svg');
647       $('#expand_all').attr('alt', kivi.t8('Show all details'));
648       $('#expand_all').attr('title', kivi.t8('Show all details'));
649       $('.row_entry').each(function(idx, elt) {
650         kivi.Order.hide_second_row(elt);
651       });
652     } else {
653       $('#expand_all').data('expanded', 1);
654       $('#expand_all').attr('src', "image/collapse.svg");
655       $('#expand_all').attr('alt', kivi.t8('Hide all details'));
656       $('#expand_all').attr('title', kivi.t8('Hide all details'));
657       kivi.Order.load_all_second_rows();
658       $('.row_entry').each(function(idx, elt) {
659         kivi.Order.show_second_row(elt);
660       });
661     }
662     return false;
663   });
664
665 });