Auftrags-Controller: E-Mail-Dialog aus common verwenden.
[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 });
550
551 $(function(){
552   if ($('#type').val() == 'sales_order') {
553     $('#order_customer_id').change(kivi.Order.reload_cv_dependant_selections);
554   } else {
555     $('#order_vendor_id').change(kivi.Order.reload_cv_dependant_selections);
556   }
557
558   if ($('#type').val() == 'sales_order') {
559     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
560   } else {
561     $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) });
562   }
563   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
564   $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
565
566   $('.add_item_input').keydown(function(event) {
567     if(event.keyCode == 13) {
568       event.preventDefault();
569       kivi.Order.add_item();
570       return false;
571     }
572   });
573
574   kivi.Order.init_row_handlers();
575
576   $('#row_table_id').on('sortstop', function(event, ui) {
577     $('#row_table_id thead a img').remove();
578     kivi.Order.renumber_positions();
579   });
580
581   $('#expand_all').on('click', function(event) {
582     event.preventDefault();
583     if ($('#expand_all').data('expanded') == 1) {
584       $('#expand_all').data('expanded', 0);
585       $('#expand_all').attr('src', 'image/expand.svg');
586       $('#expand_all').attr('alt', kivi.t8('Show all details'));
587       $('#expand_all').attr('title', kivi.t8('Show all details'));
588       $('.row_entry').each(function(idx, elt) {
589         kivi.Order.hide_second_row(elt);
590       });
591     } else {
592       $('#expand_all').data('expanded', 1);
593       $('#expand_all').attr('src', "image/collapse.svg");
594       $('#expand_all').attr('alt', kivi.t8('Hide all details'));
595       $('#expand_all').attr('title', kivi.t8('Hide all details'));
596       kivi.Order.load_all_second_rows();
597       $('.row_entry').each(function(idx, elt) {
598         kivi.Order.show_second_row(elt);
599       });
600     }
601     return false;
602   });
603
604 });