Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 7b349901

Von Jan Büren vor fast 2 Jahren hinzugefügt

  • ID 7b34990183880f750bb4489c216ee789e1bc520e
  • Vorgänger 607163f5
  • Nachfolger 8b1787aa

wip: REMOVE Wechselkursberechungen geändert in Payment-Helper

Unterschiede anzeigen:

SL/Controller/BankTransaction.pm
689 689
    # sign is simply the sign of amount in bank_transactions: positive for increase and negative for decrease
690 690
    # $amount_for_booking *= $sign;
691 691

  
692
    # check exchangerate and if fx_loss calculate new booking_amount for this invoice
693
    if ($fx_rate > 0)  {
694
      die "Exchangerate without currency"                     unless $currency_id;
695
      die "Invoice currency differs from user input currency" unless $currency_id == $invoice->currency->id;
696

  
697
      # 1 set daily default or custom record exchange rate
698
      my $default_rate = $invoice->get_exchangerate_for_bank_transaction($bank_transaction->id);
699
      if (!$default_rate) { # set new daily default
700
        # helper
701
        my $buysell = $invoice->is_sales ? 'buy' : 'sell';
702
        my $ex = SL::DB::Manager::Exchangerate->find_by(currency_id => $currency_id,
703
                                                        transdate => $bank_transaction->valutadate)
704
              ||              SL::DB::Exchangerate->new(currency_id => $currency_id,
705
                                                        transdate   => $bank_transaction->valutadate);
706
        $ex->update_attributes($buysell => $fx_rate);
707
      } elsif ($default_rate != $fx_rate) {           # set record (banktransaction) exchangerate
708
        $bank_transaction->exchangerate($fx_rate);    # custom rate, will be displayed in ap, ir, is
709
      } elsif ($default_rate == $fx_rate) {
710
        # should be last valid state -> do nothing
711
      } else { die "Invalid exchange rate state:" . $default_rate . " " . $fx_rate; }
712

  
713
      # 2 if fx_loss, we probably need a higher amount to pay the original amount of the ap invoice
714
      if ($invoice->get_exchangerate < $fx_rate) {
715
        # set whole bank_transaction amount -> pay_invoice will try to calculate losses and bank fees
716
        my $not_assigned_amount = abs($bank_transaction->not_assigned_amount);
717
        $amount_for_payment = $not_assigned_amount;
718
        $amount_for_payment *= -1 if $invoice->amount < 0;
719
      } elsif ($invoice->get_exchangerate > $fx_rate) {
720
        # if fx_gain do nothing, because gain
721
        # bla bla
722
      } else {
723
        die "Invalid exchange rate state for record:" . $invoice->get_exchangerate . " " . $fx_rate;
724
      }
725
    }
692 726
    # ... and then pay the invoice
693 727
    my @acc_ids = $invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id,
694 728
                          trans_id      => $invoice->id,
SL/DB/Helper/Payment.pm
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, $return_bank_amount);
96
  $return_bank_amount = 0;
97
  if ($params{currency} || $params{currency_id}) {
98
    if ($params{currency} || $params{currency_id} ) { # currency was specified
99
      $currency = SL::DB::Manager::Currency->find_by(name => $params{currency}) || SL::DB::Manager::Currency->find_by(id => $params{currency_id});
100
    } else { # use invoice currency
101
      $currency = SL::DB::Manager::Currency->find_by(id => $self->currency_id);
102
    };
103
    die "no currency" unless $currency;
104
    if ($currency->id == $::instance_conf->get_currency_id) {
105
      $exchangerate = 1;
106
    } else {
107
      my $rate = SL::DB::Manager::Exchangerate->find_by(currency_id => $currency->id,
108
                                                        transdate   => $transdate_obj,
109
                                                       );
110
      if ($rate) {
111
        $exchangerate = $is_sales ? $rate->buy : $rate->sell;
112
      } else {
113
        die "No exchange rate for " . $transdate_obj->to_kivitendo;
114
      };
115
    };
116
  } 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
117 126
    $exchangerate = 1;
118
  };
127
  } else {
128
    die "Cannot calculate exchange rate, if invoices uses the default currency";
129
  }
119 130

  
120 131
  # absolute skonto amount for invoice, use as reference sum to see if the
121 132
  # calculated skontos add up
......
135 146
  my $source = $params{source} // '';
136 147

  
137 148
  my $rounded_params_amount = _round( $params{amount} ); # / $exchangerate);
138
  my $fx_gain_loss_amount = 0; # for fx_gain and fx_loss
139

  
140
  my $return_bank_amount;  # will be returned for invoice_amount
141 149
  my $db = $self->db;
142 150
  $db->with_transaction(sub {
143 151
    my $new_acc_trans;
......
157 165
      $pay_amount = $self->amount_less_skonto if $params{payment_type} eq 'with_skonto_pt';
158 166

  
159 167
      # bank account and AR/AP
160
      $paid_amount += $pay_amount * $exchangerate;
168
      $paid_amount += $pay_amount;
161 169

  
162 170
      my $amount = (-1 * $pay_amount) * $mult;
163 171

  
......
177 185
      $new_acc_trans->save;
178 186
      $return_bank_amount = $amount;
179 187
      push @new_acc_ids, $new_acc_trans->acc_trans_id;
180
      # deal with fxtransaction
181
      if ( $self->currency_id != $::instance_conf->get_currency_id && $exchangerate != 1) {
182
        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

  
183 202
        $new_acc_trans = SL::DB::AccTransaction->new(trans_id       => $self->id,
184
                                                     chart_id       => $account_bank->id,
185
                                                     chart_link     => $account_bank->link,
186
                                                     amount         => $fxamount * -1,
203
                                                     chart_id       => $gain_loss_chart->id,
204
                                                     chart_link     => $gain_loss_chart->link,
205
                                                     amount         => $fx_gain_loss_amount,
187 206
                                                     transdate      => $transdate_obj,
188 207
                                                     source         => $source,
189 208
                                                     memo           => $memo,
190 209
                                                     taxkey         => 0,
191
                                                     fx_transaction => 1,
210
                                                     fx_transaction => 0, # probably indicates a real bank account in foreign currency
192 211
                                                     tax_id         => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
193 212
        $new_acc_trans->save;
194 213
        push @new_acc_ids, $new_acc_trans->acc_trans_id;
195
        # if invoice exchangerate differs from exchangerate of payment
196
        # deal with fxloss and fxamount
197
        if ($self->exchangerate and $self->exchangerate != 1 and $self->exchangerate != $exchangerate) {
198
          my $fxgain_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxgain_accno_id) || die "Can't determine fxgain chart";
199
          my $fxloss_chart = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxloss_accno_id) || die "Can't determine fxloss chart";
200
          # would nearly work if $amount is in foreign currency. Old code in AP.pm
201
          # and old code says USD * ( rate invoice - rate payment )
202
          my $gain_loss_amount = _round($amount * ($exchangerate - $self->exchangerate ) * -1,2);
203
          #                               EUR / rate payment   * ( rate invoice - rate bank transaction)
204
          my $gain_loss_chart = $gain_loss_amount > 0 ? $fxgain_chart : $fxloss_chart;
205
          $fx_gain_loss_amount = $gain_loss_amount;
206

  
207
          $new_acc_trans = SL::DB::AccTransaction->new(trans_id       => $self->id,
208
                                                       chart_id       => $gain_loss_chart->id,
209
                                                       chart_link     => $gain_loss_chart->link,
210
                                                       amount         => $gain_loss_amount,
211
                                                       transdate      => $transdate_obj,
212
                                                       source         => $source,
213
                                                       memo           => $memo,
214
                                                       taxkey         => 0,
215
                                                       fx_transaction => 0,
216
                                                       tax_id         => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
217
          $new_acc_trans->save;
218
          push @new_acc_ids, $new_acc_trans->acc_trans_id;
219

  
220
        }
221 214
      }
222 215
    }
223 216
    # skonto cases
......
253 246
        push @new_acc_ids, $new_acc_trans->acc_trans_id;
254 247

  
255 248
        $reference_amount -= abs($amount);
256
        $paid_amount      += -1 * $amount * $exchangerate;
249
        $paid_amount      += -1 * $amount;
257 250
        $skonto_amount_check -= $skonto_booking->{'skonto_amount'};
258 251
      }
259 252
    }
......
273 266
    }
274 267

  
275 268
    # regardless of payment_type there is always only exactly one arap booking
276
    # 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
277 270
    my $arap_booking= SL::DB::AccTransaction->new(trans_id   => $self->id,
278 271
                                                  chart_id   => $reference_account->id,
279 272
                                                  chart_link => $reference_account->link,
280
                                                  amount     => _round($arap_amount * $mult * $exchangerate - $fx_gain_loss_amount),
273
                                                  amount     => _round($arap_amount * $mult - $fx_gain_loss_amount),
281 274
                                                  transdate  => $transdate_obj,
282 275
                                                  source     => '', #$params{source},
283 276
                                                  taxkey     => 0,
......
346 339
        push @new_acc_ids, $tax_booking->acc_trans_id;
347 340
      }
348 341
    }
349
    $fx_gain_loss_amount *= -1 if $self->is_sales;
350
    $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;
351 344
    $self->datepaid($transdate_obj);
352 345
    $self->save;
353 346

  
......
656 649
  return @skonto_charts;
657 650
}
658 651

  
659

  
660 652
sub within_skonto_period {
661 653
  my $self = shift;
662 654
  validate(

Auch abrufbar als: Unified diff