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