Verwaltung von benutzerdefinierten Variablen auf Controller umgestellt
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 24 May 2013 12:12:27 +0000 (14:12 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 24 Jun 2013 14:45:38 +0000 (16:45 +0200)
16 files changed:
SL/CVar.pm
SL/Controller/CustomVariableConfig.pm
SL/DB/CustomVariableConfig.pm
SL/DB/Manager/CustomVariableConfig.pm [new file with mode: 0644]
amcvar.pl [deleted symlink]
bin/mozilla/amcvar.pl [deleted file]
css/kivitendo/main.css
css/lx-office-erp/main.css
js/locale/de.js
locale/de/all
menu.ini
scripts/mklinks.sh [deleted file]
templates/webpages/amcvar/display_cvar_config_form.html [deleted file]
templates/webpages/amcvar/list_cvar_configs.html [deleted file]
templates/webpages/custom_variable_config/form.html [new file with mode: 0644]
templates/webpages/custom_variable_config/list.html [new file with mode: 0644]

index 02456cb..d023081 100644 (file)
@@ -64,30 +64,6 @@ SQL
   return $::form->{CVAR_CONFIGS}->{$params{module}};
 }
 
-sub get_config {
-  $main::lxdebug->enter_sub();
-
-  my $self     = shift;
-  my %params   = @_;
-
-  Common::check_params(\%params, qw(id));
-
-  my $myconfig = \%main::myconfig;
-  my $form     = $main::form;
-
-  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
-
-  my $query    = qq|SELECT * FROM custom_variable_configs WHERE id = ?|;
-
-  my $config   = selectfirst_hashref_query($form, $dbh, $query, conv_i($params{id})) || { };
-
-  $self->_unpack_flags($config);
-
-  $main::lxdebug->leave_sub();
-
-  return $config;
-}
-
 sub _unpack_flags {
   $main::lxdebug->enter_sub();
 
@@ -105,96 +81,6 @@ sub _unpack_flags {
   $main::lxdebug->leave_sub();
 }
 
-sub save_config {
-  $main::lxdebug->enter_sub();
-
-  my $self     = shift;
-  my %params   = @_;
-
-  Common::check_params(\%params, qw(module config));
-
-  my $myconfig = \%main::myconfig;
-  my $form     = $main::form;
-
-  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
-
-  my $q_id     = qq|SELECT nextval('custom_variable_configs_id')|;
-  my $h_id     = prepare_query($form, $dbh, $q_id);
-
-  my $q_new    =
-    qq|INSERT INTO custom_variable_configs (name, description, type, default_value, options, searchable, includeable, included_by_default, module, flags, id, sortkey)
-       VALUES                              (?,    ?,           ?,    ?,             ?,       ?,          ?,           ?,                   ?,      ?,     ?,
-         (SELECT COALESCE(MAX(sortkey) + 1, 1) FROM custom_variable_configs))|;
-  my $h_new    = prepare_query($form, $dbh, $q_new);
-
-  my $q_update =
-    qq|UPDATE custom_variable_configs SET
-         name        = ?, description         = ?,
-         type        = ?, default_value       = ?,
-         options     = ?, searchable          = ?,
-         includeable = ?, included_by_default = ?,
-         module      = ?, flags               = ?
-       WHERE id  = ?|;
-  my $h_update = prepare_query($form, $dbh, $q_update);
-
-  my @configs;
-  if ('ARRAY' eq ref $params{config}) {
-    @configs = @{ $params{config} };
-  } else {
-    @configs = ($params{config});
-  }
-
-  foreach my $config (@configs) {
-    my ($h_actual, $q_actual);
-
-    if (!$config->{id}) {
-      do_statement($form, $h_id, $q_id);
-      ($config->{id}) = $h_id->fetchrow_array();
-
-      $h_actual       = $h_new;
-      $q_actual       = $q_new;
-
-    } else {
-      $h_actual       = $h_update;
-      $q_actual       = $q_update;
-    }
-
-    do_statement($form, $h_actual, $q_actual, @{$config}{qw(name description type default_value options)},
-                 $config->{searchable} ? 't' : 'f', $config->{includeable} ? 't' : 'f', $config->{included_by_default} ? 't' : 'f',
-                 $params{module}, $config->{flags}, conv_i($config->{id}));
-  }
-
-  $h_id->finish();
-  $h_new->finish();
-  $h_update->finish();
-
-  $dbh->commit();
-
-  $main::lxdebug->leave_sub();
-}
-
-sub delete_config {
-  $main::lxdebug->enter_sub();
-
-  my $self     = shift;
-  my %params   = @_;
-
-  Common::check_params(\%params, qw(id));
-
-  my $myconfig = \%main::myconfig;
-  my $form     = $main::form;
-
-  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
-
-  do_query($form, $dbh, qq|DELETE FROM custom_variables          WHERE config_id = ?|, conv_i($params{id}));
-  do_query($form, $dbh, qq|DELETE FROM custom_variables_validity WHERE config_id = ?|, conv_i($params{id}));
-  do_query($form, $dbh, qq|DELETE FROM custom_variable_configs   WHERE id        = ?|, conv_i($params{id}));
-
-  $dbh->commit();
-
-  $main::lxdebug->leave_sub();
-}
-
 sub get_custom_variables {
   $main::lxdebug->enter_sub();
 
@@ -768,10 +654,6 @@ SL::CVar.pm - Custom Variables module
   # dealing with configs
 
   my $all_configs = CVar->get_configs()
-  my $config      = CVar->get_config(id => '1234')
-
-  CVar->save_config($config);
-  CVar->delete->config($config)
 
   # dealing with custom vars
 
index 6f29f52..d87b8ac 100644 (file)
@@ -4,14 +4,100 @@ use strict;
 
 use parent qw(SL::Controller::Base);
 
+use List::Util qw(first);
+
 use SL::DB::CustomVariableConfig;
+use SL::Helper::Flash;
+use SL::Locale::String;
+
+use Rose::Object::MakeMethods::Generic (
+  scalar                  => [ qw(config module module_description flags) ],
+  'scalar --get_set_init' => [ qw(translated_types modules) ],
+);
 
 __PACKAGE__->run_before('check_auth');
+__PACKAGE__->run_before('check_module');
+__PACKAGE__->run_before('load_config', only => [ qw(edit update destroy) ]);
+
+our %translations = (
+  text      => t8('Free-form text'),
+  textfield => t8('Text field'),
+  number    => t8('Number'),
+  date      => t8('Date'),
+  timestamp => t8('Timestamp'),
+  bool      => t8('Yes/No (Checkbox)'),
+  select    => t8('Selection'),
+  customer  => t8('Customer'),
+  vendor    => t8('Vendor'),
+  part      => t8('Part'),
+);
+
+our @types = qw(text textfield number date bool select customer vendor part); # timestamp
 
 #
 # actions
 #
 
+sub action_list {
+  my ($self) = @_;
+
+  my $configs = SL::DB::Manager::CustomVariableConfig->get_all_sorted(where => [ module => $self->module ]);
+
+  $::form->header;
+  $self->render('custom_variable_config/list',
+                title   => t8('List of custom variables'),
+                CONFIGS => $configs);
+}
+
+sub action_new {
+  my ($self) = @_;
+
+  $self->config(SL::DB::CustomVariableConfig->new(module => $self->module));
+  $self->show_form(title => t8('Add custom variable'));
+}
+
+sub show_form {
+  my ($self, %params) = @_;
+
+  $self->flags([
+    map { split m/=/, 2 }
+    split m/;/, ($self->config->flags || '')
+  ]);
+
+  $::request->layout->focus('#config_name');
+  $self->render('custom_variable_config/form', %params);
+}
+
+sub action_edit {
+  my ($self) = @_;
+
+  $self->show_form(title => t8('Edit custom variable'));
+}
+
+sub action_create {
+  my ($self) = @_;
+
+  $self->config(SL::DB::CustomVariableConfig->new);
+  $self->create_or_update;
+}
+
+sub action_update {
+  my ($self) = @_;
+  $self->create_or_update;
+}
+
+sub action_destroy {
+  my ($self) = @_;
+
+  if (eval { $self->config->delete; 1; }) {
+    flash_later('info',  t8('The custom variable has been deleted.'));
+  } else {
+    flash_later('error', t8('The custom variable is in use and cannot be deleted.'));
+  }
+
+  $self->redirect_to(action => 'list');
+}
+
 sub action_reorder {
   my ($self) = @_;
 
@@ -28,4 +114,75 @@ sub check_auth {
   $::auth->assert('config');
 }
 
+sub check_module {
+  my ($self)          = @_;
+
+  $::form->{module} ||= 'CT';
+  my $mod_desc        = first { $_->{module} eq $::form->{module} } @{ $self->modules };
+  die "Invalid 'module' parameter '" . $::form->{module} . "'" if !$mod_desc;
+
+  $self->module($mod_desc->{module});
+  $self->module_description($mod_desc->{description});
+}
+
+sub load_config {
+  my ($self) = @_;
+
+  $self->config(SL::DB::CustomVariableConfig->new(id => $::form->{id})->load);
+}
+
+#
+# helpers
+#
+
+sub get_translation {
+  my ($self, $type) = @_;
+
+  return $translations{$type};
+}
+
+sub init_translated_types {
+  my ($self) = @_;
+
+  return [ map { { type => $_, translation => $translations{$_} } } @types ];
+}
+
+sub init_modules {
+  my ($self, %params) = @_;
+
+  return [
+    { module => 'CT',       description => t8('Customers and vendors')          },
+    { module => 'Contacts', description => t8('Contact persons')                },
+    { module => 'IC',       description => t8('Parts, services and assemblies') },
+    { module => 'Projects', description => t8('Projects')                       },
+  ];
+}
+
+sub create_or_update {
+  my ($self) = @_;
+  my $is_new = !$self->config->id;
+
+  my $params = delete($::form->{config}) || { };
+  delete $params->{id};
+
+  $params->{default_value}       = $::form->parse_amount(\%::myconfig, $params->{default_value}) if $params->{type} eq 'number';
+  $params->{included_by_default} = 0                                                             if !$params->{includeable};
+  $params->{flags}               = join ':', map { m/^flag_(.*)/; "${1}=" . delete($params->{$_}) } grep { m/^flag_/ } keys %{ $params };
+
+  $self->config->assign_attributes(%{ $params }, module => $self->module);
+
+  my @errors = $self->config->validate;
+
+  if (@errors) {
+    flash('error', @errors);
+    $self->show_form(title => $is_new ? t8('Add new custom variable') : t8('Edit custom variable'));
+    return;
+  }
+
+  $self->config->save;
+
+  flash_later('info', $is_new ? t8('The custom variable has been created.') : t8('The custom variable has been saved.'));
+  $self->redirect_to(action => 'list', module => $self->module);
+}
+
 1;
index 5823e9b..6c836f0 100644 (file)
@@ -6,9 +6,21 @@ package SL::DB::CustomVariableConfig;
 use strict;
 
 use SL::DB::MetaSetup::CustomVariableConfig;
+use SL::DB::Manager::CustomVariableConfig;
 use SL::DB::Helper::ActsAsList;
 
-# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
-__PACKAGE__->meta->make_manager_class;
+__PACKAGE__->configure_acts_as_list(group_by => [qw(module)]);
+
+sub validate {
+  my ($self) = @_;
+
+  my @errors;
+  push @errors, $::locale->text('The name is missing.')        if !$self->name;
+  push @errors, $::locale->text('The description is missing.') if !$self->description;
+  push @errors, $::locale->text('The type is missing.')        if !$self->type;
+  push @errors, $::locale->text('The option field is empty.')  if (($self->type || '') eq 'select') && !$self->options;
+
+  return @errors;
+}
 
 1;
diff --git a/SL/DB/Manager/CustomVariableConfig.pm b/SL/DB/Manager/CustomVariableConfig.pm
new file mode 100644 (file)
index 0000000..1def3c8
--- /dev/null
@@ -0,0 +1,20 @@
+package SL::DB::Manager::CustomVariableConfig;
+
+use strict;
+
+use SL::DB::Helper::Manager;
+use base qw(SL::DB::Helper::Manager);
+
+use SL::DB::Helper::Paginated;
+use SL::DB::Helper::Sorted;
+
+sub object_class { 'SL::DB::CustomVariableConfig' }
+
+__PACKAGE__->make_manager_methods;
+
+sub _sort_spec {
+  return ( default => [ 'sortkey', 1 ],
+           columns => { SIMPLE => 'ALL' } );
+}
+
+1;
diff --git a/amcvar.pl b/amcvar.pl
deleted file mode 120000 (symlink)
index 385000d..0000000
--- a/amcvar.pl
+++ /dev/null
@@ -1 +0,0 @@
-am.pl
\ No newline at end of file
diff --git a/bin/mozilla/amcvar.pl b/bin/mozilla/amcvar.pl
deleted file mode 100644 (file)
index 343350a..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#=====================================================================
-# LX-Office ERP
-# Copyright (C) 2004
-# Based on SQL-Ledger Version 2.1.9
-# Web http://www.lx-office.org
-#
-#=====================================================================
-# SQL-Ledger Accounting
-# Copyright (c) 1998-2002
-#
-#  Author: Dieter Simader
-#   Email: dsimader@sql-ledger.org
-#     Web: http://www.sql-ledger.org
-#
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#======================================================================
-#
-# administration
-#
-#======================================================================
-
-use SL::AM;
-use SL::CVar;
-use SL::Form;
-
-use Data::Dumper;
-use List::MoreUtils qw(any);
-
-require "bin/mozilla/common.pl";
-
-use strict;
-
-1;
-
-# end of main
-
-my $locale   = $main::locale;
-our %translations = ('text'      => $locale->text('Free-form text'),
-                     'textfield' => $locale->text('Text field'),
-                     'number'    => $locale->text('Number'),
-                     'date'      => $locale->text('Date'),
-                     'timestamp' => $locale->text('Timestamp'),
-                     'bool'      => $locale->text('Yes/No (Checkbox)'),
-                     'select'    => $locale->text('Selection'),
-                     'customer'  => $locale->text('Customer'),
-                     'vendor'    => $locale->text('Vendor'),
-                     'part'      => $locale->text('Part'),
-                     );
-
-our @types = qw(text textfield number date bool select customer vendor part); # timestamp
-
-our @modules = ({ module => 'CT',       description => $locale->text('Customers and vendors')          },
-                { module => 'Contacts', description => $locale->text('Contact persons')                },
-                { module => 'IC',       description => $locale->text('Parts, services and assemblies') },
-                { module => 'Projects', description => $locale->text('Projects')                       },
-               );
-
-sub add {
-  add_cvar_config();
-}
-
-sub edit {
-  edit_cvar_config();
-}
-
-sub _is_valid_module {
-  my $module = shift;
-
-  return any { $_->{module} eq $module } @modules;
-}
-
-sub list_cvar_configs {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my $locale   = $main::locale;
-
-  $main::auth->assert('config');
-
-  $form->{module} = $form->{module} || $form->{cvar_module} || 'CT';
-  $form->{module} = 'CT' unless _is_valid_module($form->{module});
-
-  my @configs = @{ CVar->get_configs(module => $form->{module}) };
-
-  foreach my $config (@configs) {
-    $config->{type_tr} = $translations{$config->{type}};
-  }
-
-  $form->{title} = $locale->text('List of custom variables');
-  $form->header();
-  print $form->parse_html_template('amcvar/list_cvar_configs', { CONFIGS => \@configs,
-                                                                 MODULES => \@modules });
-
-#  $main::lxdebug->dump(0, "modules", \@modules);
-
-  $main::lxdebug->leave_sub();
-}
-
-sub add_cvar_config {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-
-  $main::auth->assert('config');
-
-  $form->{module} = $form->{module} || $form->{cvar_module} || 'CT';
-
-  $form->{edit} = 0;
-  display_cvar_config_form();
-
-  $main::lxdebug->leave_sub();
-}
-
-sub edit_cvar_config {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-
-  $main::auth->assert('config');
-
-  my $config = CVar->get_config('id' => $form->{id});
-
-  map { $form->{$_} = $config->{$_} } keys %{ $config };
-
-  $form->{edit} = 1;
-  display_cvar_config_form();
-
-  $main::lxdebug->leave_sub();
-}
-
-sub save {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-
-  $main::auth->assert('config');
-
-  $form->isblank('name',        $locale->text('The name is missing.'));
-  $form->isblank('description', $locale->text('The description is missing.'));
-  $form->isblank('options',     $locale->text('The option field is empty.')) if ($form->{type} eq 'select');
-
-  if ($form->{name} !~ /^[a-z][a-z0-9_]*$/i) {
-    $form->error($locale->text('The name must only consist of letters, numbers and underscores and start with a letter.'));
-  }
-
-  if (($form->{type} eq 'number') && ($form->{default_value} ne '')) {
-    $form->{default_value} = $form->parse_amount(\%myconfig, $form->{default_value});
-  }
-
-  $form->{included_by_default} = $form->{inclusion} eq 'yes_default_on';
-  $form->{includeable}         = $form->{inclusion} ne 'no';
-  $form->{flags}               = join ':', map { m/^flag_(.*)/; "${1}=" . $form->{$_} } grep { m/^flag_/ } keys %{ $form };
-
-  CVar->save_config('module' => $form->{module},
-                    'config' => $form);
-
-  $form->{MESSAGE} = $locale->text('The custom variable has been saved.');
-
-  list_cvar_configs();
-
-  $main::lxdebug->leave_sub();
-}
-
-sub delete {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my $locale   = $main::locale;
-
-  CVar->delete_config('id' => $form->{id});
-
-  $form->{MESSAGE} = $locale->text('The custom variable has been deleted.');
-
-  list_cvar_configs();
-
-  $main::lxdebug->leave_sub();
-}
-
-sub display_cvar_config_form {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-
-  $main::auth->assert('config');
-
-  my @types = map { { 'type' => $_, 'type_tr' => $translations{$_} } } @types;
-
-  if (($form->{type} eq 'number') && ($form->{default_value} ne '')) {
-    $form->{default_value} = $form->format_amount(\%myconfig, $form->{default_value});
-  }
-
-  $form->{title} = $form->{edit} ? $locale->text("Edit custom variable") : $locale->text("Add custom variable");
-
-  $form->header();
-  print $form->parse_html_template("amcvar/display_cvar_config_form", { TYPES   => \@types,
-                                                                        MODULES => \@modules });
-
-  $main::lxdebug->leave_sub();
-}
-
-sub update {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-
-  $main::auth->assert('config');
-
-  $form->{included_by_default} = $form->{inclusion} eq 'yes_default_on';
-  $form->{includeable}         = $form->{inclusion} ne 'no';
-
-  display_cvar_config_form();
-
-  $main::lxdebug->leave_sub();
-}
-
-
-sub dispatcher {
-  my $form     = $main::form;
-  my $locale   = $main::locale;
-
-  foreach my $action (qw(list_cvar_configs add_cvar_config update)) {
-    if ($form->{"action_${action}"}) {
-      call_sub($action);
-      return;
-    }
-  }
-
-  $form->error($locale->text('No action defined.'));
-}
-
-1;
-
index 9e55c4e..e6cd0a6 100644 (file)
@@ -376,3 +376,7 @@ label {
   margin-left: 6px;
   margin-right: 6px;
 }
+
+.small-text {
+  font-size: 0.75em;
+}
index 27a3aa2..067d71d 100644 (file)
@@ -428,3 +428,7 @@ label {
   margin-left: 6px;
   margin-right: 6px;
 }
+
+.small-text {
+  font-size: 0.75em;
+}
index ccba6a3..c452769 100644 (file)
@@ -1,2 +1,6 @@
 namespace("kivi").setupLocale({
+"The description is missing.":"Die Beschreibung fehlt.",
+"The name is missing.":"Der Name fehlt.",
+"The name must only consist of letters, numbers and underscores and start with a letter.":"Der Name darf nur aus Buchstaben (keine Umlaute), Ziffern und Unterstrichen bestehen und muss mit einem Buchstaben beginnen.",
+"The option field is empty.":"Das Optionsfeld ist leer."
 });
index 7a9b168..640d895 100755 (executable)
@@ -164,6 +164,7 @@ $self->{texts} = {
   'Add link: select records to link with' => 'Verknüpfungen hinzufügen: zu verknüpfende Belege auswählen',
   'Add links'                   => 'Verknüpfungen hinzufügen',
   'Add new currency'            => 'Neue Währung hinzufügen',
+  'Add new custom variable'     => 'Neue benutzerdefinierte Variable erfassen',
   'Add note'                    => 'Notiz erfassen',
   'Add printer'                 => 'Drucker hinzufügen',
   'Add unit'                    => 'Einheit hinzuf&uuml;gen',
@@ -1052,6 +1053,7 @@ $self->{texts} = {
   'Include in drop-down menus'  => 'In Aufklappmenü aufnehmen',
   'Include invalid warehouses ' => 'Ungültige Lager berücksichtigen',
   'Includeable in reports'      => 'In Berichten anzeigbar',
+  'Included in reports by default' => 'In Berichten standardmäßig enthalten',
   'Including'                   => 'Enthaltene',
   'Income Statement'            => 'GuV',
   'Incoming Payments'           => 'Zahlungseingänge',
@@ -1996,8 +1998,10 @@ $self->{texts} = {
   'The connection was established successfully.' => 'Die Verbindung zur Datenbank wurde erfolgreich hergestellt.',
   'The contact person attribute "birthday" is converted from a free-form text field into a date field.' => 'Das Kontaktpersonenfeld "Geburtstag" wird von einem freien Textfeld auf ein Datumsfeld umgestellt.',
   'The creation of the authentication database failed:' => 'Das Anlegen der Authentifizierungsdatenbank schlug fehl:',
+  'The custom variable has been created.' => 'Die benutzerdefinierte Varieble wurde erfasst.',
   'The custom variable has been deleted.' => 'Die benutzerdefinierte Variable wurde gel&ouml;scht.',
   'The custom variable has been saved.' => 'Die benutzerdefinierte Variable wurde gespeichert.',
+  'The custom variable is in use and cannot be deleted.' => 'Die benutzerdefinierte Variable ist in Benutzung und kann nicht gelöscht werden.',
   'The database for user management and authentication does not exist. You can create let kivitendo create it with the following parameters:' => 'Die Datenbank für die Benutzeranmeldung existiert nicht. Sie können Sie von kivitendo automatisch mit den folgenden Parametern anlegen lassen:',
   'The database host is missing.' => 'Der Datenbankhost fehlt.',
   'The database name is missing.' => 'Der Datenbankname fehlt.',
@@ -2107,6 +2111,7 @@ $self->{texts} = {
   'The third way is to download the module from the above mentioned URL and to install the module manually following the installations instructions contained in the source archive.' => 'Die dritte Variante besteht darin, das Paket von der oben genannten URL herunterzuladen und es manuell zu installieren. Beachten Sie dabei die im Paket enthaltenen Installationsanweisungen.',
   'The three columns "make_X", "model_X" and "lastcost_X" with the same number "X" are used to import vendor part numbers and vendor prices.' => 'Die drei Spalten "make_X", "model_X" und "lastcost_X" mit derselben Nummer "X" werden zum Import von Lieferantenartikelnummern und -preisen genutzt.',
   'The transaction is shown below in its current state.' => 'Nachfolgend wird angezeigt, wie die Buchung momentan aussieht.',
+  'The type is missing.'        => 'Der Typ fehlt.',
   'The unit has been saved.'    => 'Die Einheit wurde gespeichert.',
   'The unit in row %d has been deleted in the meantime.' => 'Die Einheit in Zeile %d ist in der Zwischentzeit gel&ouml;scht worden.',
   'The unit in row %d has been used in the meantime and cannot be changed anymore.' => 'Die Einheit in Zeile %d wurde in der Zwischenzeit benutzt und kann nicht mehr ge&auml;ndert werden.',
index 6f00c8c..73ac2d0 100644 (file)
--- a/menu.ini
+++ b/menu.ini
@@ -598,8 +598,8 @@ module=controller.pl
 action=PaymentTerm/list
 
 [System--Manage Custom Variables]
-module=amcvar.pl
-action=list_cvar_configs
+module=controller.pl
+action=CustomVariableConfig/list
 
 [System--Warehouses]
 module=am.pl
diff --git a/scripts/mklinks.sh b/scripts/mklinks.sh
deleted file mode 100755 (executable)
index 3fab3bd..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-for i in am dispatcher login; do
-       rm $i.pl 2> /dev/null
-       ln -s admin.pl $i.pl
-done
-for i in acctranscorrections amcvar amtemplates ap ar bankaccounts bp ca common cp ct datev dn do fu gl ic ir is menujs menunew menu menuv3 menuv4 oe pe projects rc rp sepa todo ustva wh vk; do
-       rm $i.pl 2> /dev/null
-       ln -s am.pl $i.pl
-done
-rm generictranslations.pl licenses.pl 2> /dev/null
-ln -s common.pl generictranslations.pl
-rm dispatcher.fcgi 2> /dev/null
-ln -s dispatcher.fpl dispatcher.fcgi
diff --git a/templates/webpages/amcvar/display_cvar_config_form.html b/templates/webpages/amcvar/display_cvar_config_form.html
deleted file mode 100644 (file)
index 6c2ebe1..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-[%- USE T8 %]
-[%- USE HTML %]
-  <script type='text/javascript'>
-    $(function(){document.Form.name.focus();});
-  </script>
-
- <style type="text/css">
-  .small {
-    font-size: 0.75em;
-  }
- </style>
-
- <div class="listtop">[% title %]</div>
-
- <form action="amcvar.pl" name="Form" method="post">
-
-  <p>
-   <table>
-    <tr>
-     <td align="right">[% 'Module' | $T8 %]</td>
-     <td>
-      [%- INCLUDE generic/multibox.html
-            name      = 'module',
-            id_key    = 'module',
-            label_key = 'description',
-            DATA      = MODULES,
-            onChange   = "document.getElementById('update_button').click();" %]
-     </td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Variable Name' | $T8 %]<sup><span class="small">(1)</span></sup></td>
-     <td><input name="name" value="[% HTML.escape(name) %]"></td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Variable Description' | $T8 %]<sup><span class="small">(2)</span></sup></td>
-     <td><input name="description" value="[% HTML.escape(description) %]"></td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Type' | $T8 %]<sup><span class="small">(3)</span></sup></td>
-     <td>
-      <select name="type">
-       [%- FOREACH row = TYPES %]
-       <option value="[% HTML.escape(row.type) %]"[% IF row.type == type %] selected[% END %]>[% HTML.escape(row.type_tr) %]</option>
-       [%- END %]
-      </select>
-     </td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Default value' | $T8 %]<sup><span class="small">(4)</span></sup></td>
-     <td><input name="default_value" value="[% HTML.escape(default_value) %]"></td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Options' | $T8 %]<sup><span class="small">(5)</span></sup></td>
-     <td><input name="options" value="[% HTML.escape(options) %]"></td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Is Searchable' | $T8 %]<sup><span class="small"></span></sup></td>
-     <td>
-      <input type="radio" name="searchable" id="searchable_1" value="1"[% IF searchable %] checked[% END %]>
-      <label for="searchable_1">[% 'Yes' | $T8 %]</label>
-      <input type="radio" name="searchable" id="searchable_0" value="0"[% UNLESS searchable %] checked[% END %]>
-      <label for="searchable_0">[% 'No' | $T8 %]</label>
-     </td>
-    </tr>
-
-    <tr>
-     <td align="right">[% 'Includeable in reports' | $T8 %]<sup><span class="small"></span></sup></td>
-     <td>
-      <select name="inclusion">
-       <option value="no"[% UNLESS includeable %] selected[% END %]>[% 'No' | $T8 %]</option>
-       <option value="yes"[% IF includeable && !included_by_default %] selected[% END %]>[% 'Yes' | $T8 %]</option>
-       <option value="yes_default_on"[% IF included_by_default %] selected[% END %]>[% 'Yes, included by default' | $T8 %]</option>
-      </select>
-     </td>
-    </tr>
-
-    [%- IF module == 'IC' %]
-    <tr>
-     <td align="right">[% 'Editable' | $T8 %]<sup><span class="small">(5)</span></sup></td>
-     <td>
-      <input type="radio" name="flag_editable" id="flag_editable_1" value="1"[% IF flag_editable %] checked[% END %]>
-      <label for="flag_editable_1">[% 'Yes' | $T8 %]</label>
-      <input type="radio" name="flag_editable" id="flag_editable_0" value="0"[% UNLESS flag_editable %] checked[% END %]>
-      <label for="flag_editable_0">[% 'No' | $T8 %]</label>
-     </td>
-    </tr>
-    [%- END %]
-   </table>
-  </p>
-
-  <input type="hidden" name="id" value="[% HTML.escape(id) %]">
-
-  <p>
-   <input type="submit" name="action" id="update_button" value="[% 'Update' | $T8 %]">
-   <input type="submit" name="action" value="[% 'Save' | $T8 %]">
-   [%- IF id %]
-   <input type="submit" name="action" value="[% 'Delete' | $T8 %]">
-   [%- END %]
-  </p>
-
-  <hr>
-
-  <h3>[% 'Annotations' | $T8 %]</h3>
-
-  <p>
-   (1) [% 'The variable name must only consist of letters, numbers and underscores. It must begin with a letter. Example: send_christmas_present' | $T8 %]
-  </p>
-
-  <p>
-   (2) [% 'The description is shown on the form. Chose something short and descriptive.' | $T8 %]
-  </p>
-  <p>
-   (3) [% 'For type "customer" the perl module JSON is required. Please check this on system level: $ ./scripts/installation_check.pl' | $T8 %]
-  </p>
-
-  <p>
-   (4) [% 'The default value depends on the variable type:' | $T8 %]
-   <br>
-   <ul>
-    <li>[%- 'Text, text field and number variables: The default value will be used as-is.' | $T8 %]</li>
-    <li>[%- 'Boolean variables: If the default value is non-empty then the checkbox will be checked by default and unchecked otherwise.' | $T8 %]</li>
-    <li>[%- 'Date and timestamp variables: If the default value equals \'NOW\' then the current date/current timestamp will be used. Otherwise the default value is copied as-is.' | $T8 %]</li>
-   </ul>
-  </p>
-
-  <p>
-   (5) [% 'The available options depend on the varibale type:' | $T8 %]
-   <br>
-   <ul>
-    <li>[%- 'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' | $T8 %]</li>
-    <li>[%- 'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' | $T8 %]</li>
-    <li>[%- 'Number variables: \'PRECISION=n\' forces numbers to be shown with exactly n decimal places.' | $T8 %]</li>
-    <li>[%- 'Selection fields: The option field must contain the available options for the selection. Options are separated by \'##\', for example \'Early##Normal##Late\'.' | $T8 %]</li>
-   </ul>
-   <br>
-   [% 'Other values are ignored.' | $T8 %]
-  </p>
-
-  [%- IF module == 'IC' %]
-  <p>
-   (6)
-
-   [%- 'A variable marked as \'editable\' can be changed in each quotation, order, invoice etc.' | $T8 %]
-
-   [% 'Otherwise the variable is only available for printing.' | $T8 %]
-  </p>
-  [%- END %]
-
- </form>
-
diff --git a/templates/webpages/amcvar/list_cvar_configs.html b/templates/webpages/amcvar/list_cvar_configs.html
deleted file mode 100644 (file)
index b3631e3..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-[%- USE T8 %][% USE LxERP %][% USE L %]
-[% USE HTML %]
-
- [% IF MESSAGE %]<p>[% MESSAGE %]</p>[% END %]
-
- <div class="listtop">[% title %]</div>
-
- <form method="post" action="amcvar.pl">
-  <input type="hidden" name="action" value="dispatcher">
-  <input type="hidden" name="callback" value="[% HTML.escape(callback) %]">
-
-  <p>
-   [% 'Custom variables for module' | $T8 %]
-   [%- INCLUDE generic/multibox.html
-         name      = 'module',
-         id_key    = 'module',
-         label_key = 'description',
-         DATA      = MODULES %]
-   <input type="submit" class="submit" name="action_list_cvar_configs" value="[% 'Show' | $T8 %]">
-  </p>
-
-  <p>
-   <table width="100%" id="cvarcfg_list">
-    <thead>
-    <tr class="listheading">
-     <th align="center"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></th>
-     <th width="20%">[% 'Name' | $T8 %]</th>
-     <th width="20%">[% 'Description' | $T8 %]</th>
-     <th width="20%">[% 'Type' | $T8 %]</th>
-     <th width="20%">[% 'Searchable' | $T8 %]</th>
-     <th width="20%">[% 'Includeable in reports' | $T8 %]</th>
-     [%- IF module == 'IC' %]
-     <th width="20%">[% 'Editable' | $T8 %]</th>
-     [%- END %]
-    </tr>
-    </thead>
-
-    <tbody>
-    [%- FOREACH cfg = CONFIGS %]
-    <tr class="listrow[% loop.count % 2 %]" id="cvarcfg_id_[% cfg.id %]">
-     <td align="center" class="dragdrop"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></td>
-
-     <td>
-      <a href="amcvar.pl?action=edit_cvar_config&module=[% HTML.url(module) %]&id=[% HTML.url(cfg.id) %]&callback=[% HTML.url(callback) %]">
-       [% HTML.escape(cfg.name) %]
-      </a>
-     </td>
-
-     <td>[% HTML.escape(cfg.description) %]</td>
-     <td>[% HTML.escape(cfg.type_tr) %]</td>
-
-     <td>
-      [%- IF cfg.searchable %]
-      [% 'Yes' | $T8 %]
-      [%- ELSE %]
-      [% 'No' | $T8 %]
-      [%- END %]
-     </td>
-
-     <td>
-      [%- IF cfg.included_by_default %]
-      [% 'Yes, included by default' | $T8 %]
-      [%- ELSIF cfg.includeable %]
-      [% 'Yes' | $T8 %]
-      [%- ELSE %]
-      [% 'No' | $T8 %]
-      [%- END %]
-     </td>
-
-     [%- IF module == 'IC' %]
-     <td>
-      [%- IF cfg.flag_editable %]
-      [% 'Yes' | $T8 %]
-      [%- ELSE %]
-      [% 'No' | $T8 %]
-      [%- END %]
-     </td>
-     [%- END %]
-    </tr>
-    [%- END %]
-    </tbody>
-   </table>
-  </p>
-
-  <hr height="3">
-
-  <p>
-   <a href="amcvar.pl?action=add_cvar_config&callback=[% HTML.url(callback) %]">[%- 'Add' | $T8 %]</a>
-  </p>
- </form>
-
- [% L.sortable_element('#cvarcfg_list tbody', url => 'controller.pl?action=CustomVariableConfig/reorder', with => 'cvarcfg_id') %]
diff --git a/templates/webpages/custom_variable_config/form.html b/templates/webpages/custom_variable_config/form.html
new file mode 100644 (file)
index 0000000..f29a3d8
--- /dev/null
@@ -0,0 +1,165 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]<h1>[% HTML.escape(title) %]</h1>
+
+<form action="controller.pl" method="post">
+ [%- L.hidden_tag("id", SELF.config.id) %]
+
+ <p>
+  <table>
+   <tr>
+    <td align="right">[% 'Module' | $T8 %]</td>
+    <td>[%- L.select_tag('module', SELF.modules, value_key='module', title_key='description', default=SELF.module, onchange="update_ic_rows();") %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Variable Name' | $T8 %]<sup><span class="small-text">(1)</span></sup></td>
+    <td>[%- L.input_tag("config.name", SELF.config.name) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Variable Description' | $T8 %]<sup><span class="small-text">(2)</span></sup></td>
+    <td>[%- L.input_tag("config.description", SELF.config.description) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Type' | $T8 %]<sup><span class="small-text">(3)</span></sup></td>
+    <td>[% L.select_tag("config.type", SELF.translated_types, value_key='type', title_key='translation', default=SELF.config.type) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Default value' | $T8 %]<sup><span class="small-text">(4)</span></sup></td>
+    <td>[%- L.input_tag("config.default_value", SELF.config.type == 'number' ? LxERP.format_amount(SELF.config.default_value, 2) : SELF.config.default_value) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Options' | $T8 %]<sup><span class="small-text">(5)</span></sup></td>
+    <td>[%- L.input_tag("config.options", SELF.config.options) %]</td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Is Searchable' | $T8 %]</td>
+    <td>
+     [% L.radio_button_tag('config.searchable', value='1', id='config_searchable_1', label=LxERP.t8('Yes'), checked=(SELF.config.searchable ?  1 : '')) %]
+     [% L.radio_button_tag('config.searchable', value='0', id='config_searchable_0', label=LxERP.t8('No'),  checked=(SELF.config.searchable ? '' :  1)) %]
+    </td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Includeable in reports' | $T8 %]</td>
+    <td>
+     [% L.radio_button_tag('config.includeable', value='1', id='config_includeable_1', label=LxERP.t8('Yes'), checked=(SELF.config.includeable ?  1 : ''), onclick='update_included_by_default()') %]
+     [% L.radio_button_tag('config.includeable', value='0', id='config_includeable_0', label=LxERP.t8('No'),  checked=(SELF.config.includeable ? '' :  1), onclick='update_included_by_default()') %]
+    </td>
+   </tr>
+
+   <tr>
+    <td align="right">[% 'Included in reports by default' | $T8 %]</td>
+    <td>
+     [% SET disabled = SELF.config.includeable ? '' : 'disabled' %]
+     [% L.radio_button_tag('config.included_by_default', value='1', id='config_included_by_default_1', label=LxERP.t8('Yes'), checked=(SELF.config.included_by_default ?  1 : ''), disabled=disabled) %]
+     [% L.radio_button_tag('config.included_by_default', value='0', id='config_included_by_default_0', label=LxERP.t8('No'),  checked=(SELF.config.included_by_default ? '' :  1), disabled=disabled) %]
+    </td>
+   </tr>
+
+   <tr data-show-for="IC"[% UNLESS SELF.module == 'IC' %] style="display: none;"[% END %]>
+    <td align="right">[% 'Editable' | $T8 %]<sup><span class="small-text">(6)</span></sup></td>
+    <td>
+     [% L.radio_button_tag('config.flag_editable', value='1', id='config.flag_editable_1', label=LxERP.t8('Yes'), checked=(SELF.flags.editable ?  1 : '')) %]
+     [% L.radio_button_tag('config.flag_editable', value='0', id='config.flag_editable_0', label=LxERP.t8('No'),  checked=(SELF.flags.editable ? '' :  1)) %]
+    </td>
+   </tr>
+  </table>
+ </p>
+
+ <p>
+  [% L.hidden_tag("action", "CustomVariableConfig/dispatch") %]
+  [% L.submit_tag("action_" _  (SELF.config.id ? "update" : "create"), LxERP.t8('Save'), onclick="return check_prerequisites();") %]
+  [%- IF SELF.config.id %]
+   [% L.submit_tag("action_create", LxERP.t8('Save as new'), onclick="return check_prerequisites();") %]
+   [% L.submit_tag("action_destroy", LxERP.t8('Delete'), confirm=LxERP.t8('Are you sure?')) %]
+  [%- END %]
+  <a href="[% SELF.url_for(action='list', module=SELF.module) %]">[%- LxERP.t8("Cancel") %]</a>
+ </p>
+
+ <hr>
+
+ <h3>[% 'Annotations' | $T8 %]</h3>
+
+ <p>
+  (1) [% 'The variable name must only consist of letters, numbers and underscores. It must begin with a letter. Example: send_christmas_present' | $T8 %]
+ </p>
+
+ <p>
+  (2) [% 'The description is shown on the form. Chose something short and descriptive.' | $T8 %]
+ </p>
+ <p>
+  (3) [% 'For type "customer" the perl module JSON is required. Please check this on system level: $ ./scripts/installation_check.pl' | $T8 %]
+ </p>
+
+ <p>
+  (4) [% 'The default value depends on the variable type:' | $T8 %]
+  <br>
+  <ul>
+   <li>[%- 'Text, text field and number variables: The default value will be used as-is.' | $T8 %]</li>
+   <li>[%- 'Boolean variables: If the default value is non-empty then the checkbox will be checked by default and unchecked otherwise.' | $T8 %]</li>
+   <li>[%- 'Date and timestamp variables: If the default value equals \'NOW\' then the current date/current timestamp will be used. Otherwise the default value is copied as-is.' | $T8 %]</li>
+  </ul>
+ </p>
+
+ <p>
+  (5) [% 'The available options depend on the varibale type:' | $T8 %]
+  <br>
+  <ul>
+   <li>[%- 'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' | $T8 %]</li>
+   <li>[%- 'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' | $T8 %]</li>
+   <li>[%- 'Number variables: \'PRECISION=n\' forces numbers to be shown with exactly n decimal places.' | $T8 %]</li>
+   <li>[%- 'Selection fields: The option field must contain the available options for the selection. Options are separated by \'##\', for example \'Early##Normal##Late\'.' | $T8 %]</li>
+  </ul>
+  <br>
+  [% 'Other values are ignored.' | $T8 %]
+ </p>
+
+ <p data-show-for="IC"[% UNLESS SELF.module == 'IC' %] style="display: none;"[% END %]>
+  (6)
+
+  [%- 'A variable marked as \'editable\' can be changed in each quotation, order, invoice etc.' | $T8 %]
+
+  [% 'Otherwise the variable is only available for printing.' | $T8 %]
+ </p>
+
+</form>
+
+<script type="text/javascript">
+<!--
+function update_included_by_default() {
+  $('INPUT[name="config.included_by_default"]').prop('disabled', !$('#config_includeable_1').prop('checked'));
+}
+
+function update_ic_rows() {
+  $('[data-show-for="IC"]').toggle($('#module').val() === "IC");
+}
+
+function check_prerequisites() {
+  if (($('#config_type').val() === "select") && ($('#config_options').val() === "")) {
+    alert(kivi.t8('The option field is empty.'));
+    return false;
+  }
+
+  if ($('#config_name').val() === "") {
+    alert(kivi.t8('The name is missing.'));
+    return false;
+  }
+
+  if (!$('#config_name').val().match(/^[a-z][a-z0-9_]*$/i)) {
+    alert(kivi.t8('The name must only consist of letters, numbers and underscores and start with a letter.'));
+    return false;
+  }
+
+  if ($('#config_description').val() === "") {
+    alert(kivi.t8('The description is missing.'));
+    return false;
+  }
+
+  return true;
+}
+-->
+</script>
diff --git a/templates/webpages/custom_variable_config/list.html b/templates/webpages/custom_variable_config/list.html
new file mode 100644 (file)
index 0000000..74f90a2
--- /dev/null
@@ -0,0 +1,63 @@
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%][%- INCLUDE 'common/flash.html' %]
+
+<h1>[% title %]</h1>
+
+<p>
+ [% 'Custom variables for module' | $T8 %]
+ [%- L.select_tag('module', SELF.modules, value_key='module', title_key='description', default=SELF.module, onchange='show_module_list()') %]
+</p>
+
+<p>
+ <table width="100%" id="cvarcfg_list">
+  <thead>
+   <tr class="listheading">
+    <th align="center"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></th>
+    <th width="20%">[% 'Name' | $T8 %]</th>
+    <th width="20%">[% 'Description' | $T8 %]</th>
+    <th width="20%">[% 'Type' | $T8 %]</th>
+    <th width="20%">[% 'Searchable' | $T8 %]</th>
+    <th width="20%">[% 'Includeable in reports' | $T8 %]</th>
+    [%- IF SELF.module == 'IC' %]
+     <th width="20%">[% 'Editable' | $T8 %]</th>
+    [%- END %]
+   </tr>
+  </thead>
+
+  <tbody>
+   [%- FOREACH cfg = CONFIGS %]
+    <tr class="listrow" id="cvarcfg_id_[% cfg.id %]">
+     <td align="center" class="dragdrop"><img src="image/updown.png" alt="[ LxERP.t8('reorder item') %]"></td>
+
+     <td><a href="[% SELF.url_for(action='edit', module=SELF.module, id=cfg.id) %]">[% HTML.escape(cfg.name) %]</a></td>
+
+     <td>[% HTML.escape(cfg.description) %]</td>
+     <td>[% HTML.escape(SELF.get_translation(cfg.type)) %]</td>
+
+     <td>[%- IF cfg.searchable %][% 'Yes' | $T8 %][%- ELSE %][% 'No' | $T8 %][%- END %]</td>
+
+     <td>[%- IF cfg.included_by_default %][% 'Yes, included by default' | $T8 %][%- ELSIF cfg.includeable %][% 'Yes' | $T8 %][%- ELSE %][% 'No' | $T8 %][%- END %]</td>
+
+     [%- IF SELF.module == 'IC' %]
+      <td>[%- IF cfg.flags.match('editable=1') %][% 'Yes' | $T8 %][%- ELSE %][% 'No' | $T8 %][%- END %]</td>
+     [%- END %]
+    </tr>
+    [%- END %]
+  </tbody>
+ </table>
+</p>
+
+<hr height="3">
+
+<p>
+ <a href="[% SELF.url_for(action='new', module=SELF.module) %]">[%- 'Add' | $T8 %]</a>
+</p>
+
+[% L.sortable_element('#cvarcfg_list tbody', url=SELF.url_for(action='reorder'), with='cvarcfg_id', params='"&module=" + encodeURIComponent($("#module").val())') %]
+
+<script type="text/javascript">
+<!--
+  function show_module_list() {
+    window.location.href = '[% SELF.url_for(action='list') %]&module=' + encodeURIComponent($('#module').val());
+  }
+-->
+</script>