Revision 0e68056c
Von Kivitendo Admin vor etwa 10 Jahren hinzugefügt
SL/Form.pm | ||
---|---|---|
79 | 79 |
use URI; |
80 | 80 |
use List::Util qw(first max min sum); |
81 | 81 |
use List::MoreUtils qw(all any apply); |
82 |
use SL::DB::Tax; |
|
82 | 83 |
|
83 | 84 |
use strict; |
84 | 85 |
|
... | ... | |
3446 | 3447 |
return $self; |
3447 | 3448 |
} |
3448 | 3449 |
|
3450 |
sub calculate_arap { |
|
3451 |
my ($self,$buysell,$taxincluded,$exchangerate,$roundplaces) = @_; |
|
3452 |
|
|
3453 |
# this function is used to calculate netamount, total_tax and amount for AP and |
|
3454 |
# AR transactions (Kreditoren-/Debitorenbuchungen) by going over all lines |
|
3455 |
# (1..$rowcount) |
|
3456 |
# Thus it needs a fully prepared $form to work on. |
|
3457 |
# calculate_arap assumes $form->{amount_$i} entries still need to be parsed |
|
3458 |
|
|
3459 |
# The calculated total values are all rounded (default is to 2 places) and |
|
3460 |
# returned as parameters rather than directly modifying form. The aim is to |
|
3461 |
# make the calculation of AP and AR behave identically. There is a test-case |
|
3462 |
# for this function in t/form/arap.t |
|
3463 |
|
|
3464 |
# While calculating the totals $form->{amount_$i} and $form->{tax_$i} are |
|
3465 |
# modified and formatted and receive the correct sign for writing straight to |
|
3466 |
# acc_trans, depending on whether they are ar or ap. |
|
3467 |
|
|
3468 |
# check parameters |
|
3469 |
die "taxincluded needed in Form->calculate_arap" unless defined $taxincluded; |
|
3470 |
die "exchangerate needed in Form->calculate_arap" unless defined $exchangerate; |
|
3471 |
die 'illegal buysell parameter, has to be \"buy\" or \"sell\" in Form->calculate_arap\n' unless $buysell =~ /^(buy|sell)$/; |
|
3472 |
$roundplaces = 2 unless $roundplaces; |
|
3473 |
|
|
3474 |
my $sign = 1; # adjust final results for writing amount to acc_trans |
|
3475 |
$sign = -1 if $buysell eq 'buy'; |
|
3476 |
|
|
3477 |
my ($netamount,$total_tax,$amount); |
|
3478 |
|
|
3479 |
my $tax; |
|
3480 |
|
|
3481 |
# parse and round amounts, setting correct sign for writing to acc_trans |
|
3482 |
for my $i (1 .. $self->{rowcount}) { |
|
3483 |
$self->{"amount_$i"} = $self->round_amount($self->parse_amount(\%::myconfig, $self->{"amount_$i"}) * $exchangerate * $sign, $roundplaces); |
|
3484 |
|
|
3485 |
$amount += $self->{"amount_$i"} * $sign; |
|
3486 |
} |
|
3487 |
|
|
3488 |
for my $i (1 .. $self->{rowcount}) { |
|
3489 |
next unless $self->{"amount_$i"}; |
|
3490 |
($self->{"tax_id_$i"}) = split /--/, $self->{"taxchart_$i"}; |
|
3491 |
my $tax_id = $self->{"tax_id_$i"}; |
|
3492 |
|
|
3493 |
my $selected_tax = SL::DB::Manager::Tax->find_by(id => "$tax_id"); |
|
3494 |
|
|
3495 |
if ( $selected_tax ) { |
|
3496 |
|
|
3497 |
if ( $buysell eq 'sell' ) { |
|
3498 |
$self->{AR_amounts}{"tax_$i"} = $selected_tax->chart->accno unless $selected_tax->taxkey == 0; |
|
3499 |
} else { |
|
3500 |
$self->{AP_amounts}{"tax_$i"} = $selected_tax->chart->accno unless $selected_tax->taxkey == 0; |
|
3501 |
}; |
|
3502 |
|
|
3503 |
$self->{"taxkey_$i"} = $selected_tax->taxkey; |
|
3504 |
$self->{"taxrate_$i"} = $selected_tax->rate; |
|
3505 |
}; |
|
3506 |
|
|
3507 |
($self->{"amount_$i"}, $self->{"tax_$i"}) = $self->calculate_tax($self->{"amount_$i"},$self->{"taxrate_$i"},$taxincluded,$roundplaces); |
|
3508 |
|
|
3509 |
$netamount += $self->{"amount_$i"}; |
|
3510 |
$total_tax += $self->{"tax_$i"}; |
|
3511 |
|
|
3512 |
} |
|
3513 |
$amount = $netamount + $total_tax; |
|
3514 |
|
|
3515 |
# due to $sign amount_$i und tax_$i already have the right sign for acc_trans |
|
3516 |
# but reverse sign of totals for writing amounts to ar |
|
3517 |
if ( $buysell eq 'buy' ) { |
|
3518 |
$netamount *= -1; |
|
3519 |
$amount *= -1; |
|
3520 |
$total_tax *= -1; |
|
3521 |
}; |
|
3522 |
|
|
3523 |
return($netamount,$total_tax,$amount); |
|
3524 |
} |
|
3525 |
|
|
3449 | 3526 |
sub format_dates { |
3450 | 3527 |
my ($self, $dateformat, $longformat, @indices) = @_; |
3451 | 3528 |
|
... | ... | |
3558 | 3635 |
return $layout; |
3559 | 3636 |
} |
3560 | 3637 |
|
3638 |
sub calculate_tax { |
|
3639 |
# this function calculates the net amount and tax for the lines in ar, ap and |
|
3640 |
# gl and is used for update as well as post. When used with update the return |
|
3641 |
# value of amount isn't needed |
|
3642 |
|
|
3643 |
# calculate_tax should always work with positive values, or rather as the user inputs them |
|
3644 |
# calculate_tax uses db/perl numberformat, i.e. parsed numbers |
|
3645 |
# convert to negative numbers (when necessary) only when writing to acc_trans |
|
3646 |
# the amount from $form for ap/ar/gl is currently always rounded to 2 decimals before it reaches here |
|
3647 |
# for post_transaction amount already contains exchangerate and correct sign and is rounded |
|
3648 |
# calculate_tax doesn't (need to) know anything about exchangerate |
|
3649 |
|
|
3650 |
my ($self,$amount,$taxrate,$taxincluded,$roundplaces) = @_; |
|
3651 |
|
|
3652 |
$roundplaces = 2 unless defined $roundplaces; |
|
3653 |
|
|
3654 |
my $tax; |
|
3655 |
|
|
3656 |
if ($taxincluded *= 1) { |
|
3657 |
# calculate tax (unrounded), subtract from amount, round amount and round tax |
|
3658 |
$tax = $amount - ($amount / ($taxrate + 1)); # equivalent to: taxrate * amount / (taxrate + 1) |
|
3659 |
$amount = $self->round_amount($amount - $tax, $roundplaces); |
|
3660 |
$tax = $self->round_amount($tax, $roundplaces); |
|
3661 |
} else { |
|
3662 |
$tax = $amount * $taxrate; |
|
3663 |
$tax = $self->round_amount($tax, $roundplaces); |
|
3664 |
} |
|
3665 |
|
|
3666 |
$tax = 0 unless $tax; |
|
3667 |
|
|
3668 |
return ($amount,$tax); |
|
3669 |
}; |
|
3670 |
|
|
3561 | 3671 |
1; |
3562 | 3672 |
|
3563 | 3673 |
__END__ |
Auch abrufbar als: Unified diff
Rundung bei Debitorenbuchung, Kreditorenbuchung und Dialogbuchung
Zwei neue Hilfsfunktionen für Form eingeführt die von ap/ar/gl genutzt
werden:
vorhandenen $form in ar/ap, und formatiert und rundet die amount_$i and
tax_$i in der $form.
Das Ziel war es, daß diese drei Belege mit den gleichen Formeln zur
Steuerberechnung bei Steuer inkl./exkl. arbeiten. Ein Vorteil im
Vergleich zur Einkaufs- und Verkaufsrechnung ist, daß es hier keine
Positionen/Mengen/Rabatte/etc gibt, sondern direkt Werte auf Konten
bebucht werden, man muß nur Währungskurse berücksichtigen und beim
Schreiben in die Datenbank auf die Vorzeichen achten. Einkaufs- und
Verkaufsrechnungen werden hiervon nicht beeinflußt.
Vor allem bei der Einstellung "MwSt. inkl" wird die Steuer nun immer auf
zwei Stellen gerundet in die Datenbank geschrieben, und nicht (wie
bisher in manchen Fällen) mit 5 Nachkommastellen, was zu mehreren Bugs
geführt hat.
Es gibt einen neuen Test t/form/arap.t der die Berechnungen dieser
beiden Funktionen testet, nicht aber das eigentliche Buchen der Belege.
Mit diesem Commit sollten für zukünftige Buchungen folgende Bugs behoben
sein:
1691 - Rundung bei Berichten bei Buchungen mit MwSt inkl.
2029 - Rundungsfehler bei Dialogbuchung
2033 - Unterschiede in Rundungen durch taxincluded
2094 - Rundungsprobleme in Kreditorenbuchungen: Cent "kippt" bei Zahlungseinbuchung
2435 - Rundungsfehler in Kreditorenbuchungen (Netto vs. Brutto)
Dieser Commit greift in die Eingeweide von Uraltcode ein, wo die
diversen Stellen alle mal mit copy&paste entstanden und dann langsam
divergiert sind, hat also hohes Fehlerpotential. Es lohnt sich, den
DATEV-Check anzuschalten.