Merge von 681 aus unstable: Sammelauftraege + Bugfix
[kivitendo-erp.git] / SL / Form.pm
index 62a76e7..5fb58af 100644 (file)
@@ -1,4 +1,4 @@
-#=====================================================================
+#====================================================================
 # LX-Office ERP
 # Copyright (C) 2004
 # Based on SQL-Ledger Version 2.1.9
@@ -192,6 +192,42 @@ sub unescape {
   return $str;
 }
 
+sub quote {
+  my ($self, $str) = @_;
+
+  if ($str && ! ref($str)) {
+    $str =~ s/"/"/g;
+  }
+
+  $str;
+
+}
+
+
+sub unquote {
+  my ($self, $str) = @_;
+
+  if ($str && ! ref($str)) {
+    $str =~ s/"/"/g;
+  }
+
+  $str;
+
+}
+
+sub hide_form {
+  my $self = shift;
+
+  if (@_) {
+    for (@_) { print qq|<input type=hidden name="$_" value="|.$self->quote($self->{$_}).qq|">\n| }
+  } else {
+    delete $self->{header};
+    for (sort keys %$self) { print qq|<input type=hidden name="$_" value="|.$self->quote($self->{$_}).qq|">\n| }
+  }
+  
+}
+
 sub error {
   $main::lxdebug->enter_sub();
 
@@ -346,8 +382,9 @@ function fokus(){document.$self->{fokus}.focus();}
       $jsscript = qq|
         <style type="text/css">\@import url(js/jscalendar/calendar-win2k-1.css);</style>
         <script type="text/javascript" src="js/jscalendar/calendar.js"></script>
-        <script type="text/javascript" src="js/jscalendar/lang/calendar-de.js"></script>
-        <script type="text/javascript" src="js/jscalendar/calendar-setup.js"></script>
+        <script type="text/javascript" src="js/jscalendar/lang/calendar-de.js"></script>
+        <script type="text/javascript" src="js/jscalendar/calendar-setup.js"></script>
+        $self->{javascript}
        |;
     }
 
@@ -413,25 +450,25 @@ sub write_trigger {
 
   $trigger_1 = qq|
        Calendar.setup(
-       {
-         inputField  : "$inputField_1",
-         ifFormat    :"$ifFormat",
-         align    : "$align_1",     
-         button      : "$button_1"
-       }
-       );
+      {
+      inputField : "$inputField_1",
+      ifFormat :"$ifFormat",
+      align : "$align_1", 
+      button : "$button_1"
+      }
+      );
        |;
 
   if ($qty == 2) {
     $trigger_2 = qq|
        Calendar.setup(
        {
-         inputField  : "$inputField_2",
-         ifFormat    :"$ifFormat",
-         align    : "$align_2",     
-         button      : "$button_2"
-       }
-       );
+      inputField : "$inputField_2",
+      ifFormat :"$ifFormat",
+      align : "$align_2", 
+      button : "$button_2"
+      }
+      );
         |;
   }
   $jsscript = qq|
@@ -489,6 +526,7 @@ sub format_amount {
 
   # is the amount negative
   my $negative = ($amount < 0);
+  my $fillup = "";
 
   if ($amount != 0) {
     if ($myconfig->{numberformat} && ($myconfig->{numberformat} ne '1000.00'))
@@ -496,24 +534,25 @@ sub format_amount {
       my ($whole, $dec) = split /\./, "$amount";
       $whole =~ s/-//;
       $amount = join '', reverse split //, $whole;
+      $fillup = "0" x ($places - length($dec));
 
       if ($myconfig->{numberformat} eq '1,000.00') {
         $amount =~ s/\d{3,}?/$&,/g;
         $amount =~ s/,$//;
         $amount = join '', reverse split //, $amount;
-        $amount .= "\.$dec" if ($dec ne "");
+        $amount .= "\.$dec".$fillup if ($places ne '' && $places*1 != 0);
       }
 
       if ($myconfig->{numberformat} eq '1.000,00') {
         $amount =~ s/\d{3,}?/$&./g;
         $amount =~ s/\.$//;
         $amount = join '', reverse split //, $amount;
-        $amount .= ",$dec" if ($dec ne "");
+        $amount .= ",$dec".$fillup if ($places ne '' && $places*1 != 0);
       }
 
       if ($myconfig->{numberformat} eq '1000,00') {
         $amount = "$whole";
-        $amount .= ",$dec" if ($dec ne "");
+        $amount .= ",$dec" .$fillup if ($places ne '' && $places*1 != 0);
       }
 
       if ($dash =~ /-/) {
@@ -565,28 +604,25 @@ sub round_amount {
   $main::lxdebug->enter_sub();
 
   my ($self, $amount, $places) = @_;
-  my $rc;
-
-  #  $places = 3 if $places == 2;
+  my $round_amount;
 
-  if (($places * 1) >= 0) {
-
-    # add 1/10^$places+3
-    $rc =
-      sprintf("%.${places}f",
-              $amount + (1 / (10**($places + 3))) * (($amount > 0) ? 1 : -1));
-  } else {
-    $places *= -1;
-    $rc =
-      sprintf("%.f", $amount / (10**$places) + (($amount > 0) ? 0.1 : -0.1)) *
-      (10**$places);
-  }
+  # Rounding like "Kaufmannsrunden"
+  # Descr. http://de.wikipedia.org/wiki/Rundung
+  # Inspired by 
+  # http://www.perl.com/doc/FAQs/FAQ/oldfaq-html/Q4.13.html
+  # Solves Bug: 189
+  # Udo Spallek
+  $amount       = $amount * (10 ** ($places));
+  $round_amount = int($amount + .5 * ($amount <=> 0))/(10**($places));
 
   $main::lxdebug->leave_sub();
 
-  return $rc;
+  return $round_amount;
+  
 }
 
+
+
 sub parse_template {
   $main::lxdebug->enter_sub();
 
@@ -596,7 +632,7 @@ sub parse_template {
   # Some variables used for page breaks
   my ($chars_per_line, $lines_on_first_page, $lines_on_second_page) =
     (0, 0, 0);
-  my ($current_page, $current_line) = (1, 1);
+  my ($current_page, $current_line, $current_row) = (1, 1, 0);
   my $pagebreak = "";
   my $sum       = 0;
 
@@ -700,8 +736,9 @@ sub parse_template {
             $lpp = $lines_on_second_page;
           }
 
-          # Yes we need a manual page break
-          if (($current_line + $lines) > $lpp) {
+          # Yes we need a manual page break -- or the user has forced one
+          if ((($current_line + $lines) > $lpp) ||
+              ($self->{"_forced_pagebreaks"} && grep(/^${current_row}$/, @{$self->{"_forced_pagebreaks"}}))) {
             my $pb = $pagebreak;
 
             # replace the special variables <%sumcarriedforward%>
@@ -722,6 +759,7 @@ sub parse_template {
             $current_line = 1;
           }
           $current_line += $lines;
+          $current_row++;
         }
         $sum += $self->parse_amount($myconfig, $self->{"linetotal"}[$i]);
 
@@ -987,6 +1025,18 @@ sub format_string {
 
   %unique_fields = map({ $_ => 1 } @fields);
   @fields = keys(%unique_fields);
+
+  foreach my $field (@fields) {
+    next unless ($self->{$field} =~ /\<pagebreak\>/);
+    $self->{$field} =~ s/\<pagebreak\>//g;
+    if ($field =~ /.*_(\d+)$/) {
+      if (!$self->{"_forced_pagebreaks"}) {
+        $self->{"_forced_pagebreaks"} = [];
+      }
+      push(@{ $self->{"_forced_pagebreaks"} }, "$1");
+    }
+  }
+
   my $format = $self->{format};
   if ($self->{format} =~ /(postscript|pdf)/) {
     $format = 'tex';
@@ -1035,6 +1085,29 @@ sub format_string {
     map { $self->{$_} =~ s/$key/$replace{$format}{$key}/g; } @fields;
   }
 
+  # Allow some HTML markup to be converted into the output format's
+  # corresponding markup code, e.g. bold or italic.
+  if ('html' eq $format) {
+    my @markup_replace = ('b', 'i', 's', 'u');
+
+    foreach my $key (@markup_replace) {
+      map({ $self->{$_} =~ s/\&lt;(\/?)${key}\&gt;/<$1${key}>/g } @fields);
+    }
+
+  } elsif ('tex' eq $format) {
+    my %markup_replace = ('b' => 'textbf',
+                          'i' => 'textit',
+                          'u' => 'underline');
+
+    foreach my $field (@fields) {
+      foreach my $key (keys(%markup_replace)) {
+        my $new = $markup_replace{$key};
+        $self->{$field} =~
+          s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
+      }
+    }
+  }
+
   $main::lxdebug->leave_sub();
 }
 
@@ -1204,6 +1277,11 @@ sub get_exchangerate {
   $main::lxdebug->enter_sub();
 
   my ($self, $dbh, $curr, $transdate, $fld) = @_;
+  
+  unless ($transdate) {
+    $main::lxdebug->leave_sub();
+    return "";
+  }
 
   my $query = qq|SELECT e.$fld FROM exchangerate e
                  WHERE e.curr = '$curr'
@@ -2043,6 +2121,126 @@ sub get_partsgroup {
   $main::lxdebug->leave_sub();
 }
 
+
+sub get_pricegroup {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $p) = @_;
+
+  my $dbh = $self->dbconnect($myconfig);
+
+  my $query = qq|SELECT p.id, p.pricegroup
+                 FROM pricegroup p|;
+
+  $query .= qq|
+                ORDER BY pricegroup|;
+
+  if ($p->{all}) {
+    $query = qq|SELECT id, pricegroup FROM pricegroup
+                ORDER BY pricegroup|;
+  }
+
+  my $sth = $dbh->prepare($query);
+  $sth->execute || $self->dberror($query);
+
+  $self->{all_pricegroup} = ();
+  while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+    push @{ $self->{all_pricegroup} }, $ref;
+  }
+  $sth->finish;
+  $dbh->disconnect;
+
+  $main::lxdebug->leave_sub();
+}
+
+
+sub audittrail {
+  my ($self, $dbh, $myconfig, $audittrail) = @_;
+  
+# table, $reference, $formname, $action, $id, $transdate) = @_;
+
+  my $query;
+  my $rv;
+  my $disconnect;
+
+  if (! $dbh) {
+    $dbh = $self->dbconnect($myconfig);
+    $disconnect = 1;
+  }
+    
+  # if we have an id add audittrail, otherwise get a new timestamp
+  
+  if ($audittrail->{id}) {
+    
+    $query = qq|SELECT audittrail FROM defaults|;
+    
+    if ($dbh->selectrow_array($query)) {
+      my ($null, $employee_id) = $self->get_employee($dbh);
+
+      if ($self->{audittrail} && !$myconfig) {
+       chop $self->{audittrail};
+       
+       my @a = split /\|/, $self->{audittrail};
+       my %newtrail = ();
+       my $key;
+       my $i;
+       my @flds = qw(tablename reference formname action transdate);
+
+       # put into hash and remove dups
+       while (@a) {
+         $key = "$a[2]$a[3]";
+         $i = 0;
+         $newtrail{$key} = { map { $_ => $a[$i++] } @flds };
+         splice @a, 0, 5;
+       }
+       
+       $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
+                   formname, action, employee_id, transdate)
+                   VALUES ($audittrail->{id}, ?, ?,
+                   ?, ?, $employee_id, ?)|;
+       my $sth = $dbh->prepare($query) || $self->dberror($query);
+
+       foreach $key (sort { $newtrail{$a}{transdate} cmp $newtrail{$b}{transdate} } keys %newtrail) {
+         $i = 1;
+         for (@flds) { $sth->bind_param($i++, $newtrail{$key}{$_}) }
+
+         $sth->execute || $self->dberror;
+         $sth->finish;
+       }
+      }
+
+     
+      if ($audittrail->{transdate}) {
+       $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
+                   formname, action, employee_id, transdate) VALUES (
+                   $audittrail->{id}, '$audittrail->{tablename}', |
+                   .$dbh->quote($audittrail->{reference}).qq|,
+                   '$audittrail->{formname}', '$audittrail->{action}',
+                   $employee_id, '$audittrail->{transdate}')|;
+      } else {
+       $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
+                   formname, action, employee_id) VALUES ($audittrail->{id},
+                   '$audittrail->{tablename}', |
+                   .$dbh->quote($audittrail->{reference}).qq|,
+                   '$audittrail->{formname}', '$audittrail->{action}',
+                   $employee_id)|;
+      }
+      $dbh->do($query);
+    }
+  } else {
+    
+    $query = qq|SELECT current_timestamp FROM defaults|;
+    my ($timestamp) = $dbh->selectrow_array($query);
+
+    $rv = "$audittrail->{tablename}|$audittrail->{reference}|$audittrail->{formname}|$audittrail->{action}|$timestamp|";
+  }
+
+  $dbh->disconnect if $disconnect;
+  
+  $rv;
+  
+}
+
 package Locale;
 
 sub new {