Bug 18790: Add ability to void payments
authorKyle M Hall <kyle@bywatersolutions.com>
Sat, 10 Jun 2017 11:34:56 +0000 (11:34 +0000)
committerJonathan Druart <jonathan.druart@bugs.koha-community.org>
Thu, 19 Apr 2018 15:32:21 +0000 (12:32 -0300)
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 <koha-us@koha-us.net>
Signed-off-by: BWS Sandboxes <ByWaterSandboxes@gmail.com>
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Koha/Account/Line.pm
installer/data/mysql/account_offset_types.sql
koha-tmpl/intranet-tmpl/prog/en/modules/members/boraccount.tt
members/boraccount.pl
t/db_dependent/Accounts.t

index 2065de7..83b6359 100644 (file)
@@ -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
index a0f2fb1..a9eaadc 100644 (file)
@@ -9,4 +9,5 @@ INSERT INTO account_offset_types ( type ) VALUES
 ('Dropbox'),
 ('Rental Fee'),
 ('Fine Update'),
-('Fine');
+('Fine'),
+('Void Payment');
index faccfd0..bdc142c 100644 (file)
@@ -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 ) %]
             <a href="boraccount.pl?action=reverse&amp;accountlines_id=[% account.accountlines_id %]&amp;borrowernumber=[% account.borrowernumber %]" class="btn btn-default btn-xs"><i class="fa fa-undo"></i> Reverse</a>
+            <a href="boraccount.pl?action=void&amp;accountlines_id=[% account.accountlines_id %]&amp;borrowernumber=[% account.borrowernumber %]" class="btn btn-default btn-xs"><i class="fa fa-ban"></i> Void</a>
           [% ELSE %][% SET footerjs = 1 %]
             &nbsp;
           [% END %]
index 4abb571..b3d1431 100755 (executable)
@@ -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']});
index 3d2cbea..351290c 100644 (file)
@@ -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;