@@ -, +, @@ --- 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(-) --- a/Koha/Account/Line.pm +++ a/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 --- a/installer/data/mysql/account_offset_types.sql +++ a/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'); --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt @@ -60,6 +60,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 @@ -93,6 +94,7 @@ [% IF ( reverse_col) %] [% IF ( account.payment ) %] Reverse + Void [% ELSE %][% SET footerjs = 1 %]   [% END %] --- a/members/boraccount.pl +++ a/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']}); --- a/t/db_dependent/Accounts.t +++ a/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; --