Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 2401956f

Von Tamino Steinert vor mehr als 1 Jahr hinzugefügt

  • ID 2401956fda2e97c2b828476691f9b92e451571f8
  • Vorgänger 8fa9177a
  • Nachfolger 90b47258

WIP DispositionManager

Unterschiede anzeigen:

SL/Controller/DispositionManager.pm
9 9
use SL::DB::Part;
10 10
use SL::DB::PurchaseBasketItem;
11 11
use SL::DB::Order;
12
use SL::DB::OrderItem;
12 13
use SL::DB::Vendor;
13 14
use SL::PriceSource;
14 15
use SL::Locale::String qw(t8);
......
140 141
  my ($self) = @_;
141 142

  
142 143
  $::request->{layout}->add_javascripts(
143
    'kivi.DispositionManager.js', 'kivi.PartDetail.js'
144
    'kivi.DispositionManager.js', 'kivi.Part.js'
144 145
  );
145 146
  my $basket_items = SL::DB::Manager::PurchaseBasketItem->get_all(
146 147
    query => [ cleared => 'F' ],
......
259 260
    push @order_items, $order_item;
260 261
  }
261 262

  
262
  $order->add_items( @order_items );
263
  $order->assign_attributes(orderitems => \@order_items);
263 264

  
264 265
  $order->db->with_transaction( sub {
265 266
    $order->calculate_prices_and_taxes;
SL/Controller/Part.pm
25 25
use SL::DB::PurchaseBasketItem;
26 26
use SL::DB::Shop;
27 27
use SL::Helper::Flash;
28
use SL::Helper::PrintOptions;
28 29
use SL::JSON;
29 30
use SL::Locale::String qw(t8);
30 31
use SL::MoreCommon qw(save_form);
......
758 759
  }
759 760
}
760 761

  
762
sub action_showdetails {
763
  my ($self, %params) = @_;
764

  
765
  eval {
766
      my @bindata;
767
      my $bins = SL::DB::Manager::Bin->get_all(with_objects => ['warehouse' ]);
768
      my %bins_by_id = map { $_->id => $_ } @$bins;
769
      my $inventories = SL::DB::Manager::Inventory->get_all(where => [ parts_id => $self->part->id],
770
                             with_objects => ['parts', 'trans_type' ], sort_by => 'bin_id ASC');
771
      foreach my $bin (@{ $bins }) {
772
          $bin->{qty} = 0;
773
      }
774

  
775
      foreach my $inv (@{ $inventories }) {
776
          my $bin = $bins_by_id{ $inv->bin_id };
777
          $bin->{qty}      += $inv->qty;
778
          $bin->{unit}     =  $inv->parts->unit;
779
          $bin->{reserved} =  defined $inv->reserve_for_id ? 1 : 0;
780
      }
781
      my $sum = 0;
782
      my $reserve_sum = 0;
783
      for my $bin (@{ $bins }) {
784
        push @bindata , {
785
          'warehouse'    => $bin->warehouse->forreserve ? $bin->warehouse->description.' (R)' : $bin->warehouse->description,
786
          'description'  => $bin->description,
787
          'qty'          => $bin->{qty},
788
          'unit'         => $bin->{unit},
789
        } if $bin->{qty} != 0;
790

  
791
        $sum += $bin->{qty};
792
        if($bin->warehouse->forreserve || defined $bin->warehouse->{reserve_for_id}){
793
          $reserve_sum += $bin->{qty};
794
        }
795
      }
796
      # Einfacher ? $sum = $self->part->onhand
797
      my $todate   = DateTime->now_local;
798
      my $fromdate = DateTime->now_local->add_duration(DateTime::Duration->new(years => -1));
799
      my $average  = 0;
800
      foreach my $inv (@{ $inventories }) {
801
        $average += abs($inv->qty) if $inv->shippingdate && $inv->trans_type->direction eq 'out' &&
802
          DateTime->compare($inv->shippingdate,$fromdate) != -1 &&
803
          DateTime->compare($inv->shippingdate,$todate)   == -1;
804
      }
805
      my $openitems = SL::DB::Manager::OrderItem->get_all(where => [ parts_id => $self->part->id, 'order.closed' => 0 ],
806
                                                           with_objects => ['order'],);
807
      my ($not_delivered, $ordered) = 0;
808
      for my $openitem (@{ $openitems }) {
809
        if($openitem -> order -> type eq 'sales_order') {
810
          $not_delivered += $openitem->qty - $openitem->shipped_qty;
811
        } elsif ( $openitem->order->type eq 'purchase_order' ) {
812
          $ordered += $openitem->qty - $openitem->delivered_qty;
813
        }
814
      }
815
      my $print_form = Form->new('');
816
      my $part = $self->part;
817

  
818
      my $stock_amounts = $self->part->get_simple_stock_sql;
819
      $print_form->{type}      = 'part';
820
      $print_form->{printers}  = SL::DB::Manager::Printer->get_all_sorted;
821
      my $output = SL::Presenter->get->render('part/showdetails',
822
          part          => $self->part,
823
          BINS          => \@bindata,
824
          stock_amounts => $stock_amounts,
825
          average       => $average/12,
826
          fromdate      => $fromdate,
827
          todate        => $todate,
828
          sum           => $sum,
829
          reserve_sum   => $reserve_sum,
830
          not_delivered => $not_delivered,
831
          ordered       => $ordered,
832
          type_beleg    => $::form->{type},
833
          type_id       => $::form->{type_id},
834
          maker_id      => $::form->{maker_id},
835
          drawing       => $::form->{drawing},
836
    print_options   => SL::Helper::PrintOptions->get_print_options(
837
      form => $print_form,
838
      options => {dialog_name_prefix => 'print_options.',
839
                  show_headers       => 1,
840
                  no_queue           => 1,
841
                  no_postscript      => 1,
842
                  no_opendocument    => 1,
843
                  hide_language_id_print => 1,
844
                  no_html            => 1},
845
    ),
846
      );
847
      $self->render(\$output, { layout => 0, process => 0 });
848
    1;
849
  } or do {
850
  };
851
}
852

  
853
sub action_print_label {
854
  my ($self) = @_;
855
  # TODO: implement
856
  return $self->render('generic/error', { layout => 1 }, label_error => t8('Not implemented yet!'));
857
}
858

  
761 859
sub action_export_assembly_assortment_components {
762 860
  my ($self) = @_;
763 861

  
SL/DB/Helper/ALL.pm
109 109
use SL::DB::ProjectStatus;
110 110
use SL::DB::ProjectType;
111 111
use SL::DB::PurchaseBasket;
112
use SL::DB::PurchaseBasketItem;
112 113
use SL::DB::PurchaseInvoice;
113 114
use SL::DB::Reclamation;
114 115
use SL::DB::ReclamationItem;
SL/DB/Manager/Part.pm
154 154
  my ($open_qty) = selectrow_query(
155 155
    $::form, $class->object_class->init_db->dbh,
156 156
    $query, $part_id, $part_id, $part_id
157
  );
157
  ) || 0;
158 158

  
159 159
  return $open_qty if $open_qty > 0;
160 160
  return 0;
SL/DB/Part.pm
13 13
use SL::DB::MetaSetup::Part;
14 14
use SL::DB::Manager::Part;
15 15
use SL::DB::Chart;
16
use SL::DB::Vendor;
16
use SL::DB::Manager::Vendor;
17 17
use SL::DB::Helper::AttrHTML;
18 18
use SL::DB::Helper::AttrSorted;
19 19
use SL::DB::Helper::TransNumberGenerator;
......
104 104
__PACKAGE__->before_save('_before_save_set_partnumber');
105 105
__PACKAGE__->before_save('_before_save_set_assembly_weight');
106 106

  
107
sub init_onhandqty{
108
  my ($self) = @_;
109
  my $qty = SL::Helper::Inventory::get_onhand(part => $self->id);
110
  return $qty;
111
}
112

  
113
sub init_stockqty{
114
  my ($self) = @_;
115
  my $qty = SL::Helper::Inventory::get_stock(part => $self->id);
116
  return $qty;
117
}
118

  
119
sub init_get_open_ordered_qty {
120
  my $self   = shift;
121
  my $result = SL::DB::Manager::Part->get_open_ordered_qty($self->id);
122

  
123
  return $result;
124
}
125

  
126 107
sub _before_save_set_partnumber {
127 108
  my ($self) = @_;
128 109

  
......
302 283
  return $result{ $self->id };
303 284
}
304 285

  
305
sub is_parts_first_order {
306

  
307
  my ($self, %params) = @_;
308

  
309
  #require SL::DB::OrderItem;
310
  my $orders_count = SL::DB::Manager::OrderItem->get_all_count( where => [ %params ], with_objects => 'order' );
311

  
312
  return $orders_count == 1 ? 1 : 0;
313
}
314

  
315 286
sub available_units {
316 287
  shift->unit_obj->convertible_units;
317 288
}
......
625 596
  return \@vendor_dd;
626 597
}
627 598

  
599
sub init_onhandqty{
600
  my ($self) = @_;
601
  my $qty = SL::Helper::Inventory::get_onhand(part => $self->id) || 0;
602
  return $qty;
603
}
604

  
605
sub init_stockqty{
606
  my ($self) = @_;
607
  my $qty = SL::Helper::Inventory::get_stock(part => $self->id) || 0;
608
  return $qty;
609
}
610

  
611
sub init_get_open_ordered_qty {
612
  my ($self) = @_;
613
  my $result = SL::DB::Manager::Part->get_open_ordered_qty($self->id);
614

  
615
  return $result;
616
}
617

  
628 618
1;
629 619

  
630 620
__END__
js/kivi.Part.js
22 22
    $('#ic').submit();
23 23
  };
24 24

  
25
  ns.print_from_showdetail = function(part_id) {
26
    var data = $('#print_options_form').serializeArray();
27
    data.push({ name: 'action', value: 'Part/print_label' });
28
    data.push({ name: 'part.id', value: part_id });
29
  $.download("controller.pl", data);
30
  };
31

  
25 32
  ns.delete = function() {
26 33
    var data = $('#ic').serializeArray();
27 34
    data.push({ name: 'action', value: 'Part/delete' });
locale/de/all
2506 2506
  'Normalize part description and part notes' => 'Normalisierung Artikelbeschreibung und Artikellangtext (Bemerkung)',
2507 2507
  'Not Discountable'            => 'Nicht rabattierfähig',
2508 2508
  'Not delivered'               => 'Nicht geliefert',
2509
  'Not delivered amount'        => 'nicht gelieferte Menge',
2509 2510
  'Not done yet'                => 'Noch nicht fertig',
2510 2511
  'Not enough in stock for the serial number #1' => 'Nicht genug auf Lager von der Seriennummer #1',
2511 2512
  'Not obsolete'                => 'Gültig',
......
2620 2621
  'OrderItem'                   => 'Position',
2621 2622
  'Ordered'                     => 'Von Kunden bestellt',
2622 2623
  'Ordered purchase'            => 'Bestellte Menge',
2624
  'Ordered, but not delivered (purchase)' => 'Bestellt, nicht geliefert(EK)',
2623 2625
  'Orderer'                     => 'BestellerIn',
2624 2626
  'Orders'                      => 'Aufträge',
2625 2627
  'Orders / Delivery Orders deleteable' => 'Aufträge / Lieferscheine löschbar',
......
3674 3676
  'Subtotals per quarter'       => 'Zwischensummen pro Quartal',
3675 3677
  'Such entries cannot be exported into the DATEV format and have to be fixed as well.' => 'Solche Einträge sind aber nicht DATEV-exportiertbar und müssen ebenfalls korrigiert werden.',
3676 3678
  'Suggested invoice'           => 'Rechnungsvorschlag',
3679
  'Sum Amount'                  => 'Gesamtmenge',
3677 3680
  'Sum Credit'                  => 'Summe Haben',
3678 3681
  'Sum Debit'                   => 'Summe Soll',
3679 3682
  'Sum for'                     => 'Summe für',
......
4949 4952
  'part \'#\'1 in bin \'#2\' only with qty #3 (need additional #4) and chargenumber \'#5\'.' => 'Artikel \'#1\' im \'#2\' nur mit der Menge #3 (noch #4 benötig) und Chargennummer \'#5\'.',
4950 4953
  'part_list'                   => 'Warenliste',
4951 4954
  'pdf_records.zip'             => 'pdf_belege.zip',
4955
  'per month'                   => 'pro Monat',
4952 4956
  'percental'                   => 'prozentual',
4953 4957
  'periodic'                    => 'Aufwandsmethode',
4954 4958
  'perpetual'                   => 'Bestandsmethode',
t/controllers/disposition_manager/disposition_manager.t
60 60

  
61 61
my $controller = SL::Controller::DispositionManager->new();
62 62
my $reorder_parts = $controller->_get_parts;
63
is(scalar @{$reorder_parts}, 6, "found 6 parts where onhand <= rop");
63
is(scalar @{$reorder_parts}, 5, "found 5 parts where onhand < rop");
64 64

  
65 65
# die; # die here if you want to test making basket manually
66 66

  
......
76 76
select $oldFH;
77 77
close $outputFH;
78 78

  
79
is(SL::DB::Manager::PurchaseBasketItem->get_all_count(), 6, "6 items in purchase basket ok");
79
is(SL::DB::Manager::PurchaseBasketItem->get_all_count(), 5, "5 items in purchase basket ok");
80 80

  
81 81
# die; # die here if you want to test creating purchase orders manually
82 82

  
......
97 97

  
98 98
my $purchase_order = SL::DB::Manager::Order->get_first();
99 99

  
100
is( scalar @{$purchase_order->items}, 6, "Purchase order has 6 item ok");
101
print "PART\n";
102
print Dumper($part1);
100
is( scalar @{$purchase_order->items}, 5, "Purchase order has 5 item ok");
101
# print "PART\n";
102
# print Dumper($part1);
103 103
my $first_item = $purchase_order->items_sorted->[0];
104
print "FIRST\n";
105
print Dumper($first_item);
104
# print "FIRST\n";
105
# print Dumper($first_item);
106 106
is( $first_item->parts_id, $part1->id, "Purchase order: first item is part1");
107
is( $first_item->qty, '1.0000000', "Purchase order: first item has qty 1");
108
cmp_ok( $purchase_order->netamount, '==', 52, "Purchase order: netamount ok");
109
is( $first_item->active_price_source, 'makemodel/' . $part1->makemodels->[0]->id . "/" . $part1->makemodels->[0]->parts_id . "/" . $part1->makemodels->[0]->make, "Purchase order: first item has correct active_price_source" . $first_item->part->partnumber);
107
is( $first_item->qty, '20.00000', "Purchase order: first item has qty 20");
108
cmp_ok( $purchase_order->netamount, '==', 240, "Purchase order: netamount ok");
109
is( $first_item->active_price_source, 'makemodel/' . $part1->makemodels->[0]->id, "Purchase order: first item has correct active_price_source" . $first_item->part->partnumber);
110 110

  
111 111
clear_up();
112 112
done_testing();
t/workflow/delivery_order_reclamation.t
281 281
    "sales_delivery_order_items to sales_reclamation_items",
282 282
    qw(
283 283
      id delivery_order_id reclamation_id itime mtime
284
      cusordnumber marge_price_factor ordnumber transdate
284
      cusordnumber marge_price_factor ordnumber transdate orderer_id
285 285
      description reason_description_ext reason_description_int reason_id
286 286
    ));
287 287
} @sales_delivery_order_items, @converted_sales_reclamation_items;
......
301 301
    "sales_reclamation_items to sales_delivery_order_items",
302 302
    qw(
303 303
      id delivery_order_id reclamation_id itime mtime
304
      cusordnumber marge_price_factor ordnumber transdate
304
      cusordnumber marge_price_factor ordnumber transdate orderer_id
305 305
      description reason_description_ext reason_description_int reason_id
306 306
    ));
307 307
} @sales_reclamation_items, @converted_sales_delivery_order_items;
......
323 323
    "purchase_delivery_order_items to purchase_reclamation_items",
324 324
    qw(
325 325
      id delivery_order_id reclamation_id itime mtime
326
      cusordnumber marge_price_factor ordnumber transdate
326
      cusordnumber marge_price_factor ordnumber transdate orderer_id
327 327
      description reason_description_ext reason_description_int reason_id
328 328
    ));
329 329
} @purchase_delivery_order_items, @converted_purchase_reclamation_items;
......
343 343
    "purchase_reclamation_items to purchase_delivery_order_items",
344 344
    qw(
345 345
      id delivery_order_id reclamation_id itime mtime
346
      cusordnumber marge_price_factor ordnumber transdate
346
      cusordnumber marge_price_factor ordnumber transdate orderer_id
347 347
      description reason_description_ext reason_description_int reason_id
348 348
    ));
349 349
} @purchase_reclamation_items, @converted_purchase_delivery_order_items;
t/workflow/order_reclamation.t
282 282
    "sales_order_items to sales_reclamation_items",
283 283
    qw(
284 284
      id trans_id reclamation_id itime mtime
285
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate
285
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate orderer_id
286 286
      reason_description_ext reason_description_int reason_id
287 287
      recurring_billing_mode recurring_billing_invoice_id
288 288
    ));
......
302 302
    "sales_reclamation_items to sales_order_items",
303 303
    qw(
304 304
      id trans_id reclamation_id itime mtime
305
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate
305
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate orderer_id
306 306
      reason_description_ext reason_description_int reason_id
307 307
      recurring_billing_mode recurring_billing_invoice_id
308 308
    ));
......
323 323
    "purchase_order_items to purchase_reclamation_items",
324 324
    qw(
325 325
      id trans_id reclamation_id itime mtime
326
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate
326
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate orderer_id
327 327
      reason_description_ext reason_description_int reason_id
328 328
      recurring_billing_mode recurring_billing_invoice_id
329 329
    ));
......
343 343
    "purchase_reclamation_items to purchase_order_items",
344 344
    qw(
345 345
      id trans_id reclamation_id itime mtime
346
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate
346
      cusordnumber marge_percent marge_price_factor marge_total optional ordnumber ship subtotal transdate orderer_id
347 347
      reason_description_ext reason_description_int reason_id
348 348
      recurring_billing_mode recurring_billing_invoice_id
349 349
    ));
templates/webpages/part/showdetails.html
1
[%- USE LxERP -%][% USE L %][% USE HTML %][%- USE JavaScript -%][% USE T8 %][%- USE Dumper %]
2

  
3
<div style="padding-bottom: 15px">
4
  <table style="width: 100%" border="0px" ><tbody>
5
      <tr>
6
        <td><b>[%  LxERP.t8('Description') %]</b></td><td colspan="3">[% part.description %]</td>
7
      </tr>
8
      <tr>
9
        <td style="background:wheat;"><b>[%  LxERP.t8('Internal Notes') %]</b></td><td colspan="3" style="background:wheat;">[% part.intnotes %]</td>
10
      </tr>
11
      <tr>
12
        <td><b>[%  LxERP.t8('Default Warehouse') %]</b></td><td>[% part.warehouse.description %]</td>
13
        <td><b>[%  LxERP.t8('Default Bin') %]</b></td><td>[% part.bin.description %]</td>
14
      </tr>
15
      <tr>
16
        <td><b>[%  LxERP.t8('ROP') %]</b></td><td>[% part.rop_as_number %]</td>
17
      </tr>
18
      <tr>
19
        [%- IF stock_amounts.size %]
20
        <td colspan="4"><table style="width: 100%">
21
          <tr class='listheading'>
22
           <th class="listheading">[% 'Warehouse'   | $T8 %]</th>
23
           <th class="listheading">[% 'Bin'         | $T8 %]</th>
24
           <th class="listheading">[% 'Chargenumber'         | $T8 %]</th>
25
           <th class="listheading">[% 'Qty'         | $T8 %]</th>
26
           <th class="listheading">[% 'Unit'        | $T8 %]</th>
27
         </tr>
28
         [% FOREACH stock = stock_amounts %]
29
          <tr class='listrow'>
30
           <td                >[% HTML.escape(stock.warehouse_description)  %]</td>
31
           <td                >[% IF stock.order_link %]<a target="_blank" href="[% stock.order_link %]">[% END %]
32
                               [% HTML.escape(stock.bin_description)        %]
33
                               [% IF stock.order_link %]</a>[% END %]
34
           </td>
35
           <td                >[% HTML.escape(stock.chargenumber)                   %]</td>
36
           <td class='numeric'>[% LxERP.format_amount(stock.qty, dec)       %]</td>
37
           <td                >[% HTML.escape(stock.unit)                   %]</td>
38
          </tr>
39
          [% IF stock.wh_lead != stock.warehouse_description %]
40
          <tr class='listheading'>
41
           <th class="listheading"                >[% HTML.escape(stock.warehouse_description)           %]</th>
42
           <td></td>
43
           <td></td>
44
           <td class='numeric bold'>[% LxERP.format_amount(stock.wh_run_qty, dec)         %]</td>
45
           <td></td>
46
          </tr>
47
          [% END %]
48
          [% IF loop.last %]
49
          <tr class='listheading'>
50
           <th class="listheading">[% 'Total' | $T8 %]</th>
51
           <td></td>
52
           <td></td>
53
           <td class='numeric bold'>[% LxERP.format_amount(stock.run_qty, dec)         %]</td>
54
           <td></td>
55
          </tr>
56
          [% END %]
57
         [% END %]
58
        [% ELSE %]
59
        <td>
60
          <p>[% 'No transactions yet.' | $T8 %]</p>
61
        [% END %]
62
        </td>
63
      </tr>
64
      <tr>
65
        <td><b>[%  LxERP.t8('Sum Amount') %]</b></td><td>[% LxERP.format_amount(sum, 2) %] [% part.unit %]</td>
66
        <td rowspan="5">
67
          [% file = part.default_partimage %]
68
          [%- IF file && INSTANCE_CONF.get_parts_show_image %]
69
          <img src="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]" alt="[% file.title %]" style="[% INSTANCE_CONF.get_parts_image_css %]">
70
          [% END %]
71
        </td>
72
        <td rowspan="5">
73
  [%- FOREACH file = part.get_files %]
74
      <a href="controller.pl?action=File/download&id=[% file.id %][%- IF file.version %]&version=[%- file.version %][%- END %]">
75
        <span id="[% "filename_" _ file.id %][%- IF file.version %]_[% file.version %][%- END %]">[% file.file_name %]</span></a><br><br>
76
  [%- END %]
77
        </td>
78
      </tr>
79
      <tr>
80
        <td><b>[%  LxERP.t8('Not delivered amount') %]</b></td><td colspan="3">[% LxERP.format_amount(not_delivered, 2) %] [% part.unit %]</td></tr>
81
      </tr>
82
      <tr>
83
        <td><b>[%  LxERP.t8('Ordered, but not delivered (purchase)') %]</b></td><td colspan="3">[% LxERP.format_amount(ordered, 2) %] [% part.unit %]</td></tr>
84
      </tr>
85
      <tr>
86
        <td><b>[%  LxERP.t8('Reserved amount') %]</b></td><td colspan="3">[% LxERP.format_amount(part.stockqty - part.onhandqty, 2) %] [% part.unit %]</td></tr>
87
      </tr>
88
      <tr>
89
        <td><b>[%  LxERP.t8('Available amount') %]</b></td><td colspan="3">[% LxERP.format_amount(part.onhandqty, 2) %] [% part.unit %]</td></tr>
90
      </tr>
91
      <tr>
92
        <td><b>[%  LxERP.t8('Consume average') %]</b></td><td colspan="3">[% LxERP.format_amount(average, 2) %] [% part.unit %] [% LxERP.t8('per month') %]</td></tr>
93
        <tr><td colspan="4" nowrap>([%  LxERP.t8('in the time between') %] [% fromdate.to_kivitendo %] - [% todate.to_kivitendo %])</td>
94
      </tr>
95
      <tr>
96
        <td>[%- L.button_tag("return \$('#detail_menu').dialog('close');", LxERP.t8('Close Details'), class => "submit") %]</td>
97
      </tr>
98
  </tbody></table>
99
</div>
100
<div id="print_options" >
101
  <form id="print_options_form">
102
    [% print_options %]
103
    <br>
104
    [% L.button_tag('kivi.Part.print_from_showdetail(' _ part.id _ ')', LxERP.t8('Print')) %]
105
  </form>
106
</div>
107

  

Auch abrufbar als: Unified diff