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