Revision 2532 rückgängig gemacht (Befehl aus falschem Verzeichnis abgeschickt)
[kivitendo-erp.git] / SL / Form.pm
index 8275807..67f3782 100644 (file)
@@ -43,8 +43,10 @@ use HTML::Template;
 use SL::Template;
 use CGI::Ajax;
 use SL::DBUtils;
+use SL::Mailer;
 use SL::Menu;
 use SL::User;
+use SL::Common;
 use CGI;
 
 sub _input_to_hash {
@@ -68,61 +70,77 @@ sub _request_to_hash {
   $main::lxdebug->enter_sub(2);
 
   my ($input) = @_;
-  my ($i,        $loc,  $key,    $val);
-  my (%ATTACH,   $f,    $header, $header_body, $len, $buf);
-  my ($boundary, @list, $size,   $body, $x, $blah, $name);
-
-  if ($ENV{'CONTENT_TYPE'}
-      && ($ENV{'CONTENT_TYPE'} =~ /multipart\/form-data; boundary=(.+)$/)) {
-    $boundary = quotemeta('--' . $1);
-    @list     = split(/$boundary/, $input);
-
-    # For some reason there are always 2 extra, that are empty
-    $size = @list - 2;
-
-    for ($x = 1; $x <= $size; $x++) {
-      $header_body = $list[$x];
-      $header_body =~ /\r\n\r\n|\n\n/;
-
-      # Here we split the header and body
-      $header = $`;
-      $body   = $';    #'
-      $body =~ s/\r\n$//;
-
-      # Now we try to get the file name
-      $name = $header;
-      $name =~ /name=\"(.+)\"/;
-      ($name, $blah) = split(/\"/, $1);
-
-      # If the form name is not attach, then we need to parse this like
-      # regular form data
-      if ($name ne "attach") {
-        $body =~ s/%([0-9a-fA-Z]{2})/pack("c",hex($1))/eg;
-        $ATTACH{$name} = $body;
-
-        # Otherwise it is an attachment and we need to finish it up
-      } elsif ($name eq "attach") {
-        $header =~ /filename=\"(.+)\"/;
-        $ATTACH{'FILE_NAME'} = $1;
-        $ATTACH{'FILE_NAME'} =~ s/\"//g;
-        $ATTACH{'FILE_NAME'} =~ s/\s//g;
-        $ATTACH{'FILE_CONTENT'} = $body;
-
-        for ($i = $x; $list[$i]; $i++) {
-          $list[$i] =~ s/^.+name=$//;
-          $list[$i] =~ /\"(\w+)\"/;
-          $ATTACH{$1} = $';    #'
+
+  if (!$ENV{'CONTENT_TYPE'}
+      || ($ENV{'CONTENT_TYPE'} !~ /multipart\/form-data\s*;\s*boundary\s*=\s*(.+)$/)) {
+    $main::lxdebug->leave_sub(2);
+    return _input_to_hash($input);
+  }
+
+  my ($name, $filename, $headers_done, $content_type, $boundary_found, $need_cr);
+  my %params;
+
+  my $boundary = '--' . $1;
+
+  foreach my $line (split m/\n/, $input) {
+    last if (($line eq "${boundary}--") || ($line eq "${boundary}--\r"));
+
+    if (($line eq $boundary) || ($line eq "$boundary\r")) {
+      $params{$name} =~ s|\r?\n$|| if $name;
+
+      undef $name, $filename;
+
+      $headers_done   = 0;
+      $content_type   = "text/plain";
+      $boundary_found = 1;
+      $need_cr        = 0;
+
+      next;
+    }
+
+    next unless $boundary_found;
+
+    if (!$headers_done) {
+      $line =~ s/[\r\n]*$//;
+
+      if (!$line) {
+        $headers_done = 1;
+        next;
+      }
+
+      if ($line =~ m|^content-disposition\s*:.*?form-data\s*;|i) {
+        if ($line =~ m|filename\s*=\s*"(.*?)"|i) {
+          $filename = $1;
+          substr $line, $-[0], $+[0] - $-[0], "";
         }
+
+        if ($line =~ m|name\s*=\s*"(.*?)"|i) {
+          $name = $1;
+          substr $line, $-[0], $+[0] - $-[0], "";
+        }
+
+        $params{$name}    = "";
+        $params{FILENAME} = $filename if ($filename);
+
+        next;
+      }
+
+      if ($line =~ m|^content-type\s*:\s*(.*?)$|i) {
+        $content_type = $1;
       }
+
+      next;
     }
 
-    $main::lxdebug->leave_sub(2);
-    return %ATTACH;
+    next unless $name;
 
-      } else {
-    $main::lxdebug->leave_sub(2);
-    return _input_to_hash($input);
+    $params{$name} .= "${line}\n";
   }
+
+  $params{$name} =~ s|\r?\n$|| if $name;
+
+  $main::lxdebug->leave_sub(2);
+  return %params;
 }
 
 sub new {
@@ -132,6 +150,11 @@ sub new {
 
   my $self = {};
 
+  if ($LXDebug::watch_form) {
+    require SL::Watchdog;
+    tie %{ $self }, 'SL::Watchdog';
+  }
+
   read(STDIN, $_, $ENV{CONTENT_LENGTH});
 
   if ($ENV{QUERY_STRING}) {
@@ -252,6 +275,8 @@ sub hide_form {
 sub error {
   $main::lxdebug->enter_sub();
 
+  $main::lxdebug->show_backtrace();
+
   my ($self, $msg) = @_;
   if ($ENV{HTTP_USER_AGENT}) {
     $msg =~ s/\n/<br>/g;
@@ -347,7 +372,7 @@ sub header {
     return;
   }
 
-  my ($stylesheet, $favicon, $charset);
+  my ($stylesheet, $favicon);
 
   if ($ENV{HTTP_USER_AGENT}) {
 
@@ -365,11 +390,8 @@ sub header {
   |;
     }
 
-    if ($self->{charset}) {
-      $charset =
-        qq|<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$self->{charset}">
-  |;
-    }
+    my $db_charset = $main::dbcharset ? $main::dbcharset : Common::DEFAULT_CHARSET;
+
     if ($self->{landscape}) {
       $pagelayout = qq|<style type="text/css">
                         \@page { size:landscape; }
@@ -399,7 +421,7 @@ sub header {
     foreach $item (@ { $self->{AJAX} }) {
       $ajax .= $item->show_javascript();
     }
-    print qq|Content-Type: text/html
+    print qq|Content-Type: text/html; charset=${db_charset};
 
 <html>
 <head>
@@ -407,7 +429,7 @@ sub header {
   $stylesheet
   $pagelayout
   $favicon
-  $charset
+  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=${db_charset}">
   $jsscript
   $ajax
 
@@ -461,7 +483,7 @@ sub parse_html_template {
         (-f "templates/webpages/${file}_master.html") &&
         ((stat("templates/webpages/${file}_master.html"))[9] >
          (stat("templates/webpages/${file}_${language}.html"))[9])) {
-      my $info = "Developper information: templates/webpages/${file}_master.html is newer than the localized version.\n" .
+      my $info = "Developer information: templates/webpages/${file}_master.html is newer than the localized version.\n" .
         "Please re-run 'locales.pl' in 'locale/${language}'.";
       print(qq|<pre>$info</pre>|);
       die($info);
@@ -503,9 +525,9 @@ sub parse_html_template {
     $additional_params->{"myconfig_jsc_dateformat"} = $jsc_dateformat;
   }
 
-  $additional_params->{"conf_jscalendar"} = $main::jscalendar;
-  $additional_params->{"conf_lizenzen"} = $main::lizenzen;
-  $additional_params->{"conf_latex_templates"} = $main::latex;
+  $additional_params->{"conf_webdav"}                 = $main::webdav;
+  $additional_params->{"conf_lizenzen"}               = $main::lizenzen;
+  $additional_params->{"conf_latex_templates"}        = $main::latex;
   $additional_params->{"conf_opendocument_templates"} = $main::opendocument_templates;
 
   my @additional_param_names = keys(%{$additional_params});
@@ -726,7 +748,9 @@ sub parse_template {
   $main::lxdebug->enter_sub();
 
   my ($self, $myconfig, $userspath) = @_;
-  my $template;
+  my ($template, $out);
+
+  local (*IN, *OUT);
 
   $self->{"cwd"} = getcwd();
   $self->{"tmpdir"} = $self->{cwd} . "/${userspath}";
@@ -769,7 +793,19 @@ sub parse_template {
   # OUT is used for the media, screen, printer, email
   # for postscript we store a copy in a temporary file
   my $fileid = time;
-  $self->{tmpfile} = "$userspath/${fileid}.$self->{IN}" if ( $self->{tmpfile} eq '' );
+  my $prepend_userspath;
+
+  if (!$self->{tmpfile}) {
+    $self->{tmpfile}   = "${fileid}.$self->{IN}";
+    $prepend_userspath = 1;
+  }
+
+  $prepend_userspath = 1 if substr($self->{tmpfile}, 0, length $userspath) eq $userspath;
+
+  $self->{tmpfile} =~ s|.*/||;
+  $self->{tmpfile} =~ s/[^a-zA-Z0-9\._\ \-]//g;
+  $self->{tmpfile} = "$userspath/$self->{tmpfile}" if $prepend_userspath;
+
   if ($template->uses_temp_file() || $self->{media} eq 'email') {
     $out = $self->{OUT};
     $self->{OUT} = ">$self->{tmpfile}";
@@ -793,12 +829,11 @@ sub parse_template {
 
     if ($self->{media} eq 'email') {
 
-      use SL::Mailer;
-
       my $mail = new Mailer;
 
       map { $mail->{$_} = $self->{$_} }
-        qw(cc bcc subject message version format charset);
+        qw(cc bcc subject message version format);
+      $mail->{charset} = $main::dbcharset ? $main::dbcharset : Common::DEFAULT_CHARSET;
       $mail->{to} = $self->{EMAIL_RECIPIENT} ? $self->{EMAIL_RECIPIENT} : $self->{email};
       $mail->{from}   = qq|"$myconfig->{name}" <$myconfig->{email}>|;
       $mail->{fileid} = "$fileid.";
@@ -835,7 +870,7 @@ sub parse_template {
 
       }
 
-      my $err = $mail->send($out);
+      my $err = $mail->send();
       $self->error($self->cleanup . "$err") if ($err);
 
     } else {
@@ -856,7 +891,10 @@ sub parse_template {
           open(OUT, $self->{OUT})
             or $self->error($self->cleanup . "$self->{OUT} : $!");
         } else {
-          $self->{attachment_filename} = $self->{tmpfile} if ($self->{attachment_filename} eq '');
+          $self->{attachment_filename} = ($self->{attachment_filename}) 
+                                       ? $self->{attachment_filename}
+                                       : $self->generate_attachment_filename();
+
           # launch application
           print qq|Content-Type: | . $template->get_mime_type() . qq|
 Content-Disposition: attachment; filename="$self->{attachment_filename}"
@@ -888,6 +926,48 @@ Content-Length: $numbytes
   $main::lxdebug->leave_sub();
 }
 
+sub generate_attachment_filename {
+  my ($self) = @_;
+
+  my %formname_translations = (
+     bin_list            => $main::locale->text('Bin List'),
+     credit_note         => $main::locale->text('Credit Note'),
+     invoice             => $main::locale->text('Invoice'),
+     packing_list        => $main::locale->text('Packing List'),
+     pick_list           => $main::locale->text('Pick List'),
+     proforma            => $main::locale->text('Proforma Invoice'),
+     purchase_order      => $main::locale->text('Purchase Order'),
+     request_quotation   => $main::locale->text('RFQ'),
+     sales_order         => $main::locale->text('Confirmation'),
+     sales_quotation     => $main::locale->text('Quotation'),
+     storno_invoice      => $main::locale->text('Storno Invoice'),
+     storno_packing_list => $main::locale->text('Storno Packing List'),
+  );
+
+  my $attachment_filename = $formname_translations{$self->{"formname"}};
+  my $prefix = 
+      (grep { $self->{"type"} eq $_ } qw(invoice credit_note)) ? "inv"
+    : ($self->{"type"} =~ /_quotation$/)                       ? "quo"
+    :                                                            "ord";
+
+  if ($attachment_filename && $self->{"${prefix}number"}) {
+    $attachment_filename .= "_" . $self->{"${prefix}number"}
+                            . (  $self->{format} =~ /pdf/i          ? ".pdf"
+                               : $self->{format} =~ /postscript/i   ? ".ps"
+                               : $self->{format} =~ /opendocument/i ? ".odt"
+                               : $self->{format} =~ /html/i         ? ".html"
+                               :                                      "");
+    $attachment_filename =~ s/ /_/g;
+    my %umlaute = ( "ä" => "ae", "ö" => "oe", "ü" => "ue", 
+                    "Ä" => "Ae", "Ö" => "Oe", "Ü" => "Ue", "ß" => "ss");
+    map { $attachment_filename =~ s/$_/$umlaute{$_}/g } keys %umlaute;
+  } else {
+    $attachment_filename = "";
+  }
+
+  return $attachment_filename;
+}
+
 sub cleanup {
   $main::lxdebug->enter_sub();
 
@@ -1113,7 +1193,9 @@ sub check_exchangerate {
   my $query = qq|SELECT e.$fld FROM exchangerate e
                  WHERE e.curr = ? AND e.transdate = ?|;
   my ($exchangerate) = selectrow_query($self, $dbh, $query, $currency, $transdate);
-  $dbh->disconnect;
+  $dbh->disconnect();
+
+  $exchangerate = 1 if ($exchangerate == 0);
 
   $main::lxdebug->leave_sub();
 
@@ -1329,8 +1411,8 @@ sub get_employee {
   my ($self, $dbh) = @_;
 
   my $query = qq|SELECT id, name FROM employee WHERE login = ?|;
-  ($self->{employee_id}, $self->{employee}) = selectrow_query($self, $dbh, $query, $self->{login});
-  $self->{employee_id} *= 1;
+  ($self->{"employee_id"}, $self->{"employee"}) = selectrow_query($self, $dbh, $query, $self->{login});
+  $self->{"employee_id"} *= 1;
 
   $main::lxdebug->leave_sub();
 }
@@ -1455,10 +1537,7 @@ sub _get_shipto {
   $key = "all_shipto" unless ($key);
 
   # get shipping addresses
-  my $query =
-    qq|SELECT shipto_id, shiptoname, shiptodepartment_1 | .
-    qq|FROM shipto | .
-    qq|WHERE trans_id = ?|;
+  my $query = qq|SELECT * FROM shipto WHERE trans_id = ?|;
 
   $self->{$key} = selectall_hashref_query($self, $dbh, $query, $vc_id);
 
@@ -1490,7 +1569,7 @@ sub _get_charts {
   my $transdate = quote_db_date($params->{transdate});
 
   my $query =
-    qq|SELECT c.accno, c.description, c.link, tk.taxkey_id, tk.tax_id | .
+    qq|SELECT c.id, c.accno, c.description, c.link, tk.taxkey_id, tk.tax_id | .
     qq|FROM chart c | .
     qq|LEFT JOIN taxkeys tk ON | .
     qq|(tk.id = (SELECT id FROM taxkeys | .
@@ -1534,11 +1613,10 @@ sub _get_taxzones {
 sub _get_employees {
   $main::lxdebug->enter_sub();
 
-  my ($self, $dbh, $key) = @_;
+  my ($self, $dbh, $default_key, $key) = @_;
 
-  $key = "all_employees" unless ($key);
-  $self->{$key} =
-    selectall_hashref_query($self, $dbh, qq|SELECT * FROM employee|);
+  $key = $default_key unless ($key);
+  $self->{$key} = selectall_hashref_query($self, $dbh, qq|SELECT * FROM employee ORDER BY name|);
 
   $main::lxdebug->leave_sub();
 }
@@ -1569,6 +1647,90 @@ sub _get_languages {
   $main::lxdebug->leave_sub();
 }
 
+sub _get_dunning_configs {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_dunning_configs" unless ($key);
+
+  my $query = qq|SELECT * FROM dunning_config ORDER BY dunning_level|;
+
+  $self->{$key} = selectall_hashref_query($self, $dbh, $query);
+
+  $main::lxdebug->leave_sub();
+}
+
+sub _get_currencies {
+$main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_currencies" unless ($key);
+
+  my $query = qq|SELECT curr AS currency FROM defaults|;
+  $self->{$key} = [split(/\:/ , selectfirst_hashref_query($self, $dbh, $query)->{currency})];
+
+  $main::lxdebug->leave_sub();
+}
+
+sub _get_payments {
+$main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_payments" unless ($key);
+
+  my $query = qq|SELECT * FROM payment_terms ORDER BY id|;
+  $self->{$key} = selectall_hashref_query($self, $dbh, $query);
+
+  $main::lxdebug->leave_sub();
+}
+
+sub _get_customers {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_customers" unless ($key);
+
+  my $query = qq|SELECT * FROM customer ORDER BY name|;
+
+  $self->{$key} = selectall_hashref_query($self, $dbh, $query);
+
+  $main::lxdebug->leave_sub();
+}
+
+sub _get_vendors {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_vendors" unless ($key);
+
+  my $query = qq|SELECT * FROM vendor ORDER BY name|;
+
+  $self->{$key} = selectall_hashref_query($self, $dbh, $query);
+
+  $main::lxdebug->leave_sub();
+}
+
+sub _get_departments {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $dbh, $key) = @_;
+
+  $key = "all_departments" unless ($key);
+
+  my $query = qq|SELECT * FROM department ORDER BY description|;
+
+  $self->{$key} = selectall_hashref_query($self, $dbh, $query);
+
+  $main::lxdebug->leave_sub();
+}
+
 sub get_lists {
   $main::lxdebug->enter_sub();
 
@@ -1616,13 +1778,41 @@ sub get_lists {
   }
 
   if ($params{"employees"}) {
-    $self->_get_employees($dbh, $params{"employees"});
+    $self->_get_employees($dbh, "all_employees", $params{"employees"});
+  }
+  
+  if ($params{"salesmen"}) {
+    $self->_get_employees($dbh, "all_salesmen", $params{"salesmen"});
   }
 
   if ($params{"business_types"}) {
     $self->_get_business_types($dbh, $params{"business_types"});
   }
 
+  if ($params{"dunning_configs"}) {
+    $self->_get_dunning_configs($dbh, $params{"dunning_configs"});
+  }
+  
+  if($params{"currencies"}) {
+    $self->_get_currencies($dbh, $params{"currencies"});
+  }
+  
+  if($params{"customers"}) {
+    $self->_get_customers($dbh, $params{"customers"});
+  }
+  
+  if($params{"vendors"}) {
+    $self->_get_vendors($dbh, $params{"vendors"});
+  }
+  
+  if($params{"payments"}) {
+    $self->_get_payments($dbh, $params{"payments"});
+  }
+
+  if($params{"departments"}) {
+    $self->_get_departments($dbh, $params{"departments"});
+  }
+
   $dbh->disconnect();
 
   $main::lxdebug->leave_sub();
@@ -1921,14 +2111,13 @@ sub create_links {
     }
 
     # now get the account numbers
-     $query = qq|SELECT c.accno, c.description, c.link, c.taxkey_id, tk.tax_id
-                 FROM chart c, taxkeys tk
-                 WHERE c.link LIKE ? 
-                   AND (    tk.chart_id = c.id OR     c.link LIKE '%_tax%') 
-                   AND (NOT tk.chart_id = c.id OR NOT c.link LIKE '%_tax%')
-                   AND (tk.id = (SELECT id FROM taxkeys WHERE taxkeys.chart_id = c.id AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1)
-                     OR c.link LIKE '%_tax%')
-                 ORDER BY c.accno|;
+    $query = qq|SELECT c.accno, c.description, c.link, c.taxkey_id, tk.tax_id
+                FROM chart c
+                LEFT JOIN taxkeys tk ON (tk.chart_id = c.id)
+                WHERE c.link LIKE ?
+                  AND (tk.id = (SELECT id FROM taxkeys WHERE taxkeys.chart_id = c.id AND startdate <= $transdate ORDER BY startdate DESC LIMIT 1)
+                    OR c.link LIKE '%_tax%')
+                ORDER BY c.accno|;
 
     $sth = $dbh->prepare($query);
     do_statement($self, $sth, $query, "%$module%");
@@ -2275,6 +2464,7 @@ sub save_status {
 # $main::locale->text('PRINTED')
 # $main::locale->text('MAILED')
 # $main::locale->text('SCREENED')
+# $main::locale->text('CANCELED')
 # $main::locale->text('invoice')
 # $main::locale->text('proforma')
 # $main::locale->text('sales_order')
@@ -2295,12 +2485,12 @@ sub save_history {
     &get_employee($self, $dbh);
   }
 
-  my $query =
-    qq|INSERT INTO history_erp (trans_id, employee_id, addition, what_done, snumbers) | .
-    qq|VALUES (?, ?, ?, ?, ?)|;
 my @values = (conv_i($self->{id}), conv_i($self->{employee_id}),
-                $self->{addition}, $self->{what_done}, "$self->{snumbers}");
 do_query($self, $dbh, $query, @values);
+my $query =
+   qq|INSERT INTO history_erp (trans_id, employee_id, addition, what_done, snumbers) | .
+   qq|VALUES (?, (SELECT id FROM employee WHERE login = ?), ?, ?, ?)|;
my @values = (conv_i($self->{id}), $self->{login},
+               $self->{addition}, $self->{what_done}, "$self->{snumbers}");
+ do_query($self, $dbh, $query, @values);
 
   $main::lxdebug->leave_sub();
 }
@@ -2308,10 +2498,9 @@ sub save_history {
 sub get_history {
   $main::lxdebug->enter_sub();
 
-  my $self = shift();
-  my $dbh = shift();
-  my $trans_id = shift();
-  my $restriction = shift();
+  my ($self, $dbh, $trans_id, $restriction, $order) = @_;
+  my ($orderBy, $desc) = split(/\-\-/, $order);
+  $order = " ORDER BY " . ($order eq "" ? " h.itime " : ($desc == 1 ? $orderBy . " DESC " : $orderBy . " "));
   my @tempArray;
   my $i = 0;
   if ($trans_id ne "") {
@@ -2319,12 +2508,13 @@ sub get_history {
       qq|SELECT h.employee_id, h.itime::timestamp(0) AS itime, h.addition, h.what_done, emp.name, h.snumbers, h.trans_id AS id | .
       qq|FROM history_erp h | .
       qq|LEFT JOIN employee emp ON (emp.id = h.employee_id) | .
-      qq|WHERE trans_id = ? |
-      . $restriction;
-
+      qq|WHERE trans_id = | . $trans_id
+      . $restriction . qq| |
+      . $order;
+      
     my $sth = $dbh->prepare($query) || $self->dberror($query);
 
-    $sth->execute($trans_id) || $self->dberror("$query ($trans_id)");
+    $sth->execute() || $self->dberror("$query");
 
     while(my $hash_ref = $sth->fetchrow_hashref()) {
       $hash_ref->{addition} = $main::locale->text($hash_ref->{addition});
@@ -2332,7 +2522,7 @@ sub get_history {
       $hash_ref->{snumbers} =~ s/^.+_(.*)$/$1/g;
       $tempArray[$i++] = $hash_ref;
     }
-    return \@tempArray and $main::lxdebug->leave_sub()
+    $main::lxdebug->leave_sub() and return \@tempArray 
       if ($i > 0 && $tempArray[0] ne "");
   }
   $main::lxdebug->leave_sub();