Merge remote-tracking branch 'origin/f-leistungsdatum'
[kivitendo-erp.git] / js / kivi.Order.js
1 namespace('kivi.Order', function(ns) {
2   ns.check_cv = function() {
3     if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation') {
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_duplicate_parts = function(question) {
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       question = question || kivi.t8("Do you really want to save?");
32       return confirm(kivi.t8("There are duplicate parts at positions") + "\n"
33                      + pos.join(', ') + "\n"
34                      + question);
35     }
36     return true;
37   };
38
39   ns.check_valid_reqdate = function() {
40     if ($('#order_reqdate_as_date').val() === '') {
41       alert(kivi.t8('Please select a delivery date.'));
42       return false;
43     } else {
44       return true;
45     }
46   };
47
48   ns.save = function(action, warn_on_duplicates, warn_on_reqdate) {
49     if (!ns.check_cv()) return;
50     if (warn_on_duplicates && !ns.check_duplicate_parts()) return;
51     if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
52
53     var data = $('#order_form').serializeArray();
54     data.push({ name: 'order.language_id', value: $('#language_id').val() }); // language from print options
55     data.push({ name: 'action', value: 'Order/' + action });
56
57     $.post("controller.pl", data, kivi.eval_json_result);
58   };
59
60   ns.delete_order = function() {
61     var data = $('#order_form').serializeArray();
62     data.push({ name: 'action', value: 'Order/delete' });
63
64     $.post("controller.pl", data, kivi.eval_json_result);
65   };
66
67   ns.show_print_options = function(warn_on_duplicates) {
68     if (!ns.check_cv()) return;
69     if (warn_on_duplicates && !ns.check_duplicate_parts(kivi.t8("Do you really want to print?"))) return;
70
71     kivi.popup_dialog({
72       id: 'print_options',
73       dialog: {
74         title: kivi.t8('Print options'),
75         width:  800,
76         height: 300
77       }
78     });
79   };
80
81   ns.print = function() {
82     $('#print_options').dialog('close');
83
84     var data = $('#order_form').serializeArray();
85     data = data.concat($('#print_options_form').serializeArray());
86     data.push({ name: 'order.language_id', value: $('#language_id').val() }); // language from print options
87     data.push({ name: 'action', value: 'Order/print' });
88
89     $.post("controller.pl", data, kivi.eval_json_result);
90   };
91
92   ns.email = function(warn_on_duplicates) {
93     if (warn_on_duplicates && !ns.check_duplicate_parts(kivi.t8("Do you really want to send by mail?"))) return;
94     if (!ns.check_cv()) return;
95
96     var data = $('#order_form').serializeArray();
97     data.push({ name: 'order.language_id', value: $('#language_id').val() }); // language from print options
98     data.push({ name: 'action', value: 'Order/show_email_dialog' });
99
100     $.post("controller.pl", data, kivi.eval_json_result);
101   };
102
103   var email_dialog;
104
105   ns.setup_send_email_dialog = function() {
106     kivi.SalesPurchase.show_all_print_options_elements();
107     kivi.SalesPurchase.show_print_options_elements([ 'sendmode', 'media', 'copies', 'remove_draft' ], false);
108
109     $('#print_options_form table').first().remove().appendTo('#email_form_print_options');
110
111     var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
112     $('#email_form_' + to_focus).focus();
113   };
114
115   ns.finish_send_email_dialog = function() {
116     kivi.SalesPurchase.show_all_print_options_elements();
117
118     $('#email_form_print_options table').first().remove().prependTo('#print_options_form');
119     return true;
120   };
121
122   ns.show_email_dialog = function(html) {
123     var id            = 'send_email_dialog';
124     var dialog_params = {
125       id:     id,
126       width:  800,
127       height: 600,
128       title:  kivi.t8('Send email'),
129       modal:  true,
130       beforeClose: kivi.Order.finish_send_email_dialog,
131       close: function(event, ui) {
132         email_dialog.remove();
133       }
134     };
135
136     $('#' + id).remove();
137
138     email_dialog = $('<div style="display:none" id="' + id + '"></div>').appendTo('body');
139     email_dialog.html(html);
140     email_dialog.dialog(dialog_params);
141
142     kivi.Order.setup_send_email_dialog();
143
144     $('.cancel').click(ns.close_email_dialog);
145
146     return true;
147   };
148
149   ns.send_email = function() {
150     var data = $('#order_form').serializeArray();
151     data = data.concat($('[name^="email_form."]').serializeArray());
152     data = data.concat($('[name^="print_options."]').serializeArray());
153     data.push({ name: 'order.language_id', value: $('#language_id').val() }); // language from print options
154     data.push({ name: 'action', value: 'Order/send_email' });
155     $.post("controller.pl", data, kivi.eval_json_result);
156   };
157
158   ns.close_email_dialog = function() {
159     email_dialog.dialog("close");
160   };
161
162   ns.set_number_in_title = function(elt) {
163     $('#nr_in_title').html($(elt).val());
164   };
165
166   ns.reload_cv_dependent_selections = function() {
167     var data = $('#order_form').serializeArray();
168     data.push({ name: 'action', value: 'Order/customer_vendor_changed' });
169
170     $.post("controller.pl", data, kivi.eval_json_result);
171   };
172
173   ns.reformat_number = function(event) {
174     $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
175   };
176
177   ns.recalc_amounts_and_taxes = function() {
178     var data = $('#order_form').serializeArray();
179     data.push({ name: 'action', value: 'Order/recalc_amounts_and_taxes' });
180
181     $.post("controller.pl", data, kivi.eval_json_result);
182   };
183
184   ns.unit_change = function(event) {
185     var row           = $(event.target).parents("tbody").first();
186     var item_id_dom   = $(row).find('[name="orderitem_ids[+]"]');
187     var sellprice_dom = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
188     var select_elt    = $(row).find('[name="order.orderitems[].unit"]');
189
190     var oldval = $(select_elt).data('oldval');
191     $(select_elt).data('oldval', $(select_elt).val());
192
193     var data = $('#order_form').serializeArray();
194     data.push({ name: 'action',           value: 'Order/unit_changed'     },
195               { name: 'item_id',          value: item_id_dom.val()        },
196               { name: 'old_unit',         value: oldval                   },
197               { name: 'sellprice_dom_id', value: sellprice_dom.attr('id') });
198
199     $.post("controller.pl", data, kivi.eval_json_result);
200   };
201
202   ns.update_sellprice = function(item_id, price_str) {
203     var row       = $('#item_' + item_id).parents("tbody").first();
204     var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
205     var html_elt  = $(row).find('[name="sellprice_text"]');
206     price_elt.val(price_str);
207     html_elt.html(price_str);
208   };
209
210   ns.load_second_row = function(row) {
211     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
212     var div_elt     = $(row).find('[name="second_row"]');
213
214     if ($(div_elt).data('loaded') == 1) {
215       return;
216     }
217     var data = $('#order_form').serializeArray();
218     data.push({ name: 'action',     value: 'Order/load_second_rows' },
219               { name: 'item_ids[]', value: item_id_dom.val()        });
220
221     $.post("controller.pl", data, kivi.eval_json_result);
222   };
223
224   ns.load_all_second_rows = function() {
225     var rows = $('.row_entry').filter(function(idx, elt) {
226       return $(elt).find('[name="second_row"]').data('loaded') != 1;
227     });
228
229     var item_ids = $.map(rows, function(elt) {
230       var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
231       return { name: 'item_ids[]', value: item_id };
232     });
233
234     if (item_ids.length == 0) {
235       return;
236     }
237
238     var data = $('#order_form').serializeArray();
239     data.push({ name: 'action', value: 'Order/load_second_rows' });
240     data = data.concat(item_ids);
241
242     $.post("controller.pl", data, kivi.eval_json_result);
243   };
244
245   ns.hide_second_row = function(row) {
246     $(row).children().not(':first').hide();
247     $(row).data('expanded', 0);
248     var elt = $(row).find('.expand');
249     elt.attr('src', "image/expand.svg");
250     elt.attr('alt', kivi.t8('Show details'));
251     elt.attr('title', kivi.t8('Show details'));
252   };
253
254   ns.show_second_row = function(row) {
255     $(row).children().not(':first').show();
256     $(row).data('expanded', 1);
257     var elt = $(row).find('.expand');
258     elt.attr('src', "image/collapse.svg");
259     elt.attr('alt', kivi.t8('Hide details'));
260     elt.attr('title', kivi.t8('Hide details'));
261   };
262
263   ns.toggle_second_row = function(row) {
264     if ($(row).data('expanded') == 1) {
265       ns.hide_second_row(row);
266     } else {
267       ns.show_second_row(row);
268     }
269   };
270
271   ns.init_row_handlers = function() {
272     kivi.run_once_for('.recalc', 'on_change_recalc', function(elt) {
273       $(elt).change(ns.recalc_amounts_and_taxes);
274     });
275
276     kivi.run_once_for('.reformat_number', 'on_change_reformat', function(elt) {
277       $(elt).change(ns.reformat_number);
278     });
279
280     kivi.run_once_for('.unitselect', 'on_change_unit_with_oldval', function(elt) {
281       $(elt).data('oldval', $(elt).val());
282       $(elt).change(ns.unit_change);
283     });
284
285     kivi.run_once_for('.row_entry', 'on_kbd_click_show_hide', function(elt) {
286       $(elt).keydown(function(event) {
287         var row;
288         if (event.keyCode == 40 && event.shiftKey === true) {
289           // shift arrow down
290           event.preventDefault();
291           row = $(event.target).parents(".row_entry").first();
292           ns.load_second_row(row);
293           ns.show_second_row(row);
294           return false;
295         }
296         if (event.keyCode == 38 && event.shiftKey === true) {
297           // shift arrow up
298           event.preventDefault();
299           row = $(event.target).parents(".row_entry").first();
300           ns.hide_second_row(row);
301           return false;
302         }
303       });
304     });
305
306     kivi.run_once_for('.expand', 'expand_second_row', function(elt) {
307       $(elt).click(function(event) {
308         event.preventDefault();
309         var row = $(event.target).parents(".row_entry").first();
310         ns.load_second_row(row);
311         ns.toggle_second_row(row);
312         return false;
313       })
314     });
315
316   };
317
318   ns.redisplay_line_values = function(is_sales, data) {
319     $('.row_entry').each(function(idx, elt) {
320       $(elt).find('[name="linetotal"]').html(data[idx][0]);
321       if (is_sales && $(elt).find('[name="second_row"]').data('loaded') == 1) {
322         var mt = data[idx][1];
323         var mp = data[idx][2];
324         var h  = '<span';
325         if (mt[0] === '-') h += ' class="plus0"';
326         h += '>' + mt + '&nbsp;&nbsp;' + mp + '%';
327         h += '</span>';
328         $(elt).find('[name="linemargin"]').html(h);
329       }
330     });
331   };
332
333   ns.redisplay_cvpartnumbers = function(data) {
334     $('.row_entry').each(function(idx, elt) {
335       $(elt).find('[name="cvpartnumber"]').html(data[idx][0]);
336     });
337   };
338
339   ns.renumber_positions = function() {
340     $('.row_entry [name="position"]').each(function(idx, elt) {
341       $(elt).html(idx+1);
342     });
343     $('.row_entry').each(function(idx, elt) {
344       $(elt).data("position", idx+1);
345     });
346   };
347
348   ns.reorder_items = function(order_by) {
349     var dir = $('#' + order_by + '_header_id a img').attr("data-sort-dir");
350     $('#row_table_id thead a img').remove();
351
352     var src;
353     if (dir == "1") {
354       dir = "0";
355       src = "image/up.png";
356     } else {
357       dir = "1";
358       src = "image/down.png";
359     }
360
361     $('#' + order_by + '_header_id a').append('<img border=0 data-sort-dir=' + dir + ' src=' + src + ' alt="' + kivi.t8('sort items') + '">');
362
363     var data = $('#order_form').serializeArray();
364     data.push({ name: 'action',   value: 'Order/reorder_items' },
365               { name: 'order_by', value: order_by              },
366               { name: 'sort_dir', value: dir                   });
367
368     $.post("controller.pl", data, kivi.eval_json_result);
369   };
370
371   ns.redisplay_items = function(data) {
372     var old_rows = $('.row_entry').detach();
373     var new_rows = [];
374     $(data).each(function(idx, elt) {
375       new_rows.push(old_rows[elt.old_pos - 1]);
376     });
377     $(new_rows).appendTo($('#row_table_id'));
378     ns.renumber_positions();
379   };
380
381   ns.get_insert_before_item_id = function(wanted_pos) {
382     if (wanted_pos === '') return;
383
384     var insert_before_item_id;
385     // selection by data does not seem to work if data is changed at runtime
386     // var elt = $('.row_entry [data-position="' + wanted_pos + '"]');
387     $('.row_entry').each(function(idx, elt) {
388       if ($(elt).data("position") == wanted_pos) {
389         insert_before_item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
390         return false;
391       }
392     });
393
394     return insert_before_item_id;
395   };
396
397   ns.add_item = function() {
398     if ($('#add_item_parts_id').val() === '') return;
399     if (!ns.check_cv()) return;
400
401     $('#row_table_id thead a img').remove();
402
403     var insert_before_item_id = ns.get_insert_before_item_id($('#add_item_position').val());
404
405     var data = $('#order_form').serializeArray();
406     data.push({ name: 'action', value: 'Order/add_item' },
407               { name: 'insert_before_item_id', value: insert_before_item_id });
408
409     $.post("controller.pl", data, kivi.eval_json_result);
410   };
411
412   ns.setup_multi_items_dialog = function() {
413     $('#multi_items_filter_table input, #multi_items_filter_table select').keydown(function(event) {
414       if (event.keyCode == 13) {
415         event.preventDefault();
416         ns.multi_items_dialog_update_result();
417         return false;
418       }
419     });
420
421     $('#multi_items_filter_all_substr_multi_ilike').focus();
422   };
423
424   ns.show_multi_items_dialog = function() {
425     if (!ns.check_cv()) return;
426
427     $('#row_table_id thead a img').remove();
428
429     kivi.popup_dialog({
430       url:    'controller.pl?action=Order/show_multi_items_dialog',
431       data:   { type: $('#type').val() },
432       id:     'jq_multi_items_dialog',
433       load:   kivi.Order.setup_multi_items_dialog,
434       dialog: {
435         title:  kivi.t8('Add multiple items'),
436         width:  800,
437         height: 500
438       }
439     });
440     return true;
441   };
442
443   ns.close_multi_items_dialog = function() {
444     $('#jq_multi_items_dialog').dialog('close');
445   };
446
447   ns.multi_items_dialog_update_result = function() {
448     var data = $('#multi_items_form').serializeArray();
449     data.push({ name: 'type', value: $('#type').val() });
450     $.ajax({
451       url:     'controller.pl?action=Order/multi_items_update_result',
452       data:    data,
453       method:  'post',
454       success: function(data) {
455         $('#multi_items_result').html(data);
456         ns.multi_items_dialog_enable_continue();
457         ns.multi_items_result_setup_events();
458       }
459     });
460   };
461
462   ns.multi_items_dialog_disable_continue = function() {
463     // disable keydown-event and continue button to prevent
464     // impatient users to add parts multiple times
465     $('#multi_items_result input, #multi_items_position').off("keydown");
466     $('#multi_items_dialog_continue_button').prop('disabled', true);
467   };
468
469   ns.multi_items_dialog_enable_continue = function()  {
470     $('#multi_items_result input, #multi_items_position').keydown(function(event) {
471       if(event.keyCode == 13) {
472         event.preventDefault();
473         ns.add_multi_items();
474         return false;
475       }
476     });
477     $('#multi_items_dialog_continue_button').prop('disabled', false);
478   };
479
480   ns.multi_items_result_setup_events = function() {
481     $('#multi_items_all_qty').change(ns.reformat_number);
482     $('#multi_items_all_qty').change(function(event) {
483       $('.multi_items_qty').val($(event.target).val());
484     });
485     $('.multi_items_qty').change(ns.reformat_number);
486   }
487
488   ns.add_multi_items = function() {
489     // rows at all
490     var n_rows = $('.multi_items_qty').length;
491     if (n_rows == 0) return;
492
493     // filled rows
494     n_rows = $('.multi_items_qty').filter(function() {
495       return $(this).val().length > 0;
496     }).length;
497     if (n_rows == 0) return;
498
499     ns.multi_items_dialog_disable_continue();
500
501     var insert_before_item_id = ns.get_insert_before_item_id($('#multi_items_position').val());
502
503     var data = $('#order_form').serializeArray();
504     data = data.concat($('#multi_items_form').serializeArray());
505     data.push({ name: 'action', value: 'Order/add_multi_items' },
506               { name: 'insert_before_item_id', value: insert_before_item_id });
507     $.post("controller.pl", data, kivi.eval_json_result);
508   };
509
510   ns.set_input_to_one = function(clicked) {
511     if ($(clicked).val() == '') {
512       $(clicked).val(kivi.format_amount(1.00, -2));
513     }
514     $(clicked).select();
515   };
516
517   ns.delete_order_item_row = function(clicked) {
518     var row = $(clicked).parents("tbody").first();
519     $(row).remove();
520
521     ns.renumber_positions();
522     ns.recalc_amounts_and_taxes();
523   };
524
525   ns.row_table_scroll_down = function() {
526     $('#row_table_scroll_id').scrollTop($('#row_table_scroll_id')[0].scrollHeight);
527   };
528
529   ns.show_longdescription_dialog = function(clicked) {
530     var row                 = $(clicked).parents("tbody").first();
531     var position            = $(row).find('[name="position"]').html();
532     var partnumber          = $(row).find('[name="partnumber"]').html();
533     var description_elt     = $(row).find('[name="order.orderitems[].description"]');
534     var description         = description_elt.val();
535     var longdescription_elt = $(row).find('[name="order.orderitems[].longdescription"]');
536     var longdescription;
537
538     if (!longdescription_elt.length) {
539       var data = [
540         { name: 'action',   value: 'Order/get_item_longdescription'                          },
541         { name: 'type',     value: $('#type').val()                                          },
542         { name: 'item_id',  value: $(row).find('[name="order.orderitems[+].id"]').val()      },
543         { name: 'parts_id', value: $(row).find('[name="order.orderitems[].parts_id"]').val() }
544       ];
545
546       $.ajax({
547         url:      'controller.pl',
548         data:     data,
549         method:   "GET",
550         async:    false,
551         dataType: 'text',
552         success:  function(val) {
553           longdescription = val;
554         }
555       });
556     } else {
557       longdescription = longdescription_elt.val();
558     }
559
560     var params = {
561       runningnumber:           position,
562       partnumber:              partnumber,
563       description:             description,
564       default_longdescription: longdescription,
565       set_function:            function(val) {
566         longdescription_elt.remove();
567         $('<input type="hidden" name="order.orderitems[].longdescription">').insertAfter(description_elt).val(val);
568       }
569     };
570
571     kivi.SalesPurchase.edit_longdescription_with_params(params);
572   };
573
574   ns.price_chooser_item_row = function(clicked) {
575     if (!ns.check_cv()) return;
576     var row         = $(clicked).parents("tbody").first();
577     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
578
579     var data = $('#order_form').serializeArray();
580     data.push({ name: 'action',  value: 'Order/price_popup' },
581               { name: 'item_id', value: item_id_dom.val()   });
582
583     $.post("controller.pl", data, kivi.eval_json_result);
584   };
585
586   ns.update_price_source = function(item_id, source, descr, price_str, price_editable) {
587     var row        = $('#item_' + item_id).parents("tbody").first();
588     var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]');
589     var button_elt = $(row).find('[name="price_chooser_button"]');
590
591     button_elt.val(button_elt.val().replace(/.*\|/, descr + " |"));
592     source_elt.val(source);
593
594     var editable_div_elt     = $(row).find('[name="editable_price"]');
595     var not_editable_div_elt = $(row).find('[name="not_editable_price"]');
596     if (price_editable == 1 && source === '') {
597       // editable
598       $(editable_div_elt).show();
599       $(not_editable_div_elt).hide();
600       $(editable_div_elt).find(':input').prop("disabled", false);
601       $(not_editable_div_elt).find(':input').prop("disabled", true);
602     } else {
603       // not editable
604       $(editable_div_elt).hide();
605       $(not_editable_div_elt).show();
606       $(editable_div_elt).find(':input').prop("disabled", true);
607       $(not_editable_div_elt).find(':input').prop("disabled", false);
608     }
609
610     if (price_str) {
611       var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
612       var html_elt  = $(row).find('[name="sellprice_text"]');
613       price_elt.val(price_str);
614       html_elt.html(price_str);
615       ns.recalc_amounts_and_taxes();
616     }
617
618     kivi.io.close_dialog();
619   };
620
621   ns.update_discount_source = function(item_id, source, descr, discount_str, price_editable) {
622     var row        = $('#item_' + item_id).parents("tbody").first();
623     var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]');
624     var button_elt = $(row).find('[name="price_chooser_button"]');
625
626     button_elt.val(button_elt.val().replace(/\|.*/, "| " + descr));
627     source_elt.val(source);
628
629     var editable_div_elt     = $(row).find('[name="editable_discount"]');
630     var not_editable_div_elt = $(row).find('[name="not_editable_discount"]');
631     if (price_editable == 1 && source === '') {
632       // editable
633       $(editable_div_elt).show();
634       $(not_editable_div_elt).hide();
635       $(editable_div_elt).find(':input').prop("disabled", false);
636       $(not_editable_div_elt).find(':input').prop("disabled", true);
637     } else {
638       // not editable
639       $(editable_div_elt).hide();
640       $(not_editable_div_elt).show();
641       $(editable_div_elt).find(':input').prop("disabled", true);
642       $(not_editable_div_elt).find(':input').prop("disabled", false);
643     }
644
645     if (discount_str) {
646       var discount_elt = $(row).find('[name="order.orderitems[].discount_as_percent"]');
647       var html_elt     = $(row).find('[name="discount_text"]');
648       discount_elt.val(discount_str);
649       html_elt.html(discount_str);
650       ns.recalc_amounts_and_taxes();
651     }
652
653     kivi.io.close_dialog();
654   };
655
656   ns.show_periodic_invoices_config_dialog = function() {
657     if ($('#type').val() !== 'sales_order') return;
658
659     kivi.popup_dialog({
660       url:    'controller.pl?action=Order/show_periodic_invoices_config_dialog',
661       data:   { type:              $('#type').val(),
662                 id:                $('#id').val(),
663                 config:            $('#order_periodic_invoices_config').val(),
664                 customer_id:       $('#order_customer_id').val(),
665                 transdate_as_date: $('#order_transdate_as_date').val(),
666                 language_id:       $('#language_id').val()
667               },
668       id:     'jq_periodic_invoices_config_dialog',
669       load:   kivi.reinit_widgets,
670       dialog: {
671         title:  kivi.t8('Edit the configuration for periodic invoices'),
672         width:  800,
673         height: 650
674       }
675     });
676     return true;
677   };
678
679   ns.close_periodic_invoices_config_dialog = function() {
680     $('#jq_periodic_invoices_config_dialog').dialog('close');
681   };
682
683   ns.assign_periodic_invoices_config = function() {
684     var data = $('[name="Form"]').serializeArray();
685     data.push({ name: 'type',   value: $('#type').val() },
686               { name: 'action', value: 'Order/assign_periodic_invoices_config' });
687     $.post("controller.pl", data, kivi.eval_json_result);
688   };
689
690   ns.check_save_active_periodic_invoices = function() {
691     var type = $('#type').val();
692     if (type !== 'sales_order') return true;
693
694     var active = false;
695     $.ajax({
696       url:      'controller.pl',
697       data:     { action: 'Order/get_has_active_periodic_invoices',
698                   type  : type,
699                   id    : $('#id').val(),
700                   config: $('#order_periodic_invoices_config').val(),
701                 },
702       method:   "GET",
703       async:    false,
704       dataType: 'text',
705       success:  function(val) {
706         active = val;
707       }
708     });
709
710     if (active == 1) {
711       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?'));
712     }
713
714     return true;
715   };
716
717   ns.show_vc_details_dialog = function() {
718     if (!ns.check_cv()) return;
719     var vc;
720     var vc_id;
721     var title;
722     if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
723       vc    = 'customer';
724       vc_id = $('#order_customer_id').val();
725       title = kivi.t8('Customer details');
726     } else {
727       vc    = 'vendor';
728       vc_id = $('#order_vendor_id').val();
729       title = kivi.t8('Vendor details');
730     }
731
732     kivi.popup_dialog({
733       url:    'controller.pl',
734       data:   { action: 'Order/show_customer_vendor_details_dialog',
735                 type  : $('#type').val(),
736                 vc    : vc,
737                 vc_id : vc_id
738               },
739       id:     'jq_customer_vendor_details_dialog',
740       dialog: {
741         title:  title,
742         width:  800,
743         height: 650
744       }
745     });
746     return true;
747   };
748
749   ns.update_row_from_master_data = function(clicked) {
750     var row = $(clicked).parents("tbody").first();
751     var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
752
753     var data = $('#order_form').serializeArray();
754     data.push({ name: 'action', value: 'Order/update_row_from_master_data' });
755     data.push({ name: 'item_ids[]', value: item_id_dom.val() });
756
757     $.post("controller.pl", data, kivi.eval_json_result);
758   };
759
760   ns.update_all_rows_from_master_data = function() {
761     var item_ids = $.map($('.row_entry'), function(elt) {
762       var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
763       return { name: 'item_ids[]', value: item_id };
764     });
765
766     if (item_ids.length == 0) {
767       return;
768     }
769
770     var data = $('#order_form').serializeArray();
771     data.push({ name: 'action', value: 'Order/update_row_from_master_data' });
772     data = data.concat(item_ids);
773
774     $.post("controller.pl", data, kivi.eval_json_result);
775   };
776
777   ns.show_calculate_qty_dialog = function(clicked) {
778     var row        = $(clicked).parents("tbody").first();
779     var input_id   = $(row).find('[name="order.orderitems[].qty_as_number"]').attr('id');
780     var formula_id = $(row).find('[name="formula[+]"]').attr('id');
781
782     calculate_qty_selection_dialog("", input_id, "", formula_id);
783     return true;
784   };
785
786 });
787
788 $(function() {
789   if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
790     $('#order_customer_id').change(kivi.Order.reload_cv_dependent_selections);
791   } else {
792     $('#order_vendor_id').change(kivi.Order.reload_cv_dependent_selections);
793   }
794
795   if ($('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
796     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
797   } else {
798     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) });
799   }
800   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
801   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
802
803   $('.add_item_input').keydown(function(event) {
804     if (event.keyCode == 13) {
805       event.preventDefault();
806       kivi.Order.add_item();
807       return false;
808     }
809   });
810
811   kivi.Order.init_row_handlers();
812
813   $('#row_table_id').on('sortstop', function(event, ui) {
814     $('#row_table_id thead a img').remove();
815     kivi.Order.renumber_positions();
816   });
817
818   $('#expand_all').on('click', function(event) {
819     event.preventDefault();
820     if ($('#expand_all').data('expanded') == 1) {
821       $('#expand_all').data('expanded', 0);
822       $('#expand_all').attr('src', 'image/expand.svg');
823       $('#expand_all').attr('alt', kivi.t8('Show all details'));
824       $('#expand_all').attr('title', kivi.t8('Show all details'));
825       $('.row_entry').each(function(idx, elt) {
826         kivi.Order.hide_second_row(elt);
827       });
828     } else {
829       $('#expand_all').data('expanded', 1);
830       $('#expand_all').attr('src', "image/collapse.svg");
831       $('#expand_all').attr('alt', kivi.t8('Hide all details'));
832       $('#expand_all').attr('title', kivi.t8('Hide all details'));
833       kivi.Order.load_all_second_rows();
834       $('.row_entry').each(function(idx, elt) {
835         kivi.Order.show_second_row(elt);
836       });
837     }
838     return false;
839   });
840
841 });