Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 23874369

Von Werner Hahn vor 7 Tagen hinzugefügt

  • ID 238743692805a2ce31e87be10b610b8efc541f7a
  • Vorgänger e7c613f2

aktuell 0125

Unterschiede anzeigen:

SL/Controller/POS.pm
8 8
use SL::Presenter::Tag qw(select_tag hidden_tag div_tag);
9 9
use SL::Locale::String qw(t8);
10 10

  
11
use SL::DB::Order;
12
use SL::DB::OrderItem;
13
use SL::DB::Order::TypeData qw(:types);
14
use SL::DB::Helper::TypeDataProxy;
15
use SL::DB::Helper::Record qw(get_object_name_from_type get_class_from_type);
16
use SL::Model::Record;
17

  
11 18
use SL::Helper::CreatePDF qw(:all);
12 19
use SL::Helper::PrintOptions;
13 20
use SL::Helper::ShippedQty;
......
25 32
use Cwd;
26 33
use Sort::Naturally;
27 34

  
35
use Rose::Object::MakeMethods::Generic
36
(
37
 scalar => [ qw(item_ids_to_delete ) ],
38
 'scalar --get_set_init' => [ qw(poso valid_types type type_data) ],
39
);
40

  
28 41
# show form pos
29 42
sub action_show_form {
30 43
  my ($self) = @_;
44
  $self->pre_render();
31 45
  $self->render(
32 46
    'pos/form',
33 47
    title => t8('POSO'),
34
    {header => 0,
35
    output => 0,
36
    layout => 0},
48
    %{$self->{template_args}}
37 49
  );
38 50
}
39 51

  
40
sub setup_edit_action_bar {
52
# add an item row for a new item entered in the input row
53
sub action_add_item {
54
  my ($self) = @_;
55

  
56
  delete $::form->{add_item}->{create_part_type};
57

  
58
  my $form_attr = $::form->{add_item};
59

  
60
  unless ($form_attr->{parts_id}) {
61
    $self->js->flash('error', t8("No part was selected."));
62
    return $self->js->render();
63
  }
64

  
65

  
66
  my $item = new_item($self->order, $form_attr);
67

  
68
  $self->order->add_items($item);
69

  
70
  $self->recalc();
71

  
72
  $self->get_item_cvpartnumber($item);
73

  
74
  my $item_id = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
75
  my $row_as_html = $self->p->render('pos/tabs/_row',
76
                                     ITEM => $item,
77
                                     ID   => $item_id,
78
                                     SELF => $self,
79
  );
80

  
81
  if ($::form->{insert_before_item_id}) {
82
    $self->js
83
      ->before ('.row_entry:has(#item_' . $::form->{insert_before_item_id} . ')', $row_as_html);
84
  } else {
85
    $self->js
86
      ->append('#row_table_id', $row_as_html);
87
  }
88

  
89
  $self->js
90
    ->val('.add_item_input', '')
91
    ->run('kivi.Order.init_row_handlers')
92
    ->run('kivi.Order.renumber_positions')
93
    ->focus('#add_item_parts_id_name');
94

  
95
  $self->js->run('kivi.Order.row_table_scroll_down') if !$::form->{insert_before_item_id};
96

  
97
  $self->js_redisplay_amounts_and_taxes;
98
  $self->js->render();
99
}
100

  
101
# Create a new order object
102
#
103
# And assign changes from the form to this object.
104
# Create/Update items from form (via make_item) and add them.
105
sub make_order {
106
  my ($self) = @_;
107

  
108
  # add_items adds items to an order with no items for saving, but they
109
  # cannot be retrieved via items until the order is saved. Adding empty
110
  # items to new order here solves this problem.
111
  my $order = SL::DB::Order->new(
112
                     record_type => 'sales_order',
113
                     orderitems  => [],
114
                     currency_id => $::instance_conf->get_currency_id(),
115
                   );
116

  
117
  if (!$::form->{id} && $::form->{customer_id}) {
118
    $order->customer_id($::form->{customer_id});
119
    $order = SL::Model::Record->update_after_customer_vendor_change($order);
120
  }
121

  
122
  my $form_orderitems = delete $::form->{order}->{orderitems};
123

  
124
  $order->assign_attributes(%{$::form->{order}});
125

  
126
  #$self->setup_custom_shipto_from_form($order, $::form);
127

  
128
  # remove deleted items
129
  $self->item_ids_to_delete([]);
130
  foreach my $idx (reverse 0..$#{$order->orderitems}) {
131
    my $item = $order->orderitems->[$idx];
132
    if (none { $item->id == $_->{id} } @{$form_orderitems}) {
133
      splice @{$order->orderitems}, $idx, 1;
134
      push @{$self->item_ids_to_delete}, $item->id;
135
    }
136
  }
137

  
138
  my @items;
139
  my $pos = 1;
140
  foreach my $form_attr (@{$form_orderitems}) {
141
    my $item = make_item($order, $form_attr);
142
    $item->position($pos);
143
    push @items, $item;
144
    $pos++;
145
  }
146
  $order->add_items(grep {!$_->id} @items);
147

  
148
  return $order;
149
}
150

  
151
# create a new item
152
#
153
# This is used to add one item
154
sub new_item {
155
  my ($record, $attr) = @_;
156

  
157
  my $item = SL::DB::OrderItem->new;
158

  
159
  # Remove attributes where the user left or set the inputs empty.
160
  # So these attributes will be undefined and we can distinguish them
161
  # from zero later on.
162
  for (qw(qty_as_number sellprice_as_number discount_as_percent)) {
163
    delete $attr->{$_} if $attr->{$_} eq '';
164
  }
165

  
166
  $item->assign_attributes(%$attr);
167
  $item->qty(1.0)                   if !$item->qty;
168
  $item->unit($item->part->unit)    if !$item->unit;
169

  
170
  my ($price_src, $discount_src) = get_best_price_and_discount_source($record, $item, 0);
171

  
172
  my %new_attr;
173
  $new_attr{description}            = $item->part->description     if ! $item->description;
174
  $new_attr{qty}                    = 1.0                          if ! $item->qty;
175
  $new_attr{price_factor_id}        = $item->part->price_factor_id if ! $item->price_factor_id;
176
  $new_attr{sellprice}              = $price_src->price;
177
  $new_attr{discount}               = $discount_src->discount;
178
  $new_attr{active_price_source}    = $price_src;
179
  $new_attr{active_discount_source} = $discount_src;
180
  $new_attr{longdescription}        = $item->part->notes           if ! defined $attr->{longdescription};
181
  $new_attr{project_id}             = $record->globalproject_id;
182
  $new_attr{lastcost}               = $record->is_sales ? $item->part->lastcost : 0;
183

  
184
  # add_custom_variables adds cvars to an orderitem with no cvars for saving, but
185
  # they cannot be retrieved via custom_variables until the order/orderitem is
186
  # saved. Adding empty custom_variables to new orderitem here solves this problem.
187
  $new_attr{custom_variables} = [];
188

  
189
  my $texts = get_part_texts($item->part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
190

  
191
  $item->assign_attributes(%new_attr, %{ $texts });
192

  
193
  return $item;
194
}
195

  
196
sub _setup_edit_action_bar {
41 197
  my ($self, %params) = @_;
42 198
  for my $bar ($::request->layout->get('actionbar')) {
43 199
    $bar->add(
......
50 206
    );
51 207
  }
52 208
}
209

  
210
sub pre_render {
211
  my ($self) = @_;
212

  
213
  $self->{all_taxzones}               = SL::DB::Manager::TaxZone->get_all_sorted();
214
  $self->{all_languages}              = SL::DB::Manager::Language->get_all_sorted();
215
  $self->{all_salesmen}               = SL::DB::Manager::Employee->get_all_sorted();
216
  $self->{current_employee_id}        = SL::DB::Manager::Employee->current->id;
217
  $self->{all_delivery_terms}         = SL::DB::Manager::DeliveryTerm->get_all_sorted();
218
  $self->{all_payment_terms}          = SL::DB::Manager::PaymentTerm->get_all_sorted();
219
  $::request->{layout}->use_javascript("${_}.js") for
220
    qw(kivi.SalesPurchase kivi.POS kivi.File
221
       calculate_qty kivi.Validator follow_up
222
       show_history
223
      );
224
  $self->_setup_edit_action_bar;
225
}
226

  
227
#inits
228
sub init_poso {
229
  $_[0]->make_order;
230
}
231

  
232
sub init_valid_types {
233
  $_[0]->type_data->valid_types;
234
}
235

  
236
sub init_type {
237
  my ($self) = @_;
238

  
239
  my $type = $self->poso->record_type;
240
  if (none { $type eq $_ } @{$self->valid_types}) {
241
    die "Not a valid type for order";
242
  }
243

  
244
  $self->type($type);
245
}
246

  
247
sub init_type_data {
248
  my ($self) = @_;
249
  SL::DB::Helper::TypeDataProxy->new('SL::DB::Order', $self->poso->record_type);
250
}
251

  
53 252
1;
css/design40/less/pos.less
21 21
  border: thin solid red;
22 22
}
23 23

  
24
// left_content
25

  
26
.left_input{
27
  float:left;
28
  padding-right: 3em;
29
}
30

  
24 31
// buttons
25 32

  
26 33
.buttons{
css/design40/style.css
5214 5214
  margin-right: 600px;
5215 5215
  border: thin solid red;
5216 5216
}
5217
.left_input {
5218
  float: left;
5219
  padding-right: 3em;
5220
}
5217 5221
.buttons {
5218 5222
  position: absolute;
5219 5223
  right: 0px;
js/kivi.Poso.js
1
namespace('kivi.Poso', function(ns) {
2
  ns.check_cv = function() {
3
    if ($('#order_customer_id').val() === '') {
4
      alert(kivi.t8('Please select a customer.'));
5
      return false;
6
    }
7
    return true;
8
  };
9

  
10
//  ns.check_duplicate_parts = function(question) {
11
//    var id_arr = $('[name="order.orderitems[].parts_id"]').map(function() { return this.value; }).get();
12
//
13
//    var i, obj = {}, pos = [];
14
//
15
//    for (i = 0; i < id_arr.length; i++) {
16
//      var id = id_arr[i];
17
//      if (obj.hasOwnProperty(id)) {
18
//        pos.push(i + 1);
19
//      }
20
//      obj[id] = 0;
21
//    }
22
//
23
//    if (pos.length > 0) {
24
//      question = question || kivi.t8("Do you really want to continue?");
25
//      return confirm(kivi.t8("There are duplicate parts at positions") + "\n"
26
//                     + pos.join(', ') + "\n"
27
//                     + question);
28
//    }
29
//    return true;
30
//  };
31
//
32
//  ns.check_valid_reqdate = function() {
33
//    if ($('#order_reqdate_as_date').val() === '') {
34
//      alert(kivi.t8('Please select a delivery date.'));
35
//      return false;
36
//    } else {
37
//      return true;
38
//    }
39
//  };
40

  
41
//  ns.save = function(params) {
42
//    if (!ns.check_cv()) return;
43
//
44
//    const action             = params.action;
45
//    const warn_on_duplicates = params.warn_on_duplicates;
46
//    const warn_on_reqdate    = params.warn_on_reqdate;
47
//    const form_params        = params.form_params;
48
//
49
//    if (warn_on_duplicates && !ns.check_duplicate_parts()) return;
50
//    if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
51
//
52
//    var data = $('#order_form').serializeArray();
53
//    data.push({ name: 'action', value: 'Order/' + action });
54
//
55
//    if (form_params) {
56
//      if (Array.isArray(form_params)) {
57
//        form_params.forEach(function(item) {
58
//          data.push(item);
59
//        });
60
//      } else {
61
//        data.push(form_params);
62
//      }
63
//    }
64
//
65
//    if (params.data)
66
//      data = $.merge(data, params.data);
67
//
68
//    $.post("controller.pl", data, kivi.eval_json_result);
69
//  };
70
//
71
//  ns.delete_order = function() {
72
//    var data = $('#order_form').serializeArray();
73
//    data.push({ name: 'action', value: 'Order/delete' });
74
//
75
//    $.post("controller.pl", data, kivi.eval_json_result);
76
//  };
77
//
78
//  ns.show_print_options = function(params) {
79
//    if (!ns.check_cv()) return;
80
//
81
//    const warn_on_duplicates = params.warn_on_duplicates;
82
//    const warn_on_reqdate    = params.warn_on_reqdate;
83
//
84
//    if (warn_on_duplicates && !ns.check_duplicate_parts(kivi.t8("Do you really want to print?"))) return;
85
//    if (warn_on_reqdate    && !ns.check_valid_reqdate())   return;
86
//
87
//    kivi.popup_dialog({
88
//      id: 'print_options',
89
//      dialog: {
90
//        title: kivi.t8('Print options'),
91
//        width:  800,
92
//        height: 300
93
//      }
94
//    });
95
//  };
96
//
97
//  ns.print = function() {
98
//    $('#print_options').dialog('close');
99
//
100
//    var data = $('#order_form').serializeArray();
101
//    data = data.concat($('#print_options_form').serializeArray());
102
//    data.push({ name: 'action', value: 'Order/print' });
103
//
104
//    $.post("controller.pl", data, kivi.eval_json_result);
105
//  };
106

  
107
//  var email_dialog;
108
//
109
//  ns.setup_send_email_dialog = function() {
110
//    kivi.SalesPurchase.show_all_print_options_elements();
111
//    kivi.SalesPurchase.show_print_options_elements([ 'sendmode', 'media', 'copies', 'remove_draft' ], false);
112
//
113
//    $('#print_options_form table').first().remove().appendTo('#email_form_print_options');
114
//
115
//    $('select#format').change(kivi.Order.adjust_email_attachment_name_for_template_format);
116
//    kivi.Order.adjust_email_attachment_name_for_template_format();
117
//
118
//    var to_focus = $('#email_form_to').val() === '' ? 'to' : 'subject';
119
//    $('#email_form_' + to_focus).focus();
120
//  };
121
//
122
//  ns.finish_send_email_dialog = function() {
123
//    kivi.SalesPurchase.show_all_print_options_elements();
124
//
125
//    $('#email_form_print_options table').first().remove().prependTo('#print_options_form');
126
//    return true;
127
//  };
128
//
129
//  ns.show_email_dialog = function(html) {
130
//    var id            = 'send_email_dialog';
131
//    var dialog_params = {
132
//      id:     id,
133
//      width:  800,
134
//      height: 600,
135
//      title:  kivi.t8('Send email'),
136
//      modal:  true,
137
//      beforeClose: kivi.Order.finish_send_email_dialog,
138
//      close: function(event, ui) {
139
//        email_dialog.remove();
140
//      }
141
//    };
142
//
143
//    $('#' + id).remove();
144
//
145
//    email_dialog = $('<div style="display:none" id="' + id + '"></div>').appendTo('body');
146
//    email_dialog.html(html);
147
//    email_dialog.dialog(dialog_params);
148
//
149
//    kivi.Order.setup_send_email_dialog();
150
//
151
//    $('.cancel').click(ns.close_email_dialog);
152
//
153
//    return true;
154
//  };
155
//
156
//  ns.send_email = function() {
157
//    // push button only once -> slow response from mail server
158
//    ns.email_dialog_disable_send();
159
//
160
//    var data = $('#order_form').serializeArray();
161
//    data = data.concat($('[name^="email_form."]').serializeArray());
162
//    data = data.concat($('[name^="print_options."]').serializeArray());
163
//    data.push({ name: 'action', value: 'Order/send_email' });
164
//    $.post("controller.pl", data, kivi.eval_json_result);
165
//  };
166
//
167
//  ns.email_dialog_disable_send = function() {
168
//    // disable mail send event to prevent
169
//    // impatient users to send multiple times
170
//    $('#send_email').prop('disabled', true);
171
//  };
172
//
173
//  ns.close_email_dialog = function() {
174
//    email_dialog.dialog("close");
175
//  };
176
//
177
//  ns.adjust_email_attachment_name_for_template_format = function() {
178
//    var $filename_elt = $('#email_form_attachment_filename');
179
//    var $format_elt   = $('select#format');
180
//
181
//    if (!$filename_elt || !$format_elt)
182
//      return;
183
//
184
//    var format   = $format_elt.val().toLowerCase();
185
//    var new_ext  = format == 'html' ? 'html' : format == 'opendocument' ? 'odt' : 'pdf';
186
//    var filename = $filename_elt.val();
187
//
188
//    $filename_elt.val(filename.replace(/[^.]+$/, new_ext));
189
//  };
190

  
191
  ns.set_number_in_title = function(elt) {
192
    $('#nr_in_title').html($(elt).val());
193
  };
194

  
195
  ns.reload_cv_dependent_selections = function() {
196
    $('#order_shipto_id').val('');
197
    var data = $('#order_form').serializeArray();
198
    data.push({ name: 'action', value: 'Order/customer_vendor_changed' });
199

  
200
    $.post("controller.pl", data, kivi.eval_json_result);
201
  };
202

  
203
  ns.reformat_number = function(event) {
204
    $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
205
  };
206

  
207
  ns.reformat_number_as_null_number = function(event) {
208
    if ($(event.target).val() === '') {
209
      return;
210
    }
211
    ns.reformat_number(event);
212
  };
213

  
214
//  ns.update_exchangerate = function(event) {
215
//    if (!ns.check_cv()) {
216
//      $('#order_currency_id').val($('#old_currency_id').val());
217
//      return;
218
//    }
219
//
220
//    var rate_input = $('#order_exchangerate_as_null_number');
221
//    // unset exchangerate if currency changed
222
//    if ($('#order_currency_id').val() !== $('#old_currency_id').val()) {
223
//      rate_input.val('');
224
//    }
225
//
226
//    // only set exchangerate if unset
227
//    if (rate_input.val() !== '') {
228
//      return;
229
//    }
230
//
231
//    var data = $('#order_form').serializeArray();
232
//    data.push({ name: 'action', value: 'Order/update_exchangerate' });
233
//
234
//    $.ajax({
235
//      url: 'controller.pl',
236
//      data: data,
237
//      method: 'POST',
238
//      dataType: 'json',
239
//      success: function(data){
240
//        if (!data.is_standard) {
241
//          $('#currency_name').text(data.currency_name);
242
//          if (data.exchangerate) {
243
//            rate_input.val(data.exchangerate);
244
//          } else {
245
//            rate_input.val('');
246
//          }
247
//          $('#order_exchangerate_as_null_number').data('validate', 'required');
248
//          $('#exchangerate_settings').show();
249
//        } else {
250
//          rate_input.val('');
251
//          $('#order_exchangerate_as_null_number').data('validate', '');
252
//          $('#exchangerate_settings').hide();
253
//        }
254
//        if ($('#order_currency_id').val() != $('#old_currency_id').val() ||
255
//            !data.is_standard && data.exchangerate != $('#old_exchangerate').val()) {
256
//          kivi.display_flash('warning', kivi.t8('You have changed the currency or exchange rate. Please check prices.'));
257
//        }
258
//        $('#old_currency_id').val($('#order_currency_id').val());
259
//        $('#old_exchangerate').val(data.exchangerate);
260
//      }
261
//    });
262
//  };
263
//
264
//  ns.exchangerate_changed = function(event) {
265
//    if (kivi.parse_amount($('#order_exchangerate_as_null_number').val()) != kivi.parse_amount($('#old_exchangerate').val())) {
266
//      kivi.display_flash('warning', kivi.t8('You have changed the currency or exchange rate. Please check prices.'));
267
//      $('#old_exchangerate').val($('#order_exchangerate_as_null_number').val());
268
//    }
269
//  };
270

  
271
  ns.recalc_amounts_and_taxes = function() {
272
    if (!kivi.validate_form('#order_form')) return;
273

  
274
    var data = $('#order_form').serializeArray();
275
    data.push({ name: 'action', value: 'Order/recalc_amounts_and_taxes' });
276

  
277
    $.post("controller.pl", data, kivi.eval_json_result);
278
  };
279

  
280
  ns.unit_change = function(event) {
281
    var row           = $(event.target).parents("tbody").first();
282
    var item_id_dom   = $(row).find('[name="orderitem_ids[+]"]');
283
    var sellprice_dom = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
284
    var select_elt    = $(row).find('[name="order.orderitems[].unit"]');
285

  
286
    var oldval = $(select_elt).data('oldval');
287
    $(select_elt).data('oldval', $(select_elt).val());
288

  
289
    var data = $('#order_form').serializeArray();
290
    data.push({ name: 'action',           value: 'Order/unit_changed'     },
291
              { name: 'item_id',          value: item_id_dom.val()        },
292
              { name: 'old_unit',         value: oldval                   },
293
              { name: 'sellprice_dom_id', value: sellprice_dom.attr('id') });
294

  
295
    $.post("controller.pl", data, kivi.eval_json_result);
296
  };
297

  
298
  ns.update_sellprice = function(item_id, price_str) {
299
    var row       = $('#item_' + item_id).parents("tbody").first();
300
    var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
301
    var html_elt  = $(row).find('[name="sellprice_text"]');
302
    price_elt.val(price_str);
303
    html_elt.html(price_str);
304
  };
305

  
306
  ns.load_second_row = function(row) {
307
    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
308
    var div_elt     = $(row).find('[name="second_row"]');
309

  
310
    if ($(div_elt).data('loaded') == 1) {
311
      return;
312
    }
313
    var data = $('#order_form').serializeArray();
314
    data.push({ name: 'action',     value: 'Order/load_second_rows' },
315
              { name: 'item_ids[]', value: item_id_dom.val()        });
316

  
317
    $.post("controller.pl", data, kivi.eval_json_result);
318
  };
319

  
320
  ns.load_all_second_rows = function() {
321
    var rows = $('.row_entry').filter(function(idx, elt) {
322
      return $(elt).find('[name="second_row"]').data('loaded') != 1;
323
    });
324

  
325
    var item_ids = $.map(rows, function(elt) {
326
      var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
327
      return { name: 'item_ids[]', value: item_id };
328
    });
329

  
330
    if (item_ids.length == 0) {
331
      return;
332
    }
333

  
334
    var data = $('#order_form').serializeArray();
335
    data.push({ name: 'action', value: 'Order/load_second_rows' });
336
    data = data.concat(item_ids);
337

  
338
    $.post("controller.pl", data, kivi.eval_json_result);
339
  };
340

  
341
  ns.hide_second_row = function(row) {
342
    $(row).children().not(':first').hide();
343
    $(row).data('expanded', 0);
344
    var elt = $(row).find('.expand');
345
    elt.attr('src', "image/expand.svg");
346
    elt.attr('alt', kivi.t8('Show details'));
347
    elt.attr('title', kivi.t8('Show details'));
348
  };
349

  
350
  ns.show_second_row = function(row) {
351
    $(row).children().not(':first').show();
352
    $(row).data('expanded', 1);
353
    var elt = $(row).find('.expand');
354
    elt.attr('src', "image/collapse.svg");
355
    elt.attr('alt', kivi.t8('Hide details'));
356
    elt.attr('title', kivi.t8('Hide details'));
357
  };
358

  
359
  ns.toggle_second_row = function(row) {
360
    if ($(row).data('expanded') == 1) {
361
      ns.hide_second_row(row);
362
    } else {
363
      ns.show_second_row(row);
364
    }
365
  };
366

  
367
  ns.init_row_handlers = function() {
368
    kivi.run_once_for('.recalc', 'on_change_recalc', function(elt) {
369
      $(elt).change(ns.recalc_amounts_and_taxes);
370
    });
371

  
372
    kivi.run_once_for('.reformat_number', 'on_change_reformat', function(elt) {
373
      $(elt).change(ns.reformat_number);
374
    });
375

  
376
    kivi.run_once_for('.unitselect', 'on_change_unit_with_oldval', function(elt) {
377
      $(elt).data('oldval', $(elt).val());
378
      $(elt).change(ns.unit_change);
379
    });
380

  
381
    kivi.run_once_for('.row_entry', 'on_kbd_click_show_hide', function(elt) {
382
      $(elt).keydown(function(event) {
383
        var row;
384
        if (event.keyCode == 40 && event.shiftKey === true) {
385
          // shift arrow down
386
          event.preventDefault();
387
          row = $(event.target).parents(".row_entry").first();
388
          ns.load_second_row(row);
389
          ns.show_second_row(row);
390
          return false;
391
        }
392
        if (event.keyCode == 38 && event.shiftKey === true) {
393
          // shift arrow up
394
          event.preventDefault();
395
          row = $(event.target).parents(".row_entry").first();
396
          ns.hide_second_row(row);
397
          return false;
398
        }
399
      });
400
    });
401

  
402
    kivi.run_once_for('.expand', 'expand_second_row', function(elt) {
403
      $(elt).click(function(event) {
404
        event.preventDefault();
405
        var row = $(event.target).parents(".row_entry").first();
406
        ns.load_second_row(row);
407
        ns.toggle_second_row(row);
408
        return false;
409
      })
410
    });
411

  
412
  };
413

  
414
  ns.redisplay_line_values = function(is_sales, data) {
415
    $('.row_entry').each(function(idx, elt) {
416
      $(elt).find('[name="linetotal"]').html(data[idx][0]);
417
      if (is_sales && $(elt).find('[name="second_row"]').data('loaded') == 1) {
418
        var mt = data[idx][1];
419
        var mp = data[idx][2];
420
        var h  = '<span';
421
        if (mt[0] === '-') h += ' class="plus0"';
422
        h += '>' + mt + '&nbsp;&nbsp;' + mp + '%';
423
        h += '</span>';
424
        $(elt).find('[name="linemargin"]').html(h);
425
      }
426
    });
427
  };
428

  
429
  ns.redisplay_cvpartnumbers = function(data) {
430
    $('.row_entry').each(function(idx, elt) {
431
      $(elt).find('[name="cvpartnumber"]').html(data[idx][0]);
432
    });
433
  };
434

  
435
  ns.renumber_positions = function() {
436
    $('.row_entry [name="position"]').each(function(idx, elt) {
437
      $(elt).html(idx+1);
438
    });
439
    $('.row_entry').each(function(idx, elt) {
440
      $(elt).data("position", idx+1);
441
    });
442
  };
443

  
444
  ns.reorder_items = function(order_by) {
445
    var dir = $('#' + order_by + '_header_id a img').attr("data-sort-dir");
446
    $('#row_table_id thead a img').remove();
447

  
448
    var src;
449
    if (dir == "1") {
450
      dir = "0";
451
      src = "image/up.png";
452
    } else {
453
      dir = "1";
454
      src = "image/down.png";
455
    }
456

  
457
    $('#' + order_by + '_header_id a').append('<img border=0 data-sort-dir=' + dir + ' src=' + src + ' alt="' + kivi.t8('sort items') + '">');
458

  
459
    var data = $('#order_form').serializeArray();
460
    data.push({ name: 'action',   value: 'Order/reorder_items' },
461
              { name: 'order_by', value: order_by              },
462
              { name: 'sort_dir', value: dir                   });
463

  
464
    $.post("controller.pl", data, kivi.eval_json_result);
465
  };
466

  
467
  ns.redisplay_items = function(data) {
468
    var old_rows = $('.row_entry').detach();
469
    var new_rows = [];
470
    $(data).each(function(idx, elt) {
471
      new_rows.push(old_rows[elt.old_pos - 1]);
472
    });
473
    $(new_rows).appendTo($('#row_table_id'));
474
    ns.renumber_positions();
475
  };
476

  
477
  ns.get_insert_before_item_id = function(wanted_pos) {
478
    if (wanted_pos === '') return;
479

  
480
    var insert_before_item_id;
481
    // selection by data does not seem to work if data is changed at runtime
482
    // var elt = $('.row_entry [data-position="' + wanted_pos + '"]');
483
    $('.row_entry').each(function(idx, elt) {
484
      if ($(elt).data("position") == wanted_pos) {
485
        insert_before_item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
486
        return false;
487
      }
488
    });
489

  
490
    return insert_before_item_id;
491
  };
492

  
493
  ns.update_item_input_row = function() {
494
    if (!ns.check_cv()) return;
495

  
496
    var data = $('#order_form').serializeArray();
497
    data.push({ name: 'action', value: 'Order/update_item_input_row' });
498

  
499
    $.post("controller.pl", data, kivi.eval_json_result);
500
  };
501

  
502
  ns.add_item = function() {
503
    if ($('#add_item_parts_id').val() === '') return;
504
    if (!ns.check_cv()) return;
505

  
506
    $('#row_table_id thead a img').remove();
507

  
508
    var insert_before_item_id = ns.get_insert_before_item_id($('#add_item_position').val());
509

  
510
    var data = $('#order_form').serializeArray();
511
    data.push({ name: 'action', value: 'Order/add_item' },
512
              { name: 'insert_before_item_id', value: insert_before_item_id });
513

  
514
    $.post("controller.pl", data, kivi.eval_json_result);
515
  };
516

  
517
  ns.open_multi_items_dialog = function() {
518
    if (!ns.check_cv()) return;
519

  
520
    var pp = $("#add_item_parts_id").data("part_picker");
521
    pp.o.multiple=1;
522
    pp.open_dialog();
523
  };
524

  
525
  ns.add_multi_items = function(data) {
526
    var insert_before_item_id = ns.get_insert_before_item_id($('#multi_items_position').val());
527
    data = data.concat($('#order_form').serializeArray());
528
    data.push({ name: 'action', value: 'Order/add_multi_items' },
529
              { name: 'insert_before_item_id', value: insert_before_item_id });
530
    $.post("controller.pl", data, kivi.eval_json_result);
531
  };
532

  
533
  ns.delete_order_item_row = function(clicked) {
534
    var row = $(clicked).parents("tbody").first();
535
    $(row).remove();
536

  
537
    ns.renumber_positions();
538
    ns.recalc_amounts_and_taxes();
539
  };
540

  
541
  ns.row_table_scroll_down = function() {
542
    $('#row_table_scroll_id').scrollTop($('#row_table_scroll_id')[0].scrollHeight);
543
  };
544

  
545
  ns.show_longdescription_dialog = function(clicked) {
546
    var row                 = $(clicked).parents("tbody").first();
547
    var position            = $(row).find('[name="position"]').html();
548
    var partnumber          = $(row).find('[name="partnumber"]').html();
549
    var description_elt     = $(row).find('[name="order.orderitems[].description"]');
550
    var longdescription_elt = $(row).find('[name="order.orderitems[].longdescription"]');
551

  
552
    var params = {
553
      runningnumber:           position,
554
      partnumber:              partnumber,
555
      description:             description_elt.val(),
556
      default_longdescription: longdescription_elt.val(),
557
      set_function:            function(val) {
558
        longdescription_elt.val(val);
559
      }
560
    };
561

  
562
    kivi.SalesPurchase.edit_longdescription_with_params(params);
563
  };
564

  
565
  ns.price_chooser_item_row = function(clicked) {
566
    if (!ns.check_cv()) return;
567
    var row         = $(clicked).parents("tbody").first();
568
    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
569

  
570
    var data = $('#order_form').serializeArray();
571
    data.push({ name: 'action',  value: 'Order/price_popup' },
572
              { name: 'item_id', value: item_id_dom.val()   });
573

  
574
    $.post("controller.pl", data, kivi.eval_json_result);
575
  };
576

  
577
  ns.set_price_and_source_text = function(item_id, source, descr, price_str, price_editable) {
578
    var row        = $('#item_' + item_id).parents("tbody").first();
579
    var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]');
580
    var button_elt = $(row).find('[name="price_chooser_button"]');
581

  
582
    button_elt.val(button_elt.val().replace(/.*\|/, descr + " |"));
583
    source_elt.val(source);
584

  
585
    var editable_div_elt     = $(row).find('[name="editable_price"]');
586
    var not_editable_div_elt = $(row).find('[name="not_editable_price"]');
587
    if (price_editable == 1 && source === '') {
588
      // editable
589
      $(editable_div_elt).show();
590
      $(not_editable_div_elt).hide();
591
      $(editable_div_elt).find(':input').prop("disabled", false);
592
      $(not_editable_div_elt).find(':input').prop("disabled", true);
593
    } else {
594
      // not editable
595
      $(editable_div_elt).hide();
596
      $(not_editable_div_elt).show();
597
      $(editable_div_elt).find(':input').prop("disabled", true);
598
      $(not_editable_div_elt).find(':input').prop("disabled", false);
599
    }
600

  
601
    if (price_str) {
602
      var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
603
      var html_elt  = $(row).find('[name="sellprice_text"]');
604
      price_elt.val(price_str);
605
      html_elt.html(price_str);
606
    }
607
  };
608

  
609
  ns.update_price_source = function(item_id, source, descr, price_str, price_editable) {
610
    ns.set_price_and_source_text(item_id, source, descr, price_str, price_editable);
611

  
612
    if (price_str) ns.recalc_amounts_and_taxes();
613
    kivi.io.close_dialog();
614
  };
615

  
616
  ns.set_discount_and_source_text = function(item_id, source, descr, discount_str, price_editable) {
617
    var row        = $('#item_' + item_id).parents("tbody").first();
618
    var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]');
619
    var button_elt = $(row).find('[name="price_chooser_button"]');
620

  
621
    button_elt.val(button_elt.val().replace(/\|.*/, "| " + descr));
622
    source_elt.val(source);
623

  
624
    var editable_div_elt     = $(row).find('[name="editable_discount"]');
625
    var not_editable_div_elt = $(row).find('[name="not_editable_discount"]');
626
    if (price_editable == 1 && source === '') {
627
      // editable
628
      $(editable_div_elt).show();
629
      $(not_editable_div_elt).hide();
630
      $(editable_div_elt).find(':input').prop("disabled", false);
631
      $(not_editable_div_elt).find(':input').prop("disabled", true);
632
    } else {
633
      // not editable
634
      $(editable_div_elt).hide();
635
      $(not_editable_div_elt).show();
636
      $(editable_div_elt).find(':input').prop("disabled", true);
637
      $(not_editable_div_elt).find(':input').prop("disabled", false);
638
    }
639

  
640
    if (discount_str) {
641
      var discount_elt = $(row).find('[name="order.orderitems[].discount_as_percent"]');
642
      var html_elt     = $(row).find('[name="discount_text"]');
643
      discount_elt.val(discount_str);
644
      html_elt.html(discount_str);
645
    }
646
  };
647

  
648
  ns.update_discount_source = function(item_id, source, descr, discount_str, price_editable) {
649
    ns.set_discount_and_source_text(item_id, source, descr, discount_str, price_editable);
650

  
651
    if (discount_str) ns.recalc_amounts_and_taxes();
652
    kivi.io.close_dialog();
653
  };
654

  
655
  ns.show_periodic_invoices_config_dialog = function() {
656
    if ($('#type').val() !== 'sales_order') return;
657

  
658
    kivi.popup_dialog({
659
      url:    'controller.pl?action=Order/show_periodic_invoices_config_dialog',
660
      data:   { type:              $('#type').val(),
661
                id:                $('#id').val(),
662
                config:            $('#order_periodic_invoices_config').val(),
663
                customer_id:       $('#order_customer_id').val(),
664
                transdate_as_date: $('#order_transdate_as_date').val(),
665
                language_id:       $('#language_id').val()
666
              },
667
      id:     'jq_periodic_invoices_config_dialog',
668
      load:   kivi.reinit_widgets,
669
      dialog: {
670
        title:  kivi.t8('Edit the configuration for periodic invoices'),
671
        width:  800,
672
        height: 650
673
      }
674
    });
675
    return true;
676
  };
677

  
678
  ns.close_periodic_invoices_config_dialog = function() {
679
    $('#jq_periodic_invoices_config_dialog').dialog('close');
680
  };
681

  
682
  ns.assign_periodic_invoices_config = function() {
683
    var data = $('[name="Form"]').serializeArray();
684
    data.push({ name: 'type',   value: $('#type').val() },
685
              { name: 'action', value: 'Order/assign_periodic_invoices_config' });
686
    $.post("controller.pl", data, kivi.eval_json_result);
687
  };
688

  
689
  ns.check_save_active_periodic_invoices = function() {
690
    var type = $('#type').val();
691
    if (type !== 'sales_order') return true;
692

  
693
    var active = false;
694
    $.ajax({
695
      url:      'controller.pl',
696
      data:     { action: 'Order/get_has_active_periodic_invoices',
697
                  type  : type,
698
                  id    : $('#id').val(),
699
                  config: $('#order_periodic_invoices_config').val(),
700
                },
701
      method:   "GET",
702
      async:    false,
703
      dataType: 'text',
704
      success:  function(val) {
705
        active = val;
706
      }
707
    });
708

  
709
    if (active == 1) {
710
      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?'));
711
    }
712

  
713
    return true;
714
  };
715

  
716
  ns.update_row_from_master_data = function(clicked) {
717
    var row = $(clicked).parents("tbody").first();
718
    var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
719

  
720
    var data = $('#order_form').serializeArray();
721
    data.push({ name: 'action', value: 'Order/update_row_from_master_data' });
722
    data.push({ name: 'item_ids[]', value: item_id_dom.val() });
723

  
724
    $.post("controller.pl", data, kivi.eval_json_result);
725
  };
726

  
727
  ns.update_all_rows_from_master_data = function() {
728
    var item_ids = $.map($('.row_entry'), function(elt) {
729
      var item_id = $(elt).find('[name="orderitem_ids[+]"]').val();
730
      return { name: 'item_ids[]', value: item_id };
731
    });
732

  
733
    if (item_ids.length == 0) {
734
      return;
735
    }
736

  
737
    var data = $('#order_form').serializeArray();
738
    data.push({ name: 'action', value: 'Order/update_row_from_master_data' });
739
    data = data.concat(item_ids);
740

  
741
    $.post("controller.pl", data, kivi.eval_json_result);
742
  };
743

  
744
  ns.show_calculate_qty_dialog = function(clicked) {
745
    var row        = $(clicked).parents("tbody").first();
746
    var input_id   = $(row).find('[name="order.orderitems[].qty_as_number"]').attr('id');
747
    var formula_id = $(row).find('[name="formula[+]"]').attr('id');
748

  
749
    calculate_qty_selection_dialog("", input_id, "", formula_id);
750
    return true;
751
  };
752

  
753
  ns.edit_custom_shipto = function() {
754
    if (!ns.check_cv()) return;
755

  
756
    kivi.SalesPurchase.edit_custom_shipto();
757
  };
758

  
759
  ns.purchase_check_for_direct_delivery = function(params) {
760
    const to_type = params.to_type;
761

  
762
    if ($('#type').val() != 'sales_quotation' && $('#type').val() != 'sales_order_intake' && $('#type').val() != 'sales_order') {
763
      kivi.submit_ajax_form("controller.pl", '#order_form', {action: 'Order/save_and_order_workflow', to_type: to_type});
764
      return;
765
    }
766

  
767
    var empty = true;
768
    var shipto;
769
    if ($('#order_shipto_id').val() !== '') {
770
      empty = false;
771
      shipto = $('#order_shipto_id option:selected').text();
772
    } else {
773
      $('#shipto_inputs [id^="shipto"]').each(function(idx, elt) {
774
        if (!empty)                                     return true;
775
        if (/^shipto_to_copy/.test($(elt).prop('id')))  return true;
776
        if (/^shiptocp_gender/.test($(elt).prop('id'))) return true;
777
        if (/^shiptocvar_/.test($(elt).prop('id')))     return true;
778
        if ($(elt).val() !== '') {
779
          empty = false;
780
          return false;
781
        }
782
      });
783
      var shipto_elements = [];
784
      $([$('#shiptoname').val(), $('#shiptostreet').val(), $('#shiptozipcode').val(), $('#shiptocity').val()]).each(function(idx, elt) {
785
        if (elt !== '') shipto_elements.push(elt);
786
      });
787
      shipto = shipto_elements.join('; ');
788
    }
789

  
790
    if (!empty) {
791
      ns.direct_delivery_dialog(shipto, to_type);
792
    } else {
793
      kivi.submit_ajax_form("controller.pl", '#order_form', {action: 'Order/save_and_order_workflow', to_type: to_type});
794
    }
795
  };
796

  
797
  ns.direct_delivery_callback = function(accepted, to_type) {
798
    $('#direct-delivery-dialog').dialog('close');
799

  
800
    if (accepted) {
801
      $('<input type="hidden" name="use_shipto">').appendTo('#order_form').val('1');
802
    }
803

  
804
    kivi.submit_ajax_form("controller.pl", '#order_form', {action: 'Order/save_and_order_workflow', to_type: to_type});
805
  };
806

  
807
  ns.direct_delivery_dialog = function(shipto, to_type) {
808
    $('#direct-delivery-dialog').remove();
809

  
810
    var text1 = kivi.t8('You have entered or selected the following shipping address for this customer:');
811
    var text2 = kivi.t8('Do you want to carry this shipping address over to the new purchase document so that the vendor can deliver the goods directly to your customer?');
812
    var html  = '<div id="direct-delivery-dialog"><p>' + text1 + '</p><p>' + shipto + '</p><p>' + text2 + '</p>';
813
    html      = html + '<hr><p>';
814
    html      = html + '<input type="button" value="' + kivi.t8('Yes') + '" size="30" onclick="kivi.Order.direct_delivery_callback(true,  \'' + to_type + '\')">';
815
    html      = html + '&nbsp;';
816
    html      = html + '<input type="button" value="' + kivi.t8('No')  + '" size="30" onclick="kivi.Order.direct_delivery_callback(false, \'' + to_type + '\')">';
817
    html      = html + '</p></div>';
818
    $(html).hide().appendTo('#order_form');
819

  
820
    kivi.popup_dialog({id: 'direct-delivery-dialog',
821
                       dialog: {title:  kivi.t8('Carry over shipping address'),
822
                                height: 300,
823
                                width:  500 }});
824
  };
825

  
826
  ns.follow_up_window = function() {
827
    var id   = $('#id').val();
828
    var type = $('#type').val();
829

  
830
    var number_info = '';
831
    if ($('#type').val() == 'sales_order_intake' || $('#type').val() == 'sales_order' || $('#type').val() == 'purchase_order' || $('#type').val() == 'purchase_order_confirmation') {
832
      number_info = $('#order_ordnumber').val();
833
    } else if ($('#type').val() == 'sales_quotation' || $('#type').val() == 'request_quotation' || $('#type').val() == 'purchase_quotation_intake') {
834
      number_info = $('#order_quonumber').val();
835
    }
836

  
837
    var name_info = '';
838
    if ($('#type').val() == 'sales_order_intake' || $('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation') {
839
      name_info = $('#order_customer_id_name').val();
840
    } else if ($('#type').val() == 'purchase_order' || $('#type').val() == 'purchase_order_confirmation' || $('#type').val() == 'request_quotation' || $('#type').val() == 'purchase_quotation_intake') {
841
      name_info = $('#order_vendor_id_name').val();
842
    }
843

  
844
    var info = '';
845
    if (number_info !== '') { info += ' (' + number_info + ')' }
846
    if (name_info   !== '') { info += ' (' + name_info + ')' }
847

  
848
    if (!$('#follow_up_rowcount').length) {
849
      $('<input type="hidden" name="follow_up_rowcount"        id="follow_up_rowcount">').appendTo('#order_form');
850
      $('<input type="hidden" name="follow_up_trans_id_1"      id="follow_up_trans_id_1">').appendTo('#order_form');
851
      $('<input type="hidden" name="follow_up_trans_type_1"    id="follow_up_trans_type_1">').appendTo('#order_form');
852
      $('<input type="hidden" name="follow_up_trans_info_1"    id="follow_up_trans_info_1">').appendTo('#order_form');
853
      $('<input type="hidden" name="follow_up_trans_subject_1" id="follow_up_trans_subject_1">').appendTo('#order_form');
854
    }
855
    $('#follow_up_rowcount').val(1);
856
    $('#follow_up_trans_id_1').val(id);
857
    $('#follow_up_trans_type_1').val(type);
858
    $('#follow_up_trans_info_1').val(info);
859
    $('#follow_up_trans_subject_1').val($('#order_transaction_description').val());
860

  
861
    follow_up_window();
862
  };
863

  
864
  ns.create_part = function() {
865
    var data = $('#order_form').serializeArray();
866
    data.push({ name: 'action', value: 'Order/create_part' });
867
    $.post("controller.pl", data, kivi.eval_json_result);
868
  };
869

  
870
  ns.check_transport_cost_article_presence = function() {
871
    var $form          = $('#order_form');
872
    var wanted_part_id = $form.data('transport-cost-reminder-article-id');
873

  
874
    if (!wanted_part_id) return true
875

  
876
    var id_arr = $('[name="order.orderitems[].parts_id"]').map(function() { return this.value; }).get();
877
    id_arr = $.grep(id_arr, function(elt) {
878
      return ((elt*1) === wanted_part_id);
879
    });
880

  
881
    if (id_arr.length) return true;
882

  
883
    var description = $form.data('transport-cost-reminder-article-description');
884
    return confirm(kivi.t8("The transport cost article '#1' is missing. Do you want to continue anyway?", [ description ]));
885
  };
886

  
887
  ns.check_cusordnumber_presence = function() {
888
    if ($('#order_cusordnumber').val() === '') {
889
      return confirm(kivi.t8('The customer order number is missing. Do you want to continue anyway?'));
890
    }
891
    return true;
892
  };
893

  
894
  ns.load_phone_note = function(id, subject, body) {
895
    $('#phone_note_edit_text').html(kivi.t8('Edit note'));
896
    $('#phone_note_id').val(id);
897
    $('#phone_note_subject').val(subject);
898
    $('#phone_note_body').val(body).change();
899
    $('#phone_note_delete_button').show();
900
  };
901

  
902
  ns.cancel_phone_note = function() {
903
    $('#phone_note_edit_text').html(kivi.t8('Add note'));
904
    $('#phone_note_id').val('');
905
    $('#phone_note_subject').val('');
906
    $('#phone_note_body').val('').change();
907
    $('#phone_note_delete_button').hide();
908
  };
909

  
910
  ns.save_phone_note = function() {
911
    var data = $('#order_form').serializeArray();
912
    data.push({ name: 'action', value: 'Order/save_phone_note' });
913

  
914
    $.post("controller.pl", data, kivi.eval_json_result);
915
  };
916

  
917
  ns.delete_phone_note = function() {
918
    if ($('#phone_note_id').val() === '') return;
919

  
920
    var data = $('#order_form').serializeArray();
921
    data.push({ name: 'action', value: 'Order/delete_phone_note' });
922

  
923
    $.post("controller.pl", data, kivi.eval_json_result);
924
  };
925

  
926
  ns.show_purchase_delivery_order_select_items = function(params) {
927
    var data = $('#order_form').serializeArray();
928
    data.push({ name: 'action', value: 'Order/show_conversion_to_purchase_delivery_order_item_selection' });
929

  
930
    kivi.popup_dialog({
931
      id:     "convert_to_purchase_delivery_order_item_position_selection",
932
      url:    "controller.pl",
933
      data:   data,
934
      type:   "POST",
935
      dialog: { title: kivi.t8("Select items for delivery order") },
936
      load:   function() {
937
        $("body").data("convert_to_purchase_delivery_order_item_position_selection_params", params);
938
      }
939
    });
940
  };
941

  
942
  ns.convert_to_purchase_delivery_order_item_selection = function() {
943
    let params = $("body").data("convert_to_purchase_delivery_order_item_position_selection_params");
944

  
945
    let $dialog = $("#convert_to_purchase_delivery_order_item_position_selection");
946
    let selected_items = $dialog.find("tbody input.item_position_selection_checkall").serializeArray();
947
    params.data = selected_items;
948

  
949
    additional_param = { name: 'only_selected_item_positions', value: 1 };
950
    if (params.form_params) {
951
      if (Array.isArray(params.form_params)) {
952
        params.form_params.push(additional_param);
953
      } else {
954
        params.form_params = [params.form_params];
955
        params.form_params.push(additional_param);
956
      }
957
    } else {
958
      params.form_params = [additional_param];
959
    }
960

  
961
    $dialog.dialog('close');
962
    $dialog.remove();
963

  
964
    kivi.Order.save(params);
965
  };
966
});
967

  
968
$(function() {
969
  if ($('#type').val() == 'sales_order_intake' || $('#type').val() == 'sales_order' || $('#type').val() == 'sales_quotation' ) {
970
    $('#order_customer_id').change(kivi.Order.reload_cv_dependent_selections);
971
  } else {
972
    $('#order_vendor_id').change(kivi.Order.reload_cv_dependent_selections);
973
  }
974

  
975
  $('#order_currency_id').change(kivi.Order.update_exchangerate);
976
  $('#order_transdate_as_date').change(kivi.Order.update_exchangerate);
977
  $('#order_exchangerate_as_null_number').change(kivi.Order.exchangerate_changed);
978

  
979
  $('#add_item_parts_id').on('set_item:PartPicker', function() {
980
    kivi.Order.update_item_input_row();
981
  });
982

  
983
  $('.add_item_input').keydown(function(event) {
984
    if (event.keyCode == 13) {
985
      event.preventDefault();
986
      kivi.Order.add_item();
987
      return false;
988
    }
989
  });
990

  
991
  kivi.Order.init_row_handlers();
992

  
993
  $('#row_table_id').on('sortstop', function(event, ui) {
994
    $('#row_table_id thead a img').remove();
995
    kivi.Order.renumber_positions();
996
  });
997

  
998
  $('#expand_all').on('click', function(event) {
999
    event.preventDefault();
1000
    if ($('#expand_all').data('expanded') == 1) {
1001
      $('#expand_all').data('expanded', 0);
1002
      $('#expand_all').attr('src', 'image/expand.svg');
1003
      $('#expand_all').attr('alt', kivi.t8('Show all details'));
1004
      $('#expand_all').attr('title', kivi.t8('Show all details'));
1005
      $('.row_entry').each(function(idx, elt) {
1006
        kivi.Order.hide_second_row(elt);
1007
      });
1008
    } else {
1009
      $('#expand_all').data('expanded', 1);
1010
      $('#expand_all').attr('src', "image/collapse.svg");
1011
      $('#expand_all').attr('alt', kivi.t8('Hide all details'));
1012
      $('#expand_all').attr('title', kivi.t8('Hide all details'));
1013
      kivi.Order.load_all_second_rows();
1014
      $('.row_entry').each(function(idx, elt) {
1015
        kivi.Order.show_second_row(elt);
1016
      });
1017
    }
1018
    return false;
1019
  });
1020

  
1021
  $('.reformat_number_as_null_number').change(kivi.Order.reformat_number_as_null_number);
1022

  
1023
});
locale/de/all
87 87
  'A variable marked as \'editable\' can be changed in each quotation, order, invoice etc.' => 'Eine als \'editierbar\' markierte Variable kann in jedem Angebot, Auftrag, jeder Rechnung etc für jede Position geändert werden.',
88 88
  'A vendor with the same VAT ID already exists.' => 'Ein Lieferant mit der gleichen USt-IdNr. existiert bereits.',
89 89
  'A vendor with the same taxnumber already exists.' => 'Ein Lieferant mit der gleichen Steuernummer existiert bereits.',
90
  'ACTION'                      => '',
90 91
  'ADDED'                       => 'Hinzugefügt',
91 92
  'AP'                          => 'Einkauf',
92 93
  'AP Aging'                    => 'Offene Verbindlichkeiten',
......
2768 2769
  'PDF export with attachments' => 'Als PDF mit Anhängen exportieren',
2769 2770
  'PDF-Export'                  => 'PDF-Export',
2770 2771
  'PLZ Grosskunden'             => 'PLZ Grosskunden',
2772
  'POS for kivi'                => '',
2773
  'POSO'                        => '',
2771 2774
  'POSTED'                      => 'Gebucht',
2772 2775
  'POSTED AS NEW'               => 'Als neu gebucht',
2773 2776
  'PREVIEWED'                   => 'Druckvorschau',
locale/en/all
87 87
  'A variable marked as \'editable\' can be changed in each quotation, order, invoice etc.' => '',
88 88
  'A vendor with the same VAT ID already exists.' => '',
89 89
  'A vendor with the same taxnumber already exists.' => '',
90
  'ACTION'                      => '',
90 91
  'ADDED'                       => '',
91 92
  'AP'                          => 'Purchases',
92 93
  'AP Aging'                    => 'Creditor Aging',
......
2767 2768
  'PDF export with attachments' => '',
2768 2769
  'PDF-Export'                  => '',
2769 2770
  'PLZ Grosskunden'             => '',
2771
  'POS for kivi'                => '',
2772
  'POSO'                        => '',
2770 2773
  'POSTED'                      => '',
2771 2774
  'POSTED AS NEW'               => '',
2772 2775
  'PREVIEWED'                   => '',
templates/design40_webpages/pos/form.html
14 14
<div class="wrapper">
15 15
  <div class="pos_wrapper">
16 16
    <div class="pos_content">
17
      <div class="left_input control-panel small">[% "Salesman" | $T8 %]
18
        [% L.select_tag('order.salesman_id',
19
        SELF.all_salesmen,
20
        #[{id=1,name=werner},{id=2,name=Max}],
21
        default=(SELF.order.salesman_id ? SELF.order.salesman_id : SELF.current_employee_id),
22
        class='wi-lightwide',
23
        title_key='safe_name') %]
24
      </div>
25
      <div>
17
<div class="wrapper">
18
      <div class="left_input">
26 19
        <table>
27 20
          <tr>
28 21
            <th>[% 'Customer' | $T8 %]</th>
......
31 24
          </tr>
32 25
        </table>
33 26
      </div>
34
      <div class="toggle_panel control-panel toggle_order_info %]">
27
      <div class="left_input toggle_panel control-panel toggle_order_info %]">
35 28
        <a href="#" onClick='javascript:$(".toggle_panel_block").toggle()' class="button toggle off neutral">Auftragsdaten</a>
36 29
      </div>
30
      <div class="left_input control-panel small">[% "Salesman" | $T8 %]
31
        [% L.select_tag('order.salesman_id',
32
        SELF.all_salesmen,
33
        #[{id=1,name=werner},{id=2,name=Max}],
34
        default=(SELF.order.salesman_id ? SELF.order.salesman_id : SELF.current_employee_id),
35
        class='wi-lightwide',
36
        title_key='safe_name') %]
37
      </div>
38
</div>
37 39
      <div class="toggle_panel_block" style="display:none;">
38 40
        <div id="tables_left" style="float:left;">
39 41
          <table style="width:40%">

Auch abrufbar als: Unified diff