Bugzilla – Attachment 191252 Details for
Bug 41592
Add an enhanced workflow for refunds against anonymous transactions
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 41592: Add API endpoints for global account line search
7d157f4.patch (text/plain), 25.54 KB, created by
Martin Renvoize (ashimema)
on 2026-01-12 13:13:45 UTC
(
hide
)
Description:
Bug 41592: Add API endpoints for global account line search
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2026-01-12 13:13:45 UTC
Size:
25.54 KB
patch
obsolete
>From 7d157f4ba6d0e28a57b8e1bc8f6cba07334223d9 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Sun, 11 Jan 2026 17:46:01 +0000 >Subject: [PATCH] Bug 41592: Add API endpoints for global account line search > >This patch adds new REST API endpoints to support cross-register refund >functionality by allowing global searches of account lines (credits and debits) >across all patrons. > >Changes: >- Add /api/v1/account/credits endpoint for searching credits globally >- Add /api/v1/account/debits endpoint for searching debits globally >- Support embedding of related debits in credits endpoint >- Allow searching by credit_number or accountlines_id >- Fix Koha::Account::Line credits() and debits() methods to return > proper Koha::Account::Credits and Koha::Account::Debits objects >- Make patron_id nullable in credit and debit API definitions to support > anonymous transactions > >The new endpoints require the 'anonymous_refund' cash_management permission >and enable staff to search for and refund transactions made at any register. > >Test plan: >1. Apply patch and run: yarn build && ktd --restart_all >2. Test API endpoint: GET /api/v1/account/credits?q={"credit_number":"CR-123"} >3. Test with embed: GET /api/v1/account/credits?q={"credit_number":"CR-123"} > with header x-koha-embed: debits >4. Verify results include credit details and embedded debit information >5. Bonus points: Run the new and updated unit tests: > prove -v t/db_dependent/api/v1/account.t > prove -v t/db_dependent/Koha/Account/Line.t >--- > Koha/Account/Credit.pm | 2 +- > Koha/Account/Line.pm | 4 +- > Koha/REST/V1/Account.pm | 81 ++++++ > api/v1/swagger/definitions/credit.yaml | 8 +- > api/v1/swagger/definitions/debit.yaml | 4 +- > api/v1/swagger/paths/account.yaml | 115 +++++++++ > api/v1/swagger/swagger.yaml | 4 + > t/db_dependent/Koha/Account/Line.t | 11 +- > t/db_dependent/api/v1/account.t | 343 +++++++++++++++++++++++++ > 9 files changed, 563 insertions(+), 9 deletions(-) > create mode 100644 Koha/REST/V1/Account.pm > create mode 100644 api/v1/swagger/paths/account.yaml > create mode 100755 t/db_dependent/api/v1/account.t > >diff --git a/Koha/Account/Credit.pm b/Koha/Account/Credit.pm >index cf4b715788c..bd593e1ebb9 100644 >--- a/Koha/Account/Credit.pm >+++ b/Koha/Account/Credit.pm >@@ -41,7 +41,7 @@ on the API. > sub to_api_mapping { > return { > accountlines_id => 'account_line_id', >- credit_number => undef, >+ credit_number => 'credit_number', > credit_type_code => 'type', > debit_type_code => undef, > amountoutstanding => 'amount_outstanding', >diff --git a/Koha/Account/Line.pm b/Koha/Account/Line.pm >index f44761fcf48..737571e8a11 100644 >--- a/Koha/Account/Line.pm >+++ b/Koha/Account/Line.pm >@@ -200,7 +200,7 @@ sub credits { > my $cond_m = { map { "credit." . $_ => $cond->{$_} } keys %{$cond} }; > my $rs = $self->_result->search_related('account_offsets_debits')->search_related( 'credit', $cond_m, $attr ); > return unless $rs; >- return Koha::Account::Lines->_new_from_dbic($rs); >+ return Koha::Account::Credits->_new_from_dbic($rs); > } > > =head3 debits >@@ -224,7 +224,7 @@ sub debits { > my $cond_m = { map { "debit." . $_ => $cond->{$_} } keys %{$cond} }; > my $rs = $self->_result->search_related('account_offsets_credits')->search_related( 'debit', $cond_m, $attr ); > return unless $rs; >- return Koha::Account::Lines->_new_from_dbic($rs); >+ return Koha::Account::Debits->_new_from_dbic($rs); > } > > =head3 void >diff --git a/Koha/REST/V1/Account.pm b/Koha/REST/V1/Account.pm >new file mode 100644 >index 00000000000..20888ed93ef >--- /dev/null >+++ b/Koha/REST/V1/Account.pm >@@ -0,0 +1,81 @@ >+package Koha::REST::V1::Account; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Koha::Account::Credits; >+use Koha::Account::Debits; >+ >+use Try::Tiny qw( catch try ); >+ >+=head1 NAME >+ >+Koha::REST::V1::Account - Global account line endpoints (not patron-specific) >+ >+=head1 API >+ >+=head2 Methods >+ >+=head3 list_credits >+ >+Controller function that handles listing credits globally (not patron-specific). >+Used for searching credits across all patrons by credit_number or accountlines_id. >+ >+=cut >+ >+sub list_credits { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $credits_rs = Koha::Account::Credits->new; >+ my $credits = $c->objects->search($credits_rs); >+ >+ return $c->render( >+ status => 200, >+ openapi => $credits >+ ); >+ } catch { >+ $c->unhandled_exception($_); >+ }; >+} >+ >+=head3 list_debits >+ >+Controller function that handles listing debits globally (not patron-specific). >+Used for searching debits across all patrons. >+ >+=cut >+ >+sub list_debits { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $debits_rs = Koha::Account::Debits->new; >+ my $debits = $c->objects->search($debits_rs); >+ >+ return $c->render( >+ status => 200, >+ openapi => $debits >+ ); >+ } catch { >+ $c->unhandled_exception($_); >+ }; >+} >+ >+1; >diff --git a/api/v1/swagger/definitions/credit.yaml b/api/v1/swagger/definitions/credit.yaml >index 6e997d5f124..676669c99f6 100644 >--- a/api/v1/swagger/definitions/credit.yaml >+++ b/api/v1/swagger/definitions/credit.yaml >@@ -53,7 +53,9 @@ properties: > - "null" > description: Internal identifier for the library in which the transaction took place > patron_id: >- type: integer >+ type: >+ - integer >+ - "null" > readOnly: true > description: Internal identifier for the patron the account line belongs to > payment_type: >@@ -82,6 +84,10 @@ properties: > - integer > - "null" > description: Internal patron identifier for the staff member that introduced the account line >+ debits: >+ type: array >+ items: >+ $ref: "debit.yaml" > required: > - amount > additionalProperties: false >diff --git a/api/v1/swagger/definitions/debit.yaml b/api/v1/swagger/definitions/debit.yaml >index 07ea7d7884d..4c24eb7befc 100644 >--- a/api/v1/swagger/definitions/debit.yaml >+++ b/api/v1/swagger/definitions/debit.yaml >@@ -58,7 +58,9 @@ properties: > - "null" > description: Internal identifier for the library in which the transaction took place > patron_id: >- type: integer >+ type: >+ - integer >+ - "null" > description: Internal identifier for the patron the account line belongs to > payout_type: > type: >diff --git a/api/v1/swagger/paths/account.yaml b/api/v1/swagger/paths/account.yaml >new file mode 100644 >index 00000000000..bc96a321a8c >--- /dev/null >+++ b/api/v1/swagger/paths/account.yaml >@@ -0,0 +1,115 @@ >+--- >+/account/credits: >+ get: >+ x-mojo-to: Account#list_credits >+ operationId: listAccountCredits >+ tags: >+ - account >+ summary: List account credits (global search, not patron-specific) >+ produces: >+ - application/json >+ parameters: >+ - $ref: "../swagger.yaml#/parameters/match" >+ - $ref: "../swagger.yaml#/parameters/order_by" >+ - $ref: "../swagger.yaml#/parameters/page" >+ - $ref: "../swagger.yaml#/parameters/per_page" >+ - $ref: "../swagger.yaml#/parameters/q_param" >+ - $ref: "../swagger.yaml#/parameters/q_body" >+ - $ref: "../swagger.yaml#/parameters/request_id_header" >+ - name: x-koha-embed >+ in: header >+ required: false >+ description: Embed list sent as a request header >+ type: array >+ items: >+ type: string >+ enum: >+ - debits >+ - register >+ collectionFormat: csv >+ responses: >+ "200": >+ description: A list of credits >+ schema: >+ type: array >+ items: >+ $ref: "../swagger.yaml#/definitions/credit" >+ "400": >+ description: | >+ Bad request. Possible `error_code` attribute values: >+ >+ * `invalid_query` >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "500": >+ description: Internal error >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "503": >+ description: Under maintenance >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ x-koha-authorization: >+ permissions: >+ cash_management: anonymous_refund >+/account/debits: >+ get: >+ x-mojo-to: Account#list_debits >+ operationId: listAccountDebits >+ tags: >+ - account >+ summary: List account debits (global search, not patron-specific) >+ produces: >+ - application/json >+ parameters: >+ - $ref: "../swagger.yaml#/parameters/match" >+ - $ref: "../swagger.yaml#/parameters/order_by" >+ - $ref: "../swagger.yaml#/parameters/page" >+ - $ref: "../swagger.yaml#/parameters/per_page" >+ - $ref: "../swagger.yaml#/parameters/q_param" >+ - $ref: "../swagger.yaml#/parameters/q_body" >+ - $ref: "../swagger.yaml#/parameters/request_id_header" >+ - name: x-koha-embed >+ in: header >+ required: false >+ description: Embed list sent as a request header >+ type: array >+ items: >+ type: string >+ enum: >+ - credit >+ - register >+ collectionFormat: csv >+ responses: >+ "200": >+ description: A list of debits >+ schema: >+ type: array >+ items: >+ $ref: "../swagger.yaml#/definitions/debit" >+ "400": >+ description: | >+ Bad request. Possible `error_code` attribute values: >+ >+ * `invalid_query` >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "403": >+ description: Access forbidden >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "500": >+ description: Internal error >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ "503": >+ description: Under maintenance >+ schema: >+ $ref: "../swagger.yaml#/definitions/error" >+ x-koha-authorization: >+ permissions: >+ cash_management: anonymous_refund >diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml >index dcb0a3cc66e..685e7a5f733 100644 >--- a/api/v1/swagger/swagger.yaml >+++ b/api/v1/swagger/swagger.yaml >@@ -233,6 +233,10 @@ paths: > $ref: "./paths/acquisitions_vendors.yaml#/~1acquisitions~1vendors~1{vendor_id}" > "/acquisitions/vendors/{vendor_id}/issues": > $ref: "./paths/acquisitions_vendor_issues.yaml#/~1acquisitions~1vendors~1{vendor_id}~1issues" >+ /account/credits: >+ $ref: ./paths/account.yaml#/~1account~1credits >+ /account/debits: >+ $ref: ./paths/account.yaml#/~1account~1debits > /advanced_editor/macros: > $ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros > /advanced_editor/macros/shared: >diff --git a/t/db_dependent/Koha/Account/Line.t b/t/db_dependent/Koha/Account/Line.t >index 30b623d0901..965b26a04ce 100755 >--- a/t/db_dependent/Koha/Account/Line.t >+++ b/t/db_dependent/Koha/Account/Line.t >@@ -787,7 +787,7 @@ subtest 'checkout() tests' => sub { > }; > > subtest 'credits() and debits() tests' => sub { >- plan tests => 12; >+ plan tests => 15; > > $schema->storage->txn_begin; > >@@ -827,7 +827,8 @@ subtest 'credits() and debits() tests' => sub { > $credit2->apply( { debits => [ $debit1, $debit2 ] } ); > > my $credits = $debit1->credits; >- is( $credits->count, 2, '2 Credits applied to debit 1' ); >+ is( ref($credits), 'Koha::Account::Credits', 'credits() returns a Koha::Account::Credits object' ); >+ is( $credits->count, 2, '2 Credits applied to debit 1' ); > my $credit = $credits->next; > is( $credit->amount + 0, -5, 'Correct first credit' ); > $credit = $credits->next; >@@ -839,12 +840,14 @@ subtest 'credits() and debits() tests' => sub { > is( $credit->amount + 0, -10, 'Correct first credit' ); > > my $debits = $credit1->debits; >- is( $debits->count, 1, 'Credit 1 applied to 1 debit' ); >+ is( ref($debits), 'Koha::Account::Debits', 'debits() returns a Koha::Account::Debits object' ); >+ is( $debits->count, 1, 'Credit 1 applied to 1 debit' ); > my $debit = $debits->next; > is( $debit->amount + 0, 8, 'Correct first debit' ); > > $debits = $credit2->debits; >- is( $debits->count, 2, 'Credit 2 applied to 2 debits' ); >+ is( ref($debits), 'Koha::Account::Debits', 'debits() returns a Koha::Account::Debits object' ); >+ is( $debits->count, 2, 'Credit 2 applied to 2 debits' ); > $debit = $debits->next; > is( $debit->amount + 0, 8, 'Correct first debit' ); > $debit = $debits->next; >diff --git a/t/db_dependent/api/v1/account.t b/t/db_dependent/api/v1/account.t >new file mode 100755 >index 00000000000..43525cbf9ce >--- /dev/null >+++ b/t/db_dependent/api/v1/account.t >@@ -0,0 +1,343 @@ >+#!/usr/bin/perl >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More tests => 4; >+use Test::NoWarnings; >+ >+use Test::Mojo; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use Koha::Account::Lines; >+use Koha::Account::CreditTypes; >+use Koha::Cash::Registers; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); >+ >+my $t = Test::Mojo->new('Koha::REST::V1'); >+ >+subtest 'list_credits() tests' => sub { >+ >+ plan tests => 23; >+ >+ $schema->storage->txn_begin; >+ >+ # Create test patron with anonymous_refund permission >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ $builder->build( >+ { >+ source => 'UserPermission', >+ value => { >+ borrowernumber => $librarian->borrowernumber, >+ module_bit => 25, # cash_management >+ code => 'anonymous_refund', >+ }, >+ } >+ ); >+ my $userid = $librarian->userid; >+ >+ # Create test patron without permission >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ my $password2 = 'thePassword321'; >+ $patron->set_password( { password => $password2, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ # Create test library >+ my $library = $builder->build_object( { class => 'Koha::Libraries' } ); >+ >+ # Mock userenv for creating account lines >+ t::lib::Mocks::mock_userenv( { patron => $librarian, branchcode => $library->branchcode } ); >+ >+ # Create test patrons for account lines >+ my $patron_1 = $builder->build_object( { class => 'Koha::Patrons' } ); >+ my $patron_2 = $builder->build_object( { class => 'Koha::Patrons' } ); >+ >+ # Enable credit numbers for PAYMENT type >+ my $credit_type = Koha::Account::CreditTypes->find('PAYMENT'); >+ $credit_type->credit_number_enabled(1)->store; >+ >+ # Add credits with credit numbers >+ t::lib::Mocks::mock_preference( 'AutoCreditNumber', 'incremental' ); >+ my $credit_1 = $patron_1->account->add_credit( >+ { >+ amount => 5.00, >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ interface => 'test', >+ type => 'PAYMENT', >+ } >+ ); >+ $credit_1->discard_changes; >+ >+ my $credit_2 = $patron_2->account->add_credit( >+ { >+ amount => 10.00, >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ interface => 'test', >+ type => 'PAYMENT', >+ } >+ ); >+ $credit_2->discard_changes; >+ >+ my $credit_3 = $patron_1->account->add_credit( >+ { >+ amount => 7.50, >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ interface => 'test', >+ type => 'PAYMENT', >+ } >+ ); >+ $credit_3->discard_changes; >+ >+ # TEST: Unauthorized access (no permission) >+ $t->get_ok("//$unauth_userid:$password2@/api/v1/account/credits")->status_is(403); >+ >+ # TEST: Authorized access - list all credits >+ $t->get_ok("//$userid:$password@/api/v1/account/credits")->status_is(200) >+ ->json_is( '/0/account_line_id', $credit_1->accountlines_id ) >+ ->json_is( '/1/account_line_id', $credit_2->accountlines_id ) >+ ->json_is( '/2/account_line_id', $credit_3->accountlines_id ); >+ >+ # TEST: Search by credit_number using query parameter >+ my $credit_number = $credit_1->credit_number; >+ $t->get_ok( "//$userid:$password@/api/v1/account/credits" . "?q=" . '{"credit_number":"' . $credit_number . '"}' ) >+ ->status_is(200)->json_is( '/0/account_line_id', $credit_1->accountlines_id ) >+ ->json_is( '/0/credit_number', $credit_number ); >+ >+ # TEST: Search by accountlines_id >+ $t->get_ok( "//$userid:$password@/api/v1/account/credits" . "?q=" >+ . '{"account_line_id":' >+ . $credit_2->accountlines_id >+ . '}' )->status_is(200)->json_is( '/0/account_line_id', $credit_2->accountlines_id ); >+ >+ # TEST: Pagination >+ $t->get_ok("//$userid:$password@/api/v1/account/credits?_per_page=1")->status_is(200) >+ ->json_is( '/0/account_line_id', $credit_1->accountlines_id )->header_is( 'X-Total-Count', 3 ); >+ >+ # TEST: Ordering >+ $t->get_ok("//$userid:$password@/api/v1/account/credits?_order_by=-account_line_id")->status_is(200) >+ ->json_is( '/0/account_line_id', $credit_3->accountlines_id ) >+ ->json_is( '/1/account_line_id', $credit_2->accountlines_id ) >+ ->json_is( '/2/account_line_id', $credit_1->accountlines_id ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'list_credits() with embed tests' => sub { >+ >+ plan tests => 8; >+ >+ $schema->storage->txn_begin; >+ >+ # Create test patron with anonymous_refund permission >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ $builder->build( >+ { >+ source => 'UserPermission', >+ value => { >+ borrowernumber => $librarian->borrowernumber, >+ module_bit => 25, # cash_management >+ code => 'anonymous_refund', >+ }, >+ } >+ ); >+ my $userid = $librarian->userid; >+ >+ # Create test library >+ my $library = $builder->build_object( { class => 'Koha::Libraries' } ); >+ >+ # Mock userenv for creating account lines >+ t::lib::Mocks::mock_userenv( { patron => $librarian, branchcode => $library->branchcode } ); >+ >+ # Create test patron >+ my $patron = $builder->build_object( { class => 'Koha::Patrons' } ); >+ >+ # Add debit >+ my $debit = $patron->account->add_debit( >+ { >+ amount => 10.00, >+ type => 'OVERDUE', >+ interface => 'test', >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ } >+ ); >+ >+ # Add credit and apply to debit >+ my $credit = $patron->account->add_credit( >+ { >+ amount => 10.00, >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ interface => 'test', >+ type => 'PAYMENT', >+ } >+ ); >+ $credit->apply( { debits => [$debit] } ); >+ >+ # TEST: Embed debits >+ $t->get_ok( "//$userid:$password@/api/v1/account/credits" . "?q=" >+ . '{"account_line_id":' >+ . $credit->accountlines_id >+ . '}' => { 'x-koha-embed' => 'debits' } )->status_is(200) >+ ->json_is( '/0/account_line_id', $credit->accountlines_id )->json_has('/0/debits') >+ ->json_is( '/0/debits/0/account_line_id', $debit->accountlines_id ); >+ >+ # TEST: Without embed, debits should not be present >+ $t->get_ok( >+ "//$userid:$password@/api/v1/account/credits" . "?q=" . '{"account_line_id":' . $credit->accountlines_id . '}' ) >+ ->status_is(200)->json_hasnt('/0/debits'); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'list_debits() tests' => sub { >+ >+ plan tests => 22; >+ >+ $schema->storage->txn_begin; >+ >+ # Create test patron with anonymous_refund permission >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ $builder->build( >+ { >+ source => 'UserPermission', >+ value => { >+ borrowernumber => $librarian->borrowernumber, >+ module_bit => 25, # cash_management >+ code => 'anonymous_refund', >+ }, >+ } >+ ); >+ my $userid = $librarian->userid; >+ >+ # Create test patron without permission >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ my $password2 = 'thePassword321'; >+ $patron->set_password( { password => $password2, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ # Create test library >+ my $library = $builder->build_object( { class => 'Koha::Libraries' } ); >+ >+ # Mock userenv for creating account lines >+ t::lib::Mocks::mock_userenv( { patron => $librarian, branchcode => $library->branchcode } ); >+ >+ # Create test patrons for account lines >+ my $patron_1 = $builder->build_object( { class => 'Koha::Patrons' } ); >+ my $patron_2 = $builder->build_object( { class => 'Koha::Patrons' } ); >+ >+ # Add debits >+ my $debit_1 = $patron_1->account->add_debit( >+ { >+ amount => 5.00, >+ type => 'OVERDUE', >+ interface => 'test', >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ } >+ ); >+ >+ my $debit_2 = $patron_2->account->add_debit( >+ { >+ amount => 10.00, >+ type => 'LOST', >+ interface => 'test', >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ } >+ ); >+ >+ my $debit_3 = $patron_1->account->add_debit( >+ { >+ amount => 7.50, >+ type => 'OVERDUE', >+ interface => 'test', >+ user_id => $librarian->borrowernumber, >+ library_id => $library->branchcode, >+ } >+ ); >+ >+ # TEST: Unauthorized access (no permission) >+ $t->get_ok("//$unauth_userid:$password2@/api/v1/account/debits")->status_is(403); >+ >+ # TEST: Authorized access - list all debits >+ $t->get_ok("//$userid:$password@/api/v1/account/debits")->status_is(200) >+ ->json_is( '/0/account_line_id', $debit_1->accountlines_id ) >+ ->json_is( '/1/account_line_id', $debit_2->accountlines_id ) >+ ->json_is( '/2/account_line_id', $debit_3->accountlines_id ); >+ >+ # TEST: Search by accountlines_id >+ $t->get_ok( >+ "//$userid:$password@/api/v1/account/debits" . "?q=" . '{"account_line_id":' . $debit_2->accountlines_id . '}' ) >+ ->status_is(200)->json_is( '/0/account_line_id', $debit_2->accountlines_id ); >+ >+ # TEST: Search by type >+ $t->get_ok( "//$userid:$password@/api/v1/account/debits" . "?q=" . '{"type":"LOST"}' )->status_is(200) >+ ->json_is( '/0/account_line_id', $debit_2->accountlines_id ); >+ >+ # TEST: Pagination >+ $t->get_ok("//$userid:$password@/api/v1/account/debits?_per_page=1")->status_is(200) >+ ->json_is( '/0/account_line_id', $debit_1->accountlines_id )->header_is( 'X-Total-Count', 3 ); >+ >+ # TEST: Ordering >+ $t->get_ok("//$userid:$password@/api/v1/account/debits?_order_by=-account_line_id")->status_is(200) >+ ->json_is( '/0/account_line_id', $debit_3->accountlines_id ) >+ ->json_is( '/1/account_line_id', $debit_2->accountlines_id ) >+ ->json_is( '/2/account_line_id', $debit_1->accountlines_id ); >+ >+ $schema->storage->txn_rollback; >+}; >-- >2.52.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 41592
: 191252 |
191253
|
191254
|
191255