Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 74ddad54

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

  • ID 74ddad54cc8ec2a041963f6507faf1abec73de1b
  • Vorgänger 2a4fb1bf
  • Nachfolger 40416dee

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);
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(

Auch abrufbar als: Unified diff