From f2623ae6a3a763aa699b1e64d46ee3a91b5ae901 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Tue, 16 Sep 2025 13:48:46 +0100 Subject: [PATCH] Bug 40817: Add API tests for hold-debits embedding This patch adds comprehensive API tests to verify the new hold-debits embedding functionality: holds.t: - Test GET /holds with debits embedding returns correct structure - Test POST /holds response includes embedded debits when requested - Verify embedded debits contain expected account line data - Test embedding works with both successful and failed hold creation patrons_holds.t: - Test GET /patrons/{id}/holds with debits embedding - Verify patron-specific hold debits are correctly returned - Test embedding parameter validation and error handling - Ensure proper authorization and access control --- t/db_dependent/api/v1/holds.t | 146 +++++++++++++++++++++++++- t/db_dependent/api/v1/patrons_holds.t | 75 ++++++++++++- 2 files changed, 219 insertions(+), 2 deletions(-) diff --git a/t/db_dependent/api/v1/holds.t b/t/db_dependent/api/v1/holds.t index e98d8b125e0..35a2d87d830 100755 --- a/t/db_dependent/api/v1/holds.t +++ b/t/db_dependent/api/v1/holds.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 18; +use Test::More tests => 20; use Test::NoWarnings; use Test::MockModule; use Test::Mojo; @@ -39,6 +39,7 @@ use Koha::Biblioitems; use Koha::Items; use Koha::CirculationRules; use Koha::Patron::Debarments qw(AddDebarment); +use Koha::Holds; my $schema = Koha::Database->new->schema; my $builder = t::lib::TestBuilder->new(); @@ -1885,3 +1886,146 @@ subtest 'PUT /holds/{hold_id}/lowest_priority tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'debits embedding tests' => sub { + + plan tests => 8; + + $schema->storage->txn_begin; + + # Setup proper permissions and authentication + my $categorycode = $builder->build( { source => 'Category' } )->{categorycode}; + my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode}; + my $password = 'thePassword123'; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + flags => 80, # borrowers (16) + reserveforothers (64) = 80 + } + } + ); + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + } + } + ); + my $biblio = $builder->build_sample_biblio(); + + # Create a hold using the proper API method + my $reserve_id = C4::Reserves::AddReserve( + { + branchcode => $branchcode, + borrowernumber => $patron->borrowernumber, + biblionumber => $biblio->biblionumber, + priority => 1, + } + ); + + my $hold = Koha::Holds->find($reserve_id); + + # Create account lines and link them to the hold + my $fee1 = $patron->account->add_debit( + { + amount => 2.50, + description => 'Hold placement fee', + type => 'RESERVE', + interface => 'intranet', + hold_id => $hold->id + } + ); + + # Test without embedding - should not include debits + $t->get_ok( "//$userid:$password@/api/v1/holds?hold_id=" . $hold->id )->status_is(200)->json_has('/0/hold_id') + ->json_hasnt( '/0/debits', 'No debits without embedding' ); + + # Test with debits embedding - should include debits + $t->get_ok( + "//$userid:$password@/api/v1/holds?hold_id=" . $hold->id, + { 'x-koha-embed' => 'debits' } + )->status_is(200)->json_has( '/0/debits', 'debits present when embedded' ) + ->json_is( '/0/debits/0/amount', 2.50, 'Account line amount correct' ); + + $schema->storage->txn_rollback; +}; + +subtest 'POST with debits embedding tests' => sub { + + plan tests => 4; + + $schema->storage->txn_begin; + + # Setup proper permissions and authentication + my $categorycode = $builder->build( { source => 'Category' } )->{categorycode}; + my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode}; + my $password = 'thePassword123'; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + flags => 80, # borrowers (16) + reserveforothers (64) = 80 + } + } + ); + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + } + } + ); + my $biblio = $builder->build_sample_biblio(); + my $item = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } ); + + # Set up system preference to charge fees for holds + t::lib::Mocks::mock_preference( 'HoldFeeMode', 'any_time_is_placed' ); + + # Create a circulation rule with hold fee + Koha::CirculationRules->set_rules( + { + categorycode => $patron->categorycode, + branchcode => undef, + itemtype => undef, + rules => { + hold_fee => 2.50, + } + } + ); + + # Make sure pickup location checks doesn't get in the middle + my $mock_biblio = Test::MockModule->new('Koha::Biblio'); + $mock_biblio->mock( 'pickup_locations', sub { return Koha::Libraries->search; } ); + my $mock_item = Test::MockModule->new('Koha::Item'); + $mock_item->mock( 'pickup_locations', sub { return Koha::Libraries->search } ); + + # Test POST with embedding (should include automatically charged debits in response) + $t->post_ok( + "//$userid:$password@/api/v1/holds" => { 'x-koha-embed' => 'debits' } => json => { + patron_id => $patron->borrowernumber, + biblio_id => $biblio->biblionumber, + item_id => $item->itemnumber, + pickup_library_id => $branchcode, + } + )->status_is(201)->json_has( '/debits', 'debits embedded in POST response' ) + ->json_is( '/debits/0/amount', 2.50, 'Hold fee automatically charged and embedded' ); + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/api/v1/patrons_holds.t b/t/db_dependent/api/v1/patrons_holds.t index 99066428fd1..45bfe65954d 100755 --- a/t/db_dependent/api/v1/patrons_holds.t +++ b/t/db_dependent/api/v1/patrons_holds.t @@ -18,7 +18,7 @@ use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 3; +use Test::More tests => 4; use Test::MockModule; use Test::Mojo; @@ -26,6 +26,7 @@ use t::lib::TestBuilder; use t::lib::Mocks; use Koha::Database; +use C4::Reserves; my $schema = Koha::Database->new->schema; my $builder = t::lib::TestBuilder->new(); @@ -185,3 +186,75 @@ subtest 'delete_public() tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'debits embedding tests' => sub { + + plan tests => 8; + + $schema->storage->txn_begin; + + # Setup proper permissions and authentication + my $categorycode = $builder->build( { source => 'Category' } )->{categorycode}; + my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode}; + my $password = 'thePassword123'; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + flags => 80, # borrowers (16) + reserveforothers (64) = 80 + } + } + ); + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { + categorycode => $categorycode, + branchcode => $branchcode, + } + } + ); + my $biblio = $builder->build_sample_biblio(); + + # Create a hold using the proper API method + my $reserve_id = C4::Reserves::AddReserve( + { + branchcode => $branchcode, + borrowernumber => $patron->borrowernumber, + biblionumber => $biblio->biblionumber, + priority => 1, + } + ); + + my $hold = Koha::Holds->find($reserve_id); + + # Create account lines and link them to the hold + my $fee1 = $patron->account->add_debit( + { + amount => 2.50, + description => 'Hold placement fee', + type => 'RESERVE', + interface => 'intranet', + hold_id => $hold->id, + } + ); + + # Test without embedding - should not include debits + $t->get_ok( "//$userid:$password@/api/v1/patrons/" . $patron->id . "/holds" )->status_is(200) + ->json_has('/0/hold_id')->json_hasnt( '/0/debits', 'No debits without embedding' ); + + # Test with debits embedding - should include debits + $t->get_ok( + "//$userid:$password@/api/v1/patrons/" . $patron->id . "/holds", + { 'x-koha-embed' => 'debits' } + )->status_is(200)->json_has( '/0/debits', 'debits present when embedded' ) + ->json_is( '/0/debits/0/amount', 2.50, 'Account line amount correct' ); + + $schema->storage->txn_rollback; +}; -- 2.51.0