]> wagnertech.de Git - mfinanz.git/blobdiff - SL/Form.pm
JavaScript & Templates in UTF-8 speichern
[mfinanz.git] / SL / Form.pm
index ace85e706ea4513c5963bb3057366cfc5ea7b784..9d032bf690d64eaaf85d2edeaddbc613b4749648 100644 (file)
@@ -41,11 +41,13 @@ use Carp;
 use Data::Dumper;
 
 use Carp;
+use Config;
 use CGI;
 use Cwd;
 use Encode;
 use File::Copy;
 use IO::File;
+use Math::BigInt;
 use SL::Auth;
 use SL::Auth::DB;
 use SL::Auth::LDAP;
@@ -950,28 +952,33 @@ sub parse_amount {
 sub round_amount {
   my ($self, $amount, $places) = @_;
 
-  # Rounding like "Kaufmannsrunden" (see http://de.wikipedia.org/wiki/Rundung )
+  # We use Perl's knowledge of string representation for
+  # rounding. First, convert the floating point number to a string
+  # with a high number of places. Then split the string on the decimal
+  # sign and use integer calculation for rounding the decimal places
+  # part. If an overflow occurs then apply that overflow to the part
+  # before the decimal sign as well using integer arithmetic again.
 
-  # Round amounts to eight places before rounding to the requested
-  # number of places. This gets rid of errors due to internal floating
-  # point representation.
-  $amount   = $self->round_amount($amount, 8) if $places < 8;
+  my $amount_str = sprintf '%.*f', $places + 10, abs($amount);
 
-  # Remember the amount's sign but calculate in positive values only.
-  my $sign  = $amount <=> 0;
-  $amount   = abs $amount;
+  return $amount unless $amount_str =~ m{^(\d+)\.(\d+)$};
 
-  # Shift the amount left by $places+1 decimal places and truncate it
-  # to integer. Then to the integer equivalent of rounding to the next
-  # multiple of 10: first add half of it (5). Then truncate it back to
-  # the lower multiple of 10 by subtracting $amount modulo 10.
-  my $shift = 10 ** ($places + 1);
-  $amount   = int($amount * $shift) + 5;
-  $amount  -= $amount % 10;
+  my ($pre, $post)      = ($1, $2);
+  my $decimals          = '1' . substr($post, 0, $places);
 
-  # Lastly shift the amount back right by $places+1 decimal places and
-  # restore its sign. Then we're done.
-  $amount   = ($amount / $shift) * $sign;
+  my $propagation_limit = $Config{i32size} == 4 ? 7 : 18;
+  my $add_for_rounding  = substr($post, $places, 1) >= 5 ? 1 : 0;
+
+  if ($places > $propagation_limit) {
+    $decimals = Math::BigInt->new($decimals)->badd($add_for_rounding);
+    $pre      = Math::BigInt->new($decimals)->badd(1) if substr($decimals, 0, 1) eq '2';
+
+  } else {
+    $decimals += $add_for_rounding;
+    $pre      += 1 if substr($decimals, 0, 1) eq '2';
+  }
+
+  $amount  = ("${pre}." . substr($decimals, 1)) * ($amount <=> 0);
 
   return $amount;
 }
@@ -1034,7 +1041,7 @@ sub parse_template {
                                       %{ $self->{TEMPLATE_DRIVER_OPTIONS} || {} });
 
   # Copy the notes from the invoice/sales order etc. back to the variable "notes" because that is where most templates expect it to be.
-  $self->{"notes"} = $self->{ $self->{"formname"} . "notes" };
+  $self->{"notes"} = $self->{ $self->{"formname"} . "notes" } if exists $self->{ $self->{"formname"} . "notes" };
 
   if (!$self->{employee_id}) {
     $self->{"employee_${_}"} = $myconfig->{$_} for qw(email tel fax name signature);
@@ -2145,8 +2152,10 @@ sub _get_taxzones {
   my ($self, $dbh, $key) = @_;
 
   $key = "all_taxzones" unless ($key);
+  my $tzfilter = "";
+  $tzfilter = "WHERE obsolete is FALSE" if $key eq 'ALL_ACTIVE_TAXZONES';
 
-  my $query = qq|SELECT * FROM tax_zones ORDER BY id|;
+  my $query = qq|SELECT * FROM tax_zones $tzfilter ORDER BY sortkey|;
 
   $self->{$key} = selectall_hashref_query($self, $dbh, $query);
 
@@ -3361,15 +3370,15 @@ sub prepare_for_printing {
   my ($language_tc, $output_numberformat, $output_dateformat, $output_longdates);
   if ($self->{language_id}) {
     ($language_tc, $output_numberformat, $output_dateformat, $output_longdates) = AM->get_language_details(\%::myconfig, $self, $self->{language_id});
-  } else {
-    $output_dateformat   = $::myconfig{dateformat};
-    $output_numberformat = $::myconfig{numberformat};
-    $output_longdates    = 1;
   }
 
-  $self->{myconfig_output_dateformat}   = $output_dateformat;
-  $self->{myconfig_output_longdates}    = $output_longdates;
-  $self->{myconfig_output_numberformat} = $output_numberformat;
+  $output_dateformat   ||= $::myconfig{dateformat};
+  $output_numberformat ||= $::myconfig{numberformat};
+  $output_longdates    //= 1;
+
+  $self->{myconfig_output_dateformat}   = $output_dateformat   // $::myconfig{dateformat};
+  $self->{myconfig_output_longdates}    = $output_longdates    // 1;
+  $self->{myconfig_output_numberformat} = $output_numberformat // $::myconfig{numberformat};
 
   # Retrieve accounts for tax calculation.
   IC->retrieve_accounts(\%::myconfig, $self, map { $_ => $self->{"id_$_"} } 1 .. $self->{rowcount});