Reconciliation: Veto, kein invoice_amount nachträglich setzen.
[kivitendo-erp.git] / SL / Controller / Reconciliation.pm
1 package SL::Controller::Reconciliation;
2
3 use strict;
4
5 use parent qw(SL::Controller::Base);
6
7 use SL::Locale::String;
8 use SL::JSON;
9 use SL::Controller::Helper::ParseFilter;
10 use SL::Helper::Flash;
11
12 use SL::DB::BankTransaction;
13 use SL::DB::Manager::BankAccount;
14 use SL::DB::AccTransaction;
15 use SL::DB::ReconciliationLink;
16 use List::Util qw(sum);
17
18 use Rose::Object::MakeMethods::Generic (
19   'scalar --get_set_init' => [ qw(cleared BANK_ACCOUNTS) ],
20 );
21
22 __PACKAGE__->run_before('check_auth');
23 __PACKAGE__->run_before('_bank_account');
24
25 #
26 # actions
27 #
28
29 sub action_search {
30   my ($self) = @_;
31
32   $self->setup_search_action_bar;
33   $self->render('reconciliation/search');
34 }
35
36 sub action_reconciliation {
37   my ($self) = @_;
38
39   $self->_get_proposals;
40
41   $self->_get_linked_transactions;
42
43   $self->_get_balances;
44
45   $self->setup_reconciliation_action_bar;
46   $self->render('reconciliation/form',
47                 ui_tab => scalar(@{$self->{PROPOSALS}}) > 0?1:0,
48                 title => t8('Reconciliation'));
49 }
50
51 sub action_load_overview {
52   my ($self) = @_;
53
54   $self->_get_proposals;
55
56   $self->_get_linked_transactions;
57
58   $self->_get_balances;
59
60   my $output = $self->render('reconciliation/tabs/overview', { output => 0 });
61   my %result = ( html => $output );
62
63   $self->render(\to_json(\%result), { type => 'json', process => 0 });
64 }
65
66 sub action_filter_overview {
67   my ($self) = @_;
68
69   $self->_get_linked_transactions;
70   $self->_get_balances;
71
72   my $output = $self->render('reconciliation/_linked_transactions', { output => 0 });
73   my %result = ( html               => $output,
74                  absolut_bt_balance => $::form->format_amount(\%::myconfig,      $self->{absolut_bt_balance}, 2),
75                  absolut_bb_balance => $::form->format_amount(\%::myconfig, -1 * $self->{absolut_bb_balance}, 2),
76                  bt_balance         => $::form->format_amount(\%::myconfig,      $self->{bt_balance}, 2),
77                  bb_balance         => $::form->format_amount(\%::myconfig, -1 * $self->{bb_balance}, 2)
78                  );
79
80   $self->render(\to_json(\%result), { type => 'json', process => 0 });
81 }
82
83 sub action_update_reconciliation_table {
84   my ($self) = @_;
85
86   my @errors = $self->_get_elements_and_validate();
87
88   my $output = $self->render('reconciliation/assigning_table', { output => 0 },
89                  bt_sum => $::form->format_amount(\%::myconfig, $self->{bt_sum}, 2),
90                  bb_sum => $::form->format_amount(\%::myconfig, -1 * $self->{bb_sum}, 2),
91                  errors => @errors,
92                  );
93
94   my %result = ( html => $output );
95
96   $self->render(\to_json(\%result), { type => 'json', process => 0 });
97 }
98
99 sub action_reconcile {
100   my ($self) = @_;
101
102   #Check elements
103   my @errors = $self->_get_elements_and_validate;
104
105   if (@errors) {
106     unshift(@errors, (t8('Could not reconcile chosen elements!')));
107     flash('error', @errors);
108     $self->action_reconciliation;
109     return;
110   }
111
112   $self->_reconcile;
113
114   $self->action_reconciliation;
115 }
116
117 sub action_delete_reconciliation {
118   my ($self) = @_;
119
120   my $rec_links = SL::DB::Manager::ReconciliationLink->get_all(where => [ rec_group => $::form->{rec_group} ]);
121
122   foreach my $rec_link (@{ $rec_links }) {
123     my $bank_transaction = SL::DB::Manager::BankTransaction->find_by( id           => $rec_link->bank_transaction_id );
124     my $acc_transaction  = SL::DB::Manager::AccTransaction ->find_by( acc_trans_id => $rec_link->acc_trans_id        );
125
126     $bank_transaction->cleared('0');
127     $acc_transaction->cleared('0');
128
129     $bank_transaction->save;
130     $acc_transaction->save;
131
132     $rec_link->delete;
133   }
134
135   $self->_get_linked_transactions;
136   $self->_get_balances;
137
138   my $output = $self->render('reconciliation/_linked_transactions', { output => 0 });
139   my %result = ( html               => $output,
140                  absolut_bt_balance => $::form->format_amount(\%::myconfig,      $self ->{absolut_bt_balance}, 2),
141                  absolut_bb_balance => $::form->format_amount(\%::myconfig, -1 * $self ->{absolut_bb_balance}, 2),
142                  bt_balance         => $::form->format_amount(\%::myconfig,      $self ->{bt_balance}, 2),
143                  bb_balance         => $::form->format_amount(\%::myconfig, -1 * $self ->{bb_balance}, 2)
144                  );
145
146   $self->render(\to_json(\%result), { type => 'json', process => 0 });
147 }
148
149 sub action_load_proposals {
150   my ($self) = @_;
151
152   $self->_get_proposals;
153
154   my $output = $self->render('reconciliation/tabs/automatic', { output => 0 });
155   my %result = ( html => $output );
156
157   $self->render(\to_json(\%result), { type => 'json', process => 0 });
158 }
159
160 sub action_filter_proposals {
161   my ($self) = @_;
162
163   $self->_get_balances;
164   $self->_get_proposals;
165
166   my $output = $self->render('reconciliation/proposals', { output => 0 });
167   my %result = ( html               => $output,
168                  absolut_bt_balance => $::form->format_amount(\%::myconfig,      $self ->{absolut_bt_balance}, 2),
169                  absolut_bb_balance => $::form->format_amount(\%::myconfig, -1 * $self ->{absolut_bb_balance}, 2),
170                  bt_balance         => $::form->format_amount(\%::myconfig,      $self ->{bt_balance}, 2),
171                  bb_balance         => $::form->format_amount(\%::myconfig, -1 * $self ->{bb_balance}, 2)
172                  );
173
174   $self->render(\to_json(\%result), { type => 'json', process => 0 });
175 }
176
177 sub action_reconcile_proposals {
178   my ($self) = @_;
179
180   my $counter = 0;
181
182   foreach my $bt_id ( @{ $::form->{bt_ids} }) {
183     my $rec_group = SL::DB::Manager::ReconciliationLink->get_new_rec_group();
184     my $bank_transaction = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
185     $bank_transaction->cleared('1');
186     if ( $bank_transaction->isa('SL::DB::BankTransaction') ) {
187       $bank_transaction->invoice_amount($bank_transaction->amount);
188     }
189     $bank_transaction->save;
190     foreach my $acc_trans_id (@{ $::form->{proposal_list}->{$bt_id}->{BB} }) {
191       SL::DB::ReconciliationLink->new(
192         rec_group => $rec_group,
193         bank_transaction_id => $bt_id,
194         acc_trans_id => $acc_trans_id
195       )->save;
196       my $acc_trans = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $acc_trans_id);
197       $acc_trans->cleared('1');
198       $acc_trans->save;
199     }
200     $counter++;
201   }
202
203   flash('ok', t8('#1 proposal(s) saved.', $counter));
204
205   $self->action_reconciliation;
206 }
207
208 #
209 # filters
210 #
211
212 sub check_auth {
213   $::auth->assert('bank_transaction');
214 }
215
216 sub _bank_account {
217   my ($self) = @_;
218   $self->{bank_account} = SL::DB::Manager::BankAccount->find_by(id => $::form->{filter}->{"local_bank_account_id:number"});
219 }
220
221 #
222 # helpers
223 #
224
225 sub _get_proposals {
226   my ($self) = @_;
227
228   # reconciliation suggestion is based on:
229   # * record_link exists (was paid by bank transaction)
230   # or acc_trans entry exists where
231   # * amount is exactly the same
232   # * date is the same
233   # * IBAN or account number have to match exactly (cv details, no spaces)
234   # * not a gl storno
235   # * there is exactly one match for all conditions
236
237   $self->_filter_to_where;
238
239   my $bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => [ @{ $self->{bt_where} }, cleared => '0' ]);
240
241   my $check_sum;
242
243   my @proposals;
244
245   foreach my $bt (@{ $bank_transactions }) {
246     $check_sum = $bt->amount;
247     my $proposal;
248     $proposal->{BT} = $bt;
249     $proposal->{BB} = [];
250
251     # first of all check if any of the bank_transactions are already linked (i.e. were paid via bank transactions)
252     my $linked_records = SL::DB::Manager::RecordLink->get_all(where => [ from_table => 'bank_transactions', from_id => $bt->id ]);
253     foreach my $linked_record (@{ $linked_records }) {
254       my $invoice;
255       if ($linked_record->to_table eq 'ar') {
256         $invoice = SL::DB::Manager::Invoice->find_by(id => $linked_record->to_id);
257         #find payments
258         my $payments = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, chart_link => { like => '%AR_paid%' }, transdate => $bt->transdate ]);
259         foreach my $payment (@{ $payments }) {
260           $check_sum += $payment->amount;
261           push @{ $proposal->{BB} }, $payment;
262         }
263       }
264       if ($linked_record->to_table eq 'ap') {
265         $invoice = SL::DB::Manager::PurchaseInvoice->find_by(id => $linked_record->to_id);
266         #find payments
267         my $payments = SL::DB::Manager::AccTransaction->get_all(where => [ trans_id => $invoice->id, chart_link => { like => '%AP_paid%' }, transdate => $bt->transdate ]);
268         foreach my $payment (@{ $payments }) {
269           $check_sum += $payment->amount;
270           push @{ $proposal->{BB} }, $payment;
271         }
272       }
273     }
274
275     #add proposal if something in acc_trans was found
276     #otherwise try to find another entry in acc_trans and add it
277     # for linked_records we allow a slight difference / imprecision, for acc_trans search we don't
278     if (scalar @{ $proposal->{BB} } and abs($check_sum) <= 0.01 ) {
279       push @proposals, $proposal;
280     } elsif (!scalar @{ $proposal->{BB} }) {
281       # use account_number and iban for matching remote account number
282       # don't suggest gl stornos (ar and ap stornos shouldn't have any payments)
283
284       my @account_number_match = (
285         ( 'ar.customer.iban'           => $bt->remote_account_number ),
286         ( 'ar.customer.account_number' => $bt->remote_account_number ),
287         ( 'ap.vendor.iban'             => $bt->remote_account_number ),
288         ( 'ap.vendor.account_number'   => $bt->remote_account_number ),
289         ( 'gl.storno'                  => '0' ),
290       );
291
292       my $acc_transactions = SL::DB::Manager::AccTransaction->get_all(where => [ @{ $self->{bb_where} },
293                                                                                  amount => -1 * $bt->amount,
294                                                                                  cleared => '0',
295                                                                                  'transdate' => $bt->transdate,
296                                                                                  or => [ @account_number_match ]
297                                                                                ],
298                                                                        with_objects => [ 'ar', 'ap', 'ar.customer', 'ap.vendor', 'gl' ]);
299       if (scalar @{ $acc_transactions } == 1) {
300         push @{ $proposal->{BB} }, @{ $acc_transactions }[0];
301         push @proposals, $proposal;
302       }
303     }
304   }
305
306   $self->{PROPOSALS} = \@proposals;
307 }
308
309 sub _get_elements_and_validate {
310   my ($self) = @_;
311
312   my @errors;
313
314   if ( not defined $::form->{bt_ids} ) {
315     push @errors, t8('No bank account chosen!');
316   }
317
318   if ( not defined $::form->{bb_ids} ) {
319     push @errors, t8('No transaction on chart bank chosen!');
320   }
321
322   if (!@errors) {
323     if (scalar @{ $::form->{bt_ids} } > 1 and scalar @{ $::form->{bb_ids} } > 1) {
324       push @errors, t8('No 1:n or n:1 relation');
325     }
326   }
327
328   my @elements;
329   my ($bt_sum, $bb_sum) = (0,0);
330
331   foreach my $bt_id (@{ $::form->{bt_ids} }) {
332     my $bt = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
333     $bt->{type} = 'BT';
334     $bt_sum += $bt->amount;
335     push @elements, $bt;
336   }
337
338   foreach my $bb_id (@{ $::form->{bb_ids} }) {
339     my $bb = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $bb_id);
340     $bb->{type} = 'BB';
341     $bb->{id} = $bb->acc_trans_id;
342     $bb_sum += $bb->amount;
343     push @elements, $bb;
344   }
345
346   if ($::form->round_amount($bt_sum + $bb_sum, 2) != 0) {
347     push @errors, t8('Out of balance!'), t8('Sum of bank #1 and sum of bookings #2',$bt_sum, $bb_sum);
348   }
349
350   $self->{ELEMENTS} = \@elements;
351   $self->{bt_sum} = $bt_sum;
352   $self->{bb_sum} = $bb_sum;
353
354   return @errors;
355 }
356
357 sub _reconcile {
358   my ($self) = @_;
359
360   # 1. step: set AccTrans and BankTransactions to 'cleared'
361   foreach my $element (@{ $self->{ELEMENTS} }) {
362     $element->cleared('1');
363     # veto either invoice_amount is fully assigned or not! No state tricks in later workflow!
364     # invoice_amount should be a distinct sign, that some bookings were really made from a bank transaction
365     # $element->invoice_amount($element->amount) if $element->isa('SL::DB::BankTransaction');
366     $element->save;
367   }
368
369   # 2. step: insert entry in reconciliation_links
370   my $rec_group = SL::DB::Manager::ReconciliationLink->get_new_rec_group();
371   #There is either a 1:n relation or a n:1 relation
372   if (scalar @{ $::form->{bt_ids} } == 1) {
373     my $bt_id = @{ $::form->{bt_ids} }[0];
374     foreach my $bb_id (@{ $::form->{bb_ids} }) {
375       my $rec_link = SL::DB::ReconciliationLink->new(bank_transaction_id => $bt_id,
376                                                      acc_trans_id        => $bb_id,
377                                                      rec_group           => $rec_group);
378       $rec_link->save;
379     }
380   } else {
381     my $bb_id = @{ $::form->{bb_ids} }[0];
382     foreach my $bt_id (@{ $::form->{bt_ids} }) {
383       my $rec_link = SL::DB::ReconciliationLink->new(bank_transaction_id => $bt_id,
384                                                      acc_trans_id        => $bb_id,
385                                                      rec_group           => $rec_group);
386       $rec_link->save;
387     }
388   }
389 }
390
391 sub _filter_to_where {
392   my ($self) = @_;
393
394   my %parse_filter = parse_filter($::form->{filter});
395   my %filter = @{ $parse_filter{query} };
396
397   my (@rl_where, @bt_where, @bb_where);
398   @rl_where = ('bank_transaction.local_bank_account_id' => $filter{local_bank_account_id});
399   @bt_where = (local_bank_account_id => $filter{local_bank_account_id});
400   @bb_where = (chart_id              => $self->{bank_account}->chart_id);
401
402   if ($filter{fromdate} and $filter{todate}) {
403
404     push @rl_where, (or => [ and => [ 'acc_trans.transdate'        => $filter{fromdate},
405                                       'acc_trans.transdate'        => $filter{todate}   ],
406                              and => [ 'bank_transaction.transdate' => $filter{fromdate},
407                                       'bank_transaction.transdate' => $filter{todate}   ] ] );
408
409     push @bt_where, (transdate => $filter{todate} );
410     push @bt_where, (transdate => $filter{fromdate} );
411     push @bb_where, (transdate => $filter{todate} );
412     push @bb_where, (transdate => $filter{fromdate} );
413   }
414
415   if ( $self->{bank_account}->reconciliation_starting_date ) {
416     push @bt_where, (transdate => { ge => $self->{bank_account}->reconciliation_starting_date });
417     push @bb_where, (transdate => { ge => $self->{bank_account}->reconciliation_starting_date });
418   }
419
420   # don't try to reconcile opening and closing balance transactions
421   push @bb_where, ('acc_trans.ob_transaction' => 0);
422   push @bb_where, ('acc_trans.cb_transaction' => 0);
423
424   if ($filter{fromdate} and not $filter{todate}) {
425     push @rl_where, (or => [ 'acc_trans.transdate'        => $filter{fromdate},
426                              'bank_transaction.transdate' => $filter{fromdate} ] );
427     push @bt_where, (transdate                    => $filter{fromdate} );
428     push @bb_where, (transdate                    => $filter{fromdate} );
429   }
430
431   if ($filter{todate} and not $filter{fromdate}) {
432     push @rl_where, ( or => [ 'acc_trans.transdate'        => $filter{todate} ,
433                               'bank_transaction.transdate' => $filter{todate} ] );
434     push @bt_where, (transdate                    => $filter{todate} );
435     push @bb_where, (transdate                    => $filter{todate} );
436   }
437
438   if ($filter{cleared}) {
439     $filter{cleared} = $filter{cleared} eq 'FALSE' ? '0' : '1';
440     push @rl_where, ('acc_trans.cleared'        => $filter{cleared} );
441
442     push @bt_where, (cleared                    => $filter{cleared} );
443     push @bb_where, (cleared                    => $filter{cleared} );
444   }
445
446   $self->{rl_where} = \@rl_where;
447   $self->{bt_where} = \@bt_where;
448   $self->{bb_where} = \@bb_where;
449 }
450
451 sub _get_linked_transactions {
452   my ($self) = @_;
453
454   $self->_filter_to_where;
455
456   my (@where, @bt_where, @bb_where);
457   # don't try to reconcile opening and closing balances
458   # instead use an offset in configuration
459
460   @where    = (@{ $self->{rl_where} });
461   @bt_where = (@{ $self->{bt_where} }, cleared => '0');
462   @bb_where = (@{ $self->{bb_where} }, cleared => '0');
463
464   my @rows;
465
466   my $reconciliation_groups = SL::DB::Manager::ReconciliationLink->get_all(distinct => 1,
467                                                                            select => ['rec_group'],
468                                                                            where => \@where,
469                                                                            with_objects => ['bank_transaction', 'acc_trans']);
470
471   my $fromdate = $::locale->parse_date_to_object($::form->{filter}->{fromdate_date__ge});
472   my $todate   = $::locale->parse_date_to_object($::form->{filter}->{todate_date__le});
473
474   foreach my $rec_group (@{ $reconciliation_groups }) {
475     my $linked_transactions = SL::DB::Manager::ReconciliationLink->get_all(where => [rec_group => $rec_group->rec_group], with_objects => ['bank_transaction', 'acc_trans']);
476     my $line;
477     my $first_transaction = shift @{ $linked_transactions };
478     my $first_bt = $first_transaction->bank_transaction;
479     my $first_bb = $first_transaction->acc_trans;
480
481     if (defined $fromdate) {
482       $first_bt->{class} = 'out_of_balance' if ( $first_bt->transdate lt $fromdate );
483       $first_bb->{class} = 'out_of_balance' if ( $first_bb->transdate lt $fromdate );
484     }
485     if (defined $todate) {
486       $first_bt->{class} = 'out_of_balance' if ( $first_bt->transdate gt $todate );
487       $first_bb->{class} = 'out_of_balance' if ( $first_bb->transdate gt $todate );
488     }
489     $line->{BT} = [ $first_bt ];
490     $line->{BB} = [ $first_bb ];
491     $line->{rec_group} = $first_transaction->rec_group;
492     $line->{type} = 'Link';
493
494     #add the rest of transaction of this group
495     my ($previous_bt_id, $previous_acc_trans_id) = ($first_transaction->bank_transaction_id, $first_transaction->acc_trans_id);
496     foreach my $linked_transaction (@{ $linked_transactions }) {
497       my $bank_transaction = $linked_transaction->bank_transaction;
498       my $acc_transaction  = $linked_transaction->acc_trans;
499       if (defined $fromdate) {
500         $bank_transaction->{class} = 'out_of_balance' if ( $bank_transaction->transdate lt $fromdate );
501         $acc_transaction->{class}  = 'out_of_balance' if ( $acc_transaction->transdate  lt $fromdate );
502       }
503       if (defined $todate) {
504         $bank_transaction->{class} = 'out_of_balance' if ( $bank_transaction->transdate gt $todate );
505         $acc_transaction->{class}  = 'out_of_balance' if ( $acc_transaction->transdate  gt $todate );
506       }
507       if ($bank_transaction->id != $previous_bt_id) {
508         push @{ $line->{BT} }, $bank_transaction;
509       }
510       if ($acc_transaction->acc_trans_id != $previous_acc_trans_id) {
511         push @{ $line->{BB} }, $acc_transaction;
512       }
513     }
514     push @rows, $line;
515   }
516
517   # add non-cleared bank transactions
518   my $bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => \@bt_where);
519   foreach my $bt (@{ $bank_transactions }) {
520     my $line;
521     $line->{BT} = [ $bt ];
522     $line->{type} = 'BT';
523     $line->{id} = $bt->id;
524     push @rows, $line;
525   }
526
527   # add non-cleared bookings on bank
528   my $bookings_on_bank = SL::DB::Manager::AccTransaction->get_all(where => \@bb_where);
529   foreach my $bb (@{ $bookings_on_bank }) {
530     if ($::form->{filter}->{show_stornos} or !$bb->record->storno) {
531       my $line;
532       $line->{BB} = [ $bb ];
533       $line->{type} = 'BB';
534       $line->{id} = $bb->acc_trans_id;
535       push @rows, $line;
536     }
537   }
538
539   #sort lines
540   @rows = sort sort_by_transdate @rows;
541
542   $self->{LINKED_TRANSACTIONS} = \@rows;
543 }
544
545 sub sort_by_transdate {
546   if ($a->{BT} and $b->{BT}) {
547     return $a->{BT}[0]->amount <=> $b->{BT}[0]->amount if $a->{BT}[0]->transdate eq $b->{BT}[0]->transdate;
548     return $a->{BT}[0]->transdate cmp $b->{BT}[0]->transdate;
549   }
550   if ($a->{BT}) {
551     return $a->{BT}[0]->amount <=> (-1 * $b->{BB}[0]->amount) if $a->{BT}[0]->transdate eq $b->{BB}[0]->transdate;
552     return $a->{BT}[0]->transdate cmp $b->{BB}[0]->transdate;
553   }
554   if ($b->{BT}) {
555     return (-1 * $a->{BB}[0]->amount) <=> $b->{BT}[0]->amount if $a->{BB}[0]->transdate eq $b->{BT}[0]->transdate;
556     return $a->{BB}[0]->transdate cmp $b->{BT}[0]->transdate;
557   }
558   return (-1 * $a->{BB}[0]->amount) <=> (-1 * $b->{BB}[0]->amount) if $a->{BB}[0]->transdate eq $b->{BB}[0]->transdate;
559   return $a->{BB}[0]->transdate cmp $b->{BB}[0]->transdate;
560 }
561
562 sub _get_balances {
563   my ($self) = @_;
564
565   $self->_filter_to_where;
566
567   my (@bt_where, @bb_where);
568   @bt_where = @{ $self->{bt_where} };
569   @bb_where = @{ $self->{bb_where} };
570
571   my @all_bt_where = (local_bank_account_id => $self->{bank_account}->id);
572   my @all_bb_where = (chart_id              => $self->{bank_account}->chart_id);
573
574   my ($bt_balance, $bb_balance) = (0,0);
575   my ($absolut_bt_balance, $absolut_bb_balance) = (0,0);
576
577   if ( $self->{bank_account}->reconciliation_starting_date ) {
578     $bt_balance         = $self->{bank_account}->reconciliation_starting_balance;
579     $bb_balance         = $self->{bank_account}->reconciliation_starting_balance * -1;
580     $absolut_bt_balance = $self->{bank_account}->reconciliation_starting_balance;
581     $absolut_bb_balance = $self->{bank_account}->reconciliation_starting_balance * -1;
582
583     push @all_bt_where, ( transdate => { gt => $self->{bank_account}->reconciliation_starting_date });
584     push @all_bb_where, ( transdate => { gt => $self->{bank_account}->reconciliation_starting_date });
585   }
586
587   my $bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => \@bt_where );
588   my $payments          = SL::DB::Manager::AccTransaction ->get_all(where => \@bb_where );
589
590   # for absolute balance get all bookings until todate
591   my $todate   = $::locale->parse_date_to_object($::form->{filter}->{todate_date__le});
592   my $fromdate = $::locale->parse_date_to_object($::form->{filter}->{fromdate_date__le});
593
594   if ($todate) {
595     push @all_bt_where, (transdate => { le => $todate });
596     push @all_bb_where, (transdate => { le => $todate });
597   }
598
599   my $all_bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => \@all_bt_where);
600   my $all_payments          = SL::DB::Manager::AccTransaction ->get_all(where => \@all_bb_where);
601
602   $bt_balance += sum map { $_->amount } @{ $bank_transactions };
603   $bb_balance += sum map { $_->amount if ($::form->{filter}->{show_stornos} or !$_->record->storno) } @{ $payments };
604
605   $absolut_bt_balance += sum map { $_->amount } @{ $all_bank_transactions };
606   $absolut_bb_balance += sum map { $_->amount } @{ $all_payments };
607
608
609   $self->{bt_balance}         = $bt_balance || 0;
610   $self->{bb_balance}         = $bb_balance || 0;
611   $self->{absolut_bt_balance} = $absolut_bt_balance || 0;
612   $self->{absolut_bb_balance} = $absolut_bb_balance || 0;
613
614   $self->{difference} = $bt_balance + $bb_balance;
615 }
616
617 sub init_cleared {
618   [ { title => t8("all"),       value => ''           },
619     { title => t8("cleared"),   value => 'TRUE'       },
620     { title => t8("uncleared"), value => 'FALSE'      }, ]
621 }
622
623 sub init_BANK_ACCOUNTS {
624   SL::DB::Manager::BankAccount->get_all_sorted( query => [ obsolete => 0 ] );
625 }
626
627 sub setup_search_action_bar {
628   my ($self, %params) = @_;
629
630   for my $bar ($::request->layout->get('actionbar')) {
631     $bar->add(
632       action => [
633         t8('Show'),
634         submit    => [ '#search_form', { action => 'Reconciliation/reconciliation' } ],
635         accesskey => 'enter',
636       ],
637     );
638   }
639 }
640
641 sub setup_reconciliation_action_bar {
642   my ($self, %params) = @_;
643
644   for my $bar ($::request->layout->get('actionbar')) {
645     $bar->add(
646       action => [
647         t8('Filter'),
648         call      => [ 'filter_table' ],
649         accesskey => 'enter',
650       ],
651     );
652   }
653 }
654
655 1;