+sub save_custom_variables_validity {
+  $main::lxdebug->enter_sub();
+
+  my $self     = shift;
+  my %params   = @_;
+
+  Common::check_params(\%params, qw(config_id trans_id validity));
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+  my (@where, @values);
+  add_token(\@where, \@values, col => "config_id", val => $params{config_id}, esc => \&conv_i);
+  add_token(\@where, \@values, col => "trans_id",  val => $params{trans_id},  esc => \&conv_i);
+
+  my $where = scalar @where ? "WHERE " . join ' AND ', @where : '';
+  my $query = qq|DELETE FROM custom_variables_validity $where|;
+
+  do_query($form, $dbh, $query, @values);
+
+  $query  =
+    qq|INSERT INTO custom_variables_validity (config_id, trans_id)
+       VALUES                                (?,         ?       )|;
+  my $sth = prepare_query($form, $dbh, $query);
+
+  unless ($params{validity}) {
+    foreach my $config_id (listify $params{config_id}) {
+      foreach my $trans_id (listify $params{trans_id}) {
+        do_statement($form, $sth, $query, conv_i($config_id), conv_i($trans_id));
+      }
+    }
+  }
+
+  $sth->finish();
+
+  $dbh->commit() unless $params{dbh};
+
+  $main::lxdebug->leave_sub();
+}
+
+sub get_custom_variables_validity {
+  $main::lxdebug->enter_sub(2);
+
+  my $self     = shift;
+  my %params   = @_;
+
+  Common::check_params(\%params, qw(config_id trans_id));
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+  my $query    = qq|SELECT COUNT(*) FROM custom_variables_validity WHERE config_id = ? AND trans_id = ?|;
+
+  my ($invalid) = selectfirst_array_query($form, $dbh, $query, conv_i($params{config_id}), conv_i($params{trans_id}));
+
+  $main::lxdebug->leave_sub(2);
+
+  return !$invalid;
+}
+
+sub custom_variables_validity_by_trans_id {
+  $main::lxdebug->enter_sub(2);
+
+  my $self     = shift;
+  my %params   = @_;
+
+  return sub { 0 } unless $params{trans_id};
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+  my $query    = qq|SELECT config_id, COUNT(*) FROM custom_variables_validity WHERE trans_id = ? GROUP BY config_id|;
+
+  my %invalids = selectall_as_map($form, $dbh, $query, 'config_id', 'count', $params{trans_id});
+
+  $main::lxdebug->leave_sub(2);
+
+  return sub { !$invalids{+shift} };
+}
+
+sub parse {
+  my ($self, $value, $config) = @_;
+
+  return $::form->parse_amount(\%::myconfig, $value)          if $config->{type} eq 'number';
+  return DateTime->from_lxoffice($value)                      if $config->{type} eq 'date';
+  return !ref $value ? SL::DB::Manager::Customer->find_by(id => $value * 1) : $value  if $config->{type} eq 'customer';
+  return $value;
+}
+
+sub format_to_template {
+  my ($self, $value, $config) = @_;
+  # stupid template expects everything formated. except objects
+  # do not use outside of print routines for legacy templates
+
+  return $::form->format_amount(\%::myconfig, $value) if $config->{type} eq 'number';
+  return $value->to_lxoffice if $config->{type} eq 'date' && blessed $value && $value->can('to_lxoffice');
+  return $value;
+}