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