]> wagnertech.de Git - mfinanz.git/blob - SL/Controller/CustomDataExport.pm
Merge branch 'master' of http://wagnertech.de/git/mfinanz
[mfinanz.git] / SL / Controller / CustomDataExport.pm
1 package SL::Controller::CustomDataExport;
2
3 use strict;
4 use utf8;
5
6 use parent qw(SL::Controller::Base);
7
8 use DBI qw(:sql_types);
9 use File::Temp ();
10 use List::UtilsBy qw(sort_by);
11 use POSIX qw(strftime);
12 use Text::CSV_XS;
13
14 use SL::DB::CustomDataExportQuery;
15 use SL::Controller::Helper::ReportGenerator;
16 use SL::Locale::String qw(t8);
17
18 use Rose::Object::MakeMethods::Generic
19 (
20   scalar                  => [ qw(rows) ],
21   'scalar --get_set_init' => [ qw(query queries parameters) ],
22 );
23
24 __PACKAGE__->run_before('check_auth');
25 __PACKAGE__->run_before('setup_javascripts');
26
27 #
28 # actions
29 #
30
31 sub action_list {
32   my ($self) = @_;
33
34   $self->render('custom_data_export/list', title => $::locale->text('Execute a custom report query'));
35 }
36
37 sub action_export {
38   my ($self) = @_;
39
40   if (!$::form->{parameters_set}) {
41     $self->setup_export_action_bar;
42     return $self->render('custom_data_export/export', title => t8("Execute custom report '#1'", $self->query->name));
43   }
44
45   $self->execute_query;
46
47   if (scalar(@{ $self->rows // [] }) == 1) {
48     $self->setup_empty_result_set_action_bar;
49     return $self->render('custom_data_export/empty_result_set', title => t8("Execute custom report '#1'", $self->query->name));
50   }
51
52   my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
53
54   my $report_name =  $self->query->name;
55   $report_name    =~ s{[^[:word:]]+}{_}ig;
56   $report_name   .=  strftime('_%Y-%m-%d_%H-%M-%S', localtime());
57
58   $report->set_options(
59     std_column_visibility => 1,
60     controller_class      => 'CustomDataExport',
61     output_format         => 'HTML',
62     top_info_text         => $self->query->name,
63     title                 => $self->query->name,
64     allow_pdf_export      => 1,
65     allow_csv_export      => 1,
66     allow_chart_export    => 1,
67     attachment_basename   => $report_name,
68   );
69
70   my %column_defs;
71   foreach my $key (@{ $self->rows->[0] }) {
72     $column_defs{$key} = { text => $key, sub => sub { $_[0]->{$key} } };
73   }
74
75   $report->set_columns(%column_defs);
76   $report->set_column_order(@{ $self->rows->[0] });
77
78   $report->set_export_options(qw(export id parameters_set parameters));
79   $report->set_options_from_form;
80
81   # Setup data objects (which in this case is an array of hashes).
82   my @objects;
83   foreach my $set_idx (1..$#{ $self->rows }) {
84     my %row_set;
85     foreach my $key_idx (0..$#{ $self->rows->[0] }) {
86       my $key   = $self->rows->[0]->[$key_idx];
87       my $value = $self->rows->[$set_idx]->[$key_idx];
88       $row_set{$key} = $value;
89     }
90     push @objects, \%row_set;
91   }
92
93   $self->report_generator_list_objects(report  => $report,
94                                        objects => \@objects,
95                                        options => {
96                                          action_bar_additional_submit_values => { id => $::form->{id}, },
97                                        },
98   );
99 }
100
101 #
102 # filters
103 #
104
105 sub check_auth {
106   my ($self) = @_;
107   $::auth->assert('custom_data_report');
108   $::auth->assert($self->query->access_right) if $self->query->access_right;
109 }
110
111 sub setup_javascripts {
112   $::request->layout->add_javascripts('kivi.Validator.js');
113 }
114
115 #
116 # helpers
117 #
118
119 sub init_query      { $::form->{id} ? SL::DB::CustomDataExportQuery->new(id => $::form->{id})->load : SL::DB::CustomDataExportQuery->new }
120 sub init_parameters { [ sort_by { lc $_->name } @{ $_[0]->query->parameters // [] } ] }
121
122 sub init_queries {
123   my %rights_map     = %{ $::auth->load_rights_for_user($::form->{login}) };
124   my @granted_rights = grep { $rights_map{$_} } keys %rights_map;
125
126   return scalar SL::DB::Manager::CustomDataExportQuery->get_all_sorted(
127     where => [
128       or => [
129         access_right => undef,
130         access_right => '',
131         (access_right => \@granted_rights) x !!@granted_rights,
132       ],
133     ],
134   )
135 }
136
137 sub setup_export_action_bar {
138   my ($self) = @_;
139
140   for my $bar ($::request->layout->get('actionbar')) {
141     $bar->add(
142       action => [
143         t8('Execute'),
144         submit    => [ '#form', { action => 'CustomDataExport/export' } ],
145         checks    => [ 'kivi.validate_form' ],
146         accesskey => 'enter',
147       ],
148       action => [
149         t8('Back'),
150         call => [ 'kivi.history_back' ],
151       ],
152     );
153   }
154 }
155
156 sub setup_empty_result_set_action_bar {
157   my ($self) = @_;
158
159   for my $bar ($::request->layout->get('actionbar')) {
160     $bar->add(
161       action => [
162         t8('Back'),
163         call => [ 'kivi.history_back' ],
164       ],
165     );
166   }
167 }
168
169 sub prepare_query {
170   my ($self) = @_;
171
172   my $sql_query = $self->query->sql_query;
173   my @values;
174
175   my %values_by_name;
176
177   foreach my $parameter (@{ $self->query->parameters // [] }) {
178     my $value                           = ($::form->{parameters} // {})->{ $parameter->name };
179     $values_by_name{ $parameter->name } = $parameter->parameter_type eq 'number' ? $::form->parse_amount(\%::myconfig, $value) : $value;
180   }
181
182   while ($sql_query =~ m{<\%(.+?)\%>}) {
183     push @values, $values_by_name{$1};
184     substr($sql_query, $-[0], $+[0] - $-[0], '?');
185   }
186
187   return ($sql_query, @values);
188 }
189
190 sub execute_query {
191   my ($self) = @_;
192
193   my ($sql_query, @values) = $self->prepare_query;
194   my $sth                  = $self->query->db->dbh->prepare($sql_query) || $::form->dberror;
195   $sth->execute(@values)                                                || $::form->dberror;
196
197   my @names = @{ $sth->{NAME} };
198   my @types = @{ $sth->{TYPE} };
199   my @data  = @{ $sth->fetchall_arrayref };
200
201   $sth->finish;
202
203   foreach my $row (@data) {
204     foreach my $col (0..$#types) {
205       my $type = $types[$col];
206
207       if ($type == SQL_NUMERIC) {
208         $row->[$col] = $::form->format_amount(\%::myconfig, $row->[$col]);
209       }
210     }
211   }
212
213   $self->rows([
214     \@names,
215     @data,
216   ]);
217 }
218
219 1;