last_incex_chart_id => undef,
units_by_name => \%units_by_name,
price_factors_by_id => \%price_factors_by_id,
- taxes => { },
+ taxes_by_chart_id => { },
+ taxes_by_tax_id => { },
amounts => { },
amounts_cogs => { },
allocated => { },
$self->netamount( 0);
$self->marge_total(0);
- SL::DB::Manager::Chart->cache_taxkeys(date => $self->transdate);
+ SL::DB::Manager::Chart->cache_taxkeys(date => $self->deliverydate // $self->transdate);
my $idx = 0;
- foreach my $item ($self->items) {
+ foreach my $item (@{ $self->items_sorted }) {
$idx++;
_calculate_item($self, $item, $idx, \%data, %params);
}
return $self unless wantarray;
- return map { ($_ => $data{$_}) } qw(taxes amounts amounts_cogs allocated exchangerate assembly_items items rounding);
+ return map { ($_ => $data{$_}) } qw(taxes_by_chart_id taxes_by_tax_id amounts amounts_cogs allocated exchangerate assembly_items items rounding);
}
sub _get_exchangerate {
my ($self, $item, $idx, $data, %params) = @_;
my $part = SL::DB::Part->load_cached($item->parts_id);
- return unless $item->part;
+ return unless $part;
my $part_unit = $data->{units_by_name}->{ $part->unit };
my $item_unit = $data->{units_by_name}->{ $item->unit };
$data->{invoicediff} += $sellprice * (1 - $item->discount) * $item->qty * $data->{exchangerate} / $item->price_factor - $linetotal if $self->taxincluded;
- my $linetotal_cost = 0;
-
- if (!$linetotal) {
- $item->marge_total( 0);
- $item->marge_percent(0);
-
- } else {
- my $lastcost = !(($item->lastcost // 0) * 1) ? ($part->lastcost || 0) : $item->lastcost;
- $linetotal_cost = _round($lastcost * $item->qty / $item->marge_price_factor, 2);
-
- $item->marge_total( $linetotal - $linetotal_cost);
- $item->marge_percent($item->marge_total * 100 / $linetotal);
-
- $self->marge_total( $self->marge_total + $item->marge_total);
- $data->{lastcost_total} += $linetotal_cost;
- }
-
- my $taxkey = $part->get_taxkey(date => $self->transdate, is_sales => $data->{is_sales}, taxzone => $self->taxzone_id);
+ my $taxkey = $part->get_taxkey(date => $self->deliverydate // $self->transdate, is_sales => $data->{is_sales}, taxzone => $self->taxzone_id);
my $tax_rate = $taxkey->tax->rate;
my $tax_amount = undef;
}
if ($taxkey->tax->chart_id) {
- $data->{taxes}->{ $taxkey->tax->chart_id } ||= 0;
- $data->{taxes}->{ $taxkey->tax->chart_id } += $tax_amount;
+ $data->{taxes_by_chart_id}->{ $taxkey->tax->chart_id } ||= 0;
+ $data->{taxes_by_chart_id}->{ $taxkey->tax->chart_id } += $tax_amount;
+ $data->{taxes_by_tax_id}->{ $taxkey->tax_id } ||= 0;
+ $data->{taxes_by_tax_id}->{ $taxkey->tax_id } += $tax_amount;
} elsif ($tax_amount) {
die "tax_amount != 0 but no chart_id for taxkey " . $taxkey->id . " tax " . $taxkey->tax->id;
}
- $self->netamount($self->netamount + $sellprice * (1 - $item->discount) * $item->qty / $item->price_factor);
-
my $chart = $part->get_chart(type => $data->{is_sales} ? 'income' : 'expense', taxzone => $self->taxzone_id);
$data->{amounts}->{ $chart->id } ||= { taxkey => $taxkey->taxkey_id, tax_id => $taxkey->tax_id, amount => 0 };
$data->{amounts}->{ $chart->id }->{amount} += $linetotal;
$data->{amounts}->{ $chart->id }->{amount} -= $tax_amount if $self->taxincluded;
+ my $linetotal_cost = 0;
+
+ if (!$linetotal) {
+ $item->marge_total( 0);
+ $item->marge_percent(0);
+
+ } else {
+ my $lastcost = !(($item->lastcost // 0) * 1) ? ($part->lastcost || 0) : $item->lastcost;
+ $linetotal_cost = _round($lastcost * $item->qty / $item->marge_price_factor, 2);
+ my $linetotal_net = $self->taxincluded ? $linetotal - $tax_amount : $linetotal;
+
+ $item->marge_total( $linetotal_net - $linetotal_cost);
+ $item->marge_percent($item->marge_total * 100 / $linetotal_net);
+
+ $self->marge_total( $self->marge_total + $item->marge_total);
+ $data->{lastcost_total} += $linetotal_cost;
+ }
+
push @{ $data->{assembly_items} }, [];
if ($part->is_assembly) {
_calculate_assembly_item($self, $data, $part, $item->base_qty, $item_unit->convert_to(1, $part_unit));
my ($self, $data, %params) = @_;
my $tax_diff = 0;
- foreach my $chart_id (keys %{ $data->{taxes} }) {
- my $rounded = _round($data->{taxes}->{$chart_id} * $data->{exchangerate}, 2);
- $tax_diff += $data->{taxes}->{$chart_id} * $data->{exchangerate} - $rounded if $self->taxincluded;
- $data->{taxes}->{$chart_id} = $rounded;
+ foreach my $chart_id (keys %{ $data->{taxes_by_chart_id} }) {
+ my $rounded = _round($data->{taxes_by_chart_id}->{$chart_id} * $data->{exchangerate}, 2);
+ $tax_diff += $data->{taxes_by_chart_id}->{$chart_id} * $data->{exchangerate} - $rounded if $self->taxincluded;
+ $data->{taxes_by_chart_id}->{$chart_id} = $rounded;
}
+ $self->netamount(sum map { $_->{amount} } values %{ $data->{amounts} });
+
my $amount = _round(($self->netamount + $tax_diff) * $data->{exchangerate}, 2);
my $diff = $amount - ($self->netamount + $tax_diff) * $data->{exchangerate};
my $netamount = $amount;
_dbg("Sna " . $self->netamount . " idiff " . $data->{invoicediff} . " tdiff ${tax_diff}");
- my $tax = sum values %{ $data->{taxes} };
+ my $tax = sum values %{ $data->{taxes_by_chart_id} };
$amount = $netamount + $tax;
my $grossamount = _round($amount, 2, 1);
$data->{rounding} = _round($grossamount - $amount, 2);
=over 2
-=item C<taxes>
+=item C<taxes_by_chart_id>
A hash reference with the calculated taxes. The keys are chart IDs,
+the values the rounded calculated taxes.
+
+=item C<taxes_by_tax_id>
+
+A hash reference with the calculated taxes. The keys are tax IDs,
the values the calculated taxes.
=item C<amounts>