Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision f16aaa2a

Von Moritz Bunkus vor fast 14 Jahren hinzugefügt

  • ID f16aaa2a699fbf75a3d7f2f47242ef55d12700f2
  • Vorgänger 9229c547
  • Nachfolger 5547891f

Stark erweiterte Berechnung für Rechnungen

Unterschiede anzeigen:

SL/DB/Helper/PriceTaxCalculator.pm
19 19

  
20 20
  my %data = ( lastcost_total      => 0,
21 21
               invoicediff         => 0,
22
               last_incex_chart_id => undef,
22 23
               units_by_name       => \%units_by_name,
23 24
               price_factors_by_id => \%price_factors_by_id,
24 25
               taxes               => { },
......
42 43
    _calculate_item($self, $item, $idx, \%data, %params);
43 44
  }
44 45

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

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

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

  
53 48
  return $self unless wantarray;
54 49

  
......
85 80
  my $linetotal = _round($sellprice * $item->qty / $item->price_factor, 2) * $data->{exchangerate};
86 81
  $linetotal    = _round($linetotal,                                    2);
87 82

  
88
  $data->{invoicediff} += $sellprice * $item->qty * $data->{exchangerate} / $item->price_factor - $linetotal;
83
  $data->{invoicediff} += $sellprice * $item->qty * $data->{exchangerate} / $item->price_factor - $linetotal if $self->taxincluded;
89 84

  
90 85
  if (!$linetotal) {
91 86
    $item->marge_total(  0);
......
119 114
  $self->netamount($self->netamount + $sellprice * $item->qty / $item->price_factor);
120 115

  
121 116
  my $chart = $item->part->get_chart(type => $data->{is_sales} ? 'income' : 'expense', taxzone => $self->taxzone_id);
122
  $data->{amounts}->{$chart->id} += $linetotal;
117
  $data->{amounts}->{ $chart->id }           ||= { taxkey => $taxkey->id, amount => 0 };
118
  $data->{amounts}->{ $chart->id }->{amount}  += $linetotal;
123 119

  
124 120
  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)));
121
  if ($item->part->is_assembly) {
122
    _calculate_assembly_item($self, $data, $item->part, $item->base_qty, $item->unit_obj->convert_to(1, $item->part->unit_obj));
123
  } elsif ($item->part->is_part) {
124
    $item->allocated(_calculate_part_item($self, $data, $item->part, $item->base_qty, $item->unit_obj->convert_to(1, $item->part->unit_obj)));
125
  }
126

  
127
  $data->{last_incex_chart_id} = $chart->id if $data->{is_sales};
126 128

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

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

  
134
  return unless $data->{invoice};
136
  my $tax_diff = 0;
137
  foreach my $chart_id (keys %{ $data->{taxes} }) {
138
    my $rounded                  = _round($data->{taxes}->{$chart_id} * $data->{exchangerate}, 2);
139
    $tax_diff                   += $data->{taxes}->{$chart_id} * $data->{exchangerate} - $rounded if $self->taxincluded;
140
    $data->{taxes}->{$chart_id}  = $rounded;
141
  }
142

  
143
  my $amount    = _round(($self->netamount + $tax_diff) * $data->{exchangerate}, 2);
144
  my $diff      = $amount - ($self->netamount + $tax_diff) * $data->{exchangerate};
145
  my $netamount = $amount;
146

  
147
  if ($self->taxincluded) {
148
    $data->{invoicediff}                                         += $diff;
149
    $data->{amounts}->{ $data->{last_incex_chart_id} }->{amount} += $data->{invoicediff} if $data->{last_incex_chart_id};
150
  }
151

  
152
  _dbg("Sna " . $self->netamount . " idiff " . $data->{invoicediff} . " tdiff ${tax_diff}");
153

  
154
  my $tax              = sum values %{ $data->{taxes} };
155
  $data->{arap_amount} = $netamount + $tax;
156

  
157
  $self->netamount(    $netamount);
158
  $self->amount(       $netamount + $tax);
159
  $self->marge_percent($self->netamount ? ($self->netamount - $data->{lastcost_total}) * 100 / $self->netamount : 0);
135 160
}
136 161

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

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

  
143
  my $allocated = 0;
144 167
  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);
168
    push @{ $data->{assembly_items}->[-1] }, { part      => $assembly_entry->part,
169
                                               qty       => $total_qty * $assembly_entry->qty,
170
                                               allocated => 0 };
171

  
172
    if ($assembly_entry->part->is_assembly) {
173
      _calculate_assembly_item($self, $data, $assembly_entry->part, $total_qty * $assembly_entry->qty);
174
    } elsif ($assembly_entry->part->is_part) {
175
      my $allocated = _calculate_part_item($self, $data, $assembly_entry->part, $total_qty * $assembly_entry->qty);
176
      $data->{assembly_items}->[-1]->[-1]->{allocated} = $allocated;
177
    }
147 178
  }
148

  
149
  return $allocated;
150 179
}
151 180

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

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

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

  
......
166 195
                                                                                                \'(base_qty + allocated) < 0' ] ]);
167 196

  
168 197
  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");
198
    my $qty = min($remaining_qty, $entry->base_qty * -1 - $entry->allocated - $data->{allocated}->{ $entry->id });
199
    _dbg("qty $qty");
171 200

  
172 201
    next unless $qty;
173 202

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

  
179
    $data->{allocated}->{ $part->id } ||= 0;
180
    $data->{allocated}->{ $part->id }  += $qty;
181
    $remaining_qty                     -= $qty;
208
    $data->{allocated}->{ $entry->id } ||= 0;
209
    $data->{allocated}->{ $entry->id }  += $qty;
210
    $remaining_qty                      -= $qty;
182 211
  }
183 212

  
184 213
  $iterator->finish;
......
191 220
}
192 221

  
193 222
sub _num_decimal_places {
194
  return length( (split(/\./, '' . shift, 2))[1] || '' );
223
  return length( (split(/\./, '' . ($_[0] * 1), 2))[1] || '' );
224
}
225

  
226
sub _dbg {
227
  $::lxdebug->message(0, join(' ', @_));
195 228
}
196 229

  
197 230
1;
......
213 246
=item C<calculate_prices_and_taxes %params>
214 247

  
215 248
Calculates the prices, amounts and taxes for an order, a quotation or
216
an invoice. The function assumes that the mixing package has a certain
217
layout and provides certain functions:
249
an invoice.
250

  
251
The function assumes that the mixing package has a certain layout and
252
provides certain functions:
218 253

  
219 254
=over 2
220 255

  
......
249 284

  
250 285
=over 2
251 286

  
252
=item C<self>
253

  
254
The object itself.
255

  
256 287
=item C<taxes>
257 288

  
258 289
A hash reference with the calculated taxes. The keys are chart IDs,
......
261 292
=item C<amounts>
262 293

  
263 294
A hash reference with the calculated amounts. The keys are chart IDs,
264
the values the calculated amounts.
295
the values are hash references containing the two keys C<amount> and
296
C<taxkey>.
297

  
298
=item C<amounts_cogs>
299

  
300
A hash reference with the calculated amounts for costs of goods
301
sold. The keys are chart IDs, the values the calculated amounts.
302

  
303
=item C<assembly_items>
304

  
305
An array reference with as many entries as there are items in the
306
record. Each entry is again an array reference of hash references with
307
the keys C<part> (an instance of L<SL::DB::Part>), C<qty> and
308
C<allocated>. Is only valid for invoices and can be used to populate
309
the C<invoice> table with entries for assemblies.
310

  
311
=item C<allocated>
312

  
313
A hash reference. The keys are IDs of entries in the C<invoice>
314
table. The values are the new values for the entry's C<allocated>
315
column. Only valid for invoices.
316

  
317
=item C<exchangerate>
318

  
319
The exchangerate used for the calculation.
265 320

  
266 321
=back
267 322

  

Auch abrufbar als: Unified diff