Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 9229c547

Von Moritz Bunkus vor fast 14 Jahren hinzugefügt

  • ID 9229c5479cb1260b81cf8230fe8e5df01173aa3f
  • Vorgänger 14d07f37
  • Nachfolger f16aaa2a

Weitere Berechnungen für Rechnungen

Unterschiede anzeigen:

SL/DB/Helper/PriceTaxCalculator.pm
6 6
our @EXPORT = qw(calculate_prices_and_taxes);
7 7

  
8 8
use Carp;
9
use List::Util qw(sum);
9
use List::Util qw(sum min);
10 10
use SL::DB::Default;
11 11
use SL::DB::PriceFactor;
12 12
use SL::DB::Unit;
......
14 14
sub calculate_prices_and_taxes {
15 15
  my ($self, %params) = @_;
16 16

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

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

  
25 20
  my %data = ( lastcost_total      => 0,
26 21
               invoicediff         => 0,
27 22
               units_by_name       => \%units_by_name,
28 23
               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,
24
               taxes               => { },
25
               amounts             => { },
26
               amounts_cogs        => { },
27
               allocated           => { },
28
               assembly_items      => [ ],
31 29
               exchangerate        => undef,
30
               is_sales            => $self->can('customer') && $self->customer,
31
               is_invoice          => (ref($self) =~ /Invoice/) || $params{invoice},
32 32
             );
33 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;
34
  _get_exchangerate($self, \%data, %params);
39 35

  
40 36
  $self->netamount(  0);
41 37
  $self->marge_total(0);
......
43 39
  my $idx = 0;
44 40
  foreach my $item ($self->items) {
45 41
    $idx++;
46
    _calculate_item($self, $item, $idx, \%data);
42
    _calculate_item($self, $item, $idx, \%data, %params);
47 43
  }
48 44

  
49
  my $tax_sum = sum map { _round($_, 2) } values %taxes_by_chart_id;
45
  my $tax_sum = sum map { _round($_, 2) } values %{ $data{taxes} };
50 46

  
51 47
  $self->amount(       _round($self->netamount + $tax_sum, 2));
52 48
  $self->netamount(    _round($self->netamount,            2));
53 49
  $self->marge_percent($self->netamount ? ($self->netamount - $data{lastcost_total}) * 100 / $self->netamount : 0);
54 50

  
51
  _calculate_invoice($self, \%data, %params) if $data{is_invoice};
52

  
55 53
  return $self unless wantarray;
56
  return ( self    => $self,
57
           taxes   => \%taxes_by_chart_id,
58
           amounts => \%amounts_by_chart_id,
59
         );
54

  
55
  return map { ($_ => $data{$_}) } qw(taxes amounts amounts_cogs allocated exchangerate assembly_items);
56
}
57

  
58
sub _get_exchangerate {
59
  my ($self, $data, %params) = @_;
60

  
61
  if (($self->curr || '') ne SL::DB::Default->get_default_currency) {
62
    $data->{exchangerate}   = $::form->check_exchangerate(\%::myconfig, $self->curr, $self->transdate, $data->{is_sales} ? 'buy' : 'sell');
63
    $data->{exchangerate} ||= $params{exchangerate};
64
  }
65
  $data->{exchangerate} ||= 1;
60 66
}
61 67

  
62 68
sub _calculate_item {
63
  my ($self, $item, $idx, $data) = @_;
69
  my ($self, $item, $idx, $data, %params) = @_;
64 70

  
65 71
  my $part_unit  = $data->{units_by_name}->{ $item->part->unit };
66 72
  my $item_unit  = $data->{units_by_name}->{ $item->unit       };
......
107 113
    $tax_amount = $linetotal * $tax_rate;
108 114
  }
109 115

  
110
  $data->{taxes_by_chart_id}->{ $taxkey->chart_id } ||= 0;
111
  $data->{taxes_by_chart_id}->{ $taxkey->chart_id }  += $tax_amount;
116
  $data->{taxes}->{ $taxkey->chart_id } ||= 0;
117
  $data->{taxes}->{ $taxkey->chart_id }  += $tax_amount;
112 118

  
113 119
  $self->netamount($self->netamount + $sellprice * $item->qty / $item->price_factor);
114 120

  
115 121
  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
  }
122
  $data->{amounts}->{$chart->id} += $linetotal;
123

  
124
  push @{ $data->{assembly_items} }, [];
125
  $item->allocated(_calculate_assembly_item($self, $data, $item->part, $item->base_qty, $item->unit_obj->convert_to(1, $item->part->unit_obj)));
125 126

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

  
131
sub _calculate_invoice {
132
  my ($self, $data, %params) = @_;
133

  
134
  return unless $data->{invoice};
135
}
136

  
137
sub _calculate_assembly_item {
138
  my ($self, $data, $part, $total_qty, $base_factor) = @_;
139

  
140
  return 0 unless $::eur && $data->{is_invoice};
141
  return _calculate_part_service_item($self, $data, $part, $total_qty) unless $part->is_assembly;
142

  
143
  my $allocated = 0;
144
  foreach my $assembly_entry (@{ $part->assemblies }) {
145
    push @{ $data->{assembly_items}->[-1] }, { part => $assembly_entry->part, qty => $total_qty * $assembly_entry->qty };
146
    $allocated += _calculate_assembly_item($self, $data, $assembly_entry->part, $total_qty * $assembly_entry->qty);
147
  }
148

  
149
  return $allocated;
150
}
151

  
152
sub _calculate_part_service_item {
153
  my ($self, $data, $part, $total_qty, $base_factor) = @_;
154

  
155
  $::lxdebug->message(0, "cpsi tq " . $total_qty);
156

  
157
  return 0 unless $::eur && $data->{is_invoice} && $total_qty;
158

  
159
  my ($entry);
160
  $base_factor           ||= 1;
161
  my $remaining_qty        = $total_qty;
162
  my $expense_income_chart = $part->get_chart(type => $data->{is_sales} ? 'expense' : 'income', taxzone => $self->taxzone_id);
163
  my $inventory_chart      = $part->get_chart(type => 'inventory',                              taxzone => $self->taxzone_id);
164

  
165
  my $iterator             = SL::DB::Manager::InvoiceItem->get_all_iterator(query => [ and => [ parts_id => $part->id,
166
                                                                                                \'(base_qty + allocated) < 0' ] ]);
167

  
168
  while (($remaining_qty > 0) && ($entry = $iterator->next)) {
169
    my $qty = min($remaining_qty, $entry->base_qty * -1 - $entry->allocated - $data->{allocated}->{$part->id});
170
    $::lxdebug->message(0, "qty $qty");
171

  
172
    next unless $qty;
173

  
174
    my $linetotal = _round(($entry->sellprice * $qty) / $base_factor, 2);
175

  
176
    $data->{amounts_cogs}->{ $expense_income_chart->id } -= $linetotal;
177
    $data->{amounts_cogs}->{ $inventory_chart->id      } += $linetotal;
178

  
179
    $data->{allocated}->{ $part->id } ||= 0;
180
    $data->{allocated}->{ $part->id }  += $qty;
181
    $remaining_qty                     -= $qty;
182
  }
183

  
184
  $iterator->finish;
185

  
186
  return $remaining_qty - $total_qty;
187
}
188

  
130 189
sub _round {
131 190
  return $::form->round_amount(@_);
132 191
}

Auch abrufbar als: Unified diff