@@ -, +, @@ --- Koha/Account/Line.pm | 93 +++++++++++++++++++ Koha/Exceptions.pm | 4 + t/db_dependent/Koha/Account/Lines.t | 138 +++++++++++++++++++++++++++- 3 files changed, 234 insertions(+), 1 deletion(-) --- a/Koha/Account/Line.pm +++ a/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 --- a/Koha/Exceptions.pm +++ a/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', --- a/t/db_dependent/Koha/Account/Lines.t +++ a/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; --