Merge branch 'no-cleartext-passwords-in-db'
[kivitendo-erp.git] / SL / Form.pm
index 23dd5be..582d2af 100644 (file)
@@ -52,6 +52,7 @@ use SL::AM;
 use SL::Common;
 use SL::CVar;
 use SL::DB;
 use SL::Common;
 use SL::CVar;
 use SL::DB;
+use SL::DBConnect;
 use SL::DBUtils;
 use SL::DO;
 use SL::IC;
 use SL::DBUtils;
 use SL::DO;
 use SL::IC;
@@ -61,6 +62,7 @@ use SL::Menu;
 use SL::OE;
 use SL::Template;
 use SL::User;
 use SL::OE;
 use SL::Template;
 use SL::User;
+use SL::X;
 use Template;
 use URI;
 use List::Util qw(first max min sum);
 use Template;
 use URI;
 use List::Util qw(first max min sum);
@@ -457,7 +459,7 @@ sub hide_form {
 
 sub throw_on_error {
   my ($self, $code) = @_;
 
 sub throw_on_error {
   my ($self, $code) = @_;
-  local $self->{__ERROR_HANDLER} = sub { die({ error => $_[0] }) };
+  local $self->{__ERROR_HANDLER} = sub { die SL::X::FormError->new($_[0]) };
   $code->();
 }
 
   $code->();
 }
 
@@ -629,6 +631,8 @@ sub create_http_response {
   $cgi_params{'-charset'} = $params{charset} if ($params{charset});
   $cgi_params{'-cookie'}  = $session_cookie  if ($session_cookie);
 
   $cgi_params{'-charset'} = $params{charset} if ($params{charset});
   $cgi_params{'-cookie'}  = $session_cookie  if ($session_cookie);
 
+  map { $cgi_params{'-' . $_} = $params{$_} if exists $params{$_} } qw(content_disposition content_length);
+
   my $output = $cgi->header(%cgi_params);
 
   $main::lxdebug->leave_sub();
   my $output = $cgi->header(%cgi_params);
 
   $main::lxdebug->leave_sub();
@@ -636,6 +640,18 @@ sub create_http_response {
   return $output;
 }
 
   return $output;
 }
 
+sub use_stylesheet {
+  my $self = shift;
+
+  $self->{stylesheet} = [ $self->{stylesheet} ] unless ref $self->{stylesheet} eq 'ARRAY';
+  $self->{stylesheet} = [ grep { -f                       }
+                          map  { m:^css/: ? $_ : "css/$_" }
+                          grep { $_                       }
+                               (@{ $self->{stylesheet} }, @_)
+                        ];
+
+  return @{ $self->{stylesheet} };
+}
 
 sub header {
   $::lxdebug->enter_sub;
 
 sub header {
   $::lxdebug->enter_sub;
@@ -658,8 +674,7 @@ sub header {
     push @header, "<meta http-equiv='refresh' content='$refresh_time;$refresh_url'>";
   }
 
     push @header, "<meta http-equiv='refresh' content='$refresh_time;$refresh_url'>";
   }
 
-  push @header, "<link rel='stylesheet' href='css/$_' type='text/css' title='Lx-Office stylesheet'>"
-    for grep { -f "css/$_" } apply { s|.*/|| } $self->{stylesheet}, $self->{stylesheets};
+  push @header, map { qq|<link rel="stylesheet" href="$_" type="text/css" title="Lx-Office stylesheet">| } $self->use_stylesheet;
 
   push @header, "<style type='text/css'>\@page { size:landscape; }</style>" if $self->{landscape};
   push @header, "<link rel='shortcut icon' href='$self->{favicon}' type='image/x-icon'>" if -f $self->{favicon};
 
   push @header, "<style type='text/css'>\@page { size:landscape; }</style>" if $self->{landscape};
   push @header, "<link rel='shortcut icon' href='$self->{favicon}' type='image/x-icon'>" if -f $self->{favicon};
@@ -743,7 +758,7 @@ sub redirect_header {
   my $base_uri = $self->_get_request_uri;
   my $new_uri  = URI->new_abs($new_url, $base_uri);
 
   my $base_uri = $self->_get_request_uri;
   my $new_uri  = URI->new_abs($new_url, $base_uri);
 
-  die "Headers already sent" if $::self->{header};
+  die "Headers already sent" if $self->{header};
   $self->{header} = 1;
 
   my $cgi = $main::cgi || CGI->new('');
   $self->{header} = 1;
 
   my $cgi = $main::cgi || CGI->new('');
@@ -775,13 +790,6 @@ sub _prepare_html_template {
   $language = "de" unless ($language);
 
   if (-f "templates/webpages/${file}.html") {
   $language = "de" unless ($language);
 
   if (-f "templates/webpages/${file}.html") {
-    if ((-f ".developer") && ((stat("templates/webpages/${file}.html"))[9] > (stat("locale/${language}/all"))[9])) {
-      my $info = "Developer information: templates/webpages/${file}.html is newer than the translation file locale/${language}/all.\n" .
-        "Please re-run 'locales.pl' in 'locale/${language}'.";
-      print(qq|<pre>$info</pre>|);
-      ::end_of_request();
-    }
-
     $file = "templates/webpages/${file}.html";
 
   } else {
     $file = "templates/webpages/${file}.html";
 
   } else {
@@ -810,11 +818,11 @@ sub _prepare_html_template {
   }
 
   $additional_params->{"conf_dbcharset"}              = $::lx_office_conf{system}->{dbcharset};
   }
 
   $additional_params->{"conf_dbcharset"}              = $::lx_office_conf{system}->{dbcharset};
-  $additional_params->{"conf_webdav"}                 = $::lx_office_conf{system}->{webdav};
-  $additional_params->{"conf_lizenzen"}               = $::lx_office_conf{system}->{lizenzen};
+  $additional_params->{"conf_webdav"}                 = $::lx_office_conf{features}->{webdav};
+  $additional_params->{"conf_lizenzen"}               = $::lx_office_conf{features}->{lizenzen};
   $additional_params->{"conf_latex_templates"}        = $::lx_office_conf{print_templates}->{latex};
   $additional_params->{"conf_opendocument_templates"} = $::lx_office_conf{print_templates}->{opendocument};
   $additional_params->{"conf_latex_templates"}        = $::lx_office_conf{print_templates}->{latex};
   $additional_params->{"conf_opendocument_templates"} = $::lx_office_conf{print_templates}->{opendocument};
-  $additional_params->{"conf_vertreter"}              = $::lx_office_conf{system}->{vertreter};
+  $additional_params->{"conf_vertreter"}              = $::lx_office_conf{features}->{vertreter};
   $additional_params->{"conf_show_best_before"}       = $::lx_office_conf{features}->{show_best_before};
   $additional_params->{"conf_parts_image_css"}        = $::lx_office_conf{features}->{parts_image_css};
   $additional_params->{"conf_parts_listing_images"}   = $::lx_office_conf{features}->{parts_listing_images};
   $additional_params->{"conf_show_best_before"}       = $::lx_office_conf{features}->{show_best_before};
   $additional_params->{"conf_parts_image_css"}        = $::lx_office_conf{features}->{parts_image_css};
   $additional_params->{"conf_parts_listing_images"}   = $::lx_office_conf{features}->{parts_listing_images};
@@ -993,17 +1001,13 @@ sub redirect {
   my ($self, $msg) = @_;
 
   if (!$self->{callback}) {
   my ($self, $msg) = @_;
 
   if (!$self->{callback}) {
-
     $self->info($msg);
     $self->info($msg);
-    ::end_of_request();
-  }
 
 
-#  my ($script, $argv) = split(/\?/, $self->{callback}, 2);
-#  $script =~ s|.*/||;
-#  $script =~ s|[^a-zA-Z0-9_\.]||g;
-#  exec("perl", "$script", $argv);
+  } else {
+    print $::form->redirect_header($self->{callback});
+  }
 
 
-  print $::form->redirect_header($self->{callback});
+  ::end_of_request();
 
   $main::lxdebug->leave_sub();
 }
 
   $main::lxdebug->leave_sub();
 }
@@ -1160,7 +1164,7 @@ sub parse_amount {
   if (   ($myconfig->{numberformat} eq '1.000,00')
       || ($myconfig->{numberformat} eq '1000,00')) {
     $amount =~ s/\.//g;
   if (   ($myconfig->{numberformat} eq '1.000,00')
       || ($myconfig->{numberformat} eq '1000,00')) {
     $amount =~ s/\.//g;
-    $amount =~ s/,/\./;
+    $amount =~ s/,/\./g;
   }
 
   if ($myconfig->{numberformat} eq "1'000.00") {
   }
 
   if ($myconfig->{numberformat} eq "1'000.00") {
@@ -1171,7 +1175,9 @@ sub parse_amount {
 
   $main::lxdebug->leave_sub(2);
 
 
   $main::lxdebug->leave_sub(2);
 
-  return ($amount * 1);
+  # Make sure no code wich is not a math expression ends up in eval().
+  return 0 unless $amount =~ /^ [\s \d \( \) \- \+ \* \/ \. ]* $/x;
+  return scalar(eval($amount)) * 1 ;
 }
 
 sub round_amount {
 }
 
 sub round_amount {
@@ -1580,7 +1586,7 @@ sub dbconnect {
   my ($self, $myconfig) = @_;
 
   # connect to database
   my ($self, $myconfig) = @_;
 
   # connect to database
-  my $dbh = DBI->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options)
+  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options)
     or $self->dberror;
 
   # set db options
     or $self->dberror;
 
   # set db options
@@ -1599,7 +1605,7 @@ sub dbconnect_noauto {
   my ($self, $myconfig) = @_;
 
   # connect to database
   my ($self, $myconfig) = @_;
 
   # connect to database
-  my $dbh = DBI->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options(AutoCommit => 0))
+  my $dbh = SL::DBConnect->connect($myconfig->{dbconnect}, $myconfig->{dbuser}, $myconfig->{dbpasswd}, $self->_dbconnect_options(AutoCommit => 0))
     or $self->dberror;
 
   # set db options
     or $self->dberror;
 
   # set db options
@@ -1637,7 +1643,24 @@ sub date_closed {
   my $dbh = $self->dbconnect($myconfig);
 
   my $query = "SELECT 1 FROM defaults WHERE ? < closedto";
   my $dbh = $self->dbconnect($myconfig);
 
   my $query = "SELECT 1 FROM defaults WHERE ? < closedto";
-  my $sth = prepare_execute_query($self, $dbh, $query, $date);
+  my $sth = prepare_execute_query($self, $dbh, $query, conv_date($date));
+
+  # Falls $date = '' - Fehlermeldung aus der Datenbank. Ich denke,
+  # es ist sicher ein conv_date vorher IMMER auszuführen.
+  # Testfälle ohne definiertes closedto:
+  #   Leere Datumseingabe i.O.
+  #     SELECT 1 FROM defaults WHERE '' < closedto
+  #   normale Zahlungsbuchung über Rechnungsmaske i.O.
+  #     SELECT 1 FROM defaults WHERE '10.05.2011' < closedto
+  # Testfälle mit definiertem closedto (30.04.2011):
+  #  Leere Datumseingabe i.O.
+  #   SELECT 1 FROM defaults WHERE '' < closedto
+  # normale Buchung im geschloßenem Zeitraum i.O.
+  #   SELECT 1 FROM defaults WHERE '21.04.2011' < closedto
+  #     Fehlermeldung: Es können keine Zahlungen für abgeschlossene Bücher gebucht werden!
+  # normale Buchung in aktiver Buchungsperiode i.O.
+  #   SELECT 1 FROM defaults WHERE '01.05.2011' < closedto
+
   my ($closed) = $sth->fetchrow_array;
 
   $main::lxdebug->leave_sub();
   my ($closed) = $sth->fetchrow_array;
 
   $main::lxdebug->leave_sub();
@@ -1852,12 +1875,12 @@ sub set_payment_options {
   my $dbh = $self->get_standard_dbh($myconfig);
 
   my $query =
   my $dbh = $self->get_standard_dbh($myconfig);
 
   my $query =
-    qq|SELECT p.terms_netto, p.terms_skonto, p.percent_skonto, p.description_long | .
+    qq|SELECT p.terms_netto, p.terms_skonto, p.percent_skonto, p.description_long , p.description | .
     qq|FROM payment_terms p | .
     qq|WHERE p.id = ?|;
 
   ($self->{terms_netto}, $self->{terms_skonto}, $self->{percent_skonto},
     qq|FROM payment_terms p | .
     qq|WHERE p.id = ?|;
 
   ($self->{terms_netto}, $self->{terms_skonto}, $self->{percent_skonto},
-   $self->{payment_terms}) =
+   $self->{payment_terms}, $self->{payment_description}) =
      selectrow_query($self, $dbh, $query, $self->{payment_id});
 
   if ($transdate eq "") {
      selectrow_query($self, $dbh, $query, $self->{payment_id});
 
   if ($transdate eq "") {
@@ -1904,10 +1927,12 @@ sub set_payment_options {
 
   if ($self->{"language_id"}) {
     $query =
 
   if ($self->{"language_id"}) {
     $query =
-      qq|SELECT t.description_long, l.output_numberformat, l.output_dateformat, l.output_longdates | .
-      qq|FROM translation_payment_terms t | .
+      qq|SELECT t.translation, l.output_numberformat, l.output_dateformat, l.output_longdates | .
+      qq|FROM generic_translations t | .
       qq|LEFT JOIN language l ON t.language_id = l.id | .
       qq|LEFT JOIN language l ON t.language_id = l.id | .
-      qq|WHERE (t.language_id = ?) AND (t.payment_terms_id = ?)|;
+      qq|WHERE (t.language_id = ?)
+           AND (t.translation_id = ?)
+           AND (t.translation_type = 'SL::DB::PaymentTerm/description_long')|;
     my ($description_long, $output_numberformat, $output_dateformat,
       $output_longdates) =
       selectrow_query($self, $dbh, $query,
     my ($description_long, $output_numberformat, $output_dateformat,
       $output_longdates) =
       selectrow_query($self, $dbh, $query,
@@ -2381,7 +2406,7 @@ $main::lxdebug->enter_sub();
 
   $key = "all_payments" unless ($key);
 
 
   $key = "all_payments" unless ($key);
 
-  my $query = qq|SELECT * FROM payment_terms ORDER BY id|;
+  my $query = qq|SELECT * FROM payment_terms ORDER BY sortkey|;
 
   $self->{$key} = selectall_hashref_query($self, $dbh, $query);
 
 
   $self->{$key} = selectall_hashref_query($self, $dbh, $query);
 
@@ -2459,7 +2484,8 @@ sub _get_warehouses {
   $self->{$key} = selectall_hashref_query($self, $dbh, $query);
 
   if ($bins_key) {
   $self->{$key} = selectall_hashref_query($self, $dbh, $query);
 
   if ($bins_key) {
-    $query = qq|SELECT id, description FROM bin WHERE warehouse_id = ?|;
+    $query = qq|SELECT id, description FROM bin WHERE warehouse_id = ?
+                ORDER BY description|;
     my $sth = prepare_query($self, $dbh, $query);
 
     foreach my $warehouse (@{ $self->{$key} }) {
     my $sth = prepare_query($self, $dbh, $query);
 
     foreach my $warehouse (@{ $self->{$key} }) {
@@ -3799,7 +3825,7 @@ Examples:
 =head2 C<header>
 
 Generates a general purpose http/html header and includes most of the scripts
 =head2 C<header>
 
 Generates a general purpose http/html header and includes most of the scripts
-ans stylesheets needed.
+and stylesheets needed. Stylesheets can be added with L<use_stylesheet>.
 
 Only one header will be generated. If the method was already called in this
 request it will not output anything and return undef. Also if no
 
 Only one header will be generated. If the method was already called in this
 request it will not output anything and return undef. Also if no
@@ -3819,9 +3845,8 @@ default to 3 seconds and the refering url.
 
 =item stylesheet
 
 
 =item stylesheet
 
-=item stylesheets
-
-If these are arrayrefs the contents will be inlined into the header.
+Either a scalar or an array ref. Will be inlined into the header. Add
+stylesheets with the L<use_stylesheet> function.
 
 =item landscape
 
 
 =item landscape