Merge branch 'rb-wiederkehrende-rechnungen' into 263
authorMoritz Bunkus <m.bunkus@linet-services.de>
Wed, 19 Jan 2011 11:20:43 +0000 (12:20 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Wed, 19 Jan 2011 11:20:43 +0000 (12:20 +0100)
21 files changed:
SL/AM.pm
SL/Auth/PasswordPolicy.pm [new file with mode: 0644]
SL/CVar.pm
SL/DB/Helper/Manager.pm
SL/IC.pm
SL/IS.pm
bin/mozilla/admin.pl
bin/mozilla/am.pl
bin/mozilla/ar.pl
bin/mozilla/invoice_io.pl
bin/mozilla/io.pl
bin/mozilla/is.pl
bin/mozilla/oe.pl
config/lx-erp.conf
config/lx-erp.conf.default
config/lx_office.conf.default
doc/UPGRADE
doc/changelog
locale/de/all
scripts/locales.pl
sql/Pg-upgrade2/invalid_entries_in_custom_variables_validity.sql [new file with mode: 0644]

index df7d9d2..e6101b4 100644 (file)
--- a/SL/AM.pm
+++ b/SL/AM.pm
@@ -1410,7 +1410,7 @@ sub save_defaults {
 sub save_preferences {
   $main::lxdebug->enter_sub();
 
-  my ($self, $myconfig, $form, $webdav) = @_;
+  my ($self, $myconfig, $form) = @_;
 
   my $dbh = $form->get_standard_dbh($myconfig);
 
@@ -1438,16 +1438,6 @@ sub save_preferences {
 
   my $auth = $main::auth;
 
-  if ($auth->can_change_password()
-      && defined $form->{new_password}
-      && ($form->{new_password} ne '********')) {
-    $auth->change_password($form->{login}, $form->{new_password});
-
-    $form->{password} = $form->{new_password};
-    $auth->set_session_value('password', $form->{password});
-    $auth->create_or_refresh_session();
-  }
-
   $main::lxdebug->leave_sub();
 
   return $rc;
diff --git a/SL/Auth/PasswordPolicy.pm b/SL/Auth/PasswordPolicy.pm
new file mode 100644 (file)
index 0000000..3cf5c14
--- /dev/null
@@ -0,0 +1,179 @@
+package SL::Auth::PasswordPolicy;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use constant OK                   =>   0;
+use constant TOO_SHORT            =>   1;
+use constant TOO_LONG             =>   2;
+use constant MISSING_LOWERCASE    =>   4;
+use constant MISSING_UPPERCASE    =>   8;
+use constant MISSING_DIGIT        =>  16;
+use constant MISSING_SPECIAL_CHAR =>  32;
+use constant INVALID_CHAR         =>  64;
+use constant WEAK                 => 128;
+
+use Rose::Object::MakeMethods::Generic
+(
+ 'scalar --get_set_init' => 'config',
+);
+
+sub verify {
+  my ($self, $password, $is_admin) = @_;
+
+  my $cfg = $self->config;
+  return OK() unless $cfg && %{ $cfg };
+  return OK() if $is_admin && $cfg->{disable_policy_for_admin};
+
+  my $result = OK();
+  $result |= TOO_SHORT()            if $cfg->{min_length}                && (length($password) < $cfg->{min_length});
+  $result |= TOO_LONG()             if $cfg->{max_length}                && (length($password) > $cfg->{max_length});
+  $result |= MISSING_LOWERCASE()    if $cfg->{require_lowercase}         && $password !~ m/[a-z]/;
+  $result |= MISSING_UPPERCASE()    if $cfg->{require_uppercase}         && $password !~ m/[A-Z]/;
+  $result |= MISSING_DIGIT()        if $cfg->{require_digit}             && $password !~ m/[0-9]/;
+  $result |= MISSING_SPECIAL_CHAR() if $cfg->{require_special_character} && $password !~ $cfg->{special_characters_re};
+  $result |= INVALID_CHAR()         if $cfg->{invalid_characters_re}     && $password =~ $cfg->{invalid_characters_re};
+
+  if ($cfg->{use_cracklib}) {
+    require Crypt::Cracklib;
+    $result |= WEAK() if !Crypt::Cracklib::check($password);
+  }
+
+  return $result;
+}
+
+sub errors {
+  my ($self, $result) = @_;
+
+  my @errors;
+
+  push @errors, $::locale->text('The password is too short (minimum length: #1).', $self->config->{min_length}) if $result & TOO_SHORT();
+  push @errors, $::locale->text('The password is too long (maximum length: #1).',  $self->config->{max_length}) if $result & TOO_LONG();
+  push @errors, $::locale->text('A lower-case character is required.')                                          if $result & MISSING_LOWERCASE();
+  push @errors, $::locale->text('An upper-case character is required.')                                         if $result & MISSING_UPPERCASE();
+  push @errors, $::locale->text('A digit is required.')                                                         if $result & MISSING_DIGIT();
+  push @errors, $::locale->text('The password is weak (e.g. it can be found in a dictionary).')                 if $result & WEAK();
+
+  if ($result & MISSING_SPECIAL_CHAR()) {
+    my $char_list = join ' ', sort split(m//, $self->config->{special_characters});
+    push @errors, $::locale->text('A special character is required (valid characters: #1).', $char_list);
+  }
+
+  if (($result & INVALID_CHAR())) {
+    my $char_list = join ' ', sort split(m//, $self->config->{ $self->config->{invalid_characters} ? 'invalid_characters' : 'valid_characters' });
+    push @errors, $::locale->text('An invalid character was used (invalid characters: #1).', $char_list) if $self->config->{invalid_characters};
+    push @errors, $::locale->text('An invalid character was used (valid characters: #1).',   $char_list) if $self->config->{valid_characters};
+  }
+
+  return @errors;
+}
+
+
+sub init_config {
+  my ($self) = @_;
+
+  my %cfg = %{ $::emmvee_conf{password_policy} || {} };
+
+  $cfg{valid_characters}      =~ s/[ \n\r]//g if $cfg{valid_characters};
+  $cfg{invalid_characters}    =~ s/[ \n\r]//g if $cfg{invalid_characters};
+  $cfg{invalid_characters_re} =  '[^' . quotemeta($cfg{valid_characters})   . ']' if $cfg{valid_characters};
+  $cfg{invalid_characters_re} =  '['  . quotemeta($cfg{invalid_characters}) . ']' if $cfg{invalid_characters};
+  $cfg{special_characters}    =  '!@#$%^&*()_+=[]{}<>\'"|\\,;.:?-';
+  $cfg{special_characters_re} =  '[' . quotemeta($cfg{special_characters}) . ']';
+
+  map { $cfg{"require_${_}"} = $cfg{"require_${_}"} =~ m/^(?:1|true|t|yes|y)$/i } qw(lowercase uppercase digit special_char);
+
+  $self->config(\%cfg);
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Auth::PasswordPolicy - Verify a given password against the policy
+set in the configuration file
+
+=head1 SYNOPSIS
+
+ my $verifier = SL::Auth::PasswordPolicy->new;
+ my $result   = $verifier->verify($password);
+ if ($result != SL::Auth::PasswordPolicy->OK()) {
+   print "Errors: " . join(' ', $verifier->errors($result)) . "\n";
+ }
+
+=head1 CONSTANTS
+
+=over 4
+
+=item C<OK>
+
+Password is OK.
+
+=item C<TOO_SHORT>
+
+The password is too short.
+
+=item C<TOO_LONG>
+
+The password is too long.
+
+=item C<MISSING_LOWERCASE>
+
+The password is missing a lower-case character.
+
+=item C<MISSING_UPPERCASE>
+
+The password is missing an upper-case character.
+
+=item C<MISSING_DIGIT>
+
+The password is missing a digit.
+
+=item C<MISSING_SPECIAL_CHAR>
+
+The password is missing a special character. Special characters are
+the following: ! " # $ % & ' ( ) * + , - . : ; E<lt> = E<gt> ? @ [ \ ]
+^ _ { | }
+
+=item C<INVALID_CHAR>
+
+The password contains an invalid character.
+
+=back
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<verify $password, $is_admin>
+
+Checks whether or not the password matches the policy. Returns C<OK()>
+if it does and an error code otherwise (binary or'ed of the error
+constants).
+
+If C<$is_admin> is trueish and the configuration specifies that the
+policy checks are disabled for the administrator then C<verify> will
+always return C<OK()>.
+
+=item C<errors $code>
+
+Returns an array of human-readable strings describing the issues set
+in C<$code> which should be the result of L</verify>.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index 0de9a4b..779bfc3 100644 (file)
@@ -338,10 +338,13 @@ sub save_custom_variables {
 
     do_statement($form, $sth, $query, @values);
 
-    my $valid_index = "$params{name_prefix}cvar_$config->{name}$params{name_postfix}_valid";
-    $self->save_custom_variables_validity(trans_id => $params{trans_id}, config_id => $config->{id},
-      validity => ($params{variables}{$valid_index} || $params{always_valid} ? 1 : 0)
-    );
+    if ($params{save_validity}) {
+      my $valid_index = "$params{name_prefix}cvar_$config->{name}$params{name_postfix}_valid";
+      $self->save_custom_variables_validity(trans_id  => $params{trans_id},
+                                            config_id => $config->{id},
+                                            validity  => ($params{variables}{$valid_index} || $params{always_valid} ? 1 : 0)
+                                           );
+    }
   }
 
   $sth->finish();
index 5290533..8ebc362 100644 (file)
@@ -20,6 +20,7 @@ sub find_by {
 
 sub get_first {
   shift->get_all(
+    @_,
     limit => 1,
   )->[0];
 }
index ac3d6f2..b6007d9 100644 (file)
--- a/SL/IC.pm
+++ b/SL/IC.pm
@@ -583,10 +583,11 @@ sub save {
     }
   }
 
-  CVar->save_custom_variables('dbh'       => $dbh,
-                              'module'    => 'IC',
-                              'trans_id'  => $form->{id},
-                              'variables' => $form);
+  CVar->save_custom_variables(dbh           => $dbh,
+                              module        => 'IC',
+                              trans_id      => $form->{id},
+                              variables     => $form,
+                              save_validity => 1);
 
   # commit
   my $rc = $dbh->commit;
index 3556d4b..7087c5a 100644 (file)
--- a/SL/IS.pm
+++ b/SL/IS.pm
@@ -1991,6 +1991,10 @@ sub get_pricegroups_for_parts {
     my ($price, $selectedpricegroup_id) = split(/--/, $form->{"sellprice_pg_$i"});
 
     my $pricegroup_old = $form->{"pricegroup_old_$i"};
+
+    # sellprice has format 13,0000 or 0,00000, can't check for 0 numerically
+    my $sellprice = $form->{"sellprice_$i"};
+    my $pricegroup_id = $form->{"pricegroup_id_$i"};
     $form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
     $form->{"old_pricegroup_$i"} = $pricegroup_old;
 
@@ -2069,10 +2073,27 @@ sub get_pricegroups_for_parts {
       $pkr->{price} = $form->format_amount($myconfig, $pkr->{price}, 5);
 
       if ($selectedpricegroup_id eq undef) {
-        if ($pkr->{pricegroup_id} eq $form->{customer_klass}) {
-
+        # new entries in article list, either old invoice was loaded (edit) or a new article was added
+        # Case A: open old invoice, no pricegroup selected
+        # Case B: add new article to invoice, no pricegroup selected
+
+        # to distinguish case A and B the variable pricegroup_id_$i is used
+        # for new articles this variable isn't defined, for loaded articles it is
+        # sellprice can't be used, as it already has 0,00 set
+        
+        if ($pkr->{pricegroup_id} eq $form->{"pricegroup_id_$i"} and defined $form->{"pricegroup_id_$i"}) {
+          # Case A
           $pkr->{selected}  = ' selected';
 
+        } elsif ($pkr->{pricegroup_id} eq $form->{customer_klass} 
+                 and not defined $form->{"pricegroup_id_$i"} 
+                 and $pkr->{price} != 0    # only use customer pricegroup price if it has a value, else use default_sellprice
+                                           # for the case where pricegroup prices haven't been set
+                ) {
+          # Case B: use default pricegroup of customer
+
+          $pkr->{selected}  = ' selected'; # unless $form->{selected};
+
           # no customer pricesgroup set
           if ($pkr->{price} == $pkr->{default_sellprice}) {
 
@@ -2081,29 +2102,34 @@ sub get_pricegroups_for_parts {
           } else {
 
 # this sub should not set anything and only return. --sschoeling, 20090506
-#            $form->{"sellprice_$i"} = $pkr->{price};
+# is this correct? put in again... -- grichardson 20110119
+            $form->{"sellprice_$i"} = $pkr->{price};
           }
 
-        } elsif ($pkr->{price} == $pkr->{default_sellprice}) {
+        } elsif ($pkr->{price} == $pkr->{default_sellprice} and $pkr->{default_sellprice} != 0) {
           $pkr->{price}    = $form->{"sellprice_$i"};
           $pkr->{selected} = ' selected';
         }
-      } else {
+      }
+
+      # existing article: pricegroup or price changed
+      if ($selectedpricegroup_id or $selectedpricegroup_id == 0) {
         if ($selectedpricegroup_id ne $pricegroup_old) {
+          # pricegroup has changed
           if ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
             $pkr->{selected}  = ' selected';
           }
-        } elsif (    (   $form->parse_amount($myconfig, $price_new)
-                      != $form->parse_amount($myconfig, $form->{"sellprice_$i"}))
-                 and ($price_new ne 0)) {
+        } elsif (($price_new != $form->{"sellprice_$i"}) and ($price_new ne 0) and defined $price_new) {
+          # sellprice has changed
+          # when loading existing invoices $price_new is NULL
           if ($pkr->{pricegroup_id} == 0) {
             $pkr->{price}     = $form->{"sellprice_$i"};
             $pkr->{selected}  = ' selected';
           }
         } elsif ($pkr->{pricegroup_id} eq $selectedpricegroup_id) {
+          # neither sellprice nor pricegroup changed
           $pkr->{selected}  = ' selected';
-          if (    ($pkr->{pricegroup_id} == 0)
-              and ($pkr->{price} == $form->{"sellprice_$i"})) {
+          if (    ($pkr->{pricegroup_id} == 0) and ($pkr->{price} == $form->{"sellprice_$i"})) {
             # $pkr->{price}                         = $form->{"sellprice_$i"};
           } else {
             $pkr->{price} = $form->{"sellprice_$i"};
index eac4d08..eee7999 100755 (executable)
@@ -42,6 +42,7 @@ use POSIX qw(strftime);
 use Sys::Hostname;
 
 use SL::Auth;
+use SL::Auth::PasswordPolicy;
 use SL::Form;
 use SL::Iconv;
 use SL::Mailer;
@@ -520,12 +521,6 @@ sub save_user {
 
   $myconfig->save_member();
 
-  if ($main::auth->can_change_password()
-      && defined $form->{new_password}
-      && ($form->{new_password} ne '********')) {
-    $main::auth->change_password($form->{login}, $form->{new_password});
-  }
-
   $form->{templates}       =~ s|.*/||;
   $form->{templates}       =  "$main::templates/$form->{templates}";
   $form->{mastertemplates} =~ s|.*/||;
@@ -578,8 +573,20 @@ sub save_user {
     }
   }
 
-  $form->redirect($locale->text('User saved!'));
+  if ($main::auth->can_change_password()
+      && defined $form->{new_password}
+      && ($form->{new_password} ne '********')) {
+    my $verifier = SL::Auth::PasswordPolicy->new;
+    my $result   = $verifier->verify($form->{new_password}, 1);
+
+    if ($result != SL::Auth::PasswordPolicy->OK()) {
+      $form->error($::locale->text('The settings were saved, but the password was not changed.') . ' ' . join(' ', $verifier->errors($result)));
+    }
 
+    $main::auth->change_password($form->{login}, $form->{new_password});
+  }
+
+  $form->redirect($locale->text('User saved!'));
 }
 
 sub save_user_as_new {
index b7c980c..66874c7 100644 (file)
@@ -34,6 +34,7 @@
 use utf8;
 
 use SL::Auth;
+use SL::Auth::PasswordPolicy;
 use SL::AM;
 use SL::CA;
 use SL::Form;
@@ -2549,7 +2550,27 @@ sub save_preferences {
 
   TODO->save_user_config('login' => $form->{login}, %{ $form->{todo_cfg} || { } });
 
-  $form->redirect($locale->text('Preferences saved!')) if (AM->save_preferences(\%myconfig, \%$form, 0));
+  if (AM->save_preferences(\%myconfig, $form)) {
+    if ($::auth->can_change_password()
+        && defined $form->{new_password}
+        && ($form->{new_password} ne '********')) {
+      my $verifier = SL::Auth::PasswordPolicy->new;
+      my $result   = $verifier->verify($form->{new_password});
+
+      if ($result != SL::Auth::PasswordPolicy->OK()) {
+        $form->error($::locale->text('The settings were saved, but the password was not changed.') . ' ' . join(' ', $verifier->errors($result)));
+      }
+
+      $::auth->change_password($form->{login}, $form->{new_password});
+
+      $form->{password} = $form->{new_password};
+      $::auth->set_session_value('password', $form->{password});
+      $::auth->create_or_refresh_session();
+    }
+
+    $form->redirect($locale->text('Preferences saved!'));
+  }
+
   $form->error($locale->text('Cannot save preferences!'));
 
   $main::lxdebug->leave_sub();
index 585301c..3d4fe26 100644 (file)
@@ -271,17 +271,9 @@ sub form_header {
   $form->{exchangerate} = $form->{forex} if $form->{forex};
 
   # format amounts
-  $form->{exchangerate} =
-    $form->format_amount(\%myconfig, $form->{exchangerate});
-
-  if ($form->{exchangerate} == 0) {
-    $form->{exchangerate} = "";
-  }
-
-  $form->{creditlimit} =
-    $form->format_amount(\%myconfig, $form->{creditlimit}, 0, "0");
-  $form->{creditremaining} =
-    $form->format_amount(\%myconfig, $form->{creditremaining}, 0, "0");
+  $form->{exchangerate}    = $form->{exchangerate} ? $form->format_amount(\%myconfig, $form->{exchangerate}) : '';
+  $form->{creditlimit}     = $form->format_amount(\%myconfig, $form->{creditlimit}, 0, "0");
+  $form->{creditremaining} = $form->format_amount(\%myconfig, $form->{creditremaining}, 0, "0");
 
   $exchangerate = qq|
 <input type=hidden name=forex value=$form->{forex}>
index 8c803fb..9527686 100644 (file)
@@ -126,7 +126,8 @@ sub set_pricegroup {
         if ($item->{selected} && ($pricegroup_id != 0)) {
           $form->{"pricegroup_old_$j"} = $pricegroup_id;
           $form->{"price_new_$j"}      = $price;
-          $form->{"sellprice_$j"}      = $price;
+          # edit: don't change the sellprice here
+          # $form->{"sellprice_$j"}      = $price;   # this must only be updated for existing articles, not new ones
         }
         if ($pricegroup_id == 0) {
           $form->{"price_new_$j"} = $form->{"sellprice_$j"};
index 9260981..3ec65da 100644 (file)
@@ -288,9 +288,11 @@ sub display_row {
       # for last row and report
       # set pricegroup drop down list from report menu
       if ($form->{"sellprice_$i"} != 0) {
+        # remember the pricegroup_id in pricegroup_old
+        # but don't overwrite it
         $form->{"pricegroup_old_$i"} = $form->{"pricegroup_id_$i"};
         my $default_option           = $form->{"sellprice_$i"}.'--'.$form->{"pricegroup_id_$i"};
-        $column_data{sellprice_pg}   = NTI($cgi->popup_menu("sellpricepg_$i", [ $default_option ], $default_option, { $default_option => $form->{"pricegroup_$i"} || '' }));
+        $column_data{sellprice_pg}   = NTI($cgi->popup_menu("sellprice_pg_$i", [ $default_option ], $default_option, { $default_option => $form->{"pricegroup_$i"} || '' }));
       } else {
         $column_data{sellprice_pg} = qq|&nbsp;|;
       }
index aeba187..740002b 100644 (file)
@@ -266,7 +266,13 @@ sub prepare_invoice {
 
     # get pricegroups for parts
     IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-    set_pricegroup($_) for 1 .. $form->{rowcount};
+
+    # Problem: set_pricegroup resets the sellprice of old invoices to the price
+    # currently defined in the pricegroup, which is a problem if the price has
+    # changed, as the old invoice gets the new price
+    # set_pricegroup must never be called, when an old invoice is initially loaded
+
+    # set_pricegroup($_) for 1 .. $form->{rowcount};
   }
   $main::lxdebug->leave_sub();
 }
@@ -780,6 +786,11 @@ sub use_as_template {
   $form->{paidaccounts} = 1;
   $form->{rowcount}--;
   $form->{invdate} = $form->current_date(\%myconfig);
+
+  # remember pricegroups for "use as template"
+  IS->get_pricegroups_for_parts(\%myconfig, \%$form);
+  set_pricegroup($_) for 1 .. $form->{rowcount};
+
   &display_form;
 
   $main::lxdebug->leave_sub();
index 2f63157..d70ee6f 100644 (file)
@@ -1435,6 +1435,10 @@ sub invoice {
 
   }
 
+  #  show pricegroup in newly loaded invoice when creating invoice from quotation/order
+  IS->get_pricegroups_for_parts(\%myconfig, \%$form);
+  set_pricegroup($_) for 1 .. $form->{rowcount};
+
   &display_form;
 
   $main::lxdebug->leave_sub();
index b647a5f..16e50bc 100644 (file)
@@ -1,11 +1,12 @@
 use Cwd;
 
-use vars qw(
-$dbcharset $eur $ghostscript_bin $html2ps_bin $language $latex_bin
-$latex_templates $lizenzen $memberfile $opendocument_templates
-$openofficeorg_daemon $openofficeorg_daemon_port $openofficeorg_writer_bin
-$pg_dump_exe $pg_restore_exe $sendmail $show_best_before $sid $spool $templates
-$use_rdbo $userspath $vertreter $webdav $xvfb_bin
+our qw(
+  $dbcharset $eur $ghostscript_bin $html2ps_bin $language $latex_bin
+  $latex_templates $lizenzen $memberfile $opendocument_templates
+  $openofficeorg_daemon $openofficeorg_daemon_port $openofficeorg_writer_bin
+  $parts_image_css $parts_listing_images $parts_show_image $pg_dump_exe
+  $pg_restore_exe $sendmail $show_best_before $sid $spool $templates
+  $use_rdbo $userspath $vertreter $webdav $xvfb_bin
 );
 
 # path to user configuration files
@@ -53,6 +54,13 @@ $excel_templates = 0; # Minimalunterstützung für Excel-Druckvorlagen
 # Zeige Felder für Mindesthaltbarkeitsdatum
 $show_best_before = 0;
 
+## Artikelbilder anzeigen
+# Artikelbild in der Detailansicht anzeigen
+$parts_show_image = 1; # [0|1]
+$parts_image_css = 'border:0;float:left;max-width:250px;margin-top:20px:margin-right:10px;margin-left:10px;'; # [belibige valide css definiton]
+# Artikelbilder per default in den Suchergebnissen anzeigen
+$parts_listing_images = 0; # [0|1]
+
 ## Support fuer OpenDocument-Vorlagen
 # Diese Option legt fest, ob OpenDocument-Vorlagen generell verfuegbar sind.
 $opendocument_templates = 1;
index 41d833f..16e50bc 100644 (file)
@@ -1,15 +1,14 @@
 use Cwd;
 
-use vars qw(
+our qw(
   $dbcharset $eur $ghostscript_bin $html2ps_bin $language $latex_bin
   $latex_templates $lizenzen $memberfile $opendocument_templates
   $openofficeorg_daemon $openofficeorg_daemon_port $openofficeorg_writer_bin
   $parts_image_css $parts_listing_images $parts_show_image $pg_dump_exe
-  $pg_restore_exe $sendmail $show_best_before $sid $spool $templates $userspath
-  $vertreter $webdav $xvfb_bin
+  $pg_restore_exe $sendmail $show_best_before $sid $spool $templates
+  $use_rdbo $userspath $vertreter $webdav $xvfb_bin
 );
 
-
 # path to user configuration files
 $userspath = "users";
 
@@ -22,13 +21,15 @@ $templates = "templates";
 # member file
 $memberfile = "users/members";
 
-# Wenn nicht Bilanzierung dann auf 1 setzen
+# Wenn Einnahmen-Überschussrechnung, dann auf 1 setzen
+# Wenn Bilanzierung (z.B. GmbH), dann auf 0 setzen
 $eur = 1;
 
 # location of sendmail
 $sendmail = '| /usr/sbin/sendmail -t<%if myconfig_email%> -f <%myconfig_email%><%end%>';
 
 # set language for login and admin
+# currently "de" (German), "de_DE" (new German) and "en" (English, not perfect) are available
 $language = "de";
 
 # Oracle
@@ -48,6 +49,7 @@ $ENV{PERL5LIB} .= ":/sw/lib/perl5";
 $webdav = 0;
 $lizenzen = 1;
 $vertreter = 0;
+$excel_templates = 0; # Minimalunterstützung für Excel-Druckvorlagen
 
 # Zeige Felder für Mindesthaltbarkeitsdatum
 $show_best_before = 0;
@@ -104,6 +106,13 @@ $latex_bin = 'pdflatex';
 $pg_dump_exe    = "pg_dump";
 $pg_restore_exe = "pg_restore";
 
+# Rose::DB::Object Environment laden.
+# Die RDBO Klassen bieten für Addon Schreiber sehr einfache Interfaces zu den
+# bestehenden Klassen, haben aber den Nachteil, dass der Start des Programms
+# etwa 2s mehr dauert. Damit fällt die Möglichkeit Lx-Office über CGI zu
+# betreiben weg.
+$use_rdbo = 1;
+
 # Globale Debug-Ausgaben (de-)aktivieren? Moegliche Werte sind
 # LXDebug::NONE   - keine Debugausgaben
 # LXDebug::INFO
@@ -120,7 +129,7 @@ $pg_restore_exe = "pg_restore";
 #
 # Beipiel:
 #   $LXDebug::global_level = LXDebug::TRACE | LXDebug::QUERY;
-$LXDebug::global_level = LXDebug::NONE;
+$LXDebug::global_level = LXDebug->NONE;
 
 # Überwachung der Inhalte von $form aktiviert oder nicht? Wenn ja,
 # dann können einzelne Variablen mit
index cd230d2..3e168af 100644 (file)
@@ -29,6 +29,34 @@ login = demo
 # location of history file for permanent history
 history_file = users/console_history
 
+# Settings used when the user changes his/her password. All options
+# default to no restriction if unset.
+[password_policy]
+# Minimum length in number of characters.
+min_length =
+# Maximum length in number of characters.
+max_length =
+# Require a lowe-case character?
+require_lowercase =
+# Require an upper-case character?
+require_uppercase =
+# Require a digit?
+require_digit =
+# Require a special char? Special chars are the following:
+# ! " # $ % & ' ( ) * + , - . : ; < = > ? @ [ \ ] ^ _ { | }
+require_special_character =
+# Optional list of valid characters. Spaces are ignored. If set then
+# the password must only consist of these characters.
+valid_characters =
+# Optional list of invalid characters. Spaces are ignored.
+invalid_characters =
+# Whether or not to check the policy if the password is set from the
+# user administration.
+disable_policy_for_admin =
+# Whether or not to check for weak passwords with the "cracklib"
+# library. Requires the Perl module "Crypt::Cracklib" to be installed.
+use_cracklib =
+
 [debug]
 # Use DBIx::Log4perl for logging DBI calls. The string LXDEBUGFILE
 # will be replaced by the file name configured for $::lxdebug.
index 6f9a9ec..03bb3b6 100644 (file)
@@ -27,6 +27,16 @@ Zumindest folgende Module sind neu benötigt:
   Distribution sollte für die automatische Installation der anderen
   zwei Pakete sorgen)
 
+ Neue Gruppenrechte
+ ------------------
+
+Es wurde ein neues Recht "Druck" eingeführt. Dieses bestimmt, ob die
+Benutzerin das Menü "Druck" zu Gesicht bekommt oder nicht, unabhängig
+davon, wie die Rechte für die einzelnen Unterpunkte gesetzt sind.
+
+Für bereits bestehende Gruppen muss es sofern gewünscht vom
+Administrator manuell gewährt werden.
+
 
 Upgrade auf v2.6.1
 ==================
index a9ffd7d..643eac4 100644 (file)
@@ -2,9 +2,7 @@
 # Veränderungen von Lx-Office ERP #
 ###################################
 
-
-
-
+2011-02-?? - Release 2.6.2
 
   Größere neue Features:
 
     Das Program läuft jetzt optional unter FastCGI, und damit etwa um
     Faktor 10 schneller. Siehe Dokumentation in doc INSTALL.fcgi.
 
+  - Neues Gruppenrecht "Druck"
+
+    Es wurde ein neues Recht "Druck" eingeführt. Dieses bestimmt, ob
+    die Benutzerin das Menü "Druck" zu Gesicht bekommt oder nicht,
+    unabhängig davon, wie die Rechte für die einzelnen Unterpunkte
+    gesetzt sind.
+
+    Für bereits bestehende Gruppen muss es sofern gewünscht vom
+    Administrator manuell gewährt werden.
+
   Kleinere neue Features und Detailverbesserungen:
 
   - Druckvorlage optional auf Excel erweitert, um Variablen die sich nicht in foreach-Schleifen
 
   Liste gefixter Bugs aus dem Bugtracker:
 
-
-   - Bug 1388 -  Berichte sind defekt, wenn abweichendes Datumsformat (ISO) eingestellt ist
-   - Bug 1395 -  Einlagern ueber Lieferschein: Einheiten entsprechen nicht den Standardeinheiten der Artikel
-   - Bug 1398 -  Im Lagerjournal werden Projektnummern nicht erfasst 
-   - Bug 1409 -  Bei "Erzeugnis fertigen" wird nur der Bestand der letzten Komponente geprüft
-   - Bug 1412 -  Wenn die Ware ausgewählt werden muss wird der Rabatt verworfen
-   - Bug 1421 -  Stornorechnungen loeschen bereitet Probleme
-   - Bug 1484 -  Das Ankreuzfeld 'alle' hat keine Funktion wenn man einen Auswahlliste (multibox) an Lieferanten hat
-                 Es wird trotzdem nach der Auswahlliste gefiltert und die Option 'alle' wird
-                 ignoriert auch wenn man auf Erneuern klickt.
-                 Das Eingabefeld 'Betrag' im oberen Teil der Maske hat in Lx-Office
-                 keinen Sinn mehr, da nur noch über die Auswahl der offenen
-                 Kreditorenposten ein Zahlungsausgang veranlasst wird.
-                 Neu-Aufbau Lx-Office Bildschirm
-                 Nach einer erfolgreichen Buchung erscheint die Meldung: 'Zahlung gebucht.' und
-                 die Startseite wird angezeigt. Wünschenwert wäre es, wenn man in
-                 Zahlungsverkehr bleiben würde, optimalerweise mit vorbelegten Feldern.
-   - Bug 1502 -  2. Zahlung buchen, auch wenn die erste Zahlung in einen abgeschlossenen Zeitraum liegt
-
+  - Bugfix 1131: Einkaufslieferscheine: Mengen muessen beim Auslagern manuell in die maske eingetragen werden
+  - Bugfix 1154: Debitoren und Kreditoren werden nicht korrekt gebucht
+  - Bugfix 1185: Preis überschreiben bei Preisgruppe
+  - Bugfix 1220: Zahlungsverkehr - Zahlungseingang: Aufteilung des Rechnungsbetrages
+  - Bugfix 1277: Fehler in der BWA Zuordnung in den SKR03 und dem daraus generierten skr04
+  - Bugfix 1298: SKR04 überarbeitet
+  - Bugfix 1302: Inkonsistenz in Buchungsdaten: In Verkaufsrechnungen wird die Zahlung nicht angezeit, Gegenbuchung fehlt
+  - Bugfix 1367: Feature-Vorschlag: SEPA auch für Lastschriften von Debitoren unterstützen
+  - Bugfix 1370: Umlautfehler beim Erfassen einer Einkaufsrechnung
+  - Bugfix 1375: Übersetzungsdateien im Verzeichnis ""locale/de/"" immer noch in ISO-8859-15 kodiert statt UTF-8
+  - Bugfix 1376: Benutzerdefinierte Variablen sollten auch im mahnsystem zur Verfuegung stehen
+  - Bugfix 1378: leere Buchungen (text, beschreibung und referenz) bei Splittbuchungen
+  - Bugfix 1381: missing files in package
+  - Bugfix 1383: Dienstleistungen in Stammdaten und Lager
+  - Bugfix 1384: Zinsen bei Mahnung falsch berechnet
+  - Bugfix 1387: Englische Eingabemaske bei Aufruf von Deb./Kred.-buchung aus Buchungsjournal
+  - Bugfix 1388: Berichte sind defekt, wenn abweichendes Datumsformat (ISO) eingestellt ist
+  - Bugfix 1389: Bilanz repariert
+  - Bugfix 1393: CSV-Export sollte ohne Tausender-Trenner erfolgen
+  - Bugfix 1395: Einlagern ueber Lieferschein: Einheiten entsprechen nicht den Standardeinheiten der Artikl
+  - Bugfix 1398: Im Lagerjournal werden Projektnummern nicht erfasst
+  - Bugfix 1399: Lieferdaten zu einzelnen Positionen ""verrutschen"" beim Loeschen hoeherer Positionszeilen
+  - Bugfix 1400: Lieferscheine: Usability bei Auslagerung - Positionsindikator
+  - Bugfix 1406: Kunde erfassen
+  - Bugfix 1410: Beschriftung bei Eingabe der Einkaufsrechnung falsch
+  - Bugfix 1412: Wenn die Ware ausgewählt werden muss wird der Rabatt verworfen
+  - Bugfix 1414: Einfügen der \usepackage{textcomp}-Zeile in TeX-Templates ungünstig
+  - Bugfix 1422: Loeschen von Stornos bereitet eine Reihe von Problemen: (3)Gutschriften aus Rechnungen, die einstmals storniert wurden
+  - Bugfix 1429: Debitorenbuchungen 1: Wechsel des Debitoren loescht Bemerkungsfeld nicht
+  - Bugfix 1432: Mahnläufe: Nach manuellem Zurücksetzen der Mahnstufen gibt es ein Chaos bei der weiteren Erzeugung
+  - Bugfix 1439: Sortierkriterium ""Strasse"" in Listenansicht der Lieferanten geht nicht
+  - Bugfix 1440: Eingrenzen der angelegten Waren nach Lieferant liefert immer kein Ergebnis
+  - Bugfix 1445: Kleines Chaos bei Vorlagenbezeichnungen zu Lieferscheinen: picklist, packing_list, sales_delivery_order
+  - Bugfix 1449: Konto 3170 langfristige Verbindlichkeiten SKR04 Aktiva
+  - Bugfix 1451: Menüsetup Alt (seitlich) wird nicht lokalisiert
+  - Bugfix 1452: Fehler bei Lokalisierung der Überschriften und weiterer Beschriftungen
+  - Bugfix 1454: mehrere Rechnungen mit gleicher Rechnungsnummer möglich
+  - Bugfix 1455: Feld wird nach Einlagerung nicht zurückgesetzt.
+  - Bugfix 1456: Lieferanschrift wird im Workflow nicht zuverlässig vom Auftrag in den Lieferschein übernommen
+  - Bugfix 1459: Gruppen bearbteien unter FCGI
+  - Bugfix 1467: System entsperren nicht möglich
+  - Bugfix 1468: Title Javascript setzt den Titel auch, wenn die Informationen nicht verfügbar sind.
+  - Bugfix 1469: Umlaute gehen auf der Startseite kaputt bei update von 2.6.1 auf unstable (August 2010)
+  - Bugfix 1470: Falsche Übersetzung für ""Expenses EU without UStId""
+  - Bugfix 1471: System -> Historien Suchmaschinen gibt folgenden Fehler:
+  - Bugfix 1472: Bei fehlender config/authentication.pl -> Webserver Error 500
+  - Bugfix 1475: Workflow Angebot -> Rechnung wird Angebotsnummer nicht übernommen
+  - Bugfix 1477: Sicherheitsloch bei 2.6er Versionen
+  - Bugfix 1479: Debian Paket bauen schlägt fehl
+  - Bugfix 1480: Filter für Abteilungen ohne Ergebnis
+  - Bugfix 1483: Formelberechnung und Zahlenformat
+  - Bugfix 1484: Zahlungsausgang diverses
+  - Bugfix 1485: Rechnung->neuer Artikel->Speichern->Fehler ""Can't use string ... as a HASH ref ... bin/mozilla/io.pl line 2075""
+  - Bugfix 1487: Wechselkurs wird falsch ausgelesen
+  - Bugfix 1488: Ust-Voranmeldung - Elster-Export nach Taxbird
+  - Bugfix 1491: Nitpicking: Beim ersten Login in eine DB werden im Text HTML Formatierungen ausgegeben, nicht interpretiert
+  - Bugfix 1492: ""Korrekturen im Hauptbuch"" wirft Fehler
+  - Bugfix 1494: undokumentiert -- dependency parent.pm / Dokumentvariable ustid
+  - Bugfix 1495: Ansicht von Artikelbilderen (Suchergebnis/Artikelmaske)
+  - Bugfix 1496: Grad-Symbol (°) verursacht Latex-Fehler
+  - Bugfix 1498: (versehentlicher?) commit der menu.ini mit crm Spalte
+  - Bugfix 1499: Einstellungen ""Nicht rabattierfähig"" ist nicht für Dienstleistungen verfügbar (z.B. Versandkosten)
+  - Bugfix 1502: Bücherkontrolle prüft auch ALTE Zahlungseingänge
+  - Bugfix 1504: UStVa Modul SQL Fehler: ""text >= integer"" nicht erlaubt
+  - Bugfix 1506: Email-Formular: Mailadresse der Firma anstelle des Ansprechpartners
+  - Bugfix 1517: Kreditorrechnung: Wechselkurs bei gleichem Re.-Datum nicht vorhanden
+  - Bugfix 1520: Division-by-Zero-Fehler bei einigen Rechnungsbuchungen
+  - Bugfix 1521: Fix von Bug 1521 bringt neuen Fehler bei Login und Verkaufsmasken
+  - Bugfix 1523: Rabatt geht verloren, wenn Rechnung aus Lieferscheinliste generiert wird
+  - Bugfix 1524: Kundenrabatt geht verloren (wie 1284, aber auch Einkauf)
+  - Bugfix 1528: Vorlagen
+  - Bugfix 1529: falsche Tabellendefinition in Default-request_quotation.tex
+  - Bugfix 1530: Debitorenbuchung: Abfragefehler bei Kontonummer mit ""."" (Punkt) oder Text
+  - Bugfix 1533: Zahlungen in Rechnungsmaske einbuchen scheitert an locale
+  - Bugfix 1535: CSV-Exporte sind nicht mehr UTF8
+  - Bugfix 1536: 'Alte' dbupgrade Skripte die SL::DBUtils verwenden sind defekt
+  - Bugfix 1537: Debitoren: Feld curr in Tabelle ar wird nicht gefüllt
+  - Bugfix 1541: Preisgruppeneintrag in Einkaufsrechungen ??
+  - Bugfix 1547: Kreditorenbuchung in Fremdwährung: Steuerfehler
+  - Bugfix 1550: Sortieren einer Kundenauflistung ""vergisst"" gewählte Filterkriterien
+  - Bugfix 1552: Diverse Probleme mit der Sortierfunktion bei Stammdaten
+  - Bugfix 1553: Diese Kundennummer wird bereits verwendet. - Obwohl keine eingetragen ist
+  - Bugfix 1554: Kein Wechselkurs bei Debitotenbuchung in Fremdwährung unter 1 bei gleichem Datum
+  - Bugfix 1555: Sonderzeichen nicht korrekt escaped (Stückliste beim Erstellen eines Erzeugnisses)
+  - Bugfix 1561: benutzerdefinierte Variable wird unabsichtlich deaktiviert
+  - Bugfix 1562: Fehlender Hinweis im changelog zu gaenderten Rechten Beim Druck
 
 2010-03-24 - Release 2.6.1
 
index 115222d..123433e 100644 (file)
@@ -38,9 +38,12 @@ $self->{texts} = {
   '4. Quarter'                  => '4. Quartal',
   '<b>What</b> do you want to look for?' => '<b>Wonach</b> wollen Sie suchen?',
   'A Buchungsgruppe consists of a descriptive name and the account numbers for the income and expense accounts for those four tax zones as well as the inventory account number.' => 'Eine Buchungsgruppe besteht aus einem deskriptiven Namen, den Erl&ouml;s- und Aufwandskonten f&uuml;r diese vier Steuerzonen sowie aus einem Inventarkonto.',
+  'A digit is required.'        => 'Eine Ziffer ist vorgeschrieben.',
   'A group named &quot;Full Access&quot; has been created.' => 'Eine Gruppe namens &quot;Vollzugriff&quot; wurde angelegt.',
   'A group with that name does already exist.' => 'Eine Gruppe mit diesem Namen gibt es bereits.',
   'A lot of the usability of Lx-Office has been enhanced with javascript. Although it is currently possible to use every aspect of Lx-Office without javascript, we strongly recommend it. In a future version this may change and javascript may be necessary to access advanced features.' => 'Die Bedienung von Lx-Office wurde an vielen Stellen mit Javascript verbessert. Obwohl es derzeit möglich ist, jeden Aspekt von Lx-Office auch ohne Javascript zu benutzen, empfehlen wir es. In einer zukünftigen Version wird Javascript eventuell notwendig sein um weitergehende Features zu benutzen.',
+  'A lower-case character is required.' => 'Ein Kleinbuchstabe ist vorgeschrieben.',
+  'A special character is required (valid characters: #1).' => 'Ein Sonderzeichen ist vorgeschrieben (gültige Zeichen: #1).',
   'A temporary directory could not be created:' => 'Ein tempor&auml;res Verzeichnis konnte nicht erstellt werden:',
   'A temporary file could not be created. Please verify that the directory "#1" is writeable by the webserver.' => 'Eine temporäre Datei konnte nicht angelegt werden. Bitte stellen Sie sicher, dass das Verzeichnis "#1" vom Webserver beschrieben werden darf.',
   'A temporary file could not be created:' => 'Eine tempor&auml;re Datei konnte nicht erstellt werden:',
@@ -180,6 +183,9 @@ $self->{texts} = {
   'Amount'                      => 'Betrag',
   'Amount Due'                  => 'Betrag fällig',
   'Amount has to be greater then zero! Wrong row number: ' => 'Leere Eingabe oder Werte kleiner, gleich null eingegeben. Fehler in Reihe Nummer: ',
+  'An invalid character was used (invalid characters: #1).' => 'Ein ungültiges Zeichen wurde benutzt (ungültige Zeichen: #1).',
+  'An invalid character was used (valid characters: #1).' => 'Ein ungültiges Zeichen wurde benutzt (gültige Zeichen: #1).',
+  'An upper-case character is required.' => 'Ein Großbuchstabe ist vorgeschrieben.',
   'Annotations'                 => 'Anmerkungen',
   'Another user with the login #1 does already exist.' => 'Es existiert bereits ein anderer Benutzer mit diesem Login.',
   'Ap aging on %s'              => 'Offene Verbindlichkeiten zum %s',
@@ -815,7 +821,6 @@ $self->{texts} = {
   'Help Template Variables'     => 'Hilfe zu Dokumenten-Variablen',
   'Here\'s an example command line:' => 'Hier ist eine Kommandozeile, die als Beispiel dient:',
   'Hide by default'             => 'Standardm&auml;&szlig;ig verstecken',
-  'History'                     => 'Historie',
   'History Search'              => 'Historien Suche',
   'History Search Engine'       => 'Historien Suchmaschine',
   'Homepage'                    => 'Homepage',
@@ -1679,6 +1684,9 @@ $self->{texts} = {
   'The parts have been removed.' => 'Die Waren wurden aus dem Lager entnommen.',
   'The parts have been stocked.' => 'Die Artikel wurden eingelagert.',
   'The parts have been transferred.' => 'Die Waren wurden umgelagert.',
+  'The password is too long (maximum length: #1).' => 'Das Passwort ist zu lang (maximale Länge: #1).',
+  'The password is too short (minimum length: #1).' => 'Das Password ist zu kurz (minimale Länge: #1).',
+  'The password is weak (e.g. it can be found in a dictionary).' => 'Das Passwort ist schwach (z.B. wenn es in einem Wörterbuch steht).',
   'The payments have been posted.' => 'Die Zahlungen wurden gebucht.',
   'The pg_dump process could not be started.' => 'Der pg_dump-Prozess konnte nicht gestartet werden.',
   'The pg_restore process could not be started.' => 'Der pg_restore-Prozess konnte nicht gestartet werden.',
@@ -1697,6 +1705,7 @@ $self->{texts} = {
   'The selected warehouse does not exist.' => 'Das ausgew&auml;hlte Lager existiert nicht.',
   'The selected warehouse is empty.' => 'Das ausgew&auml;hlte Lager ist leer.',
   'The session is invalid or has expired.' => 'Sie sind von Lx-Office abgemeldet.',
+  'The settings were saved, but the password was not changed.' => 'Die Einstellungen wurden gespeichert, aber das Passwort wurde nicht geändert.',
   'The source warehouse does not contain any bins.' => 'Das Quelllager enth&auml;lt keine Lagerpl&auml;tze.',
   'The start date is missing.'  => 'Das Startdatum fehlt.',
   'The subject is missing.'     => 'Der Betreff fehlt.',
index b972a49..f03e5c6 100755 (executable)
@@ -31,7 +31,7 @@ parse_args();
 my $basedir      = "../..";
 my $locales_dir  = ".";
 my $bindir       = "$basedir/bin/mozilla";
-my @progdirs     = ( "$basedir/SL/Controller", "$basedir/SL/Template/Plugin" );
+my @progdirs     = ( "$basedir/SL/Controller", "$basedir/SL/Template/Plugin", "$basedir/SL/Auth" );
 my $dbupdir      = "$basedir/sql/Pg-upgrade";
 my $dbupdir2     = "$basedir/sql/Pg-upgrade2";
 my $menufile     = "menu.ini";
diff --git a/sql/Pg-upgrade2/invalid_entries_in_custom_variables_validity.sql b/sql/Pg-upgrade2/invalid_entries_in_custom_variables_validity.sql
new file mode 100644 (file)
index 0000000..62dd944
--- /dev/null
@@ -0,0 +1,9 @@
+-- @tag: invalid_entries_in_custom_variables_validity
+-- @description: Ungültige Einträge in custom_variables_validity bereinigen
+-- @depends: release_2_6_1
+-- @charset: utf-8
+DELETE FROM custom_variables_validity
+WHERE trans_id NOT IN (
+  SELECT id
+  FROM parts
+);