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 {

Auch abrufbar als: Unified diff