Debugcode
[kivitendo-erp.git] / SL / CVar.pm
1 package CVar;
2
3 use List::Util qw(first);
4
5 use SL::DBUtils;
6
7 sub get_configs {
8   $main::lxdebug->enter_sub();
9
10   my $self     = shift;
11   my %params   = @_;
12
13   my $myconfig = \%main::myconfig;
14   my $form     = $main::form;
15
16   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
17
18   my ($where, @values);
19   if ($params{module}) {
20     $where = 'WHERE module = ?';
21     push @values, $params{module};
22   }
23
24   my $query    = qq|SELECT * FROM custom_variable_configs $where ORDER BY sortkey|;
25
26   my $configs  = selectall_hashref_query($form, $dbh, $query, @values);
27
28   foreach my $config (@{ $configs }) {
29     if ($config->{type} eq 'select') {
30       $config->{OPTIONS} = [ map { { 'value' => $_ } } split(m/\#\#/, $config->{options}) ];
31
32     } elsif ($config->{type} eq 'number') {
33       $config->{precision} = $1 if ($config->{options} =~ m/precision=(\d+)/i);
34
35     }
36   }
37
38   $main::lxdebug->leave_sub();
39
40   return $configs;
41 }
42
43 sub get_config {
44   $main::lxdebug->enter_sub();
45
46   my $self     = shift;
47   my %params   = @_;
48
49   Common::check_params(\%params, qw(id));
50
51   my $myconfig = \%main::myconfig;
52   my $form     = $main::form;
53
54   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
55
56   my $query    = qq|SELECT * FROM custom_variable_configs WHERE id = ?|;
57
58   my $config   = selectfirst_hashref_query($form, $dbh, $query, conv_i($params{id})) || { };
59
60   $main::lxdebug->leave_sub();
61
62   return $config;
63 }
64
65 sub save_config {
66   $main::lxdebug->enter_sub();
67
68   my $self     = shift;
69   my %params   = @_;
70
71   Common::check_params(\%params, qw(module config));
72
73   my $myconfig = \%main::myconfig;
74   my $form     = $main::form;
75
76   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
77
78   my $q_id     = qq|SELECT nextval('custom_variable_configs_id')|;
79   my $h_id     = prepare_query($form, $dbh, $q_id);
80
81   my $q_new    =
82     qq|INSERT INTO custom_variable_configs (name, description, type, default_value, options, searchable, includeable, included_by_default, module, id, sortkey)
83        VALUES                              (?,    ?,           ?,    ?,             ?,       ?,          ?,           ?,                   ?,      ?,
84          (SELECT COALESCE(MAX(sortkey) + 1, 1) FROM custom_variable_configs))|;
85   my $h_new    = prepare_query($form, $dbh, $q_new);
86
87   my $q_update =
88     qq|UPDATE custom_variable_configs SET
89          name        = ?, description         = ?,
90          type        = ?, default_value       = ?,
91          options     = ?, searchable          = ?,
92          includeable = ?, included_by_default = ?,
93          module      = ?
94        WHERE id  = ?|;
95   my $h_update = prepare_query($form, $dbh, $q_update);
96
97   my @configs;
98   if ('ARRAY' eq ref $params{config}) {
99     @configs = @{ $params{config} };
100   } else {
101     @configs = ($params{config});
102   }
103
104   foreach my $config (@configs) {
105     my ($h_actual, $q_actual);
106
107     if (!$config->{id}) {
108       do_statement($form, $h_id, $q_id);
109       ($config->{id}) = $h_id->fetchrow_array();
110
111       $h_actual       = $h_new;
112       $q_actual       = $q_new;
113
114     } else {
115       $h_actual       = $h_update;
116       $q_actual       = $q_update;
117     }
118
119     do_statement($form, $h_actual, $q_actual, @{$config}{qw(name description type default_value options)},
120                  $config->{searchable} ? 't' : 'f', $config->{includeable} ? 't' : 'f', $config->{included_by_default} ? 't' : 'f',
121                  $params{module}, conv_i($config->{id}));
122   }
123
124   $h_id->finish();
125   $h_new->finish();
126   $h_update->finish();
127
128   $dbh->commit();
129
130   $main::lxdebug->leave_sub();
131 }
132
133 sub delete_config {
134   $main::lxdebug->enter_sub();
135
136   my $self     = shift;
137   my %params   = @_;
138
139   Common::check_params(\%params, qw(id));
140
141   my $myconfig = \%main::myconfig;
142   my $form     = $main::form;
143
144   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
145
146   do_query($form, $dbh, qq|DELETE FROM custom_variables        WHERE config_id = ?|, conv_i($params{id}));
147   do_query($form, $dbh, qq|DELETE FROM custom_variable_configs WHERE id        = ?|, conv_i($params{id}));
148
149   $dbh->commit();
150
151   $main::lxdebug->leave_sub();
152 }
153
154 sub get_custom_variables {
155   $main::lxdebug->enter_sub();
156
157   my $self     = shift;
158   my %params   = @_;
159
160   Common::check_params(\%params, qw(module));
161
162   my $myconfig = \%main::myconfig;
163   my $form     = $main::form;
164
165   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
166
167   my $trans_id = $params{trans_id} ? 'OR (v.trans_id = ?) ' : '';
168
169   my $q_cfg    =
170     qq|SELECT id, name, description, type, default_value, options,
171          date_trunc('seconds', localtimestamp) AS current_timestamp, current_date AS current_date
172        FROM custom_variable_configs
173        WHERE module = ?
174        ORDER BY sortkey|;
175
176   my $q_var    =
177     qq|SELECT text_value, timestamp_value, timestamp_value::date AS date_value, number_value, bool_value
178        FROM custom_variables
179        WHERE (config_id = ?) AND (trans_id = ?)|;
180   my $h_var    = prepare_query($form, $dbh, $q_var);
181
182   my $custom_variables = selectall_hashref_query($form, $dbh, $q_cfg, $params{module});
183
184   foreach my $cvar (@{ $custom_variables }) {
185     if ($cvar->{type} eq 'textfield') {
186       $cvar->{width}  = 30;
187       $cvar->{height} =  5;
188
189       $cvar->{width}  = $1 if ($cvar->{options} =~ m/width=(\d+)/i);
190       $cvar->{height} = $1 if ($cvar->{options} =~ m/height=(\d+)/i);
191
192     } elsif ($cvar->{type} eq 'text') {
193       $cvar->{maxlength} = $1 if ($cvar->{options} =~ m/maxlength=(\d+)/i);
194
195     } elsif ($cvar->{type} eq 'number') {
196       $cvar->{precision} = $1 if ($cvar->{options} =~ m/precision=(\d+)/i);
197
198     } elsif ($cvar->{type} eq 'select') {
199       $cvar->{OPTIONS} = [ map { { 'value' => $_ } } split(m/\#\#/, $cvar->{options}) ];
200     }
201
202     my $act_var;
203     if ($params{trans_id}) {
204       do_statement($form, $h_var, $q_var, conv_i($cvar->{id}), conv_i($params{trans_id}));
205       $act_var = $h_var->fetchrow_hashref();
206     }
207
208     if ($act_var) {
209       $cvar->{value} = $cvar->{type} eq 'date'      ? $act_var->{date_value}
210                      : $cvar->{type} eq 'timestamp' ? $act_var->{timestamp_value}
211                      : $cvar->{type} eq 'number'    ? $act_var->{number_value}
212                      : $cvar->{type} eq 'bool'      ? $act_var->{bool_value}
213                      :                                $act_var->{text_value};
214
215     } else {
216       if ($cvar->{type} eq 'date') {
217         if ($cvar->{default_value} eq 'NOW') {
218           $cvar->{value} = $cvar->{current_date};
219         } else {
220           $cvar->{value} = $cvar->{default_value};
221         }
222
223       } elsif ($cvar->{type} eq 'timestamp') {
224         if ($cvar->{default_value} eq 'NOW') {
225           $cvar->{value} = $cvar->{current_timestamp};
226         } else {
227           $cvar->{value} = $cvar->{default_value};
228         }
229
230       } elsif ($cvar->{type} eq 'bool') {
231         $cvar->{value} = $cvar->{default_value} * 1;
232
233       } elsif ($cvar->{type} eq 'number') {
234         $cvar->{value} = $cvar->{default_value} * 1 if ($cvar->{default_value} ne '');
235
236       } else {
237         $cvar->{value} = $cvar->{default_value};
238       }
239     }
240
241     if ($cvar->{type} eq 'number') {
242       $cvar->{value} = $form->format_amount($myconfig, $cvar->{value} * 1, $cvar->{precision});
243     }
244   }
245
246   $h_var->finish();
247
248   $main::lxdebug->leave_sub();
249
250   return $custom_variables;
251 }
252
253 sub save_custom_variables {
254   $main::lxdebug->enter_sub();
255
256   my $self     = shift;
257   my %params   = @_;
258
259   Common::check_params(\%params, qw(module trans_id variables));
260
261   my $myconfig = \%main::myconfig;
262   my $form     = $main::form;
263
264   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
265
266   my @configs  = grep { $_->{module} eq $params{module} } @{ CVar->get_configs() };
267
268   my $query    =
269     qq|DELETE FROM custom_variables
270        WHERE (trans_id  = ?)
271          AND (config_id IN (SELECT DISTINCT id
272                             FROM custom_variable_configs
273                             WHERE module = ?))|;
274   do_query($form, $dbh, $query, conv_i($params{trans_id}), $params{module});
275
276   $query  =
277     qq|INSERT INTO custom_variables (config_id, trans_id, bool_value, timestamp_value, text_value, number_value)
278        VALUES                       (?,         ?,        ?,          ?,               ?,          ?)|;
279   my $sth = prepare_query($form, $dbh, $query);
280
281   foreach my $config (@configs) {
282     my @values = (conv_i($config->{id}), conv_i($params{trans_id}));
283
284     my $value  = $params{variables}->{"cvar_$config->{name}"};
285
286     if (($config->{type} eq 'text') || ($config->{type} eq 'textfield') || ($config->{type} eq 'select')) {
287       push @values, undef, undef, $value, undef;
288
289     } elsif (($config->{type} eq 'date') || ($config->{type} eq 'timestamp')) {
290       push @values, undef, conv_date($value), undef, undef;
291
292     } elsif ($config->{type} eq 'number') {
293       push @values, undef, undef, undef, conv_i($form->parse_amount($myconfig, $value));
294
295     } elsif ($config->{type} eq 'bool') {
296       push @values, $value ? 't' : 'f', undef, undef, undef;
297     }
298
299     do_statement($form, $sth, $query, @values);
300   }
301
302   $sth->finish();
303
304   $dbh->commit();
305
306   $main::lxdebug->leave_sub();
307 }
308
309 sub render_inputs {
310   $main::lxdebug->enter_sub();
311
312   my $self     = shift;
313   my %params   = @_;
314
315   Common::check_params(\%params, qw(variables));
316
317   my $myconfig = \%main::myconfig;
318   my $form     = $main::form;
319
320   foreach my $var (@{ $params{variables} }) {
321     $var->{HTML_CODE} = $form->parse_html_template('amcvar/render_inputs', { 'var' => $var });
322   }
323
324   $main::lxdebug->leave_sub();
325 }
326
327 sub render_search_options {
328   $main::lxdebug->enter_sub();
329
330   my $self     = shift;
331   my %params   = @_;
332
333   Common::check_params(\%params, qw(variables));
334
335   my $myconfig = \%main::myconfig;
336   my $form     = $main::form;
337
338   $params{include_prefix}   = 'l_' unless defined($params{include_prefix});
339   $params{include_value}  ||= '1';
340
341   my $filter  = $form->parse_html_template('amcvar/search_filter',  \%params);
342   my $include = $form->parse_html_template('amcvar/search_include', \%params);
343
344   $main::lxdebug->leave_sub();
345
346   return ($filter, $include);
347 }
348
349 sub build_filter_query {
350   $main::lxdebug->enter_sub();
351
352   my $self     = shift;
353   my %params   = @_;
354
355   Common::check_params(\%params, qw(module trans_id_field filter));
356
357   my $myconfig = \%main::myconfig;
358   my $form     = $main::form;
359
360   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
361
362   my $configs  = $self->get_configs(%params);
363
364   my (@where, @values);
365
366   foreach my $config (@{ $configs }) {
367     next unless ($config->{searchable});
368
369     my $name = "cvar_$config->{name}";
370
371     my (@sub_values, @sub_where, $not);
372
373     if (($config->{type} eq 'text') || ($config->{type} eq 'textfield')) {
374       next unless ($params{filter}->{$name});
375
376       push @sub_where,  qq|cvar.text_value ILIKE ?|;
377       push @sub_values, '%' . $params{filter}->{$name} . '%'
378
379     } elsif ($config->{type} eq 'select') {
380       next unless ($params{filter}->{$name});
381
382       push @sub_where,  qq|cvar.text_value = ?|;
383       push @sub_values, $params{filter}->{$name};
384
385     } elsif (($config->{type} eq 'date') || ($config->{type} eq 'timestamp')) {
386       my $name_from = "${name}_from";
387       my $name_to   = "${name}_to";
388
389       if ($params{filter}->{$name_from}) {
390         push @sub_where,  qq|cvar.timestamp_value >= ?|;
391         push @sub_values, conv_date($params{filter}->{$name_from});
392       }
393
394       if ($params{filter}->{$name_to}) {
395         push @sub_where,  qq|cvar.timestamp_value <= ?|;
396         push @sub_values, conv_date($params{filter}->{$name_to});
397       }
398
399     } elsif ($config->{type} eq 'number') {
400       next if ($params{filter}->{$name} eq '');
401
402       my $f_op = $params{filter}->{"${name}_qtyop"};
403
404       if ($f_op eq '==') {
405         $op  = '=';
406
407       } elsif ($f_op eq '=/=') {
408         $not = 'NOT';
409         $op  = '<>';
410
411       } elsif ($f_op eq '<') {
412         $not = 'NOT';
413         $op  = '>=';
414
415       } elsif ($f_op eq '<=') {
416         $not = 'NOT';
417         $op  = '>';
418
419       } elsif (($f_op eq '>') || ($f_op eq '>=')) {
420         $op  = $f_op;
421
422       } else {
423         $op  = '=';
424       }
425
426       push @sub_where,  qq|cvar.number_value $op ?|;
427       push @sub_values, $form->parse_amount($myconfig, $params{filter}->{$name});
428
429     } elsif ($config->{type} eq 'bool') {
430       next unless ($params{filter}->{$name});
431
432       $not = 'NOT' if ($params{filter}->{$name} eq 'no');
433       push @sub_where,  qq|COALESCE(cvar.bool_value, false) = TRUE|;
434     }
435
436     if (@sub_where) {
437       push @where,
438         qq|$not EXISTS(
439              SELECT cvar.id
440              FROM custom_variables cvar
441              LEFT JOIN custom_variable_configs cvarcfg ON (cvar.config_id = cvarcfg.id)
442              WHERE (cvarcfg.module = ?)
443                AND (cvarcfg.id     = ?)
444                AND (cvar.trans_id  = $params{trans_id_field})
445                AND | . join(' AND ', map { "($_)" } @sub_where) . qq|)|;
446       push @values, $params{module}, conv_i($config->{id}), @sub_values;
447     }
448   }
449
450   my $query = join ' AND ', @where;
451
452   $main::lxdebug->leave_sub();
453
454   return ($query, @values);
455 }
456
457 sub add_custom_variables_to_report {
458   $main::lxdebug->enter_sub();
459
460   my $self      = shift;
461   my %params    = @_;
462
463   Common::check_params(\%params, qw(module trans_id_field column_defs data configs));
464
465   my $myconfig  = \%main::myconfig;
466   my $form      = $main::form;
467   my $locale    = $main::locale;
468
469   my $dbh       = $params{dbh} || $form->get_standard_dbh($myconfig);
470
471   my $configs   = [ grep { $_->{includeable} && $params{column_defs}->{"cvar_$_->{name}"}->{visible} } @{ $params{configs} } ];
472
473   if (!scalar(@{ $params{data} }) || ! scalar(@{ $configs })) {
474     $main::lxdebug->leave_sub();
475     return;
476   }
477
478   my %cfg_map   = map { $_->{id} => $_ } @{ $configs };
479   my @cfg_ids   = keys %cfg_map;
480
481   my $query     =
482     qq|SELECT text_value, timestamp_value, timestamp_value::date AS date_value, number_value, bool_value, config_id
483        FROM custom_variables
484        WHERE (config_id IN (| . join(', ', ('?') x scalar(@cfg_ids)) . qq|)) AND (trans_id = ?)|;
485   my $sth       = prepare_query($form, $dbh, $query);
486
487   foreach my $row (@{ $params{data} }) {
488     do_statement($form, $sth, $query, @cfg_ids, conv_i($row->{$params{trans_id_field}}));
489
490     while (my $ref = $sth->fetchrow_hashref()) {
491       my $cfg = $cfg_map{$ref->{config_id}};
492
493       $row->{"cvar_$cfg->{name}"} =
494           $cfg->{type} eq 'date'      ? $ref->{date_value}
495         : $cfg->{type} eq 'timestamp' ? $ref->{timestamp_value}
496         : $cfg->{type} eq 'number'    ? $form->format_amount($myconfig, $ref->{number_value} * 1, $config->{precision})
497         : $cfg->{type} eq 'bool'      ? ($ref->{bool_value} ? $locale->text('Yes') : $locale->text('No'))
498         :                               $ref->{text_value};
499     }
500   }
501
502   $sth->finish();
503
504   $main::lxdebug->leave_sub();
505 }
506
507 sub get_field_format_list {
508   $main::lxdebug->enter_sub();
509
510   my $self          = shift;
511   my %params        = @_;
512
513   Common::check_params(\%params, qw(module));
514
515   my $myconfig      = \%main::myconfig;
516   my $form          = $main::form;
517
518   my $dbh           = $params{dbh} || $form->get_standard_dbh($myconfig);
519
520   my $configs       = $self->get_configs(%params);
521
522   my $date_fields   = [];
523   my $number_fields = {};
524
525   foreach my $config (@{ $configs }) {
526     my $name = "$params{prefix}cvar_$config->{name}";
527
528     if ($config->{type} eq 'date') {
529       push @{ $date_fields }, $name;
530
531     } elsif ($config->{type} eq 'number') {
532       $number_fields->{$config->{precision}} ||= [];
533       push @{ $number_fields->{$config->{precision}} }, $name;
534     }
535   }
536
537   $main::lxdebug->leave_sub();
538
539   return ($date_fields, $number_fields);
540 }
541
542
543 1;