Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision f275cac9

Von Bernd Bleßmann vor fast 9 Jahren hinzugefügt

  • ID f275cac9ddfb00d05435e73fc85f0a6c016095b8
  • Vorgänger 7c0f439c
  • Nachfolger 419fa9c6

Auftrags-Controller: PriceSources

Unterschiede anzeigen:

SL/Controller/Order.pm
18 18
use SL::DB::Project;
19 19
use SL::DB::Default;
20 20
use SL::DB::Unit;
21
use SL::DB::Price;
21 22

  
22 23
use SL::Helper::DateTime;
23 24
use SL::Helper::CreatePDF qw(:all);
24 25

  
25 26
use List::Util qw(max first);
26
use List::MoreUtils qw(none pairwise);
27
use List::MoreUtils qw(none pairwise first_index);
27 28
use English qw(-no_match_vars);
28 29
use File::Spec;
29 30

  
......
315 316
  my $item = SL::DB::OrderItem->new;
316 317
  $item->assign_attributes(%$form_attr);
317 318

  
318
  my $part        = SL::DB::Part->new(id => $form_attr->{parts_id})->load;
319
  my $cv_method   = $self->cv;
320
  my $cv_discount = $self->order->$cv_method? $self->order->$cv_method->discount : 0.0;
319
  my $part         = SL::DB::Part->new(id => $form_attr->{parts_id})->load;
320

  
321
  my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
322

  
323
  my $price_src;
324
  if ($item->sellprice) {
325
    $price_src = $price_source->price_from_source("");
326
    $price_src->price($item->sellprice);
327
  } else {
328
    $price_src = $price_source->best_price
329
           ? $price_source->best_price
330
           : $price_source->price_from_source("");
331
    $price_src->price(0) if !$price_source->best_price;
332
  }
333

  
334
  my $discount_src;
335
  if ($item->discount) {
336
    $discount_src = $price_source->discount_from_source("");
337
    $discount_src->discount($item->discount);
338
  } else {
339
    $discount_src = $price_source->best_discount
340
                  ? $price_source->best_discount
341
                  : $price_source->discount_from_source("");
342
    $discount_src->discount(0) if !$price_source->best_discount;
343
  }
321 344

  
322 345
  my %new_attr;
323
  $new_attr{part}        = $part;
324
  $new_attr{description} = $part->description if ! $item->description;
325
  $new_attr{qty}         = 1.0                if ! $item->qty;
326
  $new_attr{unit}        = $part->unit;
327
  $new_attr{sellprice}   = $part->sellprice   if ! $item->sellprice;
328
  $new_attr{discount}    = $cv_discount       if ! $item->discount;
346
  $new_attr{part}                   = $part;
347
  $new_attr{description}            = $part->description if ! $item->description;
348
  $new_attr{qty}                    = 1.0                if ! $item->qty;
349
  $new_attr{sellprice}              = $price_src->price;
350
  $new_attr{discount}               = $discount_src->discount;
351
  $new_attr{active_price_source}    = $price_src;
352
  $new_attr{active_discount_source} = $discount_src;
329 353

  
330 354
  # add_custom_variables adds cvars to an orderitem with no cvars for saving, but
331 355
  # they cannot be retrieved via custom_variables until the order/orderitem is
......
364 388
  $self->js->render();
365 389
}
366 390

  
391
sub action_price_popup {
392
  my ($self) = @_;
393

  
394
  my $idx  = first_index { $_ eq $::form->{item_id} } @{ $::form->{orderitem_ids} };
395
  my $item = $self->order->items->[$idx];
396

  
397
  $self->render_price_dialog($item);
398
}
399

  
367 400
sub _js_redisplay_linetotals {
368 401
  my ($self) = @_;
369 402

  
......
476 509
}
477 510

  
478 511

  
512
sub render_price_dialog {
513
  my ($self, $record_item) = @_;
514

  
515
  my $price_source = SL::PriceSource->new(record_item => $record_item, record => $self->order);
516

  
517
  $self->js
518
    ->run(
519
      'kivi.io.price_chooser_dialog',
520
      t8('Available Prices'),
521
      $self->render('order/tabs/_price_sources_dialog', { output => 0 }, price_source => $price_source)
522
    )
523
    ->reinit_widgets;
524

  
525
#   if (@errors) {
526
#     $self->js->text('#dialog_flash_error_content', join ' ', @errors);
527
#     $self->js->show('#dialog_flash_error');
528
#   }
529

  
530
  $self->js->render;
531
}
532

  
479 533
sub _make_order {
480 534
  my ($self) = @_;
481 535

  
......
491 545
  return $order;
492 546
}
493 547

  
494

  
495 548
sub _recalc {
496 549
  my ($self) = @_;
497 550

  
......
520 573
    if ($item->id) {
521 574
      # load data from orderitems (db)
522 575
      my $db_item = SL::DB::OrderItem->new(id => $item->id)->load;
523
      $item->$_($db_item->$_) for qw(active_discount_source active_price_source longdescription);
576
      $item->$_($db_item->$_) for qw(longdescription);
524 577
    } else {
525 578
      # set data from part (or other sources)
526 579
      $item->longdescription($item->part->notes);
527
      #$item->active_price_source('');
528
      #$item->active_discount_source('');
529 580
    }
530 581

  
531 582
    # autovivify all cvars that are not in the form (cvars_by_config can do it).
......
591 642

  
592 643
  $self->{current_employee_id} = SL::DB::Manager::Employee->current->id;
593 644

  
645
  foreach  my $item (@{$self->order->items}) {
646
    my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
647
    $item->active_price_source(   $price_source->price_from_source(   $item->active_price_source   ));
648
    $item->active_discount_source($price_source->discount_from_source($item->active_discount_source));
649

  
650
  }
651

  
594 652
  $::request->{layout}->use_javascript("${_}.js")  for qw(ckeditor/ckeditor ckeditor/adapters/jquery);
595 653
}
596 654

  
templates/webpages/order/tabs/_item_input.html
16 16
      <tr valign="top" class="listrow">
17 17
        <td>[% L.part_picker('add_item.parts_id', '', fat_set_item=1, style='width: 300px', class="add_item_input") %]</td>
18 18
        <td>[% L.input_tag('add_item.description', '', class="add_item_input") %]</td>
19
        <td>[% L.input_tag('add_item.qty_as_number', '', size = 5, style='text-align:right', class="add_item_input") %]</td>
19
        <td>
20
          [% L.input_tag('add_item.qty_as_number', '', size = 5, style='text-align:right', class="add_item_input") %]
21
          [% L.hidden_tag('add_item.unit', '', class="add_item_input") %]
22
        </td>
20 23
        <td>[% L.input_tag('add_item.sellprice_as_number', '', size = 10, style='text-align:right', class="add_item_input") %]</td>
21 24
        <td>[% L.input_tag('add_item.discount_as_percent', '', size = 5, style='text-align:right', class="add_item_input") %]</td>
22 25
        <td>[% L.button_tag('add_item()', LxERP.t8('Add part')) %]</td>
templates/webpages/order/tabs/_price_sources_dialog.html
1
[%- USE T8 %]
2
[%- USE HTML %]
3
[%- USE L %]
4
[%- USE LxERP %]
5
[% SET best_price = price_source.best_price %]
6
[% SET best_discount = price_source.best_discount %]
7
  <h2>[% 'Prices' | $T8 %]</h2>
8

  
9
  <table>
10
   <tr class='listheading'>
11
    <th></th>
12
    <th>[% 'Price Source' | $T8 %]</th>
13
    <th>[% 'Price' | $T8 %]</th>
14
    <th>[% 'Best Price' | $T8 %]</th>
15
    <th>[% 'Details' | $T8 %]</th>
16
   </tr>
17
   <tr class='listrow'>
18
[%- IF price_source.record_item.active_price_source %]
19
    <td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource)') _ '\')', LxERP.t8('Select')) %]</td>
20
[%- ELSE %]
21
    <td><b>[% 'Selected' | $T8 %]</b></td>
22
[%- END %]
23
    <td>[% 'None (PriceSource)' | $T8 %]</td>
24
    <td>-</td>
25
    <td></td>
26
    <td></td>
27
   </tr>
28
   [%- FOREACH price IN price_source.available_prices %]
29
    <tr class='listrow'>
30
[%- IF price_source.record_item.active_price_source != price.source %]
31
     <td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Select')) %]</td>
32
[%- ELSIF price_source.record_item.sellprice * 1 != price.price * 1 %]
33
     <td>[% L.button_tag('update_price_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ LxERP.format_amount(price.price, -2) _ '\')', LxERP.t8('Update Price')) %]</td>
34
[%- ELSE %]
35
    <td><b>[% 'Selected' | $T8 %]</b></td>
36
[% END %]
37
     <td>[% price.source_description | html %]</td>
38
     <td>[% price.price_as_number %]</td>
39
[% IF price.source == best_price.source %]
40
     <td align='center'>&#x2022;</td>
41
[% ELSE %]
42
     <td></td>
43
[% END %]
44
     <td>[% price.description | html %]</td>
45
    </tr>
46
   [%- END %]
47
  </table>
48

  
49
  <h2>[% 'Discounts' | $T8 %]</h2>
50

  
51
  <table>
52
   <tr class='listheading'>
53
    <th></th>
54
    <th>[% 'Price Source' | $T8 %]</th>
55
    <th>[% 'Discount' | $T8 %]</th>
56
    <th>[% 'Best Discount' | $T8 %]</th>
57
    <th>[% 'Details' | $T8 %]</th>
58
   </tr>
59
   <tr class='listrow'>
60
[%- IF price_source.record_item.active_discount_source %]
61
    <td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'\', \'' _ LxERP.t8('None (PriceSource Discount)') _ '\')', LxERP.t8('Select')) %]</td>
62
[%- ELSE %]
63
    <td><b>[% 'Selected' | $T8 %]</b></td>
64
[%- END %]
65
    <td>[% 'None (PriceSource Discount)' | $T8 %]</td>
66
    <td>-</td>
67
    <td></td>
68
    <td></td>
69
   </tr>
70
   [%- FOREACH price IN price_source.available_discounts %]
71
    <tr class='listrow'>
72
[%- IF price_source.record_item.active_discount_source != price.source %]
73
     <td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent _ '\')', LxERP.t8('Select')) %]</td>
74
[%- ELSIF price_source.record_item.discount * 1 != price.discount * 1 %]
75
     <td>[% L.button_tag('update_discount_source(\'' _ FORM.item_id _ '\', \'' _ price.source _ '\', \'' _ price.source_description _ '\', \'' _ price.discount_as_percent  _ '\')', LxERP.t8('Update Discount')) %]</td>
76
[%- ELSE %]
77
    <td><b>[% 'Selected' | $T8 %]</b></td>
78
[% END %]
79
     <td>[% price.source_description | html %]</td>
80
     <td>[% price.discount_as_percent %] %</td>
81
[% IF price.source == best_discount.source %]
82
     <td align='center'>&#x2022;</td>
83
[% ELSE %]
84
     <td></td>
85
[% END %]
86
     <td>[% price.description | html %]</td>
87
    </tr>
88
   [%- END %]
89
  </table>
templates/webpages/order/tabs/_row.html
7 7

  
8 8
  <tr class="listrow0">
9 9
    <td style='display:none'>
10
      [% L.hidden_tag("orderitem_ids[+]", ID) %]
10 11
      [% L.hidden_tag("order.orderitems[+].id", ITEM.id, id='item_' _ ID) %]
11 12
      [% L.hidden_tag("order.orderitems[].parts_id", ITEM.parts_id) %]
12 13
    </td>
......
47 48
                      class="recalc") %]
48 49
    </td>
49 50
    <td>
50
      [%- L.input_tag("order.orderitems[].sellprice_as_number",
51
                      ITEM.sellprice_as_number,
52
                      size = 10,
53
                      style='text-align:right',
54
                      class="recalc") %]
51
      [%- L.button_tag("price_chooser_item_row(this)",
52
                       ITEM.active_price_source.source_description _ ' | ' _ ITEM.active_discount_source.source_description,
53
                       name = "price_chooser_button") %]
55 54
    </td>
56 55
    <td>
57
      [%- L.input_tag("order.orderitems[].discount_as_percent",
58
                      ITEM.discount_as_percent,
59
                      size = 5,
60
                      style='text-align:right',
61
                      class="recalc") %]
56
      [%- L.hidden_tag("order.orderitems[].active_price_source", ITEM.active_price_source.source) %]
57
      [%- SET EDIT_PRICE = (AUTH.assert('edit_prices', 1) && ITEM.active_price_source.source == '') %]
58
      <div name="editable_price" [%- IF !EDIT_PRICE %]style="display:none"[%- END %]>
59
        [%- L.input_tag("order.orderitems[].sellprice_as_number",
60
                        ITEM.sellprice_as_number,
61
                        size = 10,
62
                        style='text-align:right',
63
                        disabled=(EDIT_PRICE? '' : 1),
64
                        class="recalc reformat_number") %]
65
      </div>
66
      <div name="not_editable_price" [%- IF EDIT_PRICE %]style="display:none"[%- END %]>
67
        [%- L.div_tag(ITEM.sellprice_as_number, name="sellprice_text", style='text-align:right') %]
68
        [%- L.hidden_tag("order.orderitems[].sellprice_as_number",
69
                         ITEM.sellprice_as_number,
70
                         disabled=(EDIT_PRICE? 1 : '')) %]
71
      </div>
72
    </td>
73
    <td>
74
      [%- L.hidden_tag("order.orderitems[].active_discount_source", ITEM.active_discount_source.source) %]
75
      [%- SET EDIT_DISCOUNT = (AUTH.assert('edit_prices', 1) && ITEM.active_discount_source.source == '') %]
76
      <div name="editable_discount" [%- IF !EDIT_DISCOUNT %]style="display:none"[%- END %]>
77
        [%- L.input_tag("order.orderitems[].discount_as_percent",
78
                        ITEM.discount_as_percent,
79
                        size = 5,
80
                        style='text-align:right',
81
                        disabled=(EDIT_DISCOUNT? '' : 1),
82
                        class="recalc reformat_number") %]
83
      </div>
84
      <div name="not_editable_discount" [%- IF EDIT_DISCOUNT %]style="display:none"[%- END %]>
85
        [%- L.div_tag(ITEM.discount_as_percent, name="discount_text", style='text-align:right') %]
86
        [%- L.hidden_tag("order.orderitems[].discount_as_percent",
87
                         ITEM.discount_as_percent,
88
                         disabled=(EDIT_DISCOUNT? 1 : '')) %]
89
      </div>
62 90
    </td>
63 91
    <td align="right">
64 92
      [%- L.div_tag(LxERP.format_amount(ITEM.linetotal, 2, 0), name="linetotal") %]
templates/webpages/order/tabs/basic_data.html
145 145
                <th class="listheading" nowrap width="5" >[%- 'Qty'          | $T8 %] </th>
146 146
                <th class="listheading" nowrap width="5" >[%- 'Price Factor' | $T8 %] </th>
147 147
                <th class="listheading" nowrap width="5" >[%- 'Unit'         | $T8 %] </th>
148
                <th class="listheading" nowrap width="5" >[%- 'Price Source' | $T8 %] </th>
148 149
                <th class="listheading" nowrap width="15">[%- 'Price'        | $T8 %] </th>
149 150
                <th class="listheading" nowrap width="5" >[%- 'Discount'     | $T8 %] </th>
150 151
                <th class="listheading" nowrap width="10">[%- 'Extended'     | $T8 %] </th>
......
272 273
  recalc_amounts_and_taxes();
273 274
}
274 275

  
276
function price_chooser_item_row(clicked) {
277
  var row = $(clicked).parents("tbody").first();
278
  var item_id_dom = $(row).find('[name="orderitem_ids[+]"]');
279

  
280
  var data = $('#order_form').serialize();
281
  data += '&action=Order/price_popup';
282
  data += '&item_id=' + item_id_dom.val();
283

  
284
  $.post("controller.pl", data, kivi.eval_json_result);
285
}
286

  
287
function update_price_source(item_id, source, descr, price_str) {
288
  var row = $('#item_' + item_id).parents("tbody").first();
289
  var source_elt = $(row).find('[name="order.orderitems[].active_price_source"]');
290
  var button_elt = $(row).find('[name="price_chooser_button"]');
291

  
292
  button_elt.val(button_elt.val().replace(/.*\|/, descr + " |"));
293
  source_elt.val(source);
294

  
295
  var editable_div_elt = $(row).find('[name="editable_price"]');
296
  var not_editable_div_elt = $(row).find('[name="not_editable_price"]');
297
  if ([%- AUTH.assert('edit_prices', 1) %] == 1 && source == '') {
298
    // editable
299
    $(editable_div_elt).show();
300
    $(not_editable_div_elt).hide();
301
    $(editable_div_elt).find(':input').prop("disabled", false);
302
    $(not_editable_div_elt).find(':input').prop("disabled", true);
303
  } else {
304
    // not editable
305
    $(editable_div_elt).hide();
306
    $(not_editable_div_elt).show();
307
    $(editable_div_elt).find(':input').prop("disabled", true);
308
    $(not_editable_div_elt).find(':input').prop("disabled", false);
309
  }
310

  
311
  if (price_str) {
312
    var price_elt = $(row).find('[name="order.orderitems[].sellprice_as_number"]');
313
    var html_elt  = $(row).find('[name="sellprice_text"]');
314
    price_elt.val(price_str);
315
    html_elt.html(price_str);
316
    recalc_amounts_and_taxes();
317
  }
318

  
319
  kivi.io.close_dialog();
320
}
321

  
322
function update_discount_source(item_id, source, descr, discount_str) {
323
  var row = $('#item_' + item_id).parents("tbody").first();
324
  var source_elt = $(row).find('[name="order.orderitems[].active_discount_source"]');
325
  var button_elt = $(row).find('[name="price_chooser_button"]');
326

  
327
  button_elt.val(button_elt.val().replace(/\|.*/, "| " + descr));
328
  source_elt.val(source);
329

  
330
  var editable_div_elt = $(row).find('[name="editable_discount"]');
331
  var not_editable_div_elt = $(row).find('[name="not_editable_discount"]');
332
  if ([%- AUTH.assert('edit_prices', 1) %] == 1 && source == '') {
333
    // editable
334
    $(editable_div_elt).show();
335
    $(not_editable_div_elt).hide();
336
    $(editable_div_elt).find(':input').prop("disabled", false);
337
    $(not_editable_div_elt).find(':input').prop("disabled", true);
338
  } else {
339
    // not editable
340
    $(editable_div_elt).hide();
341
    $(not_editable_div_elt).show();
342
    $(editable_div_elt).find(':input').prop("disabled", true);
343
    $(not_editable_div_elt).find(':input').prop("disabled", false);
344
  }
345

  
346
  if (discount_str) {
347
    var discount_elt = $(row).find('[name="order.orderitems[].discount_as_percent"]');
348
    var html_elt     = $(row).find('[name="discount_text"]');
349
    discount_elt.val(discount_str);
350
    html_elt.html(discount_str);
351
    recalc_amounts_and_taxes();
352
  }
353

  
354
  kivi.io.close_dialog();
355
}
356

  
275 357
function reformat_number(event) {
276 358
  $(event.target).val(kivi.format_amount(kivi.parse_amount($(event.target).val()), -2));
277 359
}
......
357 439

  
358 440
$(function(){
359 441
  $('#order_[%- cv_id %]').change(reload_cv_dependend_selections);
360
  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
442
  [%- IF SELF.cv == 'customer' %]
443
    $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) });
444
  [%- ELSE %]
445
    $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.lastcost, -2)) });
446
  [%- END %]
361 447
  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_description').val(o.description) });
448
  $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_unit').val(o.unit) });
362 449
  $('.add_item_input').keydown(function(event) {
363 450
    if(event.keyCode == 13) {
364 451
      event.preventDefault();

Auch abrufbar als: Unified diff