#!/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 2 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.
+# 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.
#
-# 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
+# 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 <http://www.gnu.org/licenses>.
use Modern::Perl;
use File::Basename qw/basename/;
+
+use C4::Circulation qw( AddIssue AddReturn );
+
use Koha::Database;
use Koha::Illrequestattributes;
use Koha::Illrequest::Config;
+use Koha::Biblios;
use Koha::Patrons;
+use Koha::ItemTypes;
+use Koha::Items;
+use Koha::Libraries;
+use Koha::MessageAttributes;
+use Koha::Notice::Templates;
+use Koha::AuthorisedValueCategories;
+use Koha::AuthorisedValues;
use t::lib::Mocks;
use t::lib::TestBuilder;
use Test::MockObject;
use Test::MockModule;
use Test::Exception;
+use Test::Deep qw/ cmp_deeply ignore /;
+use Test::Warn;
-use Test::More tests => 11;
+use Test::More tests => 13;
my $schema = Koha::Database->new->schema;
my $builder = t::lib::TestBuilder->new;
subtest 'Basic object tests' => sub {
- plan tests => 21;
+ plan tests => 24;
$schema->storage->txn_begin;
"Accessurl getter works.");
is($illrq_obj->cost, $illrq->{cost},
"Cost getter works.");
+ is($illrq_obj->price_paid, $illrq->{price_paid},
+ "Price_paid getter works.");
is($illrq_obj->notesopac, $illrq->{notesopac},
"Notesopac getter works.");
is($illrq_obj->notesstaff, $illrq->{notesstaff},
is($illrq_obj->backend, $illrq->{backend},
"Backend getter works.");
+ is($illrq_obj->get_type, undef,
+ 'get_type() returns undef if no type is set');
+ $builder->build({
+ source => 'Illrequestattribute',
+ value => {
+ illrequest_id => $illrq_obj->illrequest_id,
+ type => 'type',
+ value => 'book'
+ }
+ });
+ is($illrq_obj->get_type, 'book',
+ 'get_type() returns correct type if set');
+
isnt($illrq_obj->status, 'COMP',
"ILL is not currently marked complete.");
$illrq_obj->mark_completed;
subtest 'Working with related objects' => sub {
- plan tests => 5;
+ plan tests => 7;
$schema->storage->txn_begin;
+ Koha::Illrequests->search->delete;
+
my $patron = $builder->build({ source => 'Borrower' });
my $illrq = $builder->build({
source => 'Illrequest',
is($illrq_obj->illrequestattributes->count + 1, Koha::Illrequestattributes->search->count,
"Fetching expected number of Illrequestattributes for our request.");
+ is($illrq_obj->biblio, undef, "->biblio returns undef if no biblio");
+ my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
+ my $req_bib = $builder->build_object({
+ class => 'Koha::Illrequests',
+ value => {
+ biblio_id => $biblio->biblionumber
+ }
+ });
+ isa_ok($req_bib->biblio, 'Koha::Biblio', "OK accessing related biblio");
+
$illrq_obj->delete;
is(Koha::Illrequestattributes->search->count, 1,
"Correct number of illrequestattributes after delete.");
subtest 'Status Graph tests' => sub {
- plan tests => 4;
+ plan tests => 5;
$schema->storage->txn_begin;
"REQ atom + linking QER = cyclical status graph"
);
+ # Create a new node, with no prev_actions and no next_actions. This should
+ # protect us against regressions related to bug 22280.
+ my $new_node = {
+ TEST => {
+ prev_actions => [ ],
+ id => 'TEST',
+ next_actions => [ ],
+ },
+ };
+ # Add the new node to the core_status_grpah
+ my $new_graph = $illrq_obj->_status_graph_union( $new_node, $illrq_obj->_core_status_graph);
+ # Compare the updated graph to the expected graph
+ # The structure we compare against here is just a copy of the structure found
+ # in Koha::Illrequest::_core_status_graph() + the new node we created above
+ cmp_deeply( $new_graph,
+ {
+ TEST => {
+ prev_actions => [ ],
+ id => 'TEST',
+ next_actions => [ ],
+ },
+ NEW => {
+ prev_actions => [ ], # Actions containing buttons
+ # leading to this status
+ id => 'NEW', # ID of this status
+ name => 'New request', # UI name of this status
+ ui_method_name => 'New request', # UI name of method leading
+ # to this status
+ method => 'create', # method to this status
+ next_actions => [ 'REQ', 'GENREQ', 'KILL' ], # buttons to add to all
+ # requests with this status
+ ui_method_icon => 'fa-plus', # UI Style class
+ },
+ REQ => {
+ prev_actions => [ 'NEW', 'REQREV', 'QUEUED', 'CANCREQ' ],
+ id => 'REQ',
+ name => 'Requested',
+ ui_method_name => 'Confirm request',
+ method => 'confirm',
+ next_actions => [ 'REQREV', 'COMP', 'CHK' ],
+ ui_method_icon => 'fa-check',
+ },
+ GENREQ => {
+ prev_actions => [ 'NEW', 'REQREV' ],
+ id => 'GENREQ',
+ name => 'Requested from partners',
+ ui_method_name => 'Place request with partners',
+ method => 'generic_confirm',
+ next_actions => [ 'COMP', 'CHK' ],
+ ui_method_icon => 'fa-send-o',
+ },
+ REQREV => {
+ prev_actions => [ 'REQ' ],
+ id => 'REQREV',
+ name => 'Request reverted',
+ ui_method_name => 'Revert Request',
+ method => 'cancel',
+ next_actions => [ 'REQ', 'GENREQ', 'KILL' ],
+ ui_method_icon => 'fa-times',
+ },
+ QUEUED => {
+ prev_actions => [ ],
+ id => 'QUEUED',
+ name => 'Queued request',
+ ui_method_name => 0,
+ method => 0,
+ next_actions => [ 'REQ', 'KILL' ],
+ ui_method_icon => 0,
+ },
+ CANCREQ => {
+ prev_actions => [ 'NEW' ],
+ id => 'CANCREQ',
+ name => 'Cancellation requested',
+ ui_method_name => 0,
+ method => 0,
+ next_actions => [ 'KILL', 'REQ' ],
+ ui_method_icon => 0,
+ },
+ COMP => {
+ prev_actions => [ 'REQ' ],
+ id => 'COMP',
+ name => 'Completed',
+ ui_method_name => 'Mark completed',
+ method => 'mark_completed',
+ next_actions => [ 'CHK' ],
+ ui_method_icon => 'fa-check',
+ },
+ KILL => {
+ prev_actions => [ 'QUEUED', 'REQREV', 'NEW', 'CANCREQ' ],
+ id => 'KILL',
+ name => 0,
+ ui_method_name => 'Delete request',
+ method => 'delete',
+ next_actions => [ ],
+ ui_method_icon => 'fa-trash',
+ },
+ CHK => {
+ prev_actions => [ 'REQ', 'GENREQ', 'COMP' ],
+ id => 'CHK',
+ name => 'Checked out',
+ ui_method_name => 'Check out',
+ needs_prefs => [ 'CirculateILL' ],
+ needs_perms => [ 'user_circulate_circulate_remaining_permissions' ],
+ needs_all => ignore(),
+ method => 'check_out',
+ next_actions => [ ],
+ ui_method_icon => 'fa-upload',
+ },
+ RET => {
+ prev_actions => [ 'CHK' ],
+ id => 'RET',
+ name => 'Returned to library',
+ ui_method_name => 'Check in',
+ method => 'check_in',
+ next_actions => [ 'COMP' ],
+ ui_method_icon => 'fa-download',
+ }
+ },
+ "new node + core_status_graph = bigger status graph"
+ ) || diag explain $new_graph;
+
$schema->storage->txn_rollback;
};
# the Dummy plugin installed. load_backend & available_backends don't
# currently have tests as a result.
+ t::lib::Mocks->mock_config('interlibrary_loans', { backend_dir => 'a_dir' } );
my $backend = Test::MockObject->new;
$backend->set_isa('Koha::Illbackends::Mock');
$backend->set_always('name', 'Mock');
my $patron = $builder->build({ source => 'Borrower' });
- my $illrq = $builder->build({
- source => 'Illrequest',
- value => { borrowernumber => $patron->{borrowernumber} }
+ my $illrq = $builder->build_object({
+ class => 'Koha::Illrequests',
});
- my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
- $illrq_obj->_backend($backend);
+ $illrq->_backend($backend);
- isa_ok($illrq_obj->_backend, 'Koha::Illbackends::Mock',
+ isa_ok($illrq->_backend, 'Koha::Illbackends::Mock',
"OK accessing mocked backend.");
# _backend_capability tests:
# functionality, such as unmediated in the BLDSS backend (also see
# bugzilla 18837).
$backend->set_always('capabilities', undef);
- is($illrq_obj->_backend_capability('Test'), 0,
+ is($illrq->_backend_capability('Test'), 0,
"0 returned on Mock not implementing capabilities.");
$backend->set_always('capabilities', 0);
- is($illrq_obj->_backend_capability('Test'), 0,
+ is($illrq->_backend_capability('Test'), 0,
"0 returned on Mock not implementing Test capability.");
$backend->set_always('capabilities', sub { return 'bar'; } );
- is($illrq_obj->_backend_capability('Test'), 'bar',
+ is($illrq->_backend_capability('Test'), 'bar',
"'bar' returned on Mock implementing Test capability.");
# metadata test: we need to be sure that we return the arbitrary values
);
is_deeply(
- $illrq_obj->metadata,
+ $illrq->metadata,
{
- ID => $illrq_obj->illrequest_id,
- Title => $illrq_obj->patron->borrowernumber
+ ID => $illrq->illrequest_id,
+ Title => $illrq->patron->borrowernumber
},
"Test metadata."
);
# No backend graph extension
$backend->set_always('status_graph', {});
- is_deeply($illrq_obj->capabilities('COMP'),
+ is_deeply($illrq->capabilities('COMP'),
{
prev_actions => [ 'REQ' ],
id => 'COMP',
name => 'Completed',
ui_method_name => 'Mark completed',
method => 'mark_completed',
- next_actions => [ ],
+ next_actions => [ 'CHK' ],
ui_method_icon => 'fa-check',
},
"Dummy status graph for COMP.");
- is($illrq_obj->capabilities('UNKNOWN'), undef,
+ is($illrq->capabilities('UNKNOWN'), undef,
"Dummy status graph for UNKNOWN.");
- is_deeply($illrq_obj->capabilities(),
- $illrq_obj->_core_status_graph,
+ is_deeply($illrq->capabilities(),
+ $illrq->_core_status_graph,
"Dummy full status graph.");
# Simple backend graph extension
$backend->set_always('status_graph',
next_actions => [ 'REQ' ],
},
});
- is_deeply($illrq_obj->capabilities('QER'),
+ is_deeply($illrq->capabilities('QER'),
{
prev_actions => [ 'REQ' ],
id => 'QER',
next_actions => [ 'REQ' ],
},
"Simple status graph for QER.");
- is($illrq_obj->capabilities('UNKNOWN'), undef,
+ is($illrq->capabilities('UNKNOWN'), undef,
"Simple status graph for UNKNOWN.");
- is_deeply($illrq_obj->capabilities(),
- $illrq_obj->_status_graph_union(
- $illrq_obj->_core_status_graph,
+ is_deeply($illrq->capabilities(),
+ $illrq->_status_graph_union(
+ $illrq->_core_status_graph,
{
QER => {
prev_actions => [ 'REQ' ],
# No backend graph extension
$backend->set_always('status_graph', {});
- is($illrq_obj->custom_capability('unknown', {}), 0,
+ is($illrq->custom_capability('unknown', {}), 0,
"Unknown candidate.");
# Simple backend graph extension
});
$backend->mock('identity',
sub { my ( $self, $params ) = @_; return $params->{other}; });
- is($illrq_obj->custom_capability('identity', { test => 1 })->{test}, 1,
+ is($illrq->custom_capability('identity', { test => 1, method => 'blah' })->{test}, 1,
"Resolve identity custom_capability");
$schema->storage->txn_rollback;
subtest 'Backend core methods' => sub {
- plan tests => 16;
+ plan tests => 18;
$schema->storage->txn_begin;
my $backend = Test::MockObject->new;
$backend->set_isa('Koha::Illbackends::Mock');
$backend->set_always('name', 'Mock');
+ $backend->mock('capabilities', sub { return 'Mock'; });
my $config = Test::MockObject->new;
$config->set_always('backend_dir', "/tmp");
$config->set_always('getLimitRules',
{ default => { count => 0, method => 'active' } });
- my $illrq = $builder->build({source => 'Illrequest'});
- my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
- $illrq_obj->_config($config);
- $illrq_obj->_backend($backend);
+ my $illrq = $builder->build_object({
+ class => 'Koha::Illrequests',
+ value => { backend => undef }
+ });
+ $illrq->_config($config);
+
+ # Test error conditions (no backend)
+ throws_ok { $illrq->load_backend; }
+ 'Koha::Exceptions::Ill::InvalidBackendId',
+ 'Exception raised correctly';
+
+ throws_ok { $illrq->load_backend(''); }
+ 'Koha::Exceptions::Ill::InvalidBackendId',
+ 'Exception raised correctly';
+
+ # Now load the mocked backend
+ $illrq->_backend($backend);
# expandTemplate:
- is_deeply($illrq_obj->expandTemplate({ test => 1, method => "bar" }),
+ is_deeply($illrq->expandTemplate({ test => 1, method => "bar" }),
{
test => 1,
method => "bar",
$backend->set_series('create',
{ stage => 'bar', method => 'create' },
{ stage => 'commit', method => 'create' },
+ { stage => 'commit', method => 'create' },
+ { stage => 'commit', method => 'create' },
{ stage => 'commit', method => 'create' });
- # Test Copyright Clearance
- t::lib::Mocks::mock_preference("ILLModuleCopyrightClearance", "Test Copyright Clearance.");
- is_deeply($illrq_obj->backend_create({test => 1}),
- {
- error => 0,
- status => '',
- message => '',
- method => 'create',
- stage => 'copyrightclearance',
- value => {
- backend => "Mock"
- }
- },
- "Backend create: copyright clearance.");
- t::lib::Mocks::mock_preference("ILLModuleCopyrightClearance", "");
# Test non-commit
- is_deeply($illrq_obj->backend_create({test => 1}),
+ is_deeply($illrq->backend_create({test => 1}),
{
stage => 'bar', method => 'create',
template => "/tmp/Mock/intra-includes/create.inc",
},
"Backend create: arbitrary stage.");
# Test commit
- is_deeply($illrq_obj->backend_create({test => 1}),
+ is_deeply($illrq->backend_create({test => 1}),
{
stage => 'commit', method => 'create', permitted => 0,
template => "/tmp/Mock/intra-includes/create.inc",
opac_template => "/tmp/Mock/opac-includes/create.inc",
},
"Backend create: arbitrary stage, not permitted.");
- is($illrq_obj->status, "QUEUED", "Backend create: queued if restricted.");
+ is($illrq->status, "QUEUED", "Backend create: queued if restricted.");
$config->set_always('getLimitRules', {});
- $illrq_obj->status('NEW');
- is_deeply($illrq_obj->backend_create({test => 1}),
+ $illrq->status('NEW');
+ is_deeply($illrq->backend_create({test => 1}),
{
stage => 'commit', method => 'create', permitted => 1,
template => "/tmp/Mock/intra-includes/create.inc",
opac_template => "/tmp/Mock/opac-includes/create.inc",
},
"Backend create: arbitrary stage, permitted.");
- is($illrq_obj->status, "NEW", "Backend create: not-queued.");
+ is($illrq->status, "NEW", "Backend create: not-queued.");
+
+ # Test that enabling the unmediated workflow causes the backend's
+ # 'unmediated_ill' method to be called
+ t::lib::Mocks::mock_preference('ILLModuleUnmediated', '1');
+ $backend->mock(
+ 'capabilities',
+ sub {
+ my ($self, $name) = @_;
+ if ($name eq 'unmediated_ill') {
+ return sub {
+ return { unmediated_ill => 1 };
+ };
+ }
+ }
+ );
+ $illrq->status('NEW');
+ is_deeply(
+ $illrq->backend_create({test => 1}),
+ {
+ 'opac_template' => '/tmp/Mock/opac-includes/.inc',
+ 'template' => '/tmp/Mock/intra-includes/.inc',
+ 'unmediated_ill' => 1
+ },
+ "Backend create: commit stage, permitted, ILLModuleUnmediated enabled."
+ );
+
+ # Test that disabling the unmediated workflow causes the backend's
+ # 'unmediated_ill' method to be NOT called
+ t::lib::Mocks::mock_preference('ILLModuleUnmediated', '0');
+ $illrq->status('NEW');
+ is_deeply(
+ $illrq->backend_create({test => 1}),
+ {
+ stage => 'commit', method => 'create', permitted => 1,
+ template => "/tmp/Mock/intra-includes/create.inc",
+ opac_template => "/tmp/Mock/opac-includes/create.inc",
+ },
+ "Backend create: commit stage, permitted, ILLModuleUnmediated disabled."
+ );
# backend_renew
$backend->set_series('renew', { stage => 'bar', method => 'renew' });
- is_deeply($illrq_obj->backend_renew({test => 1}),
+ is_deeply($illrq->backend_renew({test => 1}),
{
stage => 'bar', method => 'renew',
template => "/tmp/Mock/intra-includes/renew.inc",
# backend_cancel
$backend->set_series('cancel', { stage => 'bar', method => 'cancel' });
- is_deeply($illrq_obj->backend_cancel({test => 1}),
+ is_deeply($illrq->backend_cancel({test => 1}),
{
stage => 'bar', method => 'cancel',
template => "/tmp/Mock/intra-includes/cancel.inc",
# backend_update_status
$backend->set_series('update_status', { stage => 'bar', method => 'update_status' });
- is_deeply($illrq_obj->backend_update_status({test => 1}),
+ is_deeply($illrq->backend_update_status({test => 1}),
{
stage => 'bar', method => 'update_status',
template => "/tmp/Mock/intra-includes/update_status.inc",
# backend_confirm
$backend->set_series('confirm', { stage => 'bar', method => 'confirm' });
- is_deeply($illrq_obj->backend_confirm({test => 1}),
+ is_deeply($illrq->backend_confirm({test => 1}),
{
stage => 'bar', method => 'confirm',
template => "/tmp/Mock/intra-includes/confirm.inc",
source => 'Borrower',
value => { categorycode => "ILLTSTLIB" },
});
- my $gen_conf = $illrq_obj->generic_confirm({
+ my $gen_conf = $illrq->generic_confirm({
current_branchcode => $illbrn->{branchcode}
});
isnt(index($gen_conf->{value}->{draft}->{body}, $backend->metadata->{Test}), -1,
"Generic confirm: partner 2 is correct."
);
- dies_ok { $illrq_obj->generic_confirm({
+ dies_ok { $illrq->generic_confirm({
current_branchcode => $illbrn->{branchcode},
stage => 'draft'
}) }
"Generic confirm: missing to dies OK.";
- dies_ok { $illrq_obj->generic_confirm({
- current_branchcode => $illbrn->{branchcode},
- partners => $partner1->{email},
- stage => 'draft'
- }) }
- "Generic confirm: missing from dies OK.";
-
$schema->storage->txn_rollback;
};
subtest 'Helpers' => sub {
- plan tests => 9;
+ plan tests => 20;
$schema->storage->txn_begin;
my $backend = Test::MockObject->new;
$backend->set_isa('Koha::Illbackends::Mock');
$backend->set_always('name', 'Mock');
+ $backend->mock(
+ 'metadata',
+ sub {
+ my ( $self, $rq ) = @_;
+ return {
+ title => 'mytitle',
+ author => 'myauthor'
+ }
+ }
+ );
my $config = Test::MockObject->new;
$config->set_always('backend_dir', "/tmp");
source => 'Borrower',
value => { categorycode => "A" }
});
+ # Create a mocked branch with no email addressed defined
+ my $illbrn = $builder->build({
+ source => 'Branch',
+ value => {
+ branchcode => 'HDE',
+ branchemail => "",
+ branchillemail => "",
+ branchreplyto => ""
+ }
+ });
my $illrq = $builder->build({
source => 'Illrequest',
- value => { branchcode => "CPL", borrowernumber => $patron->{borrowernumber} }
+ value => { branchcode => "HDE", borrowernumber => $patron->{borrowernumber} }
});
my $illrq_obj = Koha::Illrequests->find($illrq->{illrequest_id});
$illrq_obj->_config($config);
# getPrefix
$config->set_series('getPrefixes',
- { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
- { A => "ATEST", C => "CBAR", default => "DEFAULT" });
- is($illrq_obj->getPrefix({ brw_cat => "C", branch => "CPL" }), "CBAR",
- "getPrefix: brw_cat");
- $config->set_series('getPrefixes',
- { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
+ { HDE => "TEST", TSL => "BAR", default => "DEFAULT" },
{ A => "ATEST", C => "CBAR", default => "DEFAULT" });
- is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "CPL" }), "TEST",
+ is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "HDE" }), "TEST",
"getPrefix: branch");
$config->set_series('getPrefixes',
- { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
+ { HDE => "TEST", TSL => "BAR", default => "DEFAULT" },
{ A => "ATEST", C => "CBAR", default => "DEFAULT" });
- is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "DEFAULT",
+ is($illrq_obj->getPrefix({ branch => "UNKNOWN" }), "",
"getPrefix: default");
$config->set_always('getPrefixes', {});
- is($illrq_obj->getPrefix({ brw_cat => "UNKNOWN", branch => "UNKNOWN" }), "",
+ is($illrq_obj->getPrefix({ branch => "UNKNOWN" }), "",
"getPrefix: the empty prefix");
# id_prefix
$config->set_series('getPrefixes',
- { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
- { A => "ATEST", C => "CBAR", default => "DEFAULT" });
- is($illrq_obj->id_prefix, "ATEST-", "id_prefix: brw_cat");
- $config->set_series('getPrefixes',
- { CPL => "TEST", TSL => "BAR", default => "DEFAULT" },
+ { HDE => "TEST", TSL => "BAR", default => "DEFAULT" },
{ AB => "ATEST", CD => "CBAR", default => "DEFAULT" });
is($illrq_obj->id_prefix, "TEST-", "id_prefix: branch");
$config->set_series('getPrefixes',
- { CPLT => "TEST", TSLT => "BAR", default => "DEFAULT" },
+ { HDET => "TEST", TSLT => "BAR", default => "DEFAULT" },
{ AB => "ATEST", CD => "CBAR", default => "DEFAULT" });
- is($illrq_obj->id_prefix, "DEFAULT-", "id_prefix: default");
+ is($illrq_obj->id_prefix, "", "id_prefix: default");
# requires_moderation
$illrq_obj->status('NEW')->store;
$illrq_obj->status('CANCREQ')->store;
is($illrq_obj->requires_moderation, 'CANCREQ', "requires_moderation: Yes.");
+ #send_patron_notice
+ my $attr = Koha::MessageAttributes->find({ message_name => 'Ill_ready' });
+ C4::Members::Messaging::SetMessagingPreference({
+ borrowernumber => $patron->{borrowernumber},
+ message_attribute_id => $attr->message_attribute_id,
+ message_transport_types => ['email']
+ });
+ my $return_patron = $illrq_obj->send_patron_notice('ILL_PICKUP_READY');
+ my $notice = $schema->resultset('MessageQueue')->search({
+ letter_code => 'ILL_PICKUP_READY',
+ message_transport_type => 'email',
+ borrowernumber => $illrq_obj->borrowernumber
+ })->next()->letter_code;
+ is_deeply(
+ $return_patron,
+ { result => { success => ['email'], fail => [] } },
+ "Correct return when notice created"
+ );
+ is($notice, 'ILL_PICKUP_READY' ,"Notice is correctly created");
+
+ my $return_patron_fail = $illrq_obj->send_patron_notice();
+ is_deeply(
+ $return_patron_fail,
+ { error => 'notice_no_type' },
+ "Correct error when missing type"
+ );
+
+ #send_staff_notice
+ # Specify that no staff notices should be send
+ t::lib::Mocks::mock_preference('ILLSendStaffNotices', '');
+ my $return_staff_cancel_fail =
+ $illrq_obj->send_staff_notice('ILL_REQUEST_CANCEL');
+ is_deeply(
+ $return_staff_cancel_fail,
+ { error => 'notice_not_enabled' },
+ "Does not send notices that are not enabled"
+ );
+ my $queue = $schema->resultset('MessageQueue')->search({
+ letter_code => 'ILL_REQUEST_CANCEL'
+ });
+ is($queue->count, 0, "Notice is not queued");
+
+ # Specify that the cancel notice can be sent
+ t::lib::Mocks::mock_preference('ILLSendStaffNotices', 'ILL_REQUEST_CANCEL');
+ my $return_staff_cancel = $illrq_obj->send_staff_notice(
+ 'ILL_REQUEST_CANCEL'
+ );
+ is_deeply(
+ $return_staff_cancel,
+ { success => 'notice_queued' },
+ "Correct return when staff notice created"
+ );
+ $queue = $schema->resultset('MessageQueue')->search({
+ letter_code => 'ILL_REQUEST_CANCEL'
+ });
+ is($queue->count, 1, "Notice queued as expected");
+
+ my $return_staff_fail = $illrq_obj->send_staff_notice();
+ is_deeply(
+ $return_staff_fail,
+ { error => 'notice_no_type' },
+ "Correct error when missing type"
+ );
+ $queue = $schema->resultset('MessageQueue')->search({
+ letter_code => 'ILL_REQUEST_CANCEL'
+ });
+ is($queue->count, 1, "Notice is not queued");
+
+ #get_notice
+ my $not = $illrq_obj->get_notice({
+ notice_code => 'ILL_REQUEST_CANCEL',
+ transport => 'email'
+ });
+
+ # We test the properties of the hashref separately because the random
+ # hash ordering of the metadata means we can't test the entire thing
+ # with is_deeply
+ ok(
+ $not->{module} eq 'ill',
+ 'Correct module return from get_notice'
+ );
+ ok(
+ $not->{name} eq 'ILL request cancelled',
+ 'Correct name return from get_notice'
+ );
+ ok(
+ $not->{message_transport_type} eq 'email',
+ 'Correct message_transport_type return from get_notice'
+ );
+ ok(
+ $not->{title} eq 'Interlibrary loan request cancelled',
+ 'Correct title return from get_notice'
+ );
+
$schema->storage->txn_rollback;
};
$schema->storage->txn_rollback;
};
+subtest 'Checking out' => sub {
+
+ plan tests => 17;
+
+ $schema->storage->txn_begin;
+
+ my $itemtype = $builder->build_object({
+ class => 'Koha::ItemTypes',
+ value => {
+ notforloan => 1
+ }
+ });
+ my $library = $builder->build_object({ class => 'Koha::Libraries' });
+ my $biblio = $builder->build_sample_biblio();
+ my $patron = $builder->build_object({
+ class => 'Koha::Patrons',
+ value => { category_type => 'x' }
+ });
+ my $request = $builder->build_object({
+ class => 'Koha::Illrequests',
+ value => {
+ borrowernumber => $patron->borrowernumber,
+ biblio_id => $biblio->biblionumber
+ }
+ });
+
+ # First test that calling check_out without a stage param returns
+ # what's required to build the form
+ my $no_stage = $request->check_out();
+ is($no_stage->{method}, 'check_out');
+ is($no_stage->{stage}, 'form');
+ isa_ok($no_stage->{value}, 'HASH');
+ isa_ok($no_stage->{value}->{itemtypes}, 'Koha::ItemTypes');
+ isa_ok($no_stage->{value}->{libraries}, 'Koha::Libraries');
+ isa_ok($no_stage->{value}->{statistical}, 'Koha::Patrons');
+ isa_ok($no_stage->{value}->{biblio}, 'Koha::Biblio');
+
+ # Now test that form validation works when we supply a 'form' stage
+ #
+ # No item_type
+ my $form_stage_missing_params = $request->check_out({
+ stage => 'form'
+ });
+ is_deeply($form_stage_missing_params->{value}->{errors}, {
+ item_type => 1
+ });
+ # inhouse passed but not a valid patron
+ my $form_stage_bad_patron = $request->check_out({
+ stage => 'form',
+ item_type => $itemtype->itemtype,
+ inhouse => 'I_DONT_EXIST'
+ });
+ is_deeply($form_stage_bad_patron->{value}->{errors}, {
+ inhouse => 1
+ });
+ # Too many items attached to biblio
+ my $item1 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
+ my $item2 = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
+ my $form_stage_two_items = $request->check_out({
+ stage => 'form',
+ item_type => $itemtype->itemtype,
+ });
+ is_deeply($form_stage_two_items->{value}->{errors}, {
+ itemcount => 1
+ });
+
+ # Delete the items we created, so we can test that we can create one
+ $item1->delete;
+ $item2->delete;
+
+ # We need to mock the user environment for AddIssue
+ t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode });
+ #
+
+ # First we pass bad parameters to the item creation to test we're
+ # catching the failure of item creation
+ my $form_stage_bad_branchcode;
+ warning_like {
+ $form_stage_bad_branchcode = $request->check_out({
+ stage => 'form',
+ item_type => $itemtype->itemtype,
+ branchcode => '---'
+ });
+ } qr/DBD::mysql::st execute failed: Cannot add or update a child row: a foreign key constraint fails/,
+ "Item creation fails on bad parameters";
+
+ is_deeply($form_stage_bad_branchcode->{value}->{errors}, {
+ item_creation => 1
+ },"We get expected failure of item creation");
+
+ # Now create a proper item
+ my $form_stage_good_branchcode = $request->check_out({
+ stage => 'form',
+ item_type => $itemtype->itemtype,
+ branchcode => $library->branchcode
+ });
+ # By default, this item should not be loanable, so check that we're
+ # informed of that fact
+ is_deeply(
+ $form_stage_good_branchcode->{value}->{check_out_errors},
+ {
+ error => {
+ NOT_FOR_LOAN => 1,
+ itemtype_notforloan => $itemtype->itemtype
+ }
+ },
+ "We get expected error on notforloan of item"
+ );
+ # Delete the item that was created
+ $biblio->items->delete;
+ # Now create an itemtype that is loanable
+ my $itemtype_loanable = $builder->build_object({
+ class => 'Koha::ItemTypes',
+ value => {
+ notforloan => 0
+ }
+ });
+ # We need to mock the user environment for AddIssue
+ t::lib::Mocks::mock_userenv({ branchcode => $library->branchcode });
+ my $form_stage_loanable = $request->check_out({
+ stage => 'form',
+ item_type => $itemtype_loanable->itemtype,
+ branchcode => $library->branchcode
+ });
+ is($form_stage_loanable->{stage}, 'done_check_out');
+ isa_ok($patron->checkouts, 'Koha::Checkouts');
+ is($patron->checkouts->count, 1);
+ is($request->status, 'CHK');
+
+ $schema->storage->txn_rollback;
+};
+
subtest 'Checking Limits' => sub {
plan tests => 30;
$schema->storage->txn_rollback;
};
-subtest 'TO_JSON() tests' => sub {
+subtest 'Custom statuses' => sub {
- plan tests => 10;
+ plan tests => 3;
- my $illreqmodule = Test::MockModule->new('Koha::Illrequest');
+ $schema->storage->txn_begin;
- # Mock ->capabilities
- $illreqmodule->mock( 'capabilities', sub { return 'capable'; } );
+ my $cat = Koha::AuthorisedValueCategories->search(
+ {
+ category_name => 'ILLSTATUS'
+ }
+ );
- # Mock ->metadata
- $illreqmodule->mock( 'metadata', sub { return 'metawhat?'; } );
+ if ($cat->count == 0) {
+ $cat = $builder->build_object(
+ {
+ class => 'Koha::AuthorisedValueCategory',
+ value => {
+ category_name => 'ILLSTATUS'
+ }
+ }
+ );
+ };
+
+ my $av = $builder->build_object(
+ {
+ class => 'Koha::AuthorisedValues',
+ value => {
+ category => 'ILLSTATUS'
+ }
+ }
+ );
+
+ is($av->category, 'ILLSTATUS',
+ "Successfully created authorised value for custom status");
+
+ my $ill_req = $builder->build_object(
+ {
+ class => 'Koha::Illrequests',
+ value => {
+ status_alias => $av->authorised_value
+ }
+ }
+ );
+ isa_ok($ill_req->statusalias, 'Koha::AuthorisedValue',
+ "statusalias correctly returning Koha::AuthorisedValue object");
+
+ $ill_req->status("COMP");
+ is($ill_req->statusalias, undef,
+ "Koha::Illrequest->status overloading resetting status_alias");
+
+ $schema->storage->txn_rollback;
+};
+
+subtest 'Checking in hook' => sub {
+
+ plan tests => 2;
$schema->storage->txn_begin;
- my $library = $builder->build_object( { class => 'Koha::Libraries' } );
- my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
- my $illreq = $builder->build_object(
+ # Build infrastructure
+ my $backend = Test::MockObject->new;
+ $backend->set_isa('Koha::Illbackends::Mock');
+ $backend->set_always('name', 'Mock');
+
+ my $config = Test::MockObject->new;
+ $config->set_always('backend_dir', "/tmp");
+
+ my $item = $builder->build_sample_item();
+ my $patron = $builder->build_object({ class => 'Koha::Patrons' });
+
+ t::lib::Mocks::mock_userenv(
+ {
+ patron => $patron,
+ branchcode => $patron->branchcode
+ }
+ );
+
+ my $illrq = $builder->build_object(
{
class => 'Koha::Illrequests',
value => {
- branchcode => $library->branchcode,
- borrowernumber => $patron->borrowernumber
+ biblio_id => $item->biblio->biblionumber,
+ status => 'NEW'
}
}
);
- my $illreq_json = $illreq->TO_JSON;
- is( $illreq_json->{patron},
- undef, '%embed not passed, no \'patron\' attribute' );
- is( $illreq_json->{metadata},
- undef, '%embed not passed, no \'metadata\' attribute' );
- is( $illreq_json->{capabilities},
- undef, '%embed not passed, no \'capabilities\' attribute' );
- is( $illreq_json->{branch},
- undef, '%embed not passed, no \'branch\' attribute' );
-
- $illreq_json = $illreq->TO_JSON(
- { patron => 1, metadata => 1, capabilities => 1, branch => 1 } );
- is( $illreq_json->{patron}->{firstname},
- $patron->firstname,
- '%embed passed, \'patron\' attribute correct (firstname)' );
- is( $illreq_json->{patron}->{surname},
- $patron->surname,
- '%embed passed, \'patron\' attribute correct (surname)' );
- is( $illreq_json->{patron}->{cardnumber},
- $patron->cardnumber,
- '%embed passed, \'patron\' attribute correct (cardnumber)' );
- is( $illreq_json->{metadata},
- 'metawhat?', '%embed passed, \'metadata\' attribute correct' );
- is( $illreq_json->{capabilities},
- 'capable', '%embed passed, \'capabilities\' attribute correct' );
- is( $illreq_json->{branch}->{branchcode},
- $library->branchcode, '%embed not passed, no \'branch\' attribute' );
+
+ $illrq->_config($config);
+ $illrq->_backend($backend);
+
+ t::lib::Mocks::mock_preference('CirculateILL', 1);
+
+ # Add an issue
+ AddIssue( $patron->unblessed, $item->barcode );
+ # Make the item withdrawn so checking-in is rejected
+ t::lib::Mocks::mock_preference('BlockReturnOfWithdrawnItems', 1);
+ $item->set({ withdrawn => 1 })->store;
+ AddReturn( $item->barcode, $patron->branchcode );
+ # refresh request
+ $illrq->discard_changes;
+ isnt( $illrq->status, 'RET' );
+
+ # allow the check-in
+ $item->set({ withdrawn => 0 })->store;
+ AddReturn( $item->barcode, $patron->branchcode );
+ # refresh request
+ $illrq->discard_changes;
+ is( $illrq->status, 'RET' );
$schema->storage->txn_rollback;
};