From b11c7ad55b4a6445860e4494e550cb3ff8d09eac Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20B=C3=BCren?= Date: Sun, 3 Mar 2019 16:16:36 +0100 Subject: [PATCH] BankTransaction: want a whole lotta test MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit neuer Test full_workflow in bank_transactions 1. Verbucht drei Verkaufsrechnungen nacheinander, davon eine mit Zahlungsbedingung Skonto nach ZB. Zusätzlich zu den Nebenbücher werden acc_trans Einträge kontrolliert, sowie der gesetzte RecordLink. 2. Da die Bankbewegung komplett aufgeht, wird diese abgeglichen und die Zustände danach kontrolliert. 3. Leider war die Verbuchung komplett Murks, weswegen die Ursprungszustand vor 1. wiederhergestellt (neues Funktion Kontoauszug-Verbuchung rückgängig machen) Bonus-Level: Damit andere Anwendungen / Schnittstellen, DB-Admins nicht auf die Idee kommen an der Hilfstabelle bank_transaction_acc_trans zu schrauben, entsprechend einen weiteren SelfTest geschrieben --- SL/BackgroundJob/SelfTest/Transactions.pm | 43 ++++++ t/bank/bank_transactions.t | 153 +++++++++++++++++++++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/SL/BackgroundJob/SelfTest/Transactions.pm b/SL/BackgroundJob/SelfTest/Transactions.pm index fea648642..4d67c35e3 100644 --- a/SL/BackgroundJob/SelfTest/Transactions.pm +++ b/SL/BackgroundJob/SelfTest/Transactions.pm @@ -43,6 +43,7 @@ sub run { $self->check_zero_amount_paid_but_datepaid_exists; $self->check_orphaned_reconciliated_links; $self->check_recommended_client_settings; + $self->check_orphaned_bank_transaction_acc_trans_links; } sub _setup { @@ -672,6 +673,48 @@ sub check_recommended_client_settings { $self->tester->ok(1, "Mandantenkonfiguration optimal eingestellt.") if ($payments_ok && $all_ok); } + +sub check_orphaned_bank_transaction_acc_trans_links { + my ($self) = @_; + + my $query = qq| + SELECT purpose from bank_transactions + WHERE invoice_amount <> 0 + AND id not in (SELECT bank_transaction_id from bank_transaction_acc_trans) + AND transdate >= ? AND transdate <= ?|; + + my $bt_assigned_no_link = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate); + + if ( scalar @{ $bt_assigned_no_link } > 0 ) { + $self->tester->ok(0, "Verwaiste Verknüpfungen zu Bankbewegungen gefunden. Bei folgenden Bankbewegungen ist eine interne Verknüpfung gelöscht worden:"); + + for my $bt_orphaned (@{ $bt_assigned_no_link }) { + $self->tester->diag("Verwendungszweck: $bt_orphaned->{purpose}"); + } + } else { + $self->tester->ok(1, "Keine verwaisten Einträge in verknüpften Bankbewegungen (Richtung Bank)."); + } + # check for deleted acc_trans_ids + my $query = qq| + SELECT purpose from bank_transactions + WHERE id in + (SELECT bank_transaction_id from bank_transaction_acc_trans + where acc_trans_id NOT IN (select acc_trans_id from acc_trans) + AND transdate >= ? AND transdate <= ?)|; + + my $bt_assigned_no_acc_trans = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate); + + if ( scalar @{ $bt_assigned_no_acc_trans } > 0 ) { + $self->tester->ok(0, "Verwaiste Verknüpfungen zu Bankbewegungen gefunden. Bei folgenden Bankbewegungen ist eine interne Verknüpfung gelöscht worden:"); + + for my $bt_orphaned (@{ $bt_assigned_no_acc_trans }) { + $self->tester->diag("Verwendungszweck: $bt_orphaned->{purpose}"); + } + } else { + $self->tester->ok(1, "Keine verwaisten Einträge in verknüpften Bankbewegungen (Richtung Buchung (Richtung Buchung))."); + } +} + 1; __END__ diff --git a/t/bank/bank_transactions.t b/t/bank/bank_transactions.t index 1652c708d..067270b7b 100644 --- a/t/bank/bank_transactions.t +++ b/t/bank/bank_transactions.t @@ -1,4 +1,4 @@ -use Test::More tests => 211; +use Test::More tests => 282; use strict; @@ -25,6 +25,7 @@ use SL::DB::PaymentTerm; use SL::DB::PurchaseInvoice; use SL::DB::BankTransaction; use SL::Controller::BankTransaction; +use SL::Controller::Reconciliation; use SL::Dev::ALL qw(:ALL); use Data::Dumper; @@ -90,6 +91,7 @@ test_neg_sales_invoice(); test_two_neg_ap_transaction(); test_one_inv_and_two_invoices_with_skonto_exact(); test_bt_error(); +test_full_workflow_ar_multiple_inv_skonto_reconciliate_and_undo(); reset_state(); test_sepa_export(); @@ -518,6 +520,153 @@ sub test_partial_payment { }; +sub test_full_workflow_ar_multiple_inv_skonto_reconciliate_and_undo { + + my $testname = 'test_partial_payment'; + + $ar_transaction = test_ar_transaction(invnumber => 'salesinv partial payment two'); + my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv 2 22d2', amount => 22); + + # amount 299.29 > 119 + my $bt = create_bank_transaction(record => $ar_transaction, + bank_chart_id => $bank->id, + amount => 299.29 + ) or die "Couldn't create bank_transaction"; + + $::form->{invoice_ids} = { + $bt->id => [ $ar_transaction->id ] + }; + + save_btcontroller_to_string(); + + $ar_transaction->load; + $bt->load; + + is($ar_transaction->paid , '119.00000' , "$testname: 'salesinv partial payment' was fully paid"); + is($bt->invoice_amount , '119.00000' , "$testname: bt invoice amount was assigned partially paid amount"); + is($bt->amount , '299.29000' , "$testname: bt amount is stil there"); + # next invoice, same bank transaction + $::form->{invoice_ids} = { + $bt->id => [ $ar_transaction_2->id ] + }; + + save_btcontroller_to_string(); + + $ar_transaction_2->load; + $bt->load; + is($ar_transaction_2->paid , '26.18000' , "$testname: 'salesinv partial payment' was fully paid"); + is($bt->invoice_amount , '145.18000' , "$testname: bt invoice amount was assigned partially paid amount"); + is($bt->amount , '299.29000' , "$testname: bt amount is stil there"); + is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}, 4, "$testname 4 acc_trans entries created"); + + # now check all 4 entries done so far and save paid acc_trans_ids for later use with reconcile + foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}) { + isnt($acc_trans_id_entry->ar_id, undef, "$testname: bt linked with acc_trans and trans_id set"); + my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions', to_id => $acc_trans_id_entry->ar_id ]); + is (ref $rl->[0], 'SL::DB::RecordLink', "$testname record link created"); + my $acc_trans = SL::DB::Manager::AccTransaction->get_all(where => [acc_trans_id => $acc_trans_id_entry->acc_trans_id]); + foreach my $entry (@{ $acc_trans }) { + like(abs($entry->amount), qr/(119|26.18)/, "$testname: abs amount correct"); + like($entry->chart_link, qr/(paid|AR)/, "$testname chart_link correct"); + push @{ $::form->{bb_ids} }, $entry->acc_trans_id if $entry->chart_link =~ m/paid/; + } + } + # great we need one last booking to clear the whole bank transaction - we include skonto + my $ar_transaction_skonto = test_ar_transaction(invnumber => 'salesinv skonto last case', + payment_id => $payment_terms->id, + amount => 136.32, + ); + + $::form->{invoice_ids} = { + $bt->id => [ $ar_transaction_skonto->id ] + }; + $::form->{invoice_skontos} = { + $bt->id => [ 'with_skonto_pt' ] + }; + + save_btcontroller_to_string(); + + $ar_transaction_skonto->load; + $bt->load; + is($ar_transaction_skonto->paid , '162.22000' , "$testname: 'salesinv skonto fully paid"); + is($bt->invoice_amount , '299.29000' , "$testname: bt invoice amount was assigned partially paid amount"); + is($bt->amount , '299.29000' , "$testname: bt amount is stil there"); + is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}, + 7, "$testname 7 acc_trans entries created"); + + # same loop as above, but only for the 3rd ar_id + foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [ar_id => $ar_transaction_skonto->id ] )}) { + isnt($acc_trans_id_entry->ar_id, '', "$testname: bt linked with acc_trans and trans_id set"); + my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions', to_id => $acc_trans_id_entry->ar_id ]); + is (ref $rl->[0], 'SL::DB::RecordLink', "$testname record link created"); + my $acc_trans = SL::DB::Manager::AccTransaction->get_all(where => [acc_trans_id => $acc_trans_id_entry->acc_trans_id]); + foreach my $entry (@{ $acc_trans }) { + like($entry->chart_link, qr/(paid|AR)/, "$testname chart_link correct"); + is ($entry->amount, '162.22000', "$testname full amont") if $entry->chart_link eq 'AR'; # full amount + like(abs($entry->amount), qr/(154.11|8.11)/, "$testname: abs amount correct") if $entry->chart_link =~ m/paid/; + push @{ $::form->{bb_ids} }, $entry->acc_trans_id if ($entry->chart_link =~ m/paid/ && $entry->amount == -154.11); + } + } + # done, now reconciliate all bookings + $::form->{bt_ids} = [ $bt->id ]; + my $rec_controller = SL::Controller::Reconciliation->new; + my @errors = $rec_controller->_get_elements_and_validate; + + is (scalar @errors, 0, "$testname unsuccesfull reconciliation with error: " . Dumper(@errors)); + $rec_controller->_reconcile; + $bt->load; + + # and check the cleared state of bt and the acc_transactions + is($bt->cleared, '1' , "$testname: bt cleared"); + foreach (@{ $::form->{bb_ids} }) { + my $acc_trans = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $_); + is($acc_trans->cleared, '1' , "$testname: acc_trans entry cleared"); + } + # now, this was a really bad idea and in general a major mistake. better undo and redo the whole bank transactions + + $::form->{ids} = [ $bt->id ]; + $bt_controller = SL::Controller::BankTransaction->new; + $bt_controller->action_unlink_bank_transaction('testcase' => 1); + + $bt->load; + + # and check the cleared state of bt and the acc_transactions + is($bt->cleared, '0' , "$testname: bt undo cleared"); + is($bt->invoice_amount, '0.00000' , "$testname: bt undo invoice amount"); + foreach (@{ $::form->{bb_ids} }) { + my $acc_trans = SL::DB::Manager::AccTransaction->find_by(acc_trans_id => $_); + is($acc_trans, undef , "$testname: cleared acc_trans entry completely removed"); + } + # this was for data integrity for reconcile, now all the other options + is(scalar @{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt->id ] )}, + 0, "$testname 7 acc_trans entries deleted"); + my $rl = SL::DB::Manager::RecordLink->get_all(where => [ from_id => $bt->id, from_table => 'bank_transactions' ]); + is (ref $rl->[0], '', "$testname record link removed"); + # double safety and check ar.paid + # load all three invoices and check for paid-link via acc_trans and paid in general + + $ar_transaction->load; + $ar_transaction_2->load; + $ar_transaction_skonto->load; + + is(scalar @{ SL::DB::Manager::AccTransaction->get_all( + where => [ trans_id => $ar_transaction->id, chart_link => { like => '%paid%' } ])}, + 0, "$testname no more paid entries in acc_trans for ar_transaction"); + is(scalar @{ SL::DB::Manager::AccTransaction->get_all( + where => [ trans_id => $ar_transaction_2->id, chart_link => { like => '%paid%' } ])}, + 0, "$testname no more paid entries in acc_trans for ar_transaction_2"); + is(scalar @{ SL::DB::Manager::AccTransaction->get_all( + where => [ trans_id => $ar_transaction_skonto->id, chart_link => { like => '%paid%' } ])}, + 0, "$testname no more paid entries in acc_trans for ar_transaction_skonto"); + + is($ar_transaction->paid , '0.00000' , "$testname: 'salesinv fully unpaid"); + is($ar_transaction_2->paid , '0.00000' , "$testname: 'salesinv 2 fully unpaid"); + is($ar_transaction_skonto->paid , '0.00000' , "$testname: 'salesinv skonto fully unpaid"); + + # whew. w(h)a(n)t a whole lotta test +} + + sub test_credit_note { my $testname = 'test_credit_note'; @@ -743,7 +892,7 @@ sub test_ap_payment_transaction { is($invoice->amount , '136.85000', "$testname: amount ok"); is($invoice->netamount, '115.00000', "$testname: netamount ok"); - is($bt->amount, '-136.85000', "$testname: bt amount ok"); + is($bt->amount, '-136.85000', "$testname: bt amount ok"); is($invoice->paid , '136.85000', "$testname: paid ok"); is($bt->invoice_amount, '-136.85000', "$testname: bt invoice amount for ap was assigned"); -- 2.20.1