Bug 20944: Add route to add credits to a patron's account
This patch adds the /patrons/{patron_id}/account/credits endpoint, that
can be used to add credits to a patron's account. It is implemented so
the new credits are used to pay existing debts.
To test:
- Run:
$ kshell
k$ prove t/db_dependent/api/v1/patrons_accounts.t
=> SUCCESS: Tests pass!
- Make your favourite REST testing tool (RESTer on Firefox?) do:
POST /api/v1/patrons/{patron_id}/account/credits
{
"amount": 100
}
- Play with other possible attributes on the credit object.
- Sign off :-D
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
parent
566badf12a
commit
d19d8ec049
|
|
@ -19,6 +19,9 @@ use Modern::Perl;
|
|||
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
|
||||
use Koha::Patrons;
|
||||
|
||||
use Scalar::Util qw(blessed);
|
||||
use Try::Tiny;
|
||||
|
||||
=head1 NAME
|
||||
|
|
@ -69,6 +72,90 @@ sub get {
|
|||
return $c->render( status => 200, openapi => $balance );
|
||||
}
|
||||
|
||||
=head3 add_credit
|
||||
|
||||
Controller function that handles adding a credit to a patron's account
|
||||
|
||||
=cut
|
||||
|
||||
sub add_credit {
|
||||
my $c = shift->openapi->valid_input or return;
|
||||
|
||||
my $patron_id = $c->validation->param('patron_id');
|
||||
my $patron = Koha::Patrons->find($patron_id);
|
||||
my $user = $c->stash('koha.user');
|
||||
|
||||
|
||||
unless ($patron) {
|
||||
return $c->render( status => 404, openapi => { error => "Patron not found." } );
|
||||
}
|
||||
|
||||
my $account = $patron->account;
|
||||
my $body = $c->validation->param('body');
|
||||
|
||||
return try {
|
||||
my $credit_type = $body->{credit_type} || 'payment'; # default to 'payment'
|
||||
my $amount = $body->{amount}; # mandatory, validated by openapi
|
||||
|
||||
unless ( $amount > 0 ) { # until we support newer JSON::Validator and thus minimumExclusive
|
||||
Koha::Exceptions::BadParameter->throw( { parameter => 'amount' } );
|
||||
}
|
||||
|
||||
# read the rest of the params
|
||||
my $payment_type = $body->{payment_type};
|
||||
my $description = $body->{description};
|
||||
my $note = $body->{note};
|
||||
|
||||
my $credit = $account->add_credit(
|
||||
{ amount => $amount,
|
||||
credit_type => $credit_type,
|
||||
payment_type => $payment_type,
|
||||
description => $description,
|
||||
note => $note,
|
||||
user_id => $user->id
|
||||
}
|
||||
);
|
||||
$credit->discard_changes;
|
||||
|
||||
my $date = $body->{date};
|
||||
$credit->date( $date )->store
|
||||
if $date;
|
||||
|
||||
my $debits_ids = $body->{account_lines_ids};
|
||||
my $debits = Koha::Account::Lines->search({ accountlines_id => { -in => $debits_ids } })
|
||||
if $debits_ids;
|
||||
|
||||
my $outstanding_credit = $credit->amountoutstanding;
|
||||
if ($debits) {
|
||||
# pay them!
|
||||
$outstanding_credit = $credit->apply({ debits => $debits, offset_type => 'payment' });
|
||||
}
|
||||
|
||||
if ($outstanding_credit) {
|
||||
my $outstanding_debits = $account->outstanding_debits;
|
||||
$credit->apply({ debits => $outstanding_debits, offset_type => 'payment' });
|
||||
}
|
||||
|
||||
return $c->render( status => 200, openapi => { account_line_id => $credit->id } );
|
||||
}
|
||||
catch {
|
||||
if ( blessed $_ && $_->can('rethrow') ) {
|
||||
return $c->render(
|
||||
status => 400,
|
||||
openapi => { error => "$_" }
|
||||
);
|
||||
}
|
||||
else {
|
||||
# Exception, rely on the stringified exception
|
||||
return $c->render(
|
||||
status => 500,
|
||||
openapi => { error => "Something went wrong, check the logs" }
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
=head3 _to_api
|
||||
|
||||
Helper function that maps unblessed Koha::Account::Line objects
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 1;
|
||||
use Test::More tests => 2;
|
||||
|
||||
use Test::Mojo;
|
||||
use Test::Warn;
|
||||
|
|
@ -45,8 +45,8 @@ subtest 'get_balance() tests' => sub {
|
|||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my ( $patron_id, $session_id ) = create_user_and_session({ authorized => 0 });
|
||||
my $patron = Koha::Patrons->find($patron_id);
|
||||
my ( $patron, $session_id ) = create_user_and_session({ authorized => 0 });
|
||||
my $patron_id = $patron->id;
|
||||
my $account = $patron->account;
|
||||
|
||||
my $tx = $t->ua->build_tx(GET => "/api/v1/patrons/$patron_id/account");
|
||||
|
|
@ -147,32 +147,112 @@ subtest 'get_balance() tests' => sub {
|
|||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'add_credit() tests' => sub {
|
||||
|
||||
plan tests => 17;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my ( $patron, $session_id ) = create_user_and_session( { authorized => 1 } );
|
||||
my $patron_id = $patron->id;
|
||||
my $account = $patron->account;
|
||||
|
||||
is( $account->outstanding_debits->count, 0, 'No outstanding debits for patron' );
|
||||
is( $account->outstanding_credits->count, 0, 'No outstanding credits for patron' );
|
||||
|
||||
my $credit = { amount => 100 };
|
||||
|
||||
my $tx = $t->ua->build_tx(
|
||||
POST => "/api/v1/patrons/$patron_id/account/credits" => json => $credit );
|
||||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
|
||||
$tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
|
||||
$t->request_ok($tx)->status_is(200)->json_has('/account_line_id');
|
||||
|
||||
my $outstanding_credits = $account->outstanding_credits;
|
||||
is( $outstanding_credits->count, 1 );
|
||||
is( $outstanding_credits->total_outstanding, -100 );
|
||||
|
||||
my $debit_1 = Koha::Account::Line->new(
|
||||
{ borrowernumber => $patron->borrowernumber,
|
||||
date => \'NOW()',
|
||||
amount => 10,
|
||||
description => "A description",
|
||||
accounttype => "N", # New card
|
||||
amountoutstanding => 10,
|
||||
manager_id => $patron->borrowernumber,
|
||||
}
|
||||
)->store();
|
||||
my $debit_2 = Koha::Account::Line->new(
|
||||
{ borrowernumber => $patron->borrowernumber,
|
||||
date => \'NOW()',
|
||||
amount => 15,
|
||||
description => "A description",
|
||||
accounttype => "N", # New card
|
||||
amountoutstanding => 15,
|
||||
manager_id => $patron->borrowernumber,
|
||||
}
|
||||
)->store();
|
||||
|
||||
is( $account->outstanding_debits->total_outstanding, 25 );
|
||||
$tx = $t->ua->build_tx(
|
||||
POST => "/api/v1/patrons/$patron_id/account/credits" => json => $credit );
|
||||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
|
||||
$tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
|
||||
$t->request_ok($tx)->status_is(200)->json_has('/account_line_id');
|
||||
|
||||
is( $account->outstanding_debits->total_outstanding,
|
||||
0, "Debits have been cancelled automatically" );
|
||||
|
||||
my $debit_3 = Koha::Account::Line->new(
|
||||
{ borrowernumber => $patron->borrowernumber,
|
||||
date => \'NOW()',
|
||||
amount => 100,
|
||||
description => "A description",
|
||||
accounttype => "N", # New card
|
||||
amountoutstanding => 100,
|
||||
manager_id => $patron->borrowernumber,
|
||||
}
|
||||
)->store();
|
||||
|
||||
$credit = {
|
||||
amount => 35,
|
||||
account_lines_ids => [ $debit_1->id, $debit_2->id, $debit_3->id ]
|
||||
};
|
||||
|
||||
$tx = $t->ua->build_tx(
|
||||
POST => "/api/v1/patrons/$patron_id/account/credits" => json => $credit );
|
||||
$tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
|
||||
$tx->req->env( { REMOTE_ADDR => '127.0.0.1' } );
|
||||
$t->request_ok($tx)->status_is(200)->json_has('/account_line_id');
|
||||
|
||||
my $outstanding_debits = $account->outstanding_debits;
|
||||
is( $outstanding_debits->total_outstanding, 65 );
|
||||
is( $outstanding_debits->count, 1 );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
sub create_user_and_session {
|
||||
|
||||
my $args = shift;
|
||||
my $flags = ( $args->{authorized} ) ? 16 : 0;
|
||||
my $flags = ( $args->{authorized} ) ? 2**10 : 0;
|
||||
|
||||
my $user = $builder->build(
|
||||
my $patron = $builder->build_object(
|
||||
{
|
||||
source => 'Borrower',
|
||||
class => 'Koha::Patrons',
|
||||
value => {
|
||||
flags => $flags,
|
||||
gonenoaddress => 0,
|
||||
lost => 0,
|
||||
email => 'nobody@example.com',
|
||||
emailpro => 'nobody@example.com',
|
||||
B_email => 'nobody@example.com'
|
||||
flags => $flags
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Create a session for the authorized user
|
||||
my $session = C4::Auth::get_session('');
|
||||
$session->param( 'number', $user->{borrowernumber} );
|
||||
$session->param( 'id', $user->{userid} );
|
||||
$session->param( 'number', $patron->id );
|
||||
$session->param( 'id', $patron->userid );
|
||||
$session->param( 'ip', '127.0.0.1' );
|
||||
$session->param( 'lasttime', time() );
|
||||
$session->flush;
|
||||
|
||||
return ( $user->{borrowernumber}, $session->id );
|
||||
return ( $patron, $session->id );
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue