Revision 9af3e192
Von Jan Büren vor fast 6 Jahren hinzugefügt
SL/Controller/BankTransaction.pm | ||
---|---|---|
17 | 17 |
use SL::DB::Invoice; |
18 | 18 |
use SL::DB::PurchaseInvoice; |
19 | 19 |
use SL::DB::RecordLink; |
20 |
use SL::DB::ReconciliationLink; |
|
20 | 21 |
use SL::JSON; |
21 | 22 |
use SL::DB::Chart; |
22 | 23 |
use SL::DB::AccTransaction; |
... | ... | |
25 | 26 |
use SL::DB::BankAccount; |
26 | 27 |
use SL::DB::RecordTemplate; |
27 | 28 |
use SL::DB::SepaExportItem; |
28 |
use SL::DBUtils qw(like); |
|
29 |
use SL::DBUtils qw(like do_query);
|
|
29 | 30 |
|
31 |
use SL::Presenter::Tag qw(checkbox_tag); |
|
32 |
use Carp; |
|
30 | 33 |
use List::UtilsBy qw(partition_by); |
31 | 34 |
use List::MoreUtils qw(any); |
32 | 35 |
use List::Util qw(max); |
... | ... | |
711 | 714 |
|
712 | 715 |
return grep { $_ } ($error, @warnings); |
713 | 716 |
} |
717 |
sub action_unlink_bank_transaction { |
|
718 |
my ($self) = @_; |
|
719 |
|
|
720 |
croak("No bank transaction ids") unless scalar @{ $::form->{ids}} > 0; |
|
721 |
|
|
722 |
my $closedto = $::locale->parse_date_to_object($::instance_conf->get_closedto); |
|
723 |
my $success_count; |
|
724 |
|
|
725 |
foreach my $bt_id (@{ $::form->{ids}} ) { |
|
726 |
|
|
727 |
my $bank_transaction = SL::DB::Manager::BankTransaction->find_by(id => $bt_id); |
|
728 |
croak("No valid bank transaction found") unless (ref($bank_transaction) eq 'SL::DB::BankTransaction'); |
|
729 |
|
|
730 |
# everything in one transaction |
|
731 |
my $rez = $bank_transaction->db->with_transaction(sub { |
|
732 |
# 1. remove all reconciliations (due to underlying trigger, this has to be the first step) |
|
733 |
my $rec_links = SL::DB::Manager::ReconciliationLink->get_all(where => [ bank_transaction_id => $bt_id ]); |
|
734 |
$_->delete for @{ $rec_links }; |
|
735 |
|
|
736 |
my %trans_ids; |
|
737 |
foreach my $acc_trans_id_entry (@{ SL::DB::Manager::BankTransactionAccTrans->get_all(where => [bank_transaction_id => $bt_id ] )}) { |
|
738 |
|
|
739 |
my $acc_trans = SL::DB::Manager::AccTransaction->get_all(where => [acc_trans_id => $acc_trans_id_entry->acc_trans_id]); |
|
740 |
# check closedto for acc trans entries |
|
741 |
croak t8('Cannot unlink payment for a closed period!') if (ref $closedto && grep { $_->transdate < $closedto } @{ $acc_trans } ); |
|
742 |
|
|
743 |
# save trans_id and type |
|
744 |
die "no type" unless ($acc_trans_id_entry->ar_id || $acc_trans_id_entry->ap_id || $acc_trans_id_entry->gl_id); |
|
745 |
$trans_ids{$acc_trans_id_entry->ar_id} = 'ar' if $acc_trans_id_entry->ar_id; |
|
746 |
$trans_ids{$acc_trans_id_entry->ap_id} = 'ap' if $acc_trans_id_entry->ap_id; |
|
747 |
$trans_ids{$acc_trans_id_entry->gl_id} = 'gl' if $acc_trans_id_entry->gl_id; |
|
748 |
|
|
749 |
# 2. all good -> ready to delete acc_trans and bt_acc link |
|
750 |
$acc_trans_id_entry->delete; |
|
751 |
$_->delete for @{ $acc_trans }; |
|
752 |
} |
|
753 |
# 3. update arap.paid (may not be 0, yet) |
|
754 |
while (my ($trans_id, $type) = each %trans_ids) { |
|
755 |
next if $type eq 'gl'; |
|
756 |
die ("invalid type") unless $type =~ m/^(ar|ap)$/; |
|
757 |
|
|
758 |
# recalc and set paid via database query |
|
759 |
my $query = qq|UPDATE $type SET paid = |
|
760 |
(SELECT COALESCE(abs(sum(amount)),0) FROM acc_trans |
|
761 |
WHERE trans_id = ? |
|
762 |
AND chart_link ilike '%paid%')|; |
|
763 |
|
|
764 |
die if (do_query($::form, $bank_transaction->db->dbh, $query, $trans_id) == -1); |
|
765 |
} |
|
766 |
# 4. and delete all (if any) record links |
|
767 |
my $rl = SL::DB::Manager::RecordLink->delete_all(where => [ from_id => $bt_id, from_table => 'bank_transactions' ]); |
|
768 |
|
|
769 |
# 5. finally reset this bank transaction |
|
770 |
$bank_transaction->invoice_amount(0); |
|
771 |
$bank_transaction->cleared(0); |
|
772 |
$bank_transaction->save; |
|
714 | 773 |
|
774 |
1; |
|
775 |
|
|
776 |
}) || die t8('error while unlinking payment #1 : ', $bank_transaction->purpose) . $bank_transaction->db->error . "\n"; |
|
777 |
|
|
778 |
$success_count++; |
|
779 |
} |
|
780 |
|
|
781 |
flash('ok', t8('#1 bank transaction bookings undone.', $success_count)); |
|
782 |
$self->action_list_all(); |
|
783 |
} |
|
715 | 784 |
# |
716 | 785 |
# filters |
717 | 786 |
# |
... | ... | |
754 | 823 |
my $report = SL::ReportGenerator->new(\%::myconfig, $::form); |
755 | 824 |
$self->{report} = $report; |
756 | 825 |
|
757 |
my @columns = qw(local_bank_name transdate valudate remote_name remote_account_number remote_bank_code amount invoice_amount invoices currency purpose local_account_number local_bank_code id); |
|
826 |
my @columns = qw(ids local_bank_name transdate valudate remote_name remote_account_number remote_bank_code amount invoice_amount invoices currency purpose local_account_number local_bank_code id);
|
|
758 | 827 |
my @sortable = qw(local_bank_name transdate valudate remote_name remote_account_number remote_bank_code amount purpose local_account_number local_bank_code); |
759 | 828 |
|
760 | 829 |
my %column_defs = ( |
830 |
ids => { raw_header_data => checkbox_tag("", id => "check_all", checkall => "[data-checkall=1]"), |
|
831 |
'align' => 'center', |
|
832 |
raw_data => sub { if (@{ $_[0]->linked_invoices } && !(grep {ref ($_) eq 'SL::DB::GLTransaction' } @{ $_[0]->linked_invoices })) { |
|
833 |
checkbox_tag("ids[]", value => $_[0]->id, "data-checkall" => 1); } } }, |
|
761 | 834 |
transdate => { sub => sub { $_[0]->transdate_as_date } }, |
762 | 835 |
valutadate => { sub => sub { $_[0]->valutadate_as_date } }, |
763 | 836 |
remote_name => { }, |
... | ... | |
815 | 888 |
by => 'transdate', |
816 | 889 |
dir => 0, # 1 = ASC, 0 = DESC : default sort is newest at top |
817 | 890 |
}, |
891 |
id => t8('ID'), |
|
818 | 892 |
transdate => t8('Transdate'), |
819 | 893 |
remote_name => t8('Remote name'), |
820 | 894 |
amount => t8('Amount'), |
... | ... | |
884 | 958 |
|
885 | 959 |
for my $bar ($::request->layout->get('actionbar')) { |
886 | 960 |
$bar->add( |
887 |
action => [ |
|
888 |
t8('Filter'), |
|
889 |
submit => [ '#filter_form', { action => 'BankTransaction/list_all' } ], |
|
961 |
combobox => [ |
|
962 |
action => [ t8('Actions') ], |
|
963 |
action => [ |
|
964 |
t8('Unlink bank transactions'), |
|
965 |
submit => [ '#form', { action => 'BankTransaction/unlink_bank_transaction' } ], |
|
966 |
checks => [ [ 'kivi.check_if_entries_selected', '[name="ids[]"]' ] ], |
|
967 |
disabled => $::instance_conf->get_payments_changeable ? t8('Cannot safely unlink bank transactions, please set the posting configuration for payments to unchangeable.') : undef, |
|
968 |
], |
|
969 |
], |
|
970 |
action => [ |
|
971 |
t8('Filter'), |
|
972 |
submit => [ '#filter_form', { action => 'BankTransaction/list_all' } ], |
|
890 | 973 |
accesskey => 'enter', |
891 | 974 |
], |
892 | 975 |
); |
... | ... | |
961 | 1044 |
|
962 | 1045 |
=back |
963 | 1046 |
|
1047 |
=item C<action_unlink_bank_transaction> |
|
1048 |
|
|
1049 |
Takes one or more bank transaction ID (as parameter C<form::ids>) and |
|
1050 |
tries to revert all payment bookings including already cleared bookings. |
|
1051 |
|
|
1052 |
This method won't undo payments that are in a closed period and assumes |
|
1053 |
that payments are not manually changed, i.e. only imported payments. |
|
1054 |
|
|
1055 |
GL-records will be deleted completely if a bank transaction was the source. |
|
1056 |
|
|
1057 |
TODO: we still rely on linked_records for the check boxes |
|
1058 |
|
|
964 | 1059 |
=back |
965 | 1060 |
|
966 | 1061 |
=head1 AUTHOR |
Auch abrufbar als: Unified diff
BankTransaction: Neue Funktion um Bankverbuchungen wieder rückgängig zu machen
action_unlink_bank_transaction inkl. POD
Der Bericht Bankbewegungen erhält im Presenter Anhakboxen (ähnlich wie bei SEPA)