From b733c4e39e0d663bdf4b2f72de1cff4094ff2821 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Thu, 22 Dec 2016 15:44:36 +0200 Subject: [PATCH] Bug 16826: Controllers for availability GET /availability/biblio/hold GET /availability/biblio/search GET /availability/item/checkout GET /availability/item/hold GET /availability/item/search Includes API tests. To test: 1. prove t/db_dependent/api/v1/availability.t 2. Use Swagger-UI or make direct GET requests to specified availability endpoints, and make sure the returned data looks ok. --- Koha/REST/V1/BiblioAvailability.pm | 145 ++++++++++++++ Koha/REST/V1/ItemAvailability.pm | 187 +++++++++++++++++ t/db_dependent/api/v1/availability.t | 378 +++++++++++++++++++++++++++++++++++ 3 files changed, 710 insertions(+) create mode 100644 Koha/REST/V1/BiblioAvailability.pm create mode 100644 Koha/REST/V1/ItemAvailability.pm create mode 100644 t/db_dependent/api/v1/availability.t diff --git a/Koha/REST/V1/BiblioAvailability.pm b/Koha/REST/V1/BiblioAvailability.pm new file mode 100644 index 0000000..8f09155 --- /dev/null +++ b/Koha/REST/V1/BiblioAvailability.pm @@ -0,0 +1,145 @@ +package Koha::REST::V1::BiblioAvailability; + +# 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::Auth qw( haspermission ); + +use Koha::Exceptions; + +use Koha::Availability::Hold; +use Koha::Availability::Search; + +use Try::Tiny; + +sub search { + my ($c, $args, $cb) = @_; + + my @availabilities; + + return try { + my $biblios = $args->{'biblionumber'}; + foreach my $biblionumber (@$biblios) { + if (my $biblio = Koha::Biblios->find($biblionumber)) { + push @availabilities, Koha::Availability::Search->biblio({ + biblio => $biblio + })->in_opac->swaggerize; + } + } + return $c->$cb(\@availabilities, 200); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->$cb( { error => $_->{msg} }, 500 ); + } + else { + return $c->$cb( + { error => "Something went wrong, check the logs." }, 500 ); + } + }; +} + +sub hold { + my ($c, $args, $cb) = @_; + + my @availabilities; + my $user = $c->stash('koha.user'); + my $borrowernumber = $args->{'borrowernumber'}; + my $to_branch = $args->{'branchcode'}; + my $limit_items = $args->{'limit_items'}; + my $patron; + my $librarian; + + return try { + ($patron, $librarian) = _get_patron($c, $user, $borrowernumber); + + my $biblios = $args->{'biblionumber'}; + my $params = { + patron => $patron, + }; + + $params->{'to_branch'} = $to_branch if $to_branch; + $params->{'limit'} = $limit_items if $limit_items; + + foreach my $biblionumber (@$biblios) { + if (my $biblio = Koha::Biblios->find($biblionumber)) { + $params->{'biblio'} = $biblio; + my $availability = Koha::Availability::Hold->biblio($params); + unless ($librarian) { + push @availabilities, $availability->in_opac->swaggerize; + } else { + push @availabilities, $availability->in_intranet->swaggerize; + } + } + } + + return $c->$cb(\@availabilities, 200); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->$cb( { error => $_->{msg} }, 500 ); + } + elsif ($_->isa('Koha::Exceptions::AuthenticationRequired')) { + return $c->$cb( + { error => "Authentication required." }, 401 ); + } + elsif ($_->isa('Koha::Exceptions::NoPermission')) { + return $c->$cb({ + error => "Authorization failure. Missing required permission(s).", + required_permissions => $_->required_permissions}, 403 ); + } + else { + return $c->$cb( + { error => "Something went wrong, check the logs. $_" }, 500 ); + } + }; +} + +sub _get_patron { + my ($c, $user, $borrowernumber) = @_; + + my $patron; + my $librarian = 0; + + unless ($user) { + Koha::Exceptions::AuthenticationRequired->throw; + } + if (haspermission($user->userid, { borrowers => 1 })) { + $librarian = 1; + } + if ($borrowernumber) { + if ($borrowernumber == $user->borrowernumber) { + $patron = $user; + } else { + if ($librarian) { + $patron = Koha::Patrons->find($borrowernumber); + } else { + Koha::Exceptions::NoPermission->throw( + required_permissions => "borrowers" + ); + } + } + } else { + $patron = $user; + } + + return ($patron, $librarian); +} + +1; diff --git a/Koha/REST/V1/ItemAvailability.pm b/Koha/REST/V1/ItemAvailability.pm new file mode 100644 index 0000000..6368f5a --- /dev/null +++ b/Koha/REST/V1/ItemAvailability.pm @@ -0,0 +1,187 @@ +package Koha::REST::V1::ItemAvailability; + +# 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::Auth qw( haspermission ); + +use Koha::Exceptions; + +use Koha::Availability::Checkout; +use Koha::Availability::Hold; +use Koha::Availability::Search; + +use Try::Tiny; + +sub checkout { + my ($c, $args, $cb) = @_; + + my @availabilities; + my $user = $c->stash('koha.user'); + my $borrowernumber = $args->{'borrowernumber'}; + my $patron; + my $librarian; + + return try { + ($patron, $librarian) = _get_patron($c, $user, $borrowernumber); + + my $items = $args->{'itemnumber'}; + foreach my $itemnumber (@$items) { + if (my $item = Koha::Items->find($itemnumber)) { + push @availabilities, Koha::Availability::Checkout->item({ + patron => $patron, + item => $item + })->in_intranet->swaggerize; + } + } + return $c->$cb(\@availabilities, 200); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->$cb( { error => $_->{msg} }, 500 ); + } + elsif ($_->isa('Koha::Exceptions::AuthenticationRequired')) { + return $c->$cb( + { error => "Authentication required." }, 401 ); + } + elsif ($_->isa('Koha::Exceptions::NoPermission')) { + return $c->$cb({ + error => "Authorization failure. Missing required permission(s).", + required_permissions => $_->required_permissions}, 403 ); + } + else { + return $c->$cb( + { error => "Something went wrong, check the logs. $_" }, 500 ); + } + }; +} + +sub hold { + my ($c, $args, $cb) = @_; + + my @availabilities; + my $user = $c->stash('koha.user'); + my $borrowernumber = $args->{'borrowernumber'}; + my $to_branch = $args->{'branchcode'}; + my $patron; + my $librarian; + + return try { + ($patron, $librarian) = _get_patron($c, $user, $borrowernumber); + + my $items = $args->{'itemnumber'}; + my $params = { + patron => $patron, + }; + if ($to_branch) { + $params->{'to_branch'} = $to_branch; + } + foreach my $itemnumber (@$items) { + if (my $item = Koha::Items->find($itemnumber)) { + $params->{'item'} = $item; + my $availability = Koha::Availability::Hold->item($params); + unless ($librarian) { + push @availabilities, $availability->in_opac->swaggerize; + } else { + push @availabilities, $availability->in_intranet->swaggerize; + } + } + } + + return $c->$cb(\@availabilities, 200); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->$cb( { error => $_->{msg} }, 500 ); + } + elsif ($_->isa('Koha::Exceptions::AuthenticationRequired')) { + return $c->$cb( + { error => "Authentication required." }, 401 ); + } + elsif ($_->isa('Koha::Exceptions::NoPermission')) { + return $c->$cb({ + error => "Authorization failure. Missing required permission(s).", + required_permissions => $_->required_permissions}, 403 ); + } + else { + return $c->$cb( + { error => "Something went wrong, check the logs. $_" }, 500 ); + } + }; +} + +sub search { + my ($c, $args, $cb) = @_; + + my @availabilities; + + return try { + my $items = $args->{'itemnumber'}; + foreach my $itemnumber (@$items) { + if (my $item = Koha::Items->find($itemnumber)) { + push @availabilities, Koha::Availability::Search->item({ + item => $item + })->in_opac->swaggerize; + } + } + return $c->$cb(\@availabilities, 200); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->$cb( { error => $_->{msg} }, 500 ); + } + else { + return $c->$cb( + { error => "Something went wrong, check the logs. $_" }, 500 ); + } + }; +} + +sub _get_patron { + my ($c, $user, $borrowernumber) = @_; + + my $patron; + my $librarian = 0; + + unless ($user) { + Koha::Exceptions::AuthenticationRequired->throw; + } + if (haspermission($user->userid, { borrowers => 1 })) { + $librarian = 1; + } + if ($borrowernumber) { + if ($borrowernumber == $user->borrowernumber) { + $patron = $user; + } else { + if ($librarian) { + $patron = Koha::Patrons->find($borrowernumber); + } else { + Koha::Exceptions::NoPermission->throw( + required_permissions => "borrowers" + ); + } + } + } else { + $patron = $user; + } + + return ($patron, $librarian); +} + +1; diff --git a/t/db_dependent/api/v1/availability.t b/t/db_dependent/api/v1/availability.t new file mode 100644 index 0000000..61cca37 --- /dev/null +++ b/t/db_dependent/api/v1/availability.t @@ -0,0 +1,378 @@ +#!/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 => 2; +use Test::Mojo; +use Test::Warn; + +use t::lib::TestBuilder; +use t::lib::Mocks; + +use C4::Auth; +use Koha::Biblio::Availability; +use Koha::Item::Availability; +use Koha::Database; + +require t::db_dependent::Koha::Availability::Helpers; + +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 '/availability/biblio' => sub { + plan tests => 2; + + subtest '/hold' => sub { + plan tests => 30; + + $schema->storage->txn_begin; + + set_default_circulation_rules(); + set_default_system_preferences(); + + my $item = build_a_test_item(); + my $item2 = build_a_test_item( + Koha::Biblios->find($item->biblionumber), + Koha::Biblioitems->find($item->biblioitemnumber) + ); + my ($patron, $session_id) = create_user_and_session(); + $patron = Koha::Patrons->find($patron); + my $route = '/api/v1/availability/biblio/hold'; + my $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->true); + + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber.'&limit_items=1' ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_has('/0/item_availabilities/0') + ->json_hasnt('/0/item_availabilities/1'); + + $patron->gonenoaddress('1')->store; + $item2->notforloan('1')->store; + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->false) + ->json_is('/0/availability/unavailabilities/Patron::GoneNoAddress' => {}) + ->json_is('/0/item_availabilities/0/itemnumber' => $item->itemnumber) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/itemnumber' => $item2->itemnumber) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->false) + ->json_is('/0/item_availabilities/1/availability/unavailabilities/Item::NotForLoan' => { + code => "Not For Loan", + status => 1, + }); + $patron->gonenoaddress('0')->store; + $item2->notforloan('0')->store; + + my $patron2 = build_a_test_patron(); + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber.'&borrowernumber='.$patron2->borrowernumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(403); + + my $branch = Koha::Libraries->find( + $builder->build({ source => 'Branch' })->{'branchcode'}); + t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1); + t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype'); + C4::Circulation::CreateBranchTransferLimit( + $branch->branchcode, + $item->holdingbranch, + $item->effective_itemtype + ); + + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber.'&branchcode='.$branch->branchcode ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->false) + ->json_is('/0/item_availabilities/1/availability/unavailabilities/Item::CannotBeTransferred' => { + from_library => $item->holdingbranch, + to_library => $branch->branchcode,}); + + $schema->storage->txn_rollback; + }; + + subtest '/search' => sub { + plan tests => 15; + + $schema->storage->txn_begin; + + set_default_circulation_rules(); + set_default_system_preferences(); + + my $item = build_a_test_item(); + my $item2 = build_a_test_item( + Koha::Biblios->find($item->biblionumber), + Koha::Biblioitems->find($item->biblioitemnumber) + ); + my $route = '/api/v1/availability/biblio/search'; + my $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->true); + + $item2->notforloan('1')->store; + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/itemnumber' => $item->itemnumber) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/itemnumber' => $item2->itemnumber) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->false) + ->json_is('/0/item_availabilities/1/availability/unavailabilities/Item::NotForLoan' => { + code => "Not For Loan", + status => 1, + }); + + $schema->storage->txn_rollback; + }; +}; + +subtest '/availability/item' => sub { + plan tests => 3; + + subtest '/hold' => sub { + plan tests => 17; + + $schema->storage->txn_begin; + + set_default_circulation_rules(); + set_default_system_preferences(); + + my $item = build_a_test_item(); + my ($patron, $session_id) = create_user_and_session(); + $patron = Koha::Patrons->find($patron); + my $route = '/api/v1/availability/item/hold'; + my $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true); + + $patron->gonenoaddress('1')->store; + $item->notforloan('1')->store; + $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->false) + ->json_is('/0/itemnumber' => $item->itemnumber) + ->json_is('/0/availability/unavailabilities/Patron::GoneNoAddress' => {}) + ->json_is('/0/availability/unavailabilities/Item::NotForLoan' => { + code => "Not For Loan", + status => 1, + }); + $patron->gonenoaddress('0')->store; + $item->notforloan('0')->store; + + my $patron2 = build_a_test_patron(); + $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber.'&borrowernumber='.$patron2->borrowernumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(403); + + my $branch = Koha::Libraries->find( + $builder->build({ source => 'Branch' })->{'branchcode'}); + t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1); + t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype'); + C4::Circulation::CreateBranchTransferLimit( + $branch->branchcode, + $item->holdingbranch, + $item->effective_itemtype + ); + + $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber.'&branchcode='.$branch->branchcode ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/availability/available' => Mojo::JSON->false) + ->json_is('/0/availability/unavailabilities/Item::CannotBeTransferred' => { + from_library => $item->holdingbranch, + to_library => $branch->branchcode,}); + + $schema->storage->txn_rollback; + }; + + subtest '/checkout' => sub { + plan tests => 12; + + $schema->storage->txn_begin; + + set_default_circulation_rules(); + set_default_system_preferences(); + + my $item = build_a_test_item(); + my ($patron, $session_id) = create_user_and_session(); + $patron = Koha::Patrons->find($patron); + my $route = '/api/v1/availability/item/checkout'; + my $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true); + + $item->notforloan('1')->store; + $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->false) + ->json_is('/0/itemnumber' => $item->itemnumber) + ->json_is('/0/availability/unavailabilities/Item::NotForLoan' => { + code => "Not For Loan", + status => 1, + }); + $item->notforloan('0')->store; + + my $patron2 = build_a_test_patron(); + $tx = $t->ua->build_tx( GET => $route . '?itemnumber='.$item->itemnumber.'&borrowernumber='.$patron2->borrowernumber ); + $tx->req->cookies( { name => 'CGISESSID', value => $session_id } ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(403); + + $schema->storage->txn_rollback; + }; + + subtest '/search' => sub { + plan tests => 15; + + $schema->storage->txn_begin; + + set_default_circulation_rules(); + set_default_system_preferences(); + + my $item = build_a_test_item(); + my $item2 = build_a_test_item( + Koha::Biblios->find($item->biblionumber), + Koha::Biblioitems->find($item->biblioitemnumber) + ); + my $route = '/api/v1/availability/biblio/search'; + my $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->true); + + $item2->notforloan('1')->store; + $tx = $t->ua->build_tx( GET => $route . '?biblionumber='.$item->biblionumber ); + $tx->req->env( { REMOTE_ADDR => $remote_address } ); + $t->request_ok($tx) + ->status_is(200) + ->json_has('/0/availability') + ->json_is('/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/0/itemnumber' => $item->itemnumber) + ->json_is('/0/item_availabilities/0/availability/available' => Mojo::JSON->true) + ->json_is('/0/item_availabilities/1/itemnumber' => $item2->itemnumber) + ->json_is('/0/item_availabilities/1/availability/available' => Mojo::JSON->false) + ->json_is('/0/item_availabilities/1/availability/unavailabilities/Item::NotForLoan' => { + code => "Not For Loan", + status => 1, + }); + + $schema->storage->txn_rollback; + }; +}; + +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, + debarred => undef, + debarredcomment => undef, + lost => undef, + gonenoaddress => undef, + dateexpiry => output_pref({ dt => dt_from_string()->add_duration( # expires in 100 days + DateTime::Duration->new(days => 100)), dateformat => 'iso', dateonly => 1 }), + dateofbirth => '1950-10-10', + } + } + ); + + # 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,'parameters_remaining_permissions')", undef, + $user->{borrowernumber} ); + } + + return ( $user->{borrowernumber}, $session->id ); +} + +1; -- 1.9.1