Inventory-Helper: Restmenge auch runden, Stück immer ganzzahlig
[kivitendo-erp.git] / SL / Controller / Helper / ReportGenerator.pm
1 package SL::Controller::Helper::ReportGenerator;
2
3 use strict;
4
5 use Carp;
6 use List::Util qw(max);
7
8 use SL::Common;
9 use SL::MoreCommon;
10 use SL::ReportGenerator;
11
12 use Exporter 'import';
13 our @EXPORT = qw(
14   action_report_generator_export_as_pdf action_report_generator_export_as_csv
15   action_report_generator_back report_generator_do
16   report_generator_list_objects
17 );
18
19 sub _setup_action_bar {
20   my ($self, $type) = @_;
21
22   my $key   = $::form->{CONTROLLER_DISPATCH} ? 'action'                             : 'report_generator_form.report_generator_dispatch_to';
23   my $value = $::form->{CONTROLLER_DISPATCH} ? $::form->{CONTROLLER_DISPATCH} . "/" : '';
24
25   for my $bar ($::request->layout->get('actionbar')) {
26     $bar->add(
27       action => [
28         $type eq 'pdf' ? $::locale->text('PDF export') : $::locale->text('CSV export'),
29         submit => [ '#report_generator_form', { $key => "${value}report_generator_export_as_${type}" } ],
30       ],
31       action => [
32         $::locale->text('Back'),
33         submit => [ '#report_generator_form', { $key => "${value}report_generator_back" } ],
34       ],
35     );
36   }
37 }
38
39 sub action_report_generator_export_as_pdf {
40   my ($self) = @_;
41
42   delete $::form->{action_report_generator_export_as_pdf};
43
44   if ($::form->{report_generator_pdf_options_set}) {
45     my $saved_form = save_form();
46
47     $self->report_generator_do('PDF');
48
49     if ($::form->{report_generator_printed}) {
50       restore_form($saved_form);
51       $::form->{MESSAGE} = $::locale->text('The list has been printed.');
52       $self->report_generator_do('HTML');
53     }
54
55     return;
56   }
57
58   my @form_values = $::form->flatten_variables(grep { ($_ ne 'login') && ($_ ne 'password') } keys %{ $::form });
59
60   $::form->get_lists('printers' => 'ALL_PRINTERS');
61   map { $_->{selected} = $::myconfig{default_printer_id} == $_->{id} } @{ $::form->{ALL_PRINTERS} };
62
63   $::form->{copies} = max $::myconfig{copies} * 1, 1;
64   $::form->{title} = $::locale->text('PDF export -- options');
65
66   _setup_action_bar($self, 'pdf'); # Sub not exported, therefore don't call via object.
67
68   $::form->header;
69   print $::form->parse_html_template('report_generator/pdf_export_options', {
70     'HIDDEN'               => \@form_values,
71     'ALLOW_FONT_SELECTION' => SL::ReportGenerator->check_for_pdf_api, });
72 }
73
74 sub action_report_generator_export_as_csv {
75   my ($self) = @_;
76
77   delete $::form->{action_report_generator_export_as_csv};
78
79   if ($::form->{report_generator_csv_options_set}) {
80     $self->report_generator_do('CSV');
81     return;
82   }
83
84   my @form_values = $::form->flatten_variables(grep { ($_ ne 'login') && ($_ ne 'password') } keys %{ $::form });
85
86   $::form->{title} = $::locale->text('CSV export -- options');
87
88   _setup_action_bar($self, 'csv'); # Sub not exported, therefore don't call via object.
89
90   $::form->header;
91   print $::form->parse_html_template('report_generator/csv_export_options', { 'HIDDEN' => \@form_values });
92 }
93
94 sub action_report_generator_back {
95   $_[0]->report_generator_do('HTML');
96 }
97
98 sub report_generator_do {
99   my ($self, $format)  = @_;
100
101   my $nextsub = $::form->{report_generator_nextsub};
102   if (!$nextsub) {
103     $::form->error($::locale->text('report_generator_nextsub is not defined.'));
104   }
105
106   foreach my $key (split m/ +/, $::form->{report_generator_variable_list}) {
107     $::form->{$key} = $::form->{"report_generator_hidden_${key}"};
108   }
109
110   $::form->{report_generator_output_format} = $format;
111
112   delete @{$::form}{map { "report_generator_$_" } qw(nextsub variable_list)};
113
114   $self->_run_action($nextsub);
115 }
116
117 sub report_generator_list_objects {
118   my ($self, %params) = @_;
119
120   croak "Parameter 'objects' must exist and be an array reference"                if                      ref($params{objects}) ne 'ARRAY';
121   croak "Parameter 'report' must exist and be an instance of SL::ReportGenerator" if                      ref($params{report})  ne 'SL::ReportGenerator';
122   croak "Parameter 'options', if exists, must be a hash reference"                if $params{options} && (ref($params{options}) ne 'HASH');
123   $params{layout} //= 1;
124
125   my $column_defs = $params{report}->{columns};
126   my @columns     = $params{report}->get_visible_columns('HTML');
127
128   for my $obj (@{ $params{objects} || [] }) {
129     my %data = map {
130       my $def = $column_defs->{$_};
131       $_ => {
132         raw_data => $def->{raw_data} ? $def->{raw_data}->($obj) : '',
133         data     => $def->{sub}      ? $def->{sub}->($obj)
134                   : $obj->can($_)    ? $obj->$_
135                   :                    $obj->{$_},
136         link     => $def->{obj_link} ? $def->{obj_link}->($obj) : '',
137       },
138     } @columns;
139
140     $params{data_callback}->(\%data) if $params{data_callback};
141
142     $params{report}->add_data(\%data);
143   }
144
145   my %options            = %{ $params{options} || {} };
146   $options{action_bar} //= $params{action_bar} // 1;
147
148   if ($params{layout}) {
149     return $params{report}->generate_with_headers(%options);
150   } else {
151     my $html = $params{report}->generate_html_content(action_bar => 0, %options);
152     $self->render(\$html , { layout => 0, process => 0 });
153   }
154 }
155
156 1;
157 __END__
158
159 =pod
160
161 =encoding utf8
162
163 =head1 NAME
164
165 SL::Controller::Helper::ReportGenerator - Mixin for controllers that
166 use the L<SL::ReportGenerator> class
167
168 =head1 SYNOPSIS
169
170   package SL::Controller::Unicorn;
171
172   use SL::Controller::Helper::ReportGenerator;
173
174   sub action_list {
175     my ($self) = @_;
176
177     # Set up the report generator instance. In this example this is
178     # hidden in "prepare_report".
179     my $report = $self->prepare_report;
180
181     # Get objects from database.
182     my $orders = SL::DB::Manager::Order->get_all(...);
183
184     # Let report generator create the output.
185     $self->report_generator_list_objects(
186       report  => $report,
187       objects => $orders,
188     );
189   }
190
191 =head1 FUNCTIONS
192
193 =over 4
194
195 =item C<action_report_generator_back>
196
197 This is the controller action that's called from the one of the report
198 generator's 'export options' pages when the user clicks on the 'back'
199 button.
200
201 It is never called from a controller manually and should just work
202 as-is.
203
204 =item C<action_report_generator_export_as_csv>
205
206 This is the controller action that's called from the generated report
207 when the user wants to export as CSV. First the CSV export options are
208 shown and afterwards the CSV file is generated and offered for
209 download.
210
211 It is never called from a controller manually and should just work
212 as-is.
213
214 =item C<action_report_generator_export_as_pdf>
215
216 This is the controller action that's called from the generated report
217 when the user wants to export as PDF. First the PDF export options are
218 shown and afterwards the PDF file is generated and offered for
219 download.
220
221 It is never called from a controller manually and should just work
222 as-is.
223
224 =item C<report_generator_do>
225
226 This is a common function that's called from
227 L<action_report_generator_back>,
228 L<action_report_generator_export_as_csv> and
229 L<action_report_generator_export_as_pdf>. It handles common options
230 and report generation after options have been set.
231
232 It is never called from a controller manually and should just work
233 as-is.
234
235 =item C<report_generator_list_objects %params>
236
237 Iterates over all objects, creates the actual rows of data, hands them
238 over to the report generator and lets the report generator create the
239 output.
240
241 C<%params> can contain the following values:
242
243 =over 2
244
245 =item C<report>
246
247 Mandatory. An instance of L<SL::ReportGenerator> that has been set up
248 already (column definitions, title, sort handling etc).
249
250 =item C<objects>
251
252 Mandatory. An array reference of RDBO models to output.
253
254 =item C<data_callback>
255
256 Optional. A callback handler (code reference) that gets called for
257 each row before it is passed to the report generator. The row passed
258 will be the handler's first and only argument (a hash reference). It's
259 the same hash reference that's passed to
260 L<SL::ReportGenrator/add_data>.
261
262 =item C<options>
263
264 An optional hash reference that's passed verbatim to the function
265 L<SL::ReportGenerator/generate_with_headers>.
266
267 =item C<action_bar>
268
269 If the buttons for exporting PDF and/or CSV variants are included in
270 the action bar. Otherwise they're rendered at the bottom of the page.
271
272 The value can be either a specific action bar instance or simply 1 in
273 which case the default action bar is used:
274 C<$::request-E<gt>layout-E<gt>get('actionbar')>.
275
276 =back
277
278 =back
279
280 =head1 BUGS
281
282 Nothing here yet.
283
284 =head1 AUTHOR
285
286 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
287
288 =cut