90 |
90 |
croak t8('Cannot post transaction above the maximum future booking date!') if $transdate_obj > DateTime->now->add( days => $::instance_conf->get_max_future_booking_interval );
|
91 |
91 |
};
|
92 |
92 |
|
93 |
|
# currency is either passed or use the invoice currency if it differs from the default currency
|
94 |
|
# TODO remove
|
95 |
|
my ($exchangerate,$currency);
|
96 |
|
if ($params{currency} || $params{currency_id}) {
|
97 |
|
if ($params{currency} || $params{currency_id} ) { # currency was specified
|
98 |
|
$currency = SL::DB::Manager::Currency->find_by(name => $params{currency}) || SL::DB::Manager::Currency->find_by(id => $params{currency_id});
|
99 |
|
} else { # use invoice currency
|
100 |
|
$currency = SL::DB::Manager::Currency->find_by(id => $self->currency_id);
|
101 |
|
};
|
102 |
|
die "no currency" unless $currency;
|
103 |
|
if ($currency->id == $::instance_conf->get_currency_id) {
|
104 |
|
$exchangerate = 1;
|
105 |
|
} else {
|
106 |
|
my $rate = SL::DB::Manager::Exchangerate->find_by(currency_id => $currency->id,
|
107 |
|
transdate => $transdate_obj,
|
108 |
|
);
|
109 |
|
if ($rate) {
|
110 |
|
$exchangerate = $is_sales ? $rate->buy : $rate->sell;
|
111 |
|
} else {
|
112 |
|
die "No exchange rate for " . $transdate_obj->to_kivitendo;
|
113 |
|
};
|
114 |
|
};
|
115 |
|
} else { # no currency param given or currency is the same as default_currency
|
|
93 |
# currency has to be passed and caller has to be sure to assign it for a forex invoice
|
|
94 |
# dies if called for a invoice with the default currency (TODO: Params::Validate before)
|
|
95 |
my ($exchangerate, $currency, $fx_gain_loss_amount, $return_bank_amount);
|
|
96 |
if ($params{currency} || $params{currency_id} && $self->forex) { # currency was specified
|
|
97 |
$currency = SL::DB::Manager::Currency->find_by(name => $params{currency}) || SL::DB::Manager::Currency->find_by(id => $params{currency_id});
|
|
98 |
# set exchangerate - no fallback
|
|
99 |
# die "No exchange rate" unless $params{exchangerate} > 0;
|
|
100 |
$exchangerate = $params{exchangerate};
|
|
101 |
# hook for gl_bookings $book_fx_bank_fees;
|
|
102 |
# and calculus fidibus total fx
|
|
103 |
# self->amount - paid / self->exchangerate * banktransaction.exchangerate = total new amount EUR
|
|
104 |
my $new_open_amount = ( $self->open_amount / $self->get_exchangerate ) * $exchangerate;
|
|
105 |
# VORHER
|
|
106 |
# my $gain_loss_amount = _round($amount * ($exchangerate - $self->get_exchangerate ) * -1,2);
|
|
107 |
$fx_gain_loss_amount = _round( $self->open_amount - $new_open_amount);
|
|
108 |
# works for ap, but change sign for ar (todo credit notes and negative ap transactions
|
|
109 |
$fx_gain_loss_amount *= -1 if $self->is_sales;
|
|
110 |
$main::lxdebug->message(0, 'h 1 ' . $new_open_amount . ' h 3 ' . $params{amount} . ' und fx ' . $fx_gain_loss_amount );
|
|
111 |
if ($params{fx_book} && $new_open_amount < $params{amount}) {
|
|
112 |
die "Bank Fees can only be added for AP transactions" if $self->is_sales;
|
|
113 |
$self->_add_bank_fx_fees(fee => _round($params{amount} - $new_open_amount),
|
|
114 |
bt_id => $params{bt_id},
|
|
115 |
bank_chart_id => $params{chart_id},
|
|
116 |
memo => $params{memo},
|
|
117 |
source => $params{source},
|
|
118 |
transdate_obj => $transdate_obj );
|
|
119 |
# invoice_amount
|
|
120 |
$return_bank_amount += _round($params{amount} - $new_open_amount);
|
|
121 |
} else { }
|
|
122 |
# always use new open amount for payment booking and add this value to arap.paid
|
|
123 |
$params{amount} = $new_open_amount;
|
|
124 |
# $paid_amount = $new_open_amount;
|
|
125 |
} elsif (!$self->forex) { # invoices uses default currency. no exchangerate
|
116 |
126 |
$exchangerate = 1;
|
117 |
|
};
|
|
127 |
} else {
|
|
128 |
die "Cannot calculate exchange rate, if invoices uses the default currency";
|
|
129 |
}
|
118 |
130 |
|
119 |
131 |
# absolute skonto amount for invoice, use as reference sum to see if the
|
120 |
132 |
# calculated skontos add up
|
... | ... | |
134 |
146 |
my $source = $params{source} // '';
|
135 |
147 |
|
136 |
148 |
my $rounded_params_amount = _round( $params{amount} ); # / $exchangerate);
|
137 |
|
my $fx_gain_loss_amount = 0; # for fx_gain and fx_loss
|
138 |
|
|
139 |
|
my $return_bank_amount; # will be returned for invoice_amount
|
140 |
149 |
my $db = $self->db;
|
141 |
150 |
$db->with_transaction(sub {
|
142 |
151 |
my $new_acc_trans;
|
... | ... | |
156 |
165 |
$pay_amount = $self->amount_less_skonto if $params{payment_type} eq 'with_skonto_pt';
|
157 |
166 |
|
158 |
167 |
# bank account and AR/AP
|
159 |
|
$paid_amount += $pay_amount * $exchangerate;
|
|
168 |
$paid_amount += $pay_amount;
|
160 |
169 |
|
161 |
170 |
my $amount = (-1 * $pay_amount) * $mult;
|
162 |
171 |
|
... | ... | |
176 |
185 |
$new_acc_trans->save;
|
177 |
186 |
$return_bank_amount = $amount;
|
178 |
187 |
push @new_acc_ids, $new_acc_trans->acc_trans_id;
|
179 |
|
# deal with fxtransaction
|
180 |
|
if ( $self->currency_id != $::instance_conf->get_currency_id && $exchangerate != 1) {
|
181 |
|
my $fxamount = _round($amount - ($amount * $exchangerate));
|
|
188 |
# deal with fxtransaction ...
|
|
189 |
# if invoice exchangerate differs from exchangerate of payment
|
|
190 |
# add fxloss or fxgain
|
|
191 |
if ($fx_gain_loss_amount && $exchangerate != 1 && $self->get_exchangerate and $self->get_exchangerate != 1 and $self->get_exchangerate != $exchangerate) {
|
|
192 |
# (self->amount - self->paid) / $self->exchangerate
|
|
193 |
my $fxgain_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxgain_accno_id) || die "Can't determine fxgain chart";
|
|
194 |
my $fxloss_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxloss_accno_id) || die "Can't determine fxloss chart";
|
|
195 |
$main::lxdebug->message(0, 'was sagt gain loss' . $fx_gain_loss_amount);
|
|
196 |
my $gain_loss_chart = $fx_gain_loss_amount > 0 ? $fxgain_chart : $fxloss_chart;
|
|
197 |
$paid_amount += $fx_gain_loss_amount if $fx_gain_loss_amount < 0; # only add if we have fx_loss
|
|
198 |
$main::lxdebug->message(0, 'paid2 ' . $paid_amount);
|
|
199 |
$main::lxdebug->message(0, 'paid2chart ' . $fx_gain_loss_amount);
|
|
200 |
# $fx_gain_loss_amount = $gain_loss_amount;
|
|
201 |
|
182 |
202 |
$new_acc_trans = SL::DB::AccTransaction->new(trans_id => $self->id,
|
183 |
|
chart_id => $account_bank->id,
|
184 |
|
chart_link => $account_bank->link,
|
185 |
|
amount => $fxamount * -1,
|
|
203 |
chart_id => $gain_loss_chart->id,
|
|
204 |
chart_link => $gain_loss_chart->link,
|
|
205 |
amount => $fx_gain_loss_amount,
|
186 |
206 |
transdate => $transdate_obj,
|
187 |
207 |
source => $source,
|
188 |
208 |
memo => $memo,
|
189 |
209 |
taxkey => 0,
|
190 |
|
fx_transaction => 1,
|
|
210 |
fx_transaction => 0, # probably indicates a real bank account in foreign currency
|
191 |
211 |
tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
|
192 |
212 |
$new_acc_trans->save;
|
193 |
213 |
push @new_acc_ids, $new_acc_trans->acc_trans_id;
|
194 |
|
# if invoice exchangerate differs from exchangerate of payment
|
195 |
|
# deal with fxloss and fxamount
|
196 |
|
if ($self->exchangerate and $self->exchangerate != 1 and $self->exchangerate != $exchangerate) {
|
197 |
|
my $fxgain_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxgain_accno_id) || die "Can't determine fxgain chart";
|
198 |
|
my $fxloss_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxloss_accno_id) || die "Can't determine fxloss chart";
|
199 |
|
my $gain_loss_amount = _round($amount * ($exchangerate - $self->exchangerate ) * -1,2);
|
200 |
|
my $gain_loss_chart = $gain_loss_amount > 0 ? $fxgain_chart : $fxloss_chart;
|
201 |
|
$fx_gain_loss_amount = $gain_loss_amount;
|
202 |
|
|
203 |
|
$new_acc_trans = SL::DB::AccTransaction->new(trans_id => $self->id,
|
204 |
|
chart_id => $gain_loss_chart->id,
|
205 |
|
chart_link => $gain_loss_chart->link,
|
206 |
|
amount => $gain_loss_amount,
|
207 |
|
transdate => $transdate_obj,
|
208 |
|
source => $source,
|
209 |
|
memo => $memo,
|
210 |
|
taxkey => 0,
|
211 |
|
fx_transaction => 0,
|
212 |
|
tax_id => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
|
213 |
|
$new_acc_trans->save;
|
214 |
|
push @new_acc_ids, $new_acc_trans->acc_trans_id;
|
215 |
|
|
216 |
|
}
|
217 |
214 |
}
|
218 |
215 |
}
|
219 |
216 |
# skonto cases
|
... | ... | |
249 |
246 |
push @new_acc_ids, $new_acc_trans->acc_trans_id;
|
250 |
247 |
|
251 |
248 |
$reference_amount -= abs($amount);
|
252 |
|
$paid_amount += -1 * $amount * $exchangerate;
|
|
249 |
$paid_amount += -1 * $amount;
|
253 |
250 |
$skonto_amount_check -= $skonto_booking->{'skonto_amount'};
|
254 |
251 |
}
|
255 |
252 |
}
|
... | ... | |
269 |
266 |
}
|
270 |
267 |
|
271 |
268 |
# regardless of payment_type there is always only exactly one arap booking
|
272 |
|
# TODO: compare $arap_amount to running total
|
|
269 |
# TODO: compare $arap_amount to running total and/or use this as running total for ar.paid|ap.paid
|
273 |
270 |
my $arap_booking= SL::DB::AccTransaction->new(trans_id => $self->id,
|
274 |
271 |
chart_id => $reference_account->id,
|
275 |
272 |
chart_link => $reference_account->link,
|
276 |
|
amount => _round($arap_amount * $mult * $exchangerate - $fx_gain_loss_amount),
|
|
273 |
amount => _round($arap_amount * $mult - $fx_gain_loss_amount),
|
277 |
274 |
transdate => $transdate_obj,
|
278 |
275 |
source => '', #$params{source},
|
279 |
276 |
taxkey => 0,
|
... | ... | |
342 |
339 |
push @new_acc_ids, $tax_booking->acc_trans_id;
|
343 |
340 |
}
|
344 |
341 |
}
|
345 |
|
$fx_gain_loss_amount *= -1 if $self->is_sales;
|
346 |
|
$self->paid($self->paid + _round($paid_amount) + $fx_gain_loss_amount) if $paid_amount;
|
|
342 |
# $fx_gain_loss_amount *= -1 if $self->is_sales;
|
|
343 |
$self->paid($self->paid + _round($paid_amount)) if $paid_amount;
|
347 |
344 |
$self->datepaid($transdate_obj);
|
348 |
345 |
$self->save;
|
349 |
346 |
|
... | ... | |
652 |
649 |
return @skonto_charts;
|
653 |
650 |
}
|
654 |
651 |
|
655 |
|
|
656 |
652 |
sub within_skonto_period {
|
657 |
653 |
my $self = shift;
|
658 |
654 |
validate(
|
wip: REMOVE Wechselkursberechungen geändert in Payment-Helper