GetModels-Filtered: Unterstützung für benutzerdefinierte Variablen
[kivitendo-erp.git] / SL / DB / Helper / CustomVariables.pm
index 7136855..4b3f399 100644 (file)
@@ -28,6 +28,7 @@ sub import {
   make_cvar_by_name($caller_package, %params);
   make_cvar_as_hashref($caller_package, %params);
   make_cvar_value_parser($caller_package, %params);
+  make_cvar_custom_filter($caller_package, %params);
 }
 
 sub save_meta_info {
@@ -223,6 +224,99 @@ sub _get_primary_key_column {
   return $column_name;
 }
 
+sub make_cvar_custom_filter {
+  my ($caller_package, %params) = @_;
+
+  my $manager    = $caller_package->meta->convention_manager->auto_manager_class_name;
+
+  return unless $manager->can('filter');
+
+  $manager->add_filter_specs(
+    cvar => sub {
+      my ($key, $value, $prefix, $config_id) = @_;
+      my $config = SL::DB::Manager::CustomVariableConfig->find_by(id => $config_id);
+
+      if (!$config) {
+        die "invalid config_id in $caller_package\::cvar custom filter: $config_id";
+      }
+
+      if ($config->module != $params{module}) {
+        die "invalid config_id in $caller_package\::cvar custom filter: expected module $params{module} - got @{[ $config->module ]}";
+      }
+
+      my (%query, %bind_vals);
+      ($query{customized}, $bind_vals{customized}) = Rose::DB::Object::QueryBuilder::build_select(
+        dbh                  => $config->dbh,
+        select               => 'trans_id',
+        tables               => [ 'custom_variables' ],
+        columns              => { custom_variables => [ qw(trans_id config_id text_value number_value bool_value timestamp_value sub_module) ] },
+        query                => [
+          config_id          => $config_id,
+          sub_module         => $params{sub_module},
+          $config->value_col => $value,
+        ],
+        query_is_sql         => 1,
+      );
+
+      my $conversion  = $config->type =~ m{^(?:date|timestamp)$}       ? $config->type
+                      : $config->type =~ m{^(?:customer|vendor|part)$} ? 'integer'
+                      : $config->type eq 'bool'                        ? 'boolean'
+                      : $config->type eq 'number'                      ? 'numeric'
+                      :                                                  '';
+
+      ($query{config}, $bind_vals{config}) = Rose::DB::Object::QueryBuilder::build_select(
+        dbh             => $config->dbh,
+        select          => 'id',
+        tables          => [ 'custom_variable_configs' ],
+        columns         => { custom_variable_configs => [ qw(id default_value) ] },
+        query           => [
+          id            => $config->id,
+          default_value => $value,
+        ],
+        query_is_sql    => 1,
+      );
+
+      $query{config} =~ s{\bdefault_value\b}{default_value::${conversion}} if $conversion;
+
+      ($query{not_customized}, $bind_vals{not_customized}) = Rose::DB::Object::QueryBuilder::build_select(
+        dbh          => $config->dbh,
+        select       => 'trans_id',
+        tables       => [ 'custom_variables' ],
+        columns      => { custom_variables => [ qw(trans_id config_id sub_module) ] },
+        query        => [
+          config_id  => $config_id,
+          sub_module => $params{sub_module},
+        ],
+        query_is_sql => 1,
+      );
+
+      foreach my $key (keys %query) {
+        # remove rose aliases. query builder sadly is not reentrant, and will reuse the same aliases. :(
+        $query{$key} =~ s{\bt\d+(?:\.)?\b}{}g;
+
+        # manually inline the values. again, rose doen't know how to handly bind params in subqueries :(
+        $query{$key} =~ s{\?}{ $config->dbh->quote($_) }xe for @{ $bind_vals{$key} };
+
+        $query{$key} =~ s{\n}{ }g;
+      }
+
+      my $qry_config = "EXISTS (" . $query{config} . ")";
+
+      my @result = (
+        'or' => [
+          $prefix . 'id'   => [ \$query{customized} ],
+          and              => [
+            "!${prefix}id" => [ \$query{not_customized}  ],
+            \$qry_config,
+          ]
+        ],
+      );
+
+      return @result;
+    }
+  );
+}
+
 1;
 
 __END__
@@ -371,6 +465,18 @@ some way then you have to call this function manually. For example:
 
 =back
 
+=head1 INSTALLED MANAGER METHODS
+
+=over 4
+
+=item Custom filter for GetModels
+
+If the Manager for the calling C<SL::DB::Object> has included the helper L<SL::DB::Helper::Filtered>, a custom filter for cvars will be added to the specs, with the following syntax:
+
+  filter.cvar.$config_id
+
+=back
+
 =head1 AUTHOR
 
 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>,