Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 2766beaf

Von Moritz Bunkus vor fast 14 Jahren hinzugefügt

  • ID 2766beaf2abefb4bd973a69bcd42f46185c7cb63
  • Vorgänger cf085911
  • Nachfolger e9fb6244

Refactoring; kleine Erweiterungen für Rechnungsberechnung

Unterschiede anzeigen:

SL/DB/Helper/PriceTaxCalculator.pm
7 7

  
8 8
use Carp;
9 9
use List::Util qw(sum);
10
use SL::DB::Default;
10 11
use SL::DB::PriceFactor;
11 12
use SL::DB::Unit;
12 13

  
13 14
sub calculate_prices_and_taxes {
14
  my ($self) = @_;
15
  my ($self, %params) = @_;
15 16

  
16 17
  my $is_sales            = $self->can('customer') && $self->customer;
18
  my $is_invoice          = (ref($self) =~ /Invoice/) || $params{invoice};
17 19

  
18 20
  my %units_by_name       = map { ( $_->name => $_ ) } @{ SL::DB::Manager::Unit->get_all        };
19 21
  my %price_factors_by_id = map { ( $_->id   => $_ ) } @{ SL::DB::Manager::PriceFactor->get_all };
20 22
  my %taxes_by_chart_id   = ();
23
  my %amounts_by_chart_id = ();
24

  
25
  my %data = ( lastcost_total      => 0,
26
               invoicediff         => 0,
27
               units_by_name       => \%units_by_name,
28
               price_factors_by_id => \%price_factors_by_id,
29
               taxes_by_chart_id   => \%taxes_by_chart_id,
30
               amounts_by_chart_id => \%amounts_by_chart_id,
31
               exchangerate        => undef,
32
             );
33

  
34
  if (($self->curr || '') ne SL::DB::Default->get_default_currency) {
35
    $data{exchangerate}   = $::form->check_exchangerate(\%::myconfig, $self->curr, $self->transdate, $is_sales ? 'buy' : 'sell');
36
    $data{exchangerate} ||= $params{exchangerate};
37
  }
38
  $data{exchangerate} ||= 1;
21 39

  
22 40
  $self->netamount(  0);
23 41
  $self->marge_total(0);
24
  my $lastcost_total = 0;
25 42

  
26 43
  my $idx = 0;
27

  
28 44
  foreach my $item ($self->items) {
29 45
    $idx++;
46
    _calculate_item($self, $item, $idx, \%data);
47
  }
30 48

  
31
    my $part_unit  = $units_by_name{ $item->part->unit };
32
    my $item_unit  = $units_by_name{ $item->unit       };
49
  my $tax_sum = sum map { _round($_, 2) } values %taxes_by_chart_id;
33 50

  
34
    croak("Undefined unit " . $item->part->unit) if !$part_unit;
35
    croak("Undefined unit " . $item->unit)       if !$item_unit;
51
  $self->amount(       _round($self->netamount + $tax_sum, 2));
52
  $self->netamount(    _round($self->netamount,            2));
53
  $self->marge_percent($self->netamount ? ($self->netamount - $data{lastcost_total}) * 100 / $self->netamount : 0);
36 54

  
37
    $item->base_qty($item_unit->convert_to($item->qty, $part_unit));
55
  return $self unless wantarray;
56
  return ( self    => $self,
57
           taxes   => \%taxes_by_chart_id,
58
           amounts => \%amounts_by_chart_id,
59
         );
60
}
38 61

  
39
    my $num_dec   = num_decimal_places($item->sellprice);
40
    my $discount  = round($item->sellprice * ($item->discount || 0), $num_dec);
41
    my $sellprice = round($item->sellprice - $discount,              $num_dec);
62
sub _calculate_item {
63
  my ($self, $item, $idx, $data) = @_;
42 64

  
43
    $item->price_factor(      ! $item->price_factor_obj   ? 1 : ($item->price_factor_obj->factor   || 1));
44
    $item->marge_price_factor(! $item->part->price_factor ? 1 : ($item->part->price_factor->factor || 1));
45
    my $linetotal = round($sellprice * $item->qty / $item->price_factor, 2);
65
  my $part_unit  = $data->{units_by_name}->{ $item->part->unit };
66
  my $item_unit  = $data->{units_by_name}->{ $item->unit       };
46 67

  
47
    if (!$linetotal) {
48
      $item->marge_total(  0);
49
      $item->marge_percent(0);
68
  croak("Undefined unit " . $item->part->unit) if !$part_unit;
69
  croak("Undefined unit " . $item->unit)       if !$item_unit;
50 70

  
51
    } else {
52
      my $lastcost = ! ($item->lastcost * 1) ? ($item->part->lastcost || 0) : $item->lastcost;
71
  $item->base_qty($item_unit->convert_to($item->qty, $part_unit));
53 72

  
54
      $item->marge_total(  $linetotal - $lastcost / $item->marge_price_factor);
55
      $item->marge_percent($item->marge_total * 100 / $linetotal);
73
  my $num_dec   = _num_decimal_places($item->sellprice);
74
  my $discount  = _round($item->sellprice * ($item->discount || 0), $num_dec);
75
  my $sellprice = _round($item->sellprice - $discount,              $num_dec);
56 76

  
57
      $self->marge_total(  $self->marge_total + $item->marge_total);
58
      $lastcost_total += $lastcost;
59
    }
77
  $item->price_factor(      ! $item->price_factor_obj   ? 1 : ($item->price_factor_obj->factor   || 1));
78
  $item->marge_price_factor(! $item->part->price_factor ? 1 : ($item->part->price_factor->factor || 1));
79
  my $linetotal = _round($sellprice * $item->qty / $item->price_factor, 2) * $data->{exchangerate};
80
  $linetotal    = _round($linetotal,                                    2);
60 81

  
61
    my $taxkey     = $item->part->get_taxkey(date => $self->transdate, is_sales => $is_sales, taxzone => $self->taxzone_id);
62
    my $tax_rate   = $taxkey->tax->rate;
63
    my $tax_amount = undef;
82
  $data->{invoicediff} += $sellprice * $item->qty * $data->{exchangerate} / $item->price_factor - $linetotal;
64 83

  
65
    if ($self->taxincluded) {
66
      $tax_amount = $linetotal * $tax_rate / ($tax_rate + 1);
67
      $sellprice  = $sellprice             / ($tax_rate + 1);
84
  if (!$linetotal) {
85
    $item->marge_total(  0);
86
    $item->marge_percent(0);
68 87

  
69
    } else {
70
      $tax_amount = $linetotal * $tax_rate;
71
    }
88
  } else {
89
    my $lastcost = ! ($item->lastcost * 1) ? ($item->part->lastcost || 0) : $item->lastcost;
90

  
91
    $item->marge_total(  $linetotal - $lastcost / $item->marge_price_factor);
92
    $item->marge_percent($item->marge_total * 100 / $linetotal);
72 93

  
73
    $taxes_by_chart_id{ $taxkey->chart_id } ||= 0;
74
    $taxes_by_chart_id{ $taxkey->chart_id }  += $tax_amount;
94
    $self->marge_total(  $self->marge_total + $item->marge_total);
95
    $data->{lastcost_total} += $lastcost;
96
  }
97

  
98
  my $taxkey     = $item->part->get_taxkey(date => $self->transdate, is_sales => $data->{is_sales}, taxzone => $self->taxzone_id);
99
  my $tax_rate   = $taxkey->tax->rate;
100
  my $tax_amount = undef;
75 101

  
76
    $self->netamount($self->netamount + $sellprice * $item->qty / $item->price_factor);
102
  if ($self->taxincluded) {
103
    $tax_amount = $linetotal * $tax_rate / ($tax_rate + 1);
104
    $sellprice  = $sellprice             / ($tax_rate + 1);
77 105

  
78
    $::lxdebug->message(0, "CALCULATE! ${idx} i.qty " . $item->qty . " i.sellprice " . $item->sellprice . " sellprice $sellprice taxamount $tax_amount " .
79
                        "i.linetotal $linetotal netamount " . $self->netamount . " marge_total " . $item->marge_total . " marge_percent " . $item->marge_percent);
106
  } else {
107
    $tax_amount = $linetotal * $tax_rate;
80 108
  }
81 109

  
82
  my $tax_sum = sum map { round($_, 2) } values %taxes_by_chart_id;
110
  $data->{taxes_by_chart_id}->{ $taxkey->chart_id } ||= 0;
111
  $data->{taxes_by_chart_id}->{ $taxkey->chart_id }  += $tax_amount;
83 112

  
84
  $self->amount(       round($self->netamount + $tax_sum, 2));
85
  $self->netamount(    round($self->netamount,            2));
86
  $self->marge_percent($self->netamount ? ($self->netamount - $lastcost_total) * 100 / $self->netamount : 0);
113
  $self->netamount($self->netamount + $sellprice * $item->qty / $item->price_factor);
87 114

  
88
  return $self unless wantarray;
89
  return ( self  => $self,
90
           taxes => \%taxes_by_chart_id,
91
         );
115
  my $chart = $item->part->get_chart(type => $data->{is_sales} ? 'income' : 'expense', taxzone => $self->taxzone_id);
116
  $data->{amounts_by_chart_id}->{$chart->id} += $linetotal;
117

  
118
  if ($data->{is_invoice}) {
119
    if ($item->part->is_assembly) {
120
      # process_assembly()...
121
    } else {
122
      # cogs...
123
    }
124
  }
125

  
126
  $::lxdebug->message(0, "CALCULATE! ${idx} i.qty " . $item->qty . " i.sellprice " . $item->sellprice . " sellprice $sellprice taxamount $tax_amount " .
127
                      "i.linetotal $linetotal netamount " . $self->netamount . " marge_total " . $item->marge_total . " marge_percent " . $item->marge_percent);
92 128
}
93 129

  
94
sub round {
130
sub _round {
95 131
  return $::form->round_amount(@_);
96 132
}
97 133

  
98
sub num_decimal_places {
134
sub _num_decimal_places {
99 135
  return length( (split(/\./, '' . shift, 2))[1] || '' );
100 136
}
101 137

  
......
163 199
A hash reference with the calculated taxes. The keys are chart IDs,
164 200
the values the calculated taxes.
165 201

  
202
=item C<amounts>
203

  
204
A hash reference with the calculated amounts. The keys are chart IDs,
205
the values the calculated amounts.
206

  
166 207
=back
167 208

  
168 209
=back

Auch abrufbar als: Unified diff