Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision a967d2a4

Von Sven Schöling vor mehr als 4 Jahren hinzugefügt

  • ID a967d2a494d1a863b95d060a52ef655e7c00d583
  • Vorgänger fd1ef8ea
  • Nachfolger 8c44628b

SL::Helper::Number - format_amount aus SL::Form ausgelagert

- Neue Funktionen können direkt exportiert werden.
- Alte Funktionen sind in SL::Form für Kompatibilität auf die neuen
geproxied.
- Tracing debug statements (enter_sub, leave_sub) entfernt
- Zusätzlich noch eine neue Kategorie eingeführt: total, um Werte für
acc_trans immer auf 2 Stellen zu runden.

Unterschiede anzeigen:

SL/Form.pm
42 42
use Data::Dumper;
43 43

  
44 44
use Carp;
45
use Config;
46 45
use CGI;
47 46
use Cwd;
48 47
use Encode;
......
88 87
use List::MoreUtils qw(all any apply);
89 88
use SL::DB::Tax;
90 89
use SL::Helper::File qw(:all);
90
use SL::Helper::Number;
91 91
use SL::Helper::CreatePDF qw(merge_pdfs);
92 92

  
93 93
use strict;
......
699 699
  return @columns;
700 700
}
701 701
#
702
sub format_amount {
703
  $main::lxdebug->enter_sub(2);
704

  
705
  my ($self, $myconfig, $amount, $places, $dash) = @_;
706
  $amount ||= 0;
707
  $dash   ||= '';
708
  my $neg = $amount < 0;
709
  my $force_places = defined $places && $places >= 0;
710

  
711
  $amount = $self->round_amount($amount, abs $places) if $force_places;
712
  $neg    = 0 if $amount == 0; # don't show negative zero
713
  $amount = sprintf "%.*f", ($force_places ? $places : 10), abs $amount; # 6 is default for %fa
714

  
715
  # before the sprintf amount was a number, afterwards it's a string. because of the dynamic nature of perl
716
  # this is easy to confuse, so keep in mind: before this comment no s///, m//, concat or other strong ops on
717
  # $amount. after this comment no +,-,*,/,abs. it will only introduce subtle bugs.
718

  
719
  $amount =~ s/0*$// unless defined $places && $places == 0;             # cull trailing 0s
720

  
721
  my @d = map { s/\d//g; reverse split // } my $tmp = $myconfig->{numberformat}; # get delim chars
722
  my @p = split(/\./, $amount);                                          # split amount at decimal point
723 702

  
724
  $p[0] =~ s/\B(?=(...)*$)/$d[1]/g if $d[1];                             # add 1,000 delimiters
725
  $amount = $p[0];
726
  if ($places || $p[1]) {
727
    $amount .= $d[0]
728
            .  ( $p[1] || '' )
729
            .  (0 x max(abs($places || 0) - length ($p[1]||''), 0));     # pad the fraction
730
  }
731

  
732
  $amount = do {
733
    ($dash =~ /-/)    ? ($neg ? "($amount)"                            : "$amount" )                              :
734
    ($dash =~ /DRCR/) ? ($neg ? "$amount " . $main::locale->text('DR') : "$amount " . $main::locale->text('CR') ) :
735
                        ($neg ? "-$amount"                             : "$amount" )                              ;
736
  };
737

  
738
  $main::lxdebug->leave_sub(2);
739
  return $amount;
740
}
703
sub format_amount { shift; goto &SL::Helper::Number::_number; }
741 704

  
742 705
sub format_amount_units {
743 706
  $main::lxdebug->enter_sub();
......
824 787

  
825 788
#
826 789

  
827
sub parse_amount {
828
  $main::lxdebug->enter_sub(2);
829

  
830
  my ($self, $myconfig, $amount) = @_;
790
sub parse_amount { shift; goto &SL::Helper::Number::_parse_number; }
831 791

  
832
  if (!defined($amount) || ($amount eq '')) {
833
    $main::lxdebug->leave_sub(2);
834
    return 0;
835
  }
836

  
837
  if (   ($myconfig->{numberformat} eq '1.000,00')
838
      || ($myconfig->{numberformat} eq '1000,00')) {
839
    $amount =~ s/\.//g;
840
    $amount =~ s/,/\./g;
841
  }
842

  
843
  if ($myconfig->{numberformat} eq "1'000.00") {
844
    $amount =~ s/\'//g;
845
  }
846

  
847
  $amount =~ s/,//g;
848

  
849
  $main::lxdebug->leave_sub(2);
850

  
851
  # Make sure no code wich is not a math expression ends up in eval().
852
  return 0 unless $amount =~ /^ [\s \d \( \) \- \+ \* \/ \. ]* $/x;
853

  
854
  # Prevent numbers from being parsed as octals;
855
  $amount =~ s{ (?<! [\d.] ) 0+ (?= [1-9] ) }{}gx;
856

  
857
  return scalar(eval($amount)) * 1 ;
858
}
859

  
860
sub round_amount {
861
  my ($self, $amount, $places, $adjust) = @_;
862

  
863
  return 0 if !defined $amount;
864

  
865
  $places //= 0;
866

  
867
  if ($adjust) {
868
    my $precision = $::instance_conf->get_precision || 0.01;
869
    return $self->round_amount( $self->round_amount($amount / $precision, 0) * $precision, $places);
870
  }
871

  
872
  # We use Perl's knowledge of string representation for
873
  # rounding. First, convert the floating point number to a string
874
  # with a high number of places. Then split the string on the decimal
875
  # sign and use integer calculation for rounding the decimal places
876
  # part. If an overflow occurs then apply that overflow to the part
877
  # before the decimal sign as well using integer arithmetic again.
878

  
879
  my $int_amount = int(abs $amount);
880
  my $str_places = max(min(10, 16 - length("$int_amount") - $places), $places);
881
  my $amount_str = sprintf '%.*f', $places + $str_places, abs($amount);
882

  
883
  return $amount unless $amount_str =~ m{^(\d+)\.(\d+)$};
884

  
885
  my ($pre, $post)      = ($1, $2);
886
  my $decimals          = '1' . substr($post, 0, $places);
887

  
888
  my $propagation_limit = $Config{i32size} == 4 ? 7 : 18;
889
  my $add_for_rounding  = substr($post, $places, 1) >= 5 ? 1 : 0;
890

  
891
  if ($places > $propagation_limit) {
892
    $decimals = Math::BigInt->new($decimals)->badd($add_for_rounding);
893
    $pre      = Math::BigInt->new($decimals)->badd(1) if substr($decimals, 0, 1) eq '2';
894

  
895
  } else {
896
    $decimals += $add_for_rounding;
897
    $pre      += 1 if substr($decimals, 0, 1) eq '2';
898
  }
899

  
900
  $amount  = ("${pre}." . substr($decimals, 1)) * ($amount <=> 0);
901

  
902
  return $amount;
903
}
792
sub round_amount { shift; goto &SL::Helper::Number::_round_number; }
904 793

  
905 794
sub parse_template {
906 795
  $main::lxdebug->enter_sub();

Auch abrufbar als: Unified diff