From 5372faf4e5be575f91eacd91ddbfba73c5835bf5 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Sat, 10 Jun 2017 11:34:56 +0000 Subject: [PATCH] Bug 18790: Add ability to void payments We've had the ability to 'reverse' a payment for a long time, but it would be much better if we had a true void payment function that replaces the paid amounts into the fee so that it appears as if the payment was never made. Test Plan: 1) Apply this patch and dependent patches 2) Run updatedatabase.pl 3) Create some fines 4) Pay those fines 5) Use the new 'void' button to void the payments 6) Note the fines were restored to their pre-payment amounts Signed-off-by: Koha-us conference Signed-off-by: BWS Sandboxes Signed-off-by: Josef Moravec Signed-off-by: Jonathan Druart --- Koha/Account/Line.pm | 46 +++++++++++++++ installer/data/mysql/account_offset_types.sql | 3 +- .../prog/en/modules/members/boraccount.tt | 2 + members/boraccount.pl | 7 ++- t/db_dependent/Accounts.t | 59 ++++++++++++++++++- 5 files changed, 114 insertions(+), 3 deletions(-) diff --git a/Koha/Account/Line.pm b/Koha/Account/Line.pm index 2065de7e2f..83b635996c 100644 --- a/Koha/Account/Line.pm +++ b/Koha/Account/Line.pm @@ -21,6 +21,7 @@ use Carp; use Koha::Database; use Koha::Items; +use Koha::Account::Offsets; use base qw(Koha::Object); @@ -46,6 +47,51 @@ sub item { return Koha::Item->_new_from_dbic( $rs ); } +=head3 void + +$payment_accountline->void(); + +=cut + +sub void { + my ($self) = @_; + + # Make sure it is a payment we are voiding + return unless $self->accounttype =~ /^Pay/; + + my @account_offsets = + Koha::Account::Offsets->search( { credit_id => $self->id, type => 'Payment' } ); + + foreach my $account_offset (@account_offsets) { + my $fee_paid = Koha::Account::Lines->find( $account_offset->debit_id ); + + next unless $fee_paid; + + my $amount_paid = $account_offset->amount * -1; # amount paid is stored as a negative amount + my $new_amount = $fee_paid->amountoutstanding + $amount_paid; + $fee_paid->amountoutstanding($new_amount); + $fee_paid->store(); + + Koha::Account::Offset->new( + { + credit_id => $self->id, + debit_id => $fee_paid->id, + amount => $amount_paid, + type => 'Void Payment', + } + )->store(); + } + + $self->set( + { + accounttype => 'VOID', + amountoutstanding => 0, + amount => 0, + } + ); + $self->store(); +} + =head3 _type =cut diff --git a/installer/data/mysql/account_offset_types.sql b/installer/data/mysql/account_offset_types.sql index a0f2fb1097..a9eaadc450 100644 --- a/installer/data/mysql/account_offset_types.sql +++ b/installer/data/mysql/account_offset_types.sql @@ -9,4 +9,5 @@ INSERT INTO account_offset_types ( type ) VALUES ('Dropbox'), ('Rental Fee'), ('Fine Update'), -('Fine'); +('Fine'), +('Void Payment'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt index faccfd0bd4..bdc142c449 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt @@ -61,6 +61,7 @@ [% CASE 'Pay00' %]Payment, thanks (cash via SIP2) [% CASE 'Pay01' %]Payment, thanks (VISA via SIP2) [% CASE 'Pay02' %]Payment, thanks (credit card via SIP2) + [% CASE 'VOID' %]Payment, Voided [% CASE 'N' %]New card [% CASE 'F' %]Fine [% CASE 'A' %]Account management fee @@ -94,6 +95,7 @@ [% IF ( reverse_col) %] [% IF ( account.payment ) %] Reverse + Void [% ELSE %][% SET footerjs = 1 %]   [% END %] diff --git a/members/boraccount.pl b/members/boraccount.pl index 4abb5714b5..b3d1431e58 100755 --- a/members/boraccount.pl +++ b/members/boraccount.pl @@ -48,7 +48,7 @@ my ($template, $loggedinuser, $cookie) = get_template_and_user( } ); -my $borrowernumber=$input->param('borrowernumber'); +my $borrowernumber = $input->param('borrowernumber'); my $action = $input->param('action') || ''; my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in"; @@ -63,6 +63,11 @@ output_and_exit_if_error( $input, $cookie, $template, { module => 'members', log if ( $action eq 'reverse' ) { ReversePayment( scalar $input->param('accountlines_id') ); } +elsif ( $action eq 'void' ) { + my $payment_id = scalar $input->param('accountlines_id'); + my $payment = Koha::Account::Lines->find( $payment_id ); + $payment->void(); +} if ( $patron->is_child ) { my $patron_categories = Koha::Patron::Categories->search_limited({ category_type => 'A' }, {order_by => ['categorycode']}); diff --git a/t/db_dependent/Accounts.t b/t/db_dependent/Accounts.t index 3d2cbea3d8..351290cdd0 100644 --- a/t/db_dependent/Accounts.t +++ b/t/db_dependent/Accounts.t @@ -18,7 +18,7 @@ use Modern::Perl; -use Test::More tests => 25; +use Test::More tests => 26; use Test::MockModule; use Test::Warn; @@ -847,4 +847,61 @@ subtest "Koha::Account::non_issues_charges tests" => sub { is( Koha::Account::Lines->count({ borrowernumber => $patron->id }), 2 + 2, "The 2 + 2 account lines still exists, the last 2 have been deleted ok" ); }; +subtest "Koha::Account::Line::void tests" => sub { + + plan tests => 12; + + # Create a borrower + my $categorycode = $builder->build({ source => 'Category' })->{ categorycode }; + my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode }; + + my $borrower = Koha::Patron->new( { + cardnumber => 'dariahall', + surname => 'Hall', + firstname => 'Daria', + } ); + $borrower->categorycode( $categorycode ); + $borrower->branchcode( $branchcode ); + $borrower->store; + + my $account = Koha::Account->new({ patron_id => $borrower->id }); + + my $line1 = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amount => 10, amountoutstanding => 10 })->store(); + my $line2 = Koha::Account::Line->new({ borrowernumber => $borrower->borrowernumber, amount => 20, amountoutstanding => 20 })->store(); + + is( $account->balance(), 30, "Account balance is 30" ); + is( $line1->amountoutstanding, 10, 'First fee has amount outstanding of 10' ); + is( $line2->amountoutstanding, 20, 'Second fee has amount outstanding of 20' ); + + my $id = $account->pay( + { + lines => [$line1, $line2], + amount => 30, + } + ); + my $account_payment = Koha::Account::Lines->find( $id ); + + is( $account->balance(), 0, "Account balance is 0" ); + + $line1->_result->discard_changes(); + $line2->_result->discard_changes(); + is( $line1->amountoutstanding, '0.000000', 'First fee has amount outstanding of 0' ); + is( $line2->amountoutstanding, '0.000000', 'Second fee has amount outstanding of 0' ); + + $account_payment->void(); + + is( $account->balance(), 30, "Account balance is again 30" ); + + $account_payment->_result->discard_changes(); + $line1->_result->discard_changes(); + $line2->_result->discard_changes(); + + is( $account_payment->accounttype, 'VOID', 'Voided payment accounttype is VOID' ); + is( $account_payment->amount, '0.000000', 'Voided payment amount is 0' ); + is( $account_payment->amountoutstanding, '0.000000', 'Voided payment amount outstanding is 0' ); + + is( $line1->amountoutstanding, '10.000000', 'First fee again has amount outstanding of 10' ); + is( $line2->amountoutstanding, '20.000000', 'Second fee again has amount outstanding of 20' ); +}; + 1; -- 2.20.1