Bugzilla – Attachment 65523 Details for
Bug 19037
Circulation and fine rules test tool
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 19037: Issuing rules test tool - REST API endpoint for effective issuing rule
Bug-19037-Issuing-rules-test-tool---REST-API-endpo.patch (text/plain), 35.62 KB, created by
Lari Taskula
on 2017-08-06 23:16:53 UTC
(
hide
)
Description:
Bug 19037: Issuing rules test tool - REST API endpoint for effective issuing rule
Filename:
MIME Type:
Creator:
Lari Taskula
Created:
2017-08-06 23:16:53 UTC
Size:
35.62 KB
patch
obsolete
>From 6d884454de4cf227f820f71790306984dfb203c9 Mon Sep 17 00:00:00 2001 >From: Lari Taskula <lari.taskula@jns.fi> >Date: Sun, 6 Aug 2017 23:02:16 +0000 >Subject: [PATCH] Bug 19037: Issuing rules test tool - REST API endpoint for > effective issuing rule > >To test: >1. prove t/db_dependent/api/v1/issuingrules.t >2. Send GET requests to /api/v1/issuingrules/effective with different parameters > as defined in the path's Swagger spec >3. Make sure it returns the correct issuing rules (don't forget that system prefs > like CircControl and HomeOrHoldingBranch affects the result) >--- > Koha/Exceptions/Item.pm | 18 ++ > Koha/Exceptions/ItemType.pm | 18 ++ > Koha/Exceptions/Library.pm | 18 ++ > Koha/Exceptions/Patron.pm | 18 ++ > Koha/Exceptions/Patron/Category.pm | 18 ++ > Koha/REST/V1/IssuingRule.pm | 237 +++++++++++++++++ > api/v1/swagger/definitions.json | 3 + > api/v1/swagger/definitions/issuingrule.json | 144 +++++++++++ > api/v1/swagger/paths.json | 3 + > api/v1/swagger/paths/issuingrules.json | 98 +++++++ > t/db_dependent/api/v1/cities.t | 2 +- > t/db_dependent/api/v1/issuingrules.t | 385 ++++++++++++++++++++++++++++ > 12 files changed, 961 insertions(+), 1 deletion(-) > create mode 100644 Koha/Exceptions/Item.pm > create mode 100644 Koha/Exceptions/ItemType.pm > create mode 100644 Koha/Exceptions/Library.pm > create mode 100644 Koha/Exceptions/Patron.pm > create mode 100644 Koha/Exceptions/Patron/Category.pm > create mode 100644 Koha/REST/V1/IssuingRule.pm > create mode 100644 api/v1/swagger/definitions/issuingrule.json > create mode 100644 api/v1/swagger/paths/issuingrules.json > create mode 100644 t/db_dependent/api/v1/issuingrules.t > >diff --git a/Koha/Exceptions/Item.pm b/Koha/Exceptions/Item.pm >new file mode 100644 >index 0000000..abbb8ed >--- /dev/null >+++ b/Koha/Exceptions/Item.pm >@@ -0,0 +1,18 @@ >+package Koha::Exceptions::Item; >+ >+use Modern::Perl; >+ >+use Exception::Class ( >+ >+ 'Koha::Exceptions::Item' => { >+ description => 'Something went wrong!', >+ }, >+ 'Koha::Exceptions::Item::NotFound' => { >+ isa => 'Koha::Exceptions::Item', >+ description => 'Item not found', >+ fields => ['itemnumber'] >+ }, >+ >+); >+ >+1; >diff --git a/Koha/Exceptions/ItemType.pm b/Koha/Exceptions/ItemType.pm >new file mode 100644 >index 0000000..b0d263d >--- /dev/null >+++ b/Koha/Exceptions/ItemType.pm >@@ -0,0 +1,18 @@ >+package Koha::Exceptions::ItemType; >+ >+use Modern::Perl; >+ >+use Exception::Class ( >+ >+ 'Koha::Exceptions::ItemType' => { >+ description => 'Something went wrong!', >+ }, >+ 'Koha::Exceptions::ItemType::NotFound' => { >+ isa => 'Koha::Exceptions::ItemType', >+ description => 'ItemType not found', >+ fields => ['itemtype'] >+ }, >+ >+); >+ >+1; >diff --git a/Koha/Exceptions/Library.pm b/Koha/Exceptions/Library.pm >new file mode 100644 >index 0000000..f6615e6 >--- /dev/null >+++ b/Koha/Exceptions/Library.pm >@@ -0,0 +1,18 @@ >+package Koha::Exceptions::Library; >+ >+use Modern::Perl; >+ >+use Exception::Class ( >+ >+ 'Koha::Exceptions::Library' => { >+ description => 'Something went wrong!', >+ }, >+ 'Koha::Exceptions::Library::NotFound' => { >+ isa => 'Koha::Exceptions::Library', >+ description => 'Library not found', >+ fields => ['branchcode'] >+ }, >+ >+); >+ >+1; >diff --git a/Koha/Exceptions/Patron.pm b/Koha/Exceptions/Patron.pm >new file mode 100644 >index 0000000..face29c >--- /dev/null >+++ b/Koha/Exceptions/Patron.pm >@@ -0,0 +1,18 @@ >+package Koha::Exceptions::Patron; >+ >+use Modern::Perl; >+ >+use Exception::Class ( >+ >+ 'Koha::Exceptions::Patron' => { >+ description => 'Something went wrong!', >+ }, >+ 'Koha::Exceptions::Patron::NotFound' => { >+ isa => 'Koha::Exceptions::Patron', >+ description => 'Patron not found', >+ fields => ['borrowernumber'] >+ }, >+ >+); >+ >+1; >diff --git a/Koha/Exceptions/Patron/Category.pm b/Koha/Exceptions/Patron/Category.pm >new file mode 100644 >index 0000000..e81b011 >--- /dev/null >+++ b/Koha/Exceptions/Patron/Category.pm >@@ -0,0 +1,18 @@ >+package Koha::Exceptions::Patron::Category; >+ >+use Modern::Perl; >+ >+use Exception::Class ( >+ >+ 'Koha::Exceptions::Patron::Category' => { >+ description => 'Something went wrong!', >+ }, >+ 'Koha::Exceptions::Patron::Category::NotFound' => { >+ isa => 'Koha::Exceptions::Patron::Category', >+ description => 'Patron::Category not found', >+ fields => ['categorycode'] >+ }, >+ >+); >+ >+1; >diff --git a/Koha/REST/V1/IssuingRule.pm b/Koha/REST/V1/IssuingRule.pm >new file mode 100644 >index 0000000..356eac1 >--- /dev/null >+++ b/Koha/REST/V1/IssuingRule.pm >@@ -0,0 +1,237 @@ >+package Koha::REST::V1::IssuingRule; >+ >+# 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, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use C4::Circulation; >+ >+use Koha::IssuingRules; >+use Koha::Items; >+use Koha::ItemTypes; >+use Koha::Libraries; >+use Koha::Patron::Categories; >+use Koha::Patrons; >+ >+use Koha::Exceptions; >+use Koha::Exceptions::ItemType; >+use Koha::Exceptions::Library; >+use Koha::Exceptions::Patron; >+use Koha::Exceptions::Patron::Category; >+ >+use Try::Tiny; >+ >+sub get_effective { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $params = $c->req->query_params->to_hash; >+ >+ my ($categorycode, $itemtype, $branchcode); >+ my $user = $c->stash('koha.user'); >+ my $patron = _find_patron($params); >+ my $item = _find_item($params); >+ $categorycode = _find_categorycode($params, $patron); >+ $itemtype = _find_itemtype($params, $item); >+ $branchcode = _find_branchcode($params, $item, $patron, $user); >+ >+ my $rule = Koha::IssuingRules->get_effective_issuing_rule({ >+ categorycode => $categorycode, >+ itemtype => $itemtype, >+ branchcode => $branchcode, >+ }); >+ >+ return $c->render(status => 200, openapi => $rule); >+ } >+ catch { >+ if ($_->isa('Koha::Exceptions::BadParameter')) { >+ return $c->render(status => 400, openapi => { error => $_->error }); >+ } >+ elsif ($_->isa('Koha::Exceptions::Item::NotFound')) { >+ return $c->render(status => 404, openapi => { error => $_->error }); >+ } >+ elsif ($_->isa('Koha::Exceptions::ItemType::NotFound')) { >+ return $c->render(status => 404, openapi => { error => $_->error }); >+ } >+ elsif ($_->isa('Koha::Exceptions::Library::NotFound')) { >+ return $c->render(status => 404, openapi => { error => $_->error }); >+ } >+ elsif ($_->isa('Koha::Exceptions::Patron::NotFound')) { >+ return $c->render(status => 404, openapi => { error => $_->error }); >+ } >+ elsif ($_->isa('Koha::Exceptions::Patron::Category::NotFound')) { >+ return $c->render(status => 404, openapi => { error => $_->error }); >+ } >+ else { >+ return $c->render(status => 500, openapi => { >+ error => 'Something went wrong, check the logs.' >+ }); >+ } >+ }; >+} >+ >+sub _find_branchcode { >+ my ($params, $item, $patron, $loggedin_user) = @_; >+ >+ my $circcontrol = C4::Context->preference('CircControl'); >+ my $branchcode; >+ if ($circcontrol eq 'PatronLibrary' && defined $patron >+ && !length $params->{branchcode}) { >+ $branchcode = C4::Circulation::_GetCircControlBranch( >+ undef, >+ $patron->unblessed >+ ); >+ } elsif ($circcontrol eq 'ItemHomeLibrary' && defined $item >+ && !length $params->{branchcode}) { >+ $branchcode = C4::Circulation::_GetCircControlBranch( >+ $item->unblessed, >+ undef >+ ); >+ } elsif ($circcontrol eq 'PickupLibrary' && !exists $params->{branchcode}) { >+ # If CircControl == PickupLibrary, expect currently logged in branch >+ # to be the homebranch of logged in user ONLY IF parameter branchcode >+ # is not provided - if the parameter exists but is not defined, allow >+ # the possibility to query with null branchcode >+ $branchcode = $loggedin_user->branchcode; >+ } >+ >+ return $branchcode if $branchcode; >+ >+ if (length $params->{branchcode}) { >+ my $library = Koha::Libraries->find($params->{branchcode}); >+ unless ($library) { >+ Koha::Exceptions::Library::NotFound->throw( >+ error => 'Branchcode not found' >+ ); >+ } >+ $branchcode = $library->branchcode; >+ } >+ >+ return $branchcode; >+ >+} >+ >+sub _find_categorycode { >+ my ($params, $patron) = @_; >+ >+ my $categorycode; >+ if (defined $patron && length $params->{categorycode}) { >+ unless ($patron->categorycode eq $params->{categorycode}) { >+ Koha::Exceptions::BadParameter->throw( >+ error => "Patron's categorycode does not match given categorycode" >+ ); >+ } >+ } >+ >+ return $patron->categorycode if $patron; >+ >+ if (length $params->{categorycode}) { >+ my $category = Koha::Patron::Categories->find($params->{categorycode}); >+ unless ($category) { >+ Koha::Exceptions::Patron::Category::NotFound->throw( >+ error => 'Categorycode not found' >+ ); >+ } >+ $categorycode = $category->categorycode; >+ } >+ >+ return $categorycode; >+} >+ >+sub _find_item { >+ my ($params) = @_; >+ >+ my $item; >+ if (length $params->{itemnumber} && length $params->{barcode}) { >+ $item = Koha::Items->find({ >+ itemnumber => $params->{itemnumber}, >+ barcode => $params->{barcode}, >+ }); >+ } elsif (length $params->{itemnumber}) { >+ $item = Koha::Items->find($params->{itemnumber}); >+ } elsif (length $params->{barcode}) { >+ $item = Koha::Items->find({ >+ barcode => $params->{barcode} >+ }); >+ } >+ >+ if ((length $params->{itemnumber} || length $params->{barcode}) >+ && !defined $item) { >+ Koha::Exceptions::Item::NotFound->throw( >+ error => 'Item not found' >+ ); >+ } >+ >+ return $item; >+} >+ >+sub _find_itemtype { >+ my ($params, $item) = @_; >+ >+ my $itemtype; >+ if (defined $item && length $params->{itemtype}) { >+ unless ($item->effective_itemtype eq $params->{itemtype}) { >+ Koha::Exceptions::BadParameter->throw( >+ error => "Item's item type does not match given item type" >+ ); >+ } >+ } >+ >+ return $item->effective_itemtype if $item; >+ >+ if (length $params->{itemtype}) { >+ my $itemtype_o = Koha::ItemTypes->find($params->{itemtype}); >+ unless ($itemtype_o) { >+ Koha::Exceptions::ItemType::NotFound->throw( >+ error => 'Item type not found' >+ ); >+ } >+ $itemtype = $itemtype_o->itemtype; >+ } >+ >+ return $itemtype; >+} >+ >+sub _find_patron { >+ my ($params) = @_; >+ >+ my $patron; >+ if (length $params->{borrowernumber} && length $params->{cardnumber}) { >+ $patron = Koha::Patrons->find({ >+ borrowernumber => $params->{borrowernumber}, >+ cardnumber => $params->{cardnumber}, >+ }); >+ } elsif (length $params->{borrowernumber}) { >+ $patron = Koha::Patrons->find($params->{borrowernumber}); >+ } elsif (length $params->{cardnumber}) { >+ $patron = Koha::Patrons->find({ >+ cardnumber => $params->{cardnumber} >+ }); >+ } >+ >+ if ((length $params->{borrowernumber} || length $params->{cardnumber}) >+ && !defined $patron) { >+ Koha::Exceptions::Patron::NotFound->throw( >+ error => 'Patron not found' >+ ); >+ } >+ >+ return $patron; >+} >+ >+1; >diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json >index 939baa8..dfaa01d 100644 >--- a/api/v1/swagger/definitions.json >+++ b/api/v1/swagger/definitions.json >@@ -11,6 +11,9 @@ > "holds": { > "$ref": "definitions/holds.json" > }, >+ "issuingrule": { >+ "$ref": "definitions/issuingrule.json" >+ }, > "patron": { > "$ref": "definitions/patron.json" > } >diff --git a/api/v1/swagger/definitions/issuingrule.json b/api/v1/swagger/definitions/issuingrule.json >new file mode 100644 >index 0000000..4bb260b >--- /dev/null >+++ b/api/v1/swagger/definitions/issuingrule.json >@@ -0,0 +1,144 @@ >+{ >+ "type": "object", >+ "properties": { >+ "issuingrules_id": { >+ "description": "internal issuing rule id", >+ "type": "integer" >+ }, >+ "categorycode": { >+ "description": "patron category this rule is for (categories.categorycode)", >+ "type": "string" >+ }, >+ "itemtype": { >+ "description": "item type this rule is for (itemtypes.itemtype)", >+ "type": "string" >+ }, >+ "restrictedtype": { >+ "description": "not used? always NULL", >+ "type": ["integer", "null"] >+ }, >+ "rentaldiscount": { >+ "description": "percent discount on the rental charge for this item", >+ "type": ["number", "null"] >+ }, >+ "reservecharge": { >+ "description": "", >+ "type": ["number", "null"] >+ }, >+ "fine": { >+ "description": "fine amount", >+ "type": ["number", "null"] >+ }, >+ "finedays": { >+ "description": "suspension in days", >+ "type": ["integer", "null"] >+ }, >+ "maxsuspensiondays": { >+ "description": "max suspension days", >+ "type": ["integer", "null"] >+ }, >+ "firstremind": { >+ "description": "fine grace period", >+ "type": ["integer", "null"] >+ }, >+ "chargeperiod": { >+ "description": "how often the fine amount is charged", >+ "type": ["integer", "null"] >+ }, >+ "chargeperiod_charge_at": { >+ "description": "Should fine be given at the start ( 1 ) or the end ( 0 ) of the period", >+ "type": "integer" >+ }, >+ "accountsent": { >+ "description": "not used? always NULL", >+ "type": ["integer", "null"] >+ }, >+ "chargename": { >+ "description": "not used? always NULL", >+ "type": ["string", "null"] >+ }, >+ "maxissueqty": { >+ "description": "total number of checkouts allowed", >+ "type": ["integer", "null"] >+ }, >+ "maxonsiteissueqty": { >+ "description": "total number of on-site checkouts allowed", >+ "type": ["integer", "null"] >+ }, >+ "issuelength": { >+ "description": "length of checkout in the unit set in issuingrules.lengthunit", >+ "type": ["integer", "null"] >+ }, >+ "lengthunit": { >+ "description": "unit of checkout length (days, hours)", >+ "type": ["string", "null"] >+ }, >+ "hardduedate": { >+ "description": "hard due date", >+ "type": ["string", "null"], >+ "format": "date" >+ }, >+ "hardduedatecompare": { >+ "description": "type of hard due date (1 = after, 0 = on, -1 = before)", >+ "type": "integer" >+ }, >+ "renewalsallowed": { >+ "description": "how many renewals are allowed", >+ "type": "integer" >+ }, >+ "renewalperiod": { >+ "description": "renewal period in the unit set in issuingrules.lengthunit", >+ "type": ["integer", "null"] >+ }, >+ "norenewalbefore": { >+ "description": "no renewal allowed until X days or hours before due date.", >+ "type": ["integer", "null"] >+ }, >+ "auto_renew": { >+ "description": "automatic renewal", >+ "type": ["integer", "null"] >+ }, >+ "no_auto_renewal_after": { >+ "description": "no auto renewal allowed after X days or hours after the issue date", >+ "type": ["integer", "null"] >+ }, >+ "no_auto_renewal_after_hard_limit": { >+ "description": "no auto renewal allowed after a given date", >+ "type": ["string", "null"], >+ "format": "date" >+ }, >+ "reservesallowed": { >+ "description": "how many holds are allowed", >+ "type": "integer" >+ }, >+ "holds_per_record": { >+ "description": "How many holds a patron can have on a given bib", >+ "type": "integer" >+ }, >+ "branchcode": { >+ "description": "the branch this rule is for (branches.branchcode)", >+ "type": "string" >+ }, >+ "overduefinescap": { >+ "description": "the maximum amount of an overdue fine", >+ "type": ["number", "null"] >+ }, >+ "cap_fine_to_replacement_price": { >+ "description": "cap the fine based on item's replacement price", >+ "type": "integer" >+ }, >+ "onshelfholds": { >+ "description": "allow holds for items that are on shelf", >+ "type": "integer" >+ }, >+ "opacitemholds": { >+ "description": "allow opac users to place specific items on hold", >+ "type": "string" >+ }, >+ "article_requests": { >+ "description": "allow article requests to be placed,", >+ "type": "string" >+ } >+ }, >+ "additionalProperties": false >+} >diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json >index b1fcf40..e5362b6 100644 >--- a/api/v1/swagger/paths.json >+++ b/api/v1/swagger/paths.json >@@ -11,6 +11,9 @@ > "/holds/{reserve_id}": { > "$ref": "paths/holds.json#/~1holds~1{reserve_id}" > }, >+ "/issuingrules/effective": { >+ "$ref": "paths/issuingrules.json#/~1issuingrules~1effective" >+ }, > "/patrons": { > "$ref": "paths/patrons.json#/~1patrons" > }, >diff --git a/api/v1/swagger/paths/issuingrules.json b/api/v1/swagger/paths/issuingrules.json >new file mode 100644 >index 0000000..c1c1348 >--- /dev/null >+++ b/api/v1/swagger/paths/issuingrules.json >@@ -0,0 +1,98 @@ >+{ >+ "/issuingrules/effective": { >+ "get": { >+ "x-mojo-to": "IssuingRule#get_effective", >+ "operationId": "getEffectiveIssuingRule", >+ "tags": ["issuingrules"], >+ "parameters": [{ >+ "name": "branchcode", >+ "in": "query", >+ "description": "Target branchcode (internal library identifier). If parameter not given, assume logged in user's homebranch. Give empty value (e.g. issuingrules/effective?branchcode=&categorycode=ASD) to query issuing rules targetting all libraries.", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "itemtype", >+ "in": "query", >+ "description": "Target itemtype (internal item type identifier)", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "categorycode", >+ "in": "query", >+ "description": "Target patron categorycode (internal category identifier)", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "barcode", >+ "in": "query", >+ "description": "Target item (barcode)", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "itemnumber", >+ "in": "query", >+ "description": "Target item (internal item identifier)", >+ "required": false, >+ "type": "integer" >+ }, { >+ "name": "borrowernumber", >+ "in": "query", >+ "description": "Target patron (internal patron identifier)", >+ "required": false, >+ "type": "integer" >+ }, { >+ "name": "cardnumber", >+ "in": "query", >+ "description": "Target patron card number", >+ "required": false, >+ "type": "string" >+ }], >+ "produces": ["application/json"], >+ "responses": { >+ "200": { >+ "description": "Effective issuing rule", >+ "schema": { "$ref": "../definitions.json#/issuingrule" } >+ }, >+ "400": { >+ "description": "Bad parameter", >+ "schema": { "$ref": "../definitions.json#/error" } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "One or more of the given parameters not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal server error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "parameters": "manage_circ_rules" >+ } >+ } >+ } >+ } >+} >diff --git a/t/db_dependent/api/v1/cities.t b/t/db_dependent/api/v1/cities.t >index ac8fe43..5652f36 100644 >--- a/t/db_dependent/api/v1/cities.t >+++ b/t/db_dependent/api/v1/cities.t >@@ -33,7 +33,7 @@ my $builder = t::lib::TestBuilder->new; > > # FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling > # this affects the other REST api tests >-t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); >+#t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); > > my $remote_address = '127.0.0.1'; > my $t = Test::Mojo->new('Koha::REST::V1'); >diff --git a/t/db_dependent/api/v1/issuingrules.t b/t/db_dependent/api/v1/issuingrules.t >new file mode 100644 >index 0000000..bd31576 >--- /dev/null >+++ b/t/db_dependent/api/v1/issuingrules.t >@@ -0,0 +1,385 @@ >+#!/usr/bin/env 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, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Test::More tests => 1; >+use Test::Mojo; >+use Test::Warn; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use C4::Auth; >+ >+use Koha::Database; >+use Koha::IssuingRules; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling >+# this affects the other REST api tests >+t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); >+ >+my $remote_address = '127.0.0.1'; >+my $t = Test::Mojo->new('Koha::REST::V1'); >+ >+subtest 'get_effective() tests' => sub { >+ >+ plan tests => 27; >+ >+ $schema->storage->txn_begin; >+ >+ # Empty current issuign rules and create two random issuing rules >+ Koha::IssuingRules->search->delete; >+ >+ my $context1 = create_test_context(); >+ my $context2 = create_test_context(); >+ my $context3 = create_test_context(); >+ >+ create_issuing_rule({ >+ categorycode => '*', >+ itemtype => '*', >+ branchcode => '*' >+ }); >+ create_issuing_rule(); >+ create_issuing_rule(); >+ create_issuing_rule({ >+ categorycode => $context1->{patron}->{categorycode}, >+ itemtype => $context1->{item}->{itype}, >+ branchcode => '*' >+ }); >+ create_issuing_rule({ >+ categorycode => $context2->{patron}->{categorycode}, >+ itemtype => $context2->{item}->{itype}, >+ branchcode => $context2->{patron}->{branchcode} >+ }); >+ create_issuing_rule({ >+ categorycode => $context3->{patron}->{categorycode}, >+ itemtype => $context3->{item}->{itype}, >+ branchcode => $context3->{item}->{homebranch} >+ }); >+ create_issuing_rule({ >+ categorycode => $context3->{patron}->{categorycode}, >+ itemtype => $context3->{item}->{itype}, >+ branchcode => $context3->{item}->{holdingbranch} >+ }); >+ my ( $borrowernumber, $session_id ) = >+ create_user_and_session( { authorized => 0 } ); >+ >+ my $tx = $t->ua->build_tx( GET => '/api/v1/issuingrules/effective' ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(401); >+ >+ $tx = $t->ua->build_tx( GET => '/api/v1/issuingrules/effective' ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(403); >+ >+ ( $borrowernumber, $session_id ) = >+ create_user_and_session( { authorized => 1 } ); >+ >+ my $path = '/api/v1/issuingrules/effective'; >+ my $params = {}; >+ >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => '*') >+ ->json_is('/itemtype' => '*'); >+ >+ $params = { >+ branchcode => '', >+ categorycode => '', >+ itemtype => '' >+ }; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => '*') >+ ->json_is('/itemtype' => '*'); >+ >+ $params = { itemtype => $context1->{item}->{itype} }; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => '*') >+ ->json_is('/itemtype' => '*'); >+ >+ $params = { >+ categorycode => $context1->{patron}->{categorycode}, >+ itemtype => $context1->{item}->{itype} >+ }; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => $context1->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context1->{item}->{itype}); >+ >+ subtest 'CircControl = ItemHomeLibrary' => sub { >+ plan tests => 15; >+ >+ t::lib::Mocks::mock_preference('CircControl', 'ItemHomeLibrary'); >+ t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'homebranch'); >+ >+ create_issuing_rule({ >+ categorycode => $context3->{patron}->{categorycode}, >+ itemtype => $context3->{item}->{itype}, >+ branchcode => '*' >+ }); >+ >+ $params = { >+ cardnumber => $context3->{patron}->{cardnumber}, >+ barcode => $context3->{item}->{barcode} >+ }; >+ # Test exact match, item's homebranch >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => $context3->{item}->{homebranch}) >+ ->json_is('/categorycode' => $context3->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context3->{item}->{itype}); >+ >+ t::lib::Mocks::mock_preference('HomeOrHoldingBranch', 'holdingbranch'); >+ $params = { >+ cardnumber => $context3->{patron}->{cardnumber}, >+ barcode => $context3->{item}->{barcode} >+ }; >+ # Test exact match, holdingbranch >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => $context3->{item}->{holdingbranch}) >+ ->json_is('/categorycode' => $context3->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context3->{item}->{itype}); >+ >+ # Test custom branch >+ $params->{'branchcode'} = $context2->{patron}->{branchcode}; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => $context3->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context3->{item}->{itype}); >+ }; >+ >+ subtest 'CircControl = PatronLibrary' => sub { >+ plan tests => 10; >+ >+ t::lib::Mocks::mock_preference('CircControl', 'PatronLibrary'); >+ create_issuing_rule({ >+ categorycode => $context2->{patron}->{categorycode}, >+ itemtype => $context2->{item}->{itype}, >+ branchcode => '*' >+ }); >+ $params = { >+ itemnumber => $context2->{item}->{itemnumber}, >+ borrowernumber => $context2->{patron}->{borrowernumber} >+ }; >+ # Test exact match >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => $context2->{patron}->{branchcode}) >+ ->json_is('/categorycode' => $context2->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context2->{item}->{itype}); >+ >+ # Test custom branchcode >+ $params->{'branchcode'} = $context3->{patron}->{branchcode}; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => $context2->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context2->{item}->{itype}); >+ }; >+ >+ subtest 'CircControl = PickupLibrary' => sub { >+ plan tests => 15; >+ >+ t::lib::Mocks::mock_preference('CircControl', 'PickupLibrary'); >+ my $patron = Koha::Patrons->find($borrowernumber); >+ create_issuing_rule({ >+ categorycode => $context2->{patron}->{categorycode}, >+ itemtype => $context2->{item}->{itype}, >+ branchcode => $patron->branchcode >+ }); >+ $params = { >+ cardnumber => $context2->{patron}->{cardnumber}, >+ barcode => $context2->{item}->{barcode} >+ }; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => $patron->branchcode) >+ ->json_is('/categorycode' => $context2->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context2->{item}->{itype}); >+ >+ $params = { >+ cardnumber => $context2->{patron}->{cardnumber}, >+ barcode => $context2->{item}->{barcode}, >+ branchcode => '', >+ }; >+ # Test all branches >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => $context2->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context2->{item}->{itype}); >+ >+ # Test another branch, should still return rule for all branches because >+ # there is no exact match to that branchcode >+ $params->{branchcode} = $context1->{patron}->{branchcode}; >+ $tx = $t->ua->build_tx( GET => _query_params($path, $params) ); >+ $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); >+ $tx->req->env( { REMOTE_ADDR => $remote_address } ); >+ $t->request_ok($tx) >+ ->status_is(200) >+ ->json_is('/branchcode' => '*') >+ ->json_is('/categorycode' => $context2->{patron}->{categorycode}) >+ ->json_is('/itemtype' => $context2->{item}->{itype}); >+ }; >+ >+ $schema->storage->txn_rollback; >+}; >+ >+sub create_test_context { >+ my $itemtype = $builder->build({ source => 'Itemtype'}); >+ my $library = $builder->build({ source => 'Branch' }); >+ my $library2 = $builder->build({ source => 'Branch' }); >+ my $biblio = $builder->build({ source => 'Biblio' }); >+ my $biblioitem = $builder->build({ >+ source => 'Biblioitem', >+ value => { >+ biblionumber => $biblio->{biblionumber}, >+ itemtype => $itemtype->{itemtype}, >+ } >+ }); >+ my $item = $builder->build({ >+ source => 'Item', >+ value => { >+ biblionumber => $biblio->{biblionumber}, >+ biblioitemnumber => $biblioitem->{biblioitemnumber}, >+ itype => $itemtype->{itemtype}, >+ homebranch => $library->{branchcode}, >+ holdingbranch => $library2->{branchcode}, >+ } >+ }); >+ my $category = $builder->build({ source => 'Category' }); >+ my $patron = $builder->build({ >+ source => 'Borrower', >+ value => { >+ categorycode => $category->{categorycode} >+ } >+ }); >+ >+ return { >+ biblio => $biblio, >+ biblioitem => $biblioitem, >+ category => $category, >+ item => $item, >+ itemtype => $itemtype, >+ library => $library, >+ library_two => $library2, >+ patron => $patron, >+ }; >+} >+ >+sub create_issuing_rule { >+ my ($params) = @_; >+ >+ my $rule = $builder->build({ >+ source => 'Issuingrule', >+ value => $params >+ }); >+ >+ return $rule; >+} >+sub create_user_and_session { >+ >+ my $args = shift; >+ my $flags = ( $args->{authorized} ) ? $args->{authorized} : 0; >+ my $dbh = C4::Context->dbh; >+ >+ my $user = $builder->build( >+ { >+ source => 'Borrower', >+ value => { >+ 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( 'ip', '127.0.0.1' ); >+ $session->param( 'lasttime', time() ); >+ $session->flush; >+ >+ if ( $args->{authorized} ) { >+ $dbh->do( " >+ INSERT INTO user_permissions (borrowernumber,module_bit,code) >+ VALUES (?,3,'manage_circ_rules')", undef, >+ $user->{borrowernumber} ); >+ } >+ >+ return ( $user->{borrowernumber}, $session->id ); >+} >+ >+sub _query_params { >+ my ($path, $params) = @_; >+ >+ $path .= '?'; >+ foreach my $param (keys %$params) { >+ $path .= $param.'='.$params->{$param}.'&'; >+ } >+ $path =~ s/\&$//; >+ return $path; >+} >+1; >-- >2.7.4
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 19037
:
65497
|
65523
|
65524
|
65525
|
65526
|
168450
|
168451
|
169037
|
169038
|
169039
|
169040