Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 34035b33

Von Martin Helmling martin.helmling@octosoft.eu vor etwa 8 Jahren hinzugefügt

  • ID 34035b33f21af21316df798b19f2a758aa86b3a8
  • Vorgänger 5e34b4af
  • Nachfolger d9ab23fa

Verbrauchsbericht: Lager->Berichte->Lagerentnahme

Ein Bericht über jährliche/quartalsweise/monatliche Lagerentnahme

Anforderungen waren:

1. Zahlen im Bericht einheitlich Formatieren (mit Tausender-Trennpunkt)

2. Spaltenüberschrift:
- "Lagerverbrauch" (Letzte zwei Spalten) > "Entnommen (ohne Korrekturen)"
"Verbrauch monatlich" (vorletzte Spalte) > "Im Zeitraum"
"Ø Verbr." (letzte Spalte -> "Ø mtl."

3. In der Suchmaske unter "Vorgewählte Zeiträume" sollte das aktuelle Jahr vorgegeben sein.

4. Filter "Freier Zeitraum" funktioniert nicht: "Es wurden keine Daten gefunden."

Bei der Berechnung des "Ø mtl." wird Folgendes beachtet:
Falls ein Zeitraum angegeben ist mit einem Enddatum in der Zukunft (z.B. auch bei "Jährlich" oder "Quartal")
muss der Bezugszeitraum mit dem aktuellen Datum (heute) begrenzt werden, ansonsten wird der Durchschnitt falsch berechnet!

Bei Zeitraum kleiner einem Monat, wird Durchschnitt des Entnommenen über einen Monat berechnet

Bei PDF/CSV Export müssen alle Werte berechnet werden
Wegen PDF-Erzeugung ausserhalb Papier X-Rand default reduziert auf 0,8 cm

Unterschiede anzeigen:

SL/Controller/Inventory.pm
2 2

  
3 3
use strict;
4 4
use warnings;
5
use POSIX qw(strftime);
5 6

  
6 7
use parent qw(SL::Controller::Base);
7 8

  
......
10 11
use SL::DB::Warehouse;
11 12
use SL::DB::Unit;
12 13
use SL::WH;
14
use SL::ReportGenerator;
13 15
use SL::Locale::String qw(t8);
14 16
use SL::Presenter;
15 17
use SL::DBUtils;
16 18
use SL::Helper::Flash;
19
use SL::Controller::Helper::ReportGenerator;
17 20

  
18 21
use English qw(-no_match_vars);
19 22

  
......
30 33
__PACKAGE__->run_before('load_bin_from_form',    only => [ qw(stock_in stock) ]);
31 34
__PACKAGE__->run_before('set_target_from_part',  only => [ qw(part_changed) ]);
32 35
__PACKAGE__->run_before('mini_stock',            only => [ qw(stock_in mini_stock) ]);
33
__PACKAGE__->run_before('sanitize_target',       only => [ qw(stock_in warehouse_changed part_changed) ]);
36
__PACKAGE__->run_before('sanitize_target',       only => [ qw(stock_usage stock_in warehouse_changed part_changed) ]);
34 37
__PACKAGE__->run_before('set_layout');
35 38

  
36 39
sub action_stock_in {
......
44 47
  $self->render('inventory/warehouse_selection_stock', title => $::form->{title}, TRANSFER_TYPES => $transfer_types );
45 48
}
46 49

  
50
sub action_stock_usage {
51
  my ($self) = @_;
52

  
53
  $::form->{title}   = t8('UsageE');
54

  
55
  $::form->get_lists('warehouses' => { 'key'    => 'WAREHOUSES',
56
                                       'bins'   => 'BINS', });
57
  $::request->layout->use_javascript("${_}.js") for qw(kivi.PartsWarehouse);
58

  
59
  $self->render('inventory/warehouse_usage',
60
                title => $::form->{title},
61
                year => DateTime->today->year,
62
  #              PARTSCLASSIFICATIONS => SL::DB:Manager::PartsClassification->get_all_classifications_by_name() ,
63
                WAREHOUSES => $::form->{WAREHOUSES},
64
                WAREHOUSE_FILTER => 1,
65
                warehouse_id => 0,
66
                bin_id => 0
67
      );
68

  
69
}
70

  
71
sub getnumcolumns {
72
  my ($self) = @_;
73
  return qw(stock incorrection found insum back outcorrection disposed 
74
                     missing shipped used outsum consumed averconsumed);
75
}
76

  
77
sub action_usage {
78
  my ($self) = @_;
79

  
80
  $main::lxdebug->enter_sub();
81

  
82
  my $form     = $main::form;
83
  my %myconfig = %main::myconfig;
84
  my $locale   = $main::locale;
85

  
86
  $form->{title}   = t8('UsageE');
87
  $form->{report_generator_output_format} = 'HTML' if !$form->{report_generator_output_format};
88

  
89
  my $report = SL::ReportGenerator->new(\%myconfig, $form);
90

  
91
  my @columns = qw(partnumber partdescription);
92

  
93
  push @columns , qw(ptype unit) if $form->{report_generator_output_format} eq 'HTML';
94

  
95
  my @numcolumns = qw(stock incorrection found insum back outcorrection disposed 
96
                     missing shipped used outsum consumed averconsumed);
97

  
98
  push @columns , $self->getnumcolumns();
99

  
100
  my @hidden_variables = qw(reporttype year duetyp fromdate todate 
101
                            warehouse_id bin_id partnumber description bestbefore chargenumber partstypes_id);
102
  my %column_defs = (
103
    'partnumber'      => { 'text' => $locale->text('Part Number'), },
104
 #   'partclass'       => { 'text' => $locale->text('Part Classification'), },
105
    'partdescription' => { 'text' => $locale->text('Part_br_Description'), },
106
    'unit'            => { 'text' => $locale->text('Unit'), },
107
    'stock'           => { 'text' => $locale->text('stock_br'), },
108
    'incorrection'    => { 'text' => $locale->text('correction_br'), },
109
    'found'           => { 'text' => $locale->text('found_br'), },
110
    'insum'           => { 'text' => $locale->text('sum'), },
111
    'back'            => { 'text' => $locale->text('back_br'), },
112
    'outcorrection'   => { 'text' => $locale->text('correction_br'), },
113
    'disposed'        => { 'text' => $locale->text('disposed_br'), },
114
    'missing'         => { 'text' => $locale->text('missing_br'), },
115
    'shipped'         => { 'text' => $locale->text('shipped_br'), },
116
    'used'            => { 'text' => $locale->text('used_br'), },
117
    'outsum'          => { 'text' => $locale->text('sum'), },
118
    'consumed'        => { 'text' => $locale->text('consumed'), },
119
    'averconsumed'    => { 'text' => $locale->text('averconsumed_br'), },
120
  );
121

  
122

  
123
  map { $column_defs{$_}->{visible} = 1 } @columns;
124
  #map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
125
  map { $column_defs{$_}->{align} = 'right' } @numcolumns;
126

  
127
  my @custom_headers = ();
128
  # Zeile 1:
129
  push @custom_headers, [
130
      { 'text' => $locale->text('Part'),   
131
        'colspan' => ($form->{report_generator_output_format} eq 'HTML'?4:2), 'align' => 'center'},
132
      { 'text' => $locale->text('Into bin'), 'colspan' => 4, 'align' => 'center'},
133
      { 'text' => $locale->text('From bin'), 'colspan' => 7, 'align' => 'center'},
134
      { 'text' => $locale->text('UsageWithout'),    'colspan' => 2, 'align' => 'center'},
135
  ];
136

  
137
  # Zeile 2:
138
  my @line_2 = ();
139
  map { push @line_2 , $column_defs{$_} } @columns;
140
  push @custom_headers, [ @line_2 ];
141

  
142
  $report->set_custom_headers(@custom_headers);
143
  $report->set_columns( %column_defs );
144
  $report->set_column_order(@columns);
145

  
146
  $report->set_export_options('usage', @hidden_variables );
147

  
148
  $report->set_sort_indicator($form->{sort}, $form->{order});
149
  $report->set_options('output_format'        => 'HTML',
150
                       'controller_class'     => 'Inventory',
151
                       'title'                => $form->{title},
152
#                      'html_template'        => 'inventory/usage_report',
153
                       'attachment_basename'  => strftime($locale->text('warehouse_usage_list') . '_%Y%m%d', localtime time));
154
  $report->set_options_from_form;
155

  
156
  my %searchparams ;
157
# form vars
158
#   reporttype = custom
159
#   year = 2014
160
#   duetyp = 7
161

  
162
  my $start       = DateTime->now_local;
163
  my $end         = DateTime->now_local;
164
  my $actualepoch = $end->epoch();
165
  my $days = 365;
166
  my $mdays=30;
167
  $searchparams{reporttype} = $form->{reporttype};
168
  if ($form->{reporttype} eq "custom") {
169
    my $smon = 1;
170
    my $emon = 12;
171
    my $sday = 1;
172
    my $eday = 31;
173
    #forgotten the year --> thisyear
174
    if ($form->{year} !~ m/^\d\d\d\d$/) {
175
      $locale->date(\%myconfig, $form->current_date(\%myconfig), 0) =~
176
        /(\d\d\d\d)/;
177
      $form->{year} = $1;
178
    }
179
    my $leapday = ($form->{year} % 4 == 0) ? 1:0;
180
    #yearly report
181
    if ($form->{duetyp} eq "13") {
182
        $days += $leapday;
183
    }
184

  
185
    #Quater reports
186
    if ($form->{duetyp} eq "A") {
187
      $emon = 3;
188
      $days = 90 + $leapday;
189
    }
190
    if ($form->{duetyp} eq "B") {
191
      $smon = 4;
192
      $emon = 6;
193
      $eday = 30;
194
      $days = 91;
195
    }
196
    if ($form->{duetyp} eq "C") {
197
      $smon = 7;
198
      $emon = 9;
199
      $eday = 30;
200
      $days = 92;
201
    }
202
    if ($form->{duetyp} eq "D") {
203
      $smon = 10;
204
      $days = 92;
205
    }
206
    #Monthly reports
207
    if ($form->{duetyp} eq "1" || $form->{duetyp} eq "3" || $form->{duetyp} eq "5" ||
208
        $form->{duetyp} eq "7" || $form->{duetyp} eq "8" || $form->{duetyp} eq "10" ||
209
        $form->{duetyp} eq "12") {
210
        $smon = $emon = $form->{duetyp}*1;
211
        $mdays=$days = 31;
212
    }
213
    if ($form->{duetyp} eq "2" || $form->{duetyp} eq "4" || $form->{duetyp} eq "6" ||
214
        $form->{duetyp} eq "9" || $form->{duetyp} eq "11" ) {
215
        $smon = $emon = $form->{duetyp}*1;
216
        $eday = 30;
217
        if ($form->{duetyp} eq "2" ) {
218
            #this works from 1901 to 2099, 1900 and 2100 fail.
219
            $eday = ($form->{year} % 4 == 0) ? 29 : 28;
220
        }
221
        $mdays=$days = $eday;
222
    }
223
    $searchparams{year} = $form->{year};
224
    $searchparams{duetyp} = $form->{duetyp};
225
    $start->set_month($smon);
226
    $start->set_day($sday);
227
    $start->set_year($form->{year}*1);
228
    $end->set_month($emon);
229
    $end->set_day($eday);
230
    $end->set_year($form->{year}*1);
231
  }  else {
232
    $searchparams{fromdate} = $form->{fromdate};
233
    $searchparams{todate} = $form->{todate};
234
#   reporttype = free
235
#   fromdate = 01.01.2014
236
#   todate = 31.05.2014
237
    my ($yy, $mm, $dd) = $locale->parse_date(\%myconfig,$form->{fromdate});
238
    $start->set_year($yy);
239
    $start->set_month($mm);
240
    $start->set_day($dd);
241
    ($yy, $mm, $dd) = $locale->parse_date(\%myconfig,$form->{todate});
242
    $end->set_year($yy);
243
    $end->set_month($mm);
244
    $end->set_day($dd);
245
    my $dur = $start->delta_md($end);
246
    $days = $dur->delta_months()*30 + $dur->delta_days() ;
247
  }
248
  $start->set_second(0);
249
  $start->set_minute(0);
250
  $start->set_hour(0);
251
  $end->set_second(59);
252
  $end->set_minute(59);
253
  $end->set_hour(23);
254
  if ( $end->epoch() > $actualepoch ) { 
255
      $end = DateTime->now_local;
256
      my $dur = $start->delta_md($end);
257
      $days = $dur->delta_months()*30 + $dur->delta_days() ;
258
  }
259
  if ( $start->epoch() > $end->epoch() ) { $start = $end;$days = 1;}
260
  $days = $mdays if $days < $mdays;
261
  #$main::lxdebug->message(LXDebug->DEBUG2(), "start=".$start->epoch());
262
  #$main::lxdebug->message(LXDebug->DEBUG2(), "  end=".$end->epoch());
263
  #$main::lxdebug->message(LXDebug->DEBUG2(), " days=".$days);
264
  my @andfilter = (shippingdate => { ge => $start }, shippingdate => { le => $end } );
265
  if ( $form->{warehouse_id} ) {
266
      push @andfilter , ( warehouse_id => $form->{warehouse_id});
267
      $searchparams{warehouse_id} = $form->{warehouse_id};
268
      if ( $form->{bin_id} ) {
269
          push @andfilter , ( bin_id => $form->{bin_id});
270
          $searchparams{bin_id} = $form->{bin_id};
271
      }
272
  }
273
  # alias class t2 entspricht parts
274
  if ( $form->{partnumber} ) {
275
      push @andfilter , ( 't2.partnumber' => { ilike => '%'. $form->{partnumber} .'%' });
276
      $searchparams{partnumber} = $form->{partnumber};
277
  }
278
  if ( $form->{description} ) {
279
      push @andfilter , ( 't2.description' => { ilike => '%'. $form->{description} .'%'  });
280
      $searchparams{description} = $form->{description};
281
  }
282
  if ( $form->{bestbefore} ) {
283
    push @andfilter , ( bestbefore => { eq => $form->{bestbefore} });
284
      $searchparams{bestbefore} = $form->{bestbefore};
285
  }
286
  if ( $form->{chargenumber} ) {
287
      push @andfilter , ( chargenumber => { ilike => '%'.$form->{chargenumber}.'%' });
288
      $searchparams{chargenumber} = $form->{chargenumber};
289
  }
290
  if ( $form->{partstypes_id} ) {
291
      push @andfilter , ( 't2.partstypes_id' => $form->{partstypes_id} );
292
      $searchparams{partstypes_id} = $form->{partstypes_id};
293
  }
294

  
295
  my @filter = (and => [ @andfilter ] );
296

  
297
  my $objs = SL::DB::Manager::Inventory->get_all(with_objects => ['parts'], where => [ @filter ] , sort_by => 'parts.partnumber ASC');
298
  #my $objs = SL::DB::Inventory->_get_manager_class->get_all(...);
299

  
300
  # manual paginating, yuck
301
  my $page = $::form->{page} || 1;
302
  my $pages = {};
303
  $pages->{per_page}        = $::form->{per_page} || 20;
304
  my $first_nr = ($page - 1) * $pages->{per_page};
305
  my $last_nr  = $first_nr + $pages->{per_page};
306

  
307
  my $last_partid = 0;
308
  my $last_row = { };
309
  my $row_ind = 0;
310
  my $allrows = 0;
311
  $allrows = 1 if $form->{report_generator_output_format} ne 'HTML' ;
312
  #$main::lxdebug->message(LXDebug->DEBUG2(), "first_nr=".$first_nr." last_nr=".$last_nr);
313
  foreach my $entry (@{ $objs } ) {
314
      if ( $entry->parts_id != $last_partid ) {
315
          if ( $last_partid > 0 ) {
316
              if ( $allrows || ($row_ind >= $first_nr && $row_ind < $last_nr )) {
317
                  $self->make_row_result($last_row,$days,$last_partid);
318
                  $report->add_data($last_row);
319
              }
320
              $row_ind++ ;
321
          } 
322
          $last_partid = $entry->parts_id;
323
          $last_row = { };
324
          $last_row->{partnumber}->{data} = $entry->part->partnumber;
325
          $last_row->{partdescription}->{data} = $entry->part->description;
326
          $last_row->{unit}->{data} = $entry->part->unit;
327
          $last_row->{stock}->{data} = 0;
328
          $last_row->{incorrection}->{data} = 0;
329
          $last_row->{found}->{data} = 0;
330
          $last_row->{back}->{data} = 0;
331
          $last_row->{outcorrection}->{data} = 0;
332
          $last_row->{disposed}->{data} = 0;
333
          $last_row->{missing}->{data} = 0;
334
          $last_row->{shipped}->{data} = 0;
335
          $last_row->{used}->{data} = 0;
336
          $last_row->{insum}->{data} = 0;
337
          $last_row->{outsum}->{data} = 0;
338
          $last_row->{consumed}->{data} = 0;
339
          $last_row->{averconsumed}->{data} = 0;
340
      }
341
      if ( !$allrows && $row_ind >= $last_nr ) {
342
          next;
343
      }
344
      my $prefix='';
345
      if ( $entry->trans_type->description eq 'correction' ) {
346
          $prefix = $entry->trans_type->direction;
347
      }
348
      $last_row->{$prefix.$entry->trans_type->description}->{data} += 
349
          ( $entry->trans_type->direction eq 'out' ? -$entry->qty : $entry->qty );
350
  }
351
  if ( $last_partid > 0 && ( $allrows || ($row_ind >= $first_nr && $row_ind < $last_nr ))) {
352
      $self->make_row_result($last_row,$days,$last_partid);
353
      $report->add_data($last_row);
354
      $row_ind++ ;
355
  } 
356
  my $num_rows = @{ $report->{data} } ;
357
  #$main::lxdebug->message(LXDebug->DEBUG2(), "count=".$row_ind." rows=".$num_rows);
358

  
359
  if ( ! $allrows ) {
360
      $pages->{max}  = SL::DB::Helper::Paginated::ceil($row_ind, $pages->{per_page}) || 1;
361
      $pages->{page} = $page < 1 ? 1: $page > $pages->{max} ? $pages->{max}: $page;
362
      $pages->{common} = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{page}, $pages->{max}) } ];
363
      $self->{pages} = $pages;
364
      $searchparams{action} = "usage";
365
      $self->{base_url} = $self->url_for(\%searchparams );
366
      #$main::lxdebug->message(LXDebug->DEBUG2(), "page=".$pages->{page}." url=".$self->{base_url});
367

  
368
      $report->set_options('raw_bottom_info_text' => $self->render('inventory/report_bottom', { output => 0 }) );
369
  }
370
  $report->generate_with_headers();
371

  
372
  $main::lxdebug->leave_sub();
373

  
374
}
375

  
376
sub make_row_result {
377
  my ($self,$row,$days,$partid) = @_;
378
  my $form     = $main::form;
379
  my $myconfig = \%main::myconfig;
380

  
381
  $row->{insum}->{data}  = $row->{stock}->{data} + $row->{incorrection}->{data} + $row->{found}->{data};
382
  $row->{outsum}->{data} = $row->{back}->{data} + $row->{outcorrection}->{data} + $row->{disposed}->{data} +
383
       $row->{missing}->{data} + $row->{shipped}->{data} + $row->{used}->{data};
384
  $row->{consumed}->{data} = $row->{outsum}->{data} - 
385
       $row->{outcorrection}->{data} - $row->{incorrection}->{data};
386
  $row->{averconsumed}->{data} = $row->{consumed}->{data}*30/$days ;
387
  map { $row->{$_}->{data} = $form->format_amount($myconfig,$row->{$_}->{data},2); } $self->getnumcolumns();
388
#  $row->{partclass}->{data} = '';
389
  $row->{partnumber}->{link} = 'ic.pl?action=edit&id='.$partid;
390
#  $row->{partdescription}->{link} = 'ic.pl?action=edit&id='.$partid;
391
}
392

  
47 393
sub action_stock {
48 394
  my ($self) = @_;
49 395

  
......
153 499
  SL::DB::Manager::Warehouse->get_all(query => [ or => [ invalid => 0, invalid => undef ]]);
154 500
}
155 501

  
502
#sub init_bins {
503
#  SL::DB::Manager::Bin->get_all();
504
#}
505

  
156 506
sub init_units {
157 507
  SL::DB::Manager::Unit->get_all;
158 508
}
......
175 525

  
176 526
  $self->warehouse($self->warehouses->[0])       if !$self->warehouse || !$self->warehouse->id;
177 527
  $self->bin      ($self->warehouse->bins->[0])  if !$self->bin       || !$self->bin->id;
528
#  foreach my $warehouse ( $self->warehouses ) {
529
#      $warehouse->{BINS} = [];
530
#      foreach my $bin ( $self->bins ) {
531
#         if ( $bin->warehouse_id == $warehouse->id ) {
532
#             push @{ $warehouse->{BINS} }, $bin;
533
#         }
534
#      }
535
#  }
178 536
}
179 537

  
180 538
sub load_part_from_form {
bin/mozilla/wh.pl
674 674
  $form->{title}   = $locale->text("WHJournal");
675 675
  $form->{sort}  ||= 'date';
676 676

  
677
  $form->{report_generator_output_format} = 'HTML' if !$form->{report_generator_output_format};
678

  
677 679
  my %filter;
678 680
  my @columns = qw(trans_id date warehouse_from bin_from warehouse_to bin_to partnumber partdescription chargenumber bestbefore trans_type comment qty employee oe_id projectnumber);
679 681

  
......
709 711
    'chargenumber'    => { 'text' => $locale->text('Charge Number'), },
710 712
    'bestbefore'      => { 'text' => $locale->text('Best Before'), },
711 713
    'qty'             => { 'text' => $locale->text('Qty'), },
714
    'unit'            => { 'text' => $locale->text('Part Unit'), },
715
    'partunit'        => { 'text' => $locale->text('Unit'), },
712 716
    'employee'        => { 'text' => $locale->text('Employee'), },
713 717
    'projectnumber'   => { 'text' => $locale->text('Project Number'), },
714 718
    'oe_id'           => { 'text' => $locale->text('Document'), },
715 719
  );
716 720

  
717 721
  my $href = build_std_url('action=generate_journal', grep { $form->{$_} } @hidden_variables);
718
  map { $column_defs{$_}->{link} = $href . "&sort=${_}&order=" . Q($_ eq $form->{sort} ? 1 - $form->{order} : $form->{order}) } @columns;
722
  my $page = $::form->{page} || 1;
723
  map { $column_defs{$_}->{link} = $href ."&page=".$page. "&sort=${_}&order=" . Q($_ eq $form->{sort} ? 1 - $form->{order} : $form->{order}) } @columns;
719 724

  
720 725
  my %column_alignment = map { $_ => 'right' } qw(qty);
721 726

  
......
747 752
                    'purchase_invoice'        => { script => 'ir', title => $locale->text('Purchase Invoice') },
748 753
                  );
749 754

  
755
   my $allrows = 0;
756
   $allrows = 1 if $form->{report_generator_output_format} ne 'HTML' ;
757
 
758
   # manual paginating
759
   my $pages = {};
760
   $pages->{per_page}        = $::form->{per_page} || 15;
761
   my $first_nr = ($page - 1) * $pages->{per_page};
762
   my $last_nr  = $first_nr + $pages->{per_page};
763
   my $idx       = 0;
764
 
750 765
  foreach my $entry (@contents) {
751 766
    $entry->{qty}        = $form->format_amount_units('amount'     => $entry->{qty},
752 767
                                                      'part_unit'  => $entry->{partunit},
......
774 789
      }
775 790
    }
776 791

  
777
    $report->add_data($row);
792
    if ( $allrows || ($idx >= $first_nr && $idx < $last_nr )) {
793
       $report->add_data($row);
794
    }
795
    $idx++;
778 796
  }
779 797

  
798
  if ( ! $allrows ) {
799
      $pages->{max}  = SL::DB::Helper::Paginated::ceil($idx, $pages->{per_page}) || 1;
800
      $pages->{page} = $page < 1 ? 1: $page > $pages->{max} ? $pages->{max}: $page;
801
      $pages->{common} = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{page}, $pages->{max}) } ];
802

  
803
      $report->set_options('raw_bottom_info_text' => $form->parse_html_template('common/paginate',
804
                                                            { 'pages' => $pages , 'base_url' => $href}) );
805
  }
780 806
  $report->generate_with_headers();
781 807

  
782 808
  $main::lxdebug->leave_sub();
......
822 848

  
823 849
  $form->{title}   = $locale->text("Report about warehouse contents");
824 850
  $form->{sort}  ||= 'partnumber';
851
  $form->{sort}  ||= 'partunit';
825 852
  my $sort_col     = $form->{sort};
826 853

  
827 854
  my %filter;
828 855
  my @columns = qw(warehousedescription bindescription partnumber partdescription chargenumber bestbefore qty stock_value);
829 856

  
830 857
  # filter stuff
831
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id partnumber description chargenumber bestbefore date include_invalid_warehouses);
858
  map { $filter{$_} = $form->{$_} if ($form->{$_}) } qw(warehouse_id bin_id partstypes_id partnumber description chargenumber bestbefore date include_invalid_warehouses);
832 859

  
833 860
  # show filter stuff also in report
834 861
  my @options;
......
862 889

  
863 890
  $form->{subtotal} = '' if (!first { $_ eq $sort_col } qw(partnumber partdescription));
864 891

  
892
  $form->{report_generator_output_format} = 'HTML' if !$form->{report_generator_output_format};
865 893
  my $report = SL::ReportGenerator->new(\%myconfig, $form);
866 894

  
867 895
  my @hidden_variables = map { "l_${_}" } @columns;
868
  push @hidden_variables, qw(warehouse_id bin_id partnumber description chargenumber bestbefore qty_op qty qty_unit l_warehousedescription l_bindescription);
896
  push @hidden_variables, qw(warehouse_id bin_id partnumber partstypes_id description chargenumber bestbefore qty_op qty qty_unit partunit l_warehousedescription l_bindescription);
869 897
  push @hidden_variables, qw(include_empty_bins subtotal include_invalid_warehouses date);
870 898

  
871 899
  my %column_defs = (
......
876 904
    'chargenumber'         => { 'text' => $locale->text('Charge Number'), },
877 905
    'bestbefore'           => { 'text' => $locale->text('Best Before'), },
878 906
    'qty'                  => { 'text' => $locale->text('Qty'), },
907
    'partunit'             => { 'text' => $locale->text('Unit'), },
879 908
    'stock_value'          => { 'text' => $locale->text('Stock value'), },
880 909
  );
881 910

  
882 911
  my $href = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
883
  map { $column_defs{$_}->{link} = $href . "&sort=${_}&order=" . Q($_ eq $sort_col ? 1 - $form->{order} : $form->{order}) } @columns;
912
  my $page = $::form->{page} || 1;
913
  map { $column_defs{$_}->{link} = $href . "&page=".$page."&sort=${_}&order=" . Q($_ eq $sort_col ? 1 - $form->{order} : $form->{order}) } @columns;
884 914

  
885 915
  my %column_alignment = map { $_ => 'right' } qw(qty stock_value);
886 916

  
......
910 940

  
911 941
  my $total_stock_value = 0;
912 942

  
943
  my $allrows = 0;
944
  $allrows = 1 if $form->{report_generator_output_format} ne 'HTML' ;
945

  
946
  # manual paginating
947
  my $pages = {};
948
  $pages->{per_page}        = $::form->{per_page} || 20;
949
  my $first_nr = ($page - 1) * $pages->{per_page};
950
  my $last_nr  = $first_nr + $pages->{per_page};
951

  
913 952
  foreach my $entry (@contents) {
914 953
    map { $subtotals{$_} += $entry->{$_} } @subtotals_columns;
915 954
    $total_stock_value   += $entry->{stock_value} * 1;
916

  
917
    $entry->{qty}         = $form->format_amount_units('amount'     => $entry->{qty},
918
                                                       'part_unit'  => $entry->{partunit},
919
                                                       'conv_units' => 'convertible');
955
    $entry->{qty}         = $form->format_amount(\%myconfig, $entry->{qty});
956
#    $entry->{qty}         = $form->format_amount_units('amount'     => $entry->{qty},
957
#                                                       'part_unit'  => $entry->{partunit},
958
#                                                       'conv_units' => 'convertible');
920 959
    $entry->{stock_value} = $form->format_amount(\%myconfig, $entry->{stock_value} * 1, 2);
921 960

  
922 961
    my $row_set = [ { map { $_ => { 'data' => $entry->{$_}, 'align' => $column_alignment{$_} } } @columns } ];
......
926 965
            || ($entry->{$sort_col} ne $contents[$idx + 1]->{$sort_col}))) {
927 966

  
928 967
      my $row = { map { $_ => { 'data' => '', 'class' => 'listsubtotal', 'align' => $column_alignment{$_}, } } @columns };
929
      $row->{qty}->{data}         = $form->format_amount_units('amount'     => $subtotals{qty} * 1,
930
                                                               'part_unit'  => $entry->{partunit},
931
                                                               'conv_units' => 'convertible');
968
      $row->{qty}->{data}         = $form->format_amount(\%myconfig, $subtotals{qty});
969
#      $row->{qty}->{data}         = $form->format_amount_units('amount'     => $subtotals{qty} * 1,
970
#                                                               'part_unit'  => $entry->{partunit},
971
#                                                               'conv_units' => 'convertible');
932 972
      $row->{stock_value}->{data} = $form->format_amount(\%myconfig, $subtotals{stock_value} * 1, 2);
933 973

  
934 974
      %subtotals                  = map { $_ => 0 } @subtotals_columns;
......
936 976
      push @{ $row_set }, $row;
937 977
    }
938 978

  
939
    $report->add_data($row_set);
940

  
979
    if ( $allrows || ($idx >= $first_nr && $idx < $last_nr )) {
980
	$report->add_data($row_set);
981
    }
941 982
    $idx++;
942 983
  }
943 984

  
doc/changelog
6 6

  
7 7
kleinere neue Features und Detailverbesserungen:
8 8

  
9
  - Weiterer Bericht in der Rubrik Lager: Lagerentnahme
10
    Gibt eine Statistik über Lagerbewegungen, pro Monat/Quartal/Jahr.
11

  
9 12
  - Für UStVA Voranmeldung über Elster gibt es die Anbindung über Geierlein (Installation/Config siehe Commit)
10 13
  
11 14
  - CSV-Import von Artikel hat nun für existierende Artikel folgende Optionen:
locale/de/all
1330 1330
  'Fristsetzung'                => 'Fristsetzung',
1331 1331
  'From'                        => 'Von',
1332 1332
  'From Date'                   => 'Von',
1333
  'From bin'                    => 'Ausgelagert',
1333 1334
  'From this version on a new feature is available.' => 'Ab dieser Version ist ein neues Feature verfügbar.',
1334 1335
  'From this version on it is necessary to name a default value.' => 'Ab dieser Version benötigt kivitendo eine Standardwährung.',
1335 1336
  'From this version on the partnumber of services, articles and assemblies have to be unique.' => 'Ab dieser Version müssen Artikelnummern eindeutig vergeben werden.',
......
1494 1495
  'Internal Phone List'         => 'Interne Telefonliste',
1495 1496
  'Internal comment'            => 'Interne Bemerkungen',
1496 1497
  'Internet'                    => 'Internet',
1498
  'Into bin'                    => 'Eingelagert',
1497 1499
  'Intra-Community supply'      => 'Gelangensbestätigung',
1498 1500
  'Introduction of clients'     => 'Einführung von Mandanten',
1499 1501
  'Inv. Duedate'                => 'Rg. Fälligkeit',
......
1985 1987
  'Part'                        => 'Ware',
1986 1988
  'Part "#1" has chargenumber or best before date set. So it cannot be transfered automatically.' => 'Bei Artikel "#1" ist eine Chargenummer oder ein Mindesthaltbarkeitsdatum vergeben. Deshalb kann dieser Artikel nicht automatisch ausgelagert werden.',
1987 1989
  'Part (database ID)'          => 'Artikel (Datenbank-ID)',
1990
  'Part Classification'         => '',
1988 1991
  'Part Description'            => 'Artikelbeschreibung',
1989 1992
  'Part Description missing!'   => 'Artikelbezeichnung fehlt!',
1990 1993
  'Part Notes'                  => 'Bemerkungen',
1991 1994
  'Part Number'                 => 'Artikelnummer',
1992 1995
  'Part Number missing!'        => 'Artikelnummer fehlt!',
1996
  'Part Unit'                   => '',
1993 1997
  'Part picker'                 => 'Artikelauswahl',
1998
  'Part_br_Description'         => 'Beschreibung',
1994 1999
  'Partial invoices'            => 'Teilrechnungen',
1995 2000
  'Partnumber'                  => 'Artikelnummer',
1996 2001
  'Partnumber must not be set to empty!' => 'Die Artikelnummer darf nicht auf leer ge&auml;ndert werden.',
......
3281 3286
  'Updating the client fields in the database "#1" on host "#2:#3" failed.' => 'Die Aktualisierung der Mandantenfelder in der Datenbank "#1" auf Host "#2:#3" schlug fehl.',
3282 3287
  'Uploaded at'                 => 'Hochgeladen um',
3283 3288
  'Uploaded on #1, size #2 kB'  => 'Am #1 hochgeladen, Größe #2 kB',
3289
  'UsageE'                      => 'Lagerentnahme',
3290
  'UsageWithout'                => 'Entnommen (ohne Korr.)',
3284 3291
  'Use As New'                  => 'Als neu verwenden',
3285 3292
  'Use Balance Sheet'           => 'Bilanz verwenden',
3286 3293
  'Use Datevautomatik'          => 'Datev-Automatik verwenden',
......
3355 3362
  'View/edit all employees sales documents' => 'Bearbeiten/ansehen der Verkaufsdokumente aller Mitarbeiter',
3356 3363
  'Von Konto: '                 => 'von Konto: ',
3357 3364
  'WHJournal'                   => 'Lagerbuchungen',
3365
  'WHUsage'                     => 'Lagerentnahme',
3358 3366
  'Warehouse'                   => 'Lager',
3359 3367
  'Warehouse (database ID)'     => 'Lager (Datenbank-ID)',
3360 3368
  'Warehouse (name)'            => 'Lager (Name)',
......
3472 3480
  'assembly'                    => 'Erzeugnis',
3473 3481
  'assembly_list'               => 'erzeugnisliste',
3474 3482
  'averaged values, in invoice mode only useful when filtered by a part' => 'gemittelte Werte, im Rechnungsmodus nur sinnvoll wenn nach Artikel gefiltert wird',
3483
  'averconsumed_br'             => 'Ø mtl.',
3475 3484
  'back'                        => 'zurück',
3485
  'back_br'                     => 'Zurk.',
3476 3486
  'balance'                     => 'Betriebsvermögensvergleich/Bilanzierung',
3477 3487
  'bank_collection_payment_list_#1' => 'bankeinzugszahlungsliste_#1',
3478 3488
  'bank_transfer_payment_list_#1' => 'ueberweisungszahlungsliste_#1',
......
3495 3505
  'config/kivitendo.conf: Key "authentication/ldap" is missing.' => 'config/kivitendo.conf: Der Schlüssel "authentication/ldap" fehlt.',
3496 3506
  'config/kivitendo.conf: Missing parameters in "authentication/database". Required parameters are "host", "db" and "user".' => 'config/kivitendo.conf: Fehlende Parameter in "authentication/database". Ben&ouml;tigte Parameter sind "host", "db" und "user".',
3497 3507
  'config/kivitendo.conf: Missing parameters in "authentication/ldap". Required parameters are "host", "attribute" and "base_dn".' => 'config/kivitendo.conf: Fehlende Parameter in "authentication/ldap". Benötigt werden "host", "attribute" und "base_dn".',
3508
  'consumed'                    => 'Im Zeitraum',
3498 3509
  'contact_list'                => 'ansprechperson_liste',
3499 3510
  'continue'                    => 'weiter',
3500 3511
  'correction'                  => 'Korrektur',
3512
  'correction_br'               => 'Korr.',
3501 3513
  'cp_greeting to cp_gender migration' => 'Datenumwandlung von Titel nach Geschlecht (cp_greeting to cp_gender)',
3502 3514
  'customer'                    => 'Kunde',
3503 3515
  'customer_list'               => 'kundenliste',
......
3511 3523
  'difference_as_skonto'        => 'Differenz als Skonto',
3512 3524
  'direct debit'                => 'Lastschrifteinzug',
3513 3525
  'disposed'                    => 'Entsorgung',
3526
  'disposed_br'                 => 'Entsgt.',
3514 3527
  'do not include'              => 'Nicht aufnehmen',
3515 3528
  'done'                        => 'erledigt',
3516 3529
  'dunning_list'                => 'mahnungsliste',
......
3533 3546
  'for all'                     => 'für alle',
3534 3547
  'for date'                    => 'zum Stichtag',
3535 3548
  'found'                       => 'Gefunden',
3549
  'found_br'                    => 'Gef.',
3536 3550
  'from (time)'                 => 'von',
3537 3551
  'general_ledger_list'         => 'buchungsjournal',
3538 3552
  'generate cb/ob transactions for selected charts' => 'Buchungen erstellen',
......
3572 3586
  'male'                        => 'männlich',
3573 3587
  'mark as paid'                => 'als bezahlt markieren',
3574 3588
  'missing'                     => 'Fehlbestand',
3589
  'missing_br'                  => 'Fehl.',
3575 3590
  'month'                       => 'Monatliche Abgabe',
3576 3591
  'monthly'                     => 'monatlich',
3577 3592
  'never'                       => 'niemals',
......
3650 3665
  'service'                     => 'Dienstleistung',
3651 3666
  'service_list'                => 'dienstleistungsliste',
3652 3667
  'shipped'                     => 'verschickt',
3668
  'shipped_br'                  => 'Verschk.',
3653 3669
  'singular first char'         => 'S',
3654 3670
  'sort items'                  => 'Positionen sortieren',
3655 3671
  'stock'                       => 'Einlagerung',
3672
  'stock_br'                    => 'Eingel.',
3656 3673
  'submit'                      => 'abschicken',
3657 3674
  'succeeded'                   => 'erfolgreich',
3675
  'sum'                         => 'Summe',
3658 3676
  'tax_chartaccno'              => 'Automatikkonto',
3659 3677
  'tax_percent'                 => 'Prozentsatz',
3660 3678
  'tax_rate'                    => 'Prozent',
......
3682 3700
  'use program settings'        => 'benutze Programmeinstellungen',
3683 3701
  'use user config'             => 'Verwende Benutzereinstellung',
3684 3702
  'used'                        => 'Verbraucht',
3703
  'used_br'                     => 'Verbr.',
3685 3704
  'valid from'                  => 'Gültig ab',
3686 3705
  'vendor'                      => 'Lieferant',
3687 3706
  'vendor_invoice_list'         => 'kreditorenbuchungsliste',
......
3689 3708
  'waiting for job to be started' => 'warte darauf, dass der Job gestartet wird',
3690 3709
  'warehouse_journal_list'      => 'lagerbuchungsliste',
3691 3710
  'warehouse_report_list'       => 'lagerbestandsliste',
3711
  'warehouse_usage_list'        => 'Lagerentnahmeliste',
3692 3712
  'with amount'                 => 'mit Betrag',
3693 3713
  'with skonto acc. to pt'      => 'mit Skonto nach ZB',
3694 3714
  'with_skonto_pt'              => 'mit Skonto nach ZB',
menus/user/12-warehouse-usage.yaml
1
#
2
# opendynamic feature
3
#
4
---
5
#
6
# Warenverbrauchsbericht
7
#
8
- parent: warehouse_reports
9
  id: warehouse_reports_whusage
10
  name: WHUsage
11
  icon: warehouse_usage
12
  order: 300
13
  access: warehouse_contents | warehouse_management
14
  params:
15
    action: Inventory/stock_usage
templates/webpages/inventory/report_bottom.html
1
[%- PROCESS 'common/paginate.html' pages=SELF.pages, base_url = SELF.base_url %]
templates/webpages/inventory/warehouse_usage.html
1
[%- USE T8 %]
2
[%- USE L %]
3
[%- USE HTML %]
4
[%- USE LxERP %]
5
[%- WAREHOUSE_FILTER = 1 %]
6
[%- PROCESS 'common/select_warehouse_bin.html' %]
7

  
8
<h1>[% title | html %]</h1>
9

  
10
[%- INCLUDE 'common/flash.html' %]
11

  
12
<form name="Form" method="post" action="controller.pl">
13

  
14
 <table border="0">
15
    <tr>
16
     <th class="listheading" align="left" valign="top" colspan="5" nowrap>[% 'Period:' | $T8 %]</th>
17
    </tr>
18
  <tr>
19
    <th align=left><input name=reporttype class=radio type=radio value="custom" checked>[% 'Customized Report' | $T8 %]</th>
20
  </tr>
21
  <tr>
22
    <th colspan=1>[% 'Year' | $T8 %]</th>
23
    <td><input name=year size=11 title="[% 'YYYY' | $T8 %]" value="[% year %]" class="initial_focus"></td>
24
  </tr>
25
  <tr>
26
    <td align=right> <b>[% 'Yearly' | $T8 %]</b> </td>
27
    <th align=left>[% 'Quarterly' | $T8 %]</th>
28
    <th align=left colspan=3>[% 'Monthly' | $T8 %]</th>
29
  </tr>
30
  <tr>
31
    <td align=right>&nbsp; <input name=duetyp class=radio type=radio value="13" checked></td>
32
    <td><input name=duetyp class=radio type=radio value="A">&nbsp;1. [% 'Quarter' | $T8 %]</td>
33
    <td><input name=duetyp class=radio type=radio value="1">&nbsp;[% 'January' | $T8 %]</td>
34
    <td><input name=duetyp class=radio type=radio value="5">&nbsp;[% 'May' | $T8 %]</td>
35
    <td><input name=duetyp class=radio type=radio value="9">&nbsp;[% 'September' | $T8 %]</td>
36
  </tr>
37
  <tr>
38
    <td align= right>&nbsp;</td>
39
    <td><input name=duetyp class=radio type=radio value="B">&nbsp;2. [% 'Quarter' | $T8 %]</td>
40
    <td><input name=duetyp class=radio type=radio value="2">&nbsp;[% 'February' | $T8 %]</td>
41
    <td><input name=duetyp class=radio type=radio value="6">&nbsp;[% 'June' | $T8 %]</td>
42
    <td><input name=duetyp class=radio type=radio value="10">&nbsp;[% 'October' | $T8 %]</td>
43
  </tr>
44
  <tr>
45
    <td> &nbsp;</td>
46
    <td><input name=duetyp class=radio type=radio value="C">&nbsp;3. [% 'Quarter' | $T8 %]</td>
47
    <td><input name=duetyp class=radio type=radio value="3">&nbsp;[% 'March' | $T8 %]</td>
48
    <td><input name=duetyp class=radio type=radio value="7">&nbsp;[% 'July' | $T8 %]</td>
49
    <td><input name=duetyp class=radio type=radio value="11">&nbsp;[% 'November' | $T8 %]</td>
50
  </tr>
51
  <tr>
52
    <td> &nbsp;</td>
53
    <td><input name=duetyp class=radio type=radio value="D">&nbsp;4. [% 'Quarter' | $T8 %]</td>
54
    <td><input name=duetyp class=radio type=radio value="4">&nbsp;[% 'April' | $T8 %]</td>
55
    <td><input name=duetyp class=radio type=radio value="8">&nbsp;[% 'August' | $T8 %]</td>
56
    <td><input name=duetyp class=radio type=radio value="12">&nbsp;[% 'December' | $T8 %]</td>
57
  </tr>
58
  <tr>
59
    <td colspan="5"><hr size=3 noshade></td>
60
  </tr>
61
  <tr>
62
    <th align=left><input name=reporttype class=radio type=radio value="free">[% 'Free report period' | $T8 %]</th>
63
    <td align=left colspan=4>
64
      [% 'From' | $T8 %] [% L.date_tag('fromdate', fromdate) %]
65
      [% 'Bis' | $T8 %] [% L.date_tag('todate', todate) %]
66
    </td>
67
  </tr>
68
    <tr>
69
     <th class="listheading" align="left" valign="top" colspan="5" nowrap>[% 'Filter' | $T8 %]</th>
70
    </tr>
71
    <tr>
72
     <td colspan="5">
73
      <table>
74
       <tr>
75
        <th align="right" nowrap>[% 'Warehouse' | $T8 %]:</th>
76
        <td>
77
         <select name="warehouse_id" id="warehouse_id" onchange="kivi.PartsWarehouse.warehouseChanged(this.value, 0)">
78
          <option value="">---</option>
79
          [%- FOREACH warehouse = WAREHOUSES %]
80
          <option value="[% HTML.escape(warehouse.id) %]">[% warehouse.description %]</option>
81
          [%- END %]
82
         </select>
83
        </td>
84
       </tr>
85
       <tr>
86
        <th align="right" nowrap>[% 'Bin' | $T8 %]:</th>
87
        <td><select name="bin_id" id="bin_id"></select></td>
88
       </tr>
89
       <tr>
90
        <th align="right" nowrap>[% 'Part Number' | $T8 %]:</th>
91
        <td><input name="partnumber" size=20></td>
92
       </tr>
93
       <tr>
94
        <th align="right" nowrap>[% 'Part Description' | $T8 %]:</th>
95
        <td><input name="description" size=40></td>
96
       </tr>
97
[% IF PARTSCLASSIFICATIONS %]
98
       <tr>
99
        <td>
100
           [% L.select_tag('partsclassification',PARTSCLASSIFICATION,title_key="partsclassification") %]
101
        </td>
102
       </tr>
103
[% END %]
104
       <tr>
105
        <th align="right" nowrap>[% 'Charge Number' | $T8 %]:</th>
106
        <td><input name="chargenumber" size=40></td>
107
       </tr>
108
       [% IF INSTANCE_CONF.get_show_bestbefore %]
109
       <tr>
110
        <th align="right" nowrap>[% 'Best Before' | $T8 %]:</th>
111
        <td>
112
          [% L.date_tag('bestbefore') %]
113
        </td>
114
       </tr>
115
       [% END %]
116
      </table>
117
     </td>
118
    </tr>
119
   </table>
120
  </p>
121

  
122
  <p>
123
 <input type="hidden" name="action" value="Inventory/dispatch">
124
 <input type="submit" id="action_usage" class="submit" name="action_usage" value="[% 'Continue' | $T8 %]"> 
125
 </p>
126
 </form>
templates/webpages/report_generator/pdf_export_options.html
1 1
[%- USE T8 %]
2 2
[%- USE HTML %][%- USE LxERP %]
3 3

  
4
 [%- SET default_margin = LxERP.format_amount(1.5) %]
4
 [%- SET default_ymargin = LxERP.format_amount(1.5) %]
5
 [%- SET default_xmargin = LxERP.format_amount(0.8) %]
5 6

  
6 7
 <h1>[% HTML.escape(title) %]</h1>
7 8

  
......
73 74

  
74 75
   <tr>
75 76
    <td align="right">[% 'Top' | $T8 %]</td>
76
    <td><input name="report_generator_pdf_options_margin_top" size="4" value="[% HTML.escape(default_margin) %]"> cm</td>
77
    <td><input name="report_generator_pdf_options_margin_top" size="4" value="[% HTML.escape(default_ymargin) %]"> cm</td>
77 78
   </tr>
78 79

  
79 80
   <tr>
80 81
    <td align="right">[% 'Left' | $T8 %]</td>
81
    <td><input name="report_generator_pdf_options_margin_left" size="4" value="[% HTML.escape(default_margin) %]"> cm</td>
82
    <td><input name="report_generator_pdf_options_margin_left" size="4" value="[% HTML.escape(default_xmargin) %]"> cm</td>
82 83
   </tr>
83 84

  
84 85
   <tr>
85 86
    <td align="right">[% 'Bottom' | $T8 %]</td>
86
    <td><input name="report_generator_pdf_options_margin_bottom" size="4" value="[% HTML.escape(default_margin) %]"> cm</td>
87
    <td><input name="report_generator_pdf_options_margin_bottom" size="4" value="[% HTML.escape(default_ymargin) %]"> cm</td>
87 88
   </tr>
88 89

  
89 90
   <tr>
90 91
    <td align="right">[% 'Right' | $T8 %]</td>
91
    <td><input name="report_generator_pdf_options_margin_right" size="4" value="[% HTML.escape(default_margin) %]"> cm</td>
92
    <td><input name="report_generator_pdf_options_margin_right" size="4" value="[% HTML.escape(default_xmargin) %]"> cm</td>
92 93
   </tr>
93 94

  
94 95
   <tr>

Auch abrufbar als: Unified diff