From 49ece3b0b387e3a33e1d97186973d9fa87172458 Mon Sep 17 00:00:00 2001
From: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Date: Thu, 21 Nov 2019 13:22:39 +0000
Subject: [PATCH] Bug 24080: Add 'payout' method to Koha::Account::Line
This enhancement adds a 'payout' method to Koha::Account::Line which can
be used to 'pay out' a credit to a patron.
When such a credit is 'paid out' this method will create a corresponding
account debit line with an amount equal to the amountoutstanding on the
original credit and the two acocuntlines will be immediately applied against
each other.
Test Plan:
1) Run the included tests and verify they pass.
2) Signoff
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
---
Koha/Account/Line.pm | 93 +++++++++++++++++++
Koha/Exceptions.pm | 4 +
t/db_dependent/Koha/Account/Lines.t | 138 +++++++++++++++++++++++++++-
3 files changed, 234 insertions(+), 1 deletion(-)
diff --git a/Koha/Account/Line.pm b/Koha/Account/Line.pm
index 571c26a986..6f1e5b6e00 100644
--- a/Koha/Account/Line.pm
+++ b/Koha/Account/Line.pm
@@ -278,6 +278,99 @@ sub apply {
return $available_credit;
}
+=head3 payout
+
+ $credit_accountline->payout(
+ {
+ payout_type => $payout_type,
+ register_id => $register_id,
+ staff_id => $staff_id,
+ interface => 'intranet',
+ amount => $amount
+ }
+ );
+
+Used to 'pay out' a credit to a user.
+
+Payout type may be one of any existing payment types
+
+Returns the payout debit line that is created via this transaction.
+
+=cut
+
+sub payout {
+ my ( $self, $params ) = @_;
+
+ # Make sure it is a credit we are paying out
+ unless ( $self->is_credit ) {
+ Koha::Exceptions::Account::IsNotCredit->throw(
+ error => 'Account line ' . $self->id . ' is not a credit' );
+ }
+
+ # Check for mandatory parameters
+ my @mandatory =
+ ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
+ for my $param (@mandatory) {
+ unless ( defined( $params->{$param} ) ) {
+ Koha::Exceptions::MissingParameter->throw(
+ error => "The $param parameter is mandatory" );
+ }
+ }
+
+ # Make sure there is outstanding credit to pay out
+ my $outstanding = -1 * $self->amountoutstanding;
+ my $amount =
+ $params->{amount} ? $params->{amount} : $outstanding;
+ Koha::Exceptions::Account::AmountNotPositive->throw(
+ error => 'Payout amount passed is not positive' )
+ unless ( $amount > 0 );
+ Koha::Exceptions::ParameterTooHigh->throw(
+ error => "Amount to payout ($amount) is higher than amountoutstanding ($outstanding)" )
+ unless ($outstanding >= $amount );
+
+ # Make sure we record the cash register for cash transactions
+ Koha::Exceptions::Account::RegisterRequired->throw()
+ if ( C4::Context->preference("UseCashRegisters")
+ && defined( $params->{payout_type} )
+ && ( $params->{payout_type} eq 'CASH' )
+ && !defined( $params->{cash_register} ) );
+
+ my $payout;
+ $self->_result->result_source->schema->txn_do(
+ sub {
+
+ # A 'payout' is a 'debit'
+ $payout = Koha::Account::Line->new(
+ {
+ date => \'NOW()',
+ amount => $amount,
+ debit_type_code => 'PAYOUT',
+ payment_type => $params->{payout_type},
+ amountoutstanding => $amount,
+ manager_id => $params->{staff_id},
+ borrowernumber => $self->borrowernumber,
+ interface => $params->{interface},
+ branchcode => $params->{branch},
+ register_id => $params->{cash_register}
+ }
+ )->store();
+
+ my $payout_offset = Koha::Account::Offset->new(
+ {
+ debit_id => $payout->accountlines_id,
+ type => 'PAYOUT',
+ amount => $amount
+ }
+ )->store();
+
+ $self->apply( { debits => [$payout], offset_type => 'PAYOUT' } );
+ $self->status('PAID')->store;
+ }
+ );
+
+ return $payout;
+}
+
=head3 adjust
This method allows updating a debit or credit on a patron's account
diff --git a/Koha/Exceptions.pm b/Koha/Exceptions.pm
index 72a56cc3af..cf56b220ef 100644
--- a/Koha/Exceptions.pm
+++ b/Koha/Exceptions.pm
@@ -26,6 +26,10 @@ use Exception::Class (
isa => 'Koha::Exceptions::Exception',
description => 'A required parameter is missing'
},
+ 'Koha::Exceptions::ParameterTooHigh' => {
+ isa => 'Koha::Exceptions::Exception',
+ description => 'A passed parameter value is too high'
+ },
'Koha::Exceptions::NoChanges' => {
isa => 'Koha::Exceptions::Exception',
description => 'No changes were made',
diff --git a/t/db_dependent/Koha/Account/Lines.t b/t/db_dependent/Koha/Account/Lines.t
index d63de70938..735b91fc15 100755
--- a/t/db_dependent/Koha/Account/Lines.t
+++ b/t/db_dependent/Koha/Account/Lines.t
@@ -19,7 +19,7 @@
use Modern::Perl;
-use Test::More tests => 9;
+use Test::More tests => 10;
use Test::Exception;
use C4::Circulation qw/AddIssue AddReturn/;
@@ -606,4 +606,140 @@ subtest "void() tests" => sub {
$schema->storage->txn_rollback;
};
+subtest "payout() tests" => sub {
+
+ plan tests => 17;
+
+ $schema->storage->txn_begin;
+
+ # 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 $staff = Koha::Patron->new(
+ {
+ cardnumber => 'bobby',
+ surname => 'Bloggs',
+ firstname => 'Bobby',
+ }
+ );
+ $staff->categorycode($categorycode);
+ $staff->branchcode($branchcode);
+ $staff->store;
+
+ my $account = Koha::Account->new( { patron_id => $borrower->id } );
+
+ my $debit1 = Koha::Account::Line->new(
+ {
+ borrowernumber => $borrower->borrowernumber,
+ amount => 10,
+ amountoutstanding => 10,
+ interface => 'commandline',
+ debit_type_code => 'OVERDUE'
+ }
+ )->store();
+ my $credit1 = Koha::Account::Line->new(
+ {
+ borrowernumber => $borrower->borrowernumber,
+ amount => -20,
+ amountoutstanding => -20,
+ interface => 'commandline',
+ credit_type_code => 'CREDIT'
+ }
+ )->store();
+
+ is( $account->balance(), -10, "Account balance is -10" );
+ is( $debit1->amountoutstanding,
+ 10, 'Overdue fee has an amount outstanding of 10' );
+ is( $credit1->amountoutstanding,
+ -20, 'Credit has an amount outstanding of -20' );
+
+ my $pay_params = {
+ interface => 'intranet',
+ staff_id => $staff->borrowernumber,
+ branch => $branchcode,
+ payout_type => 'CASH',
+ amount => 20
+ };
+
+ throws_ok { $debit1->payout($pay_params); }
+ 'Koha::Exceptions::Account::IsNotCredit',
+ '->payout() can only be used with credits';
+
+ my @required =
+ ( 'interface', 'staff_id', 'branch', 'payout_type', 'amount' );
+ for my $required (@required) {
+ my $params = {%$pay_params};
+ delete( $params->{$required} );
+ throws_ok {
+ $credit1->payout($params);
+ }
+ 'Koha::Exceptions::MissingParameter',
+ "->payout() requires the `$required` parameter is passed";
+ }
+
+ throws_ok {
+ $credit1->payout(
+ {
+ interface => 'intranet',
+ staff_id => $staff->borrowernumber,
+ branch => $branchcode,
+ payout_type => 'CASH',
+ amount => 25
+ }
+ );
+ }
+ 'Koha::Exceptions::ParameterTooHigh',
+ '->payout() cannot pay out more than the amountoutstanding';
+
+ t::lib::Mocks::mock_preference( 'UseCashRegisters', 1 );
+ throws_ok {
+ $credit1->payout(
+ {
+ interface => 'intranet',
+ staff_id => $staff->borrowernumber,
+ branch => $branchcode,
+ payout_type => 'CASH',
+ amount => 10
+ }
+ );
+ }
+ 'Koha::Exceptions::Account::RegisterRequired',
+ '->payout() requires a cash_register if payout_type is `CASH`';
+
+ t::lib::Mocks::mock_preference( 'UseCashRegisters', 0 );
+ my $payout = $credit1->payout(
+ {
+ interface => 'intranet',
+ staff_id => $staff->borrowernumber,
+ branch => $branchcode,
+ payout_type => 'CASH',
+ amount => 10
+ }
+ );
+
+ is( $payout->amount(), 10, "Payout amount is 10" );
+ is( $payout->amountoutstanding(), 0, "Payout amountoutstanding is 0" );
+ is( $account->balance(), 0, "Account balance is 0" );
+ is( $debit1->amountoutstanding,
+ 10, 'Overdue fee still has an amount outstanding of 10' );
+ is( $credit1->amountoutstanding,
+ -10, 'Credit has an new amount outstanding of -10' );
+ is( $credit1->status(), 'PAID', "Credit has a new status of PAID" );
+
+ $schema->storage->txn_rollback;
+};
+
1;
--
2.24.1