From 84f100a25d4a1562119beb0f5dbd4581081b6ea8 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Fri, 10 Feb 2017 15:11:17 +0200 Subject: [PATCH] Bug 18072: Add Koha::Biblio->can_be_transferred This patch adds a new method Koha::Biblio->can_be_transferred. The method checks if at least one of the item of that biblio can be transferred to desired location. This method will be useful for building a smarter pickup location list for holds, because we will be able to hide those libraries to which none of the items of this biblio can be transferred to due to branch transfer limits (see Bug 7614). To test: 1. prove t/db_dependent/Koha/Biblios.t Signed-off-by: Josef Moravec Signed-off-by: Tomas Cohen Arazi --- Koha/Biblio.pm | 90 +++++++++++++++++++++++++++++++++++++++++++ Koha/Item.pm | 4 ++ t/db_dependent/Koha/Biblios.t | 79 ++++++++++++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 1 deletion(-) diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index f4e5e2f..1b4464c 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -33,8 +33,12 @@ use Koha::Biblioitems; use Koha::ArticleRequests; use Koha::ArticleRequest::Status; use Koha::IssuingRules; +use Koha::Item::Transfer::Limits; +use Koha::Libraries; use Koha::Subscriptions; +use Koha::Exceptions::Library; + =head1 NAME Koha::Biblio - Koha Biblio Object class @@ -85,6 +89,92 @@ sub can_article_request { return q{}; } +=head3 can_be_transferred + +$biblio->can_be_transferred({ to => $to_library, from => $from_library }) + +Checks if at least one item of a biblio can be transferred to given library. + +This feature is controlled by two system preferences: +UseBranchTransferLimits to enable / disable the feature +BranchTransferLimitsType to use either an itemnumber or ccode as an identifier + for setting the limitations + +Performance-wise, it is recommended to use this method for a biblio instead of +iterating each item of a biblio with Koha::Item->can_be_transferred(). + +Takes HASHref that can have the following parameters: + MANDATORY PARAMETERS: + $to : Koha::Library or branchcode string + OPTIONAL PARAMETERS: + $from : Koha::Library or branchcode string # if given, only items from that + # holdingbranch are considered + +Returns 1 if at least one of the item of a biblio can be transferred +to $to_library, otherwise 0. + +=cut + +sub can_be_transferred { + my ($self, $params) = @_; + + my $to = $params->{'to'}; + my $from = $params->{'from'}; + if (ref($to) ne 'Koha::Library') { + my $tobranchcode = defined $to ? $to : ''; + $to = Koha::Libraries->find($tobranchcode); + unless ($to) { + Koha::Exceptions::Library::NotFound->throw( + error => "Library '$tobranchcode' not found.", + ); + } + } + if ($from && ref($from) ne 'Koha::Library') { + my $frombranchcode = defined $from ? $from : ''; + $from = Koha::Libraries->find($frombranchcode); + unless ($from) { + Koha::Exceptions::Library::NotFound->throw( + error => "Library '$frombranchcode' not found.", + ); + } + } + + return 1 unless C4::Context->preference('UseBranchTransferLimits'); + my $limittype = C4::Context->preference('BranchTransferLimitsType'); + + my $items; + foreach my $item_of_bib ($self->items) { + next unless $item_of_bib->holdingbranch; + next if $from && $from->branchcode ne $item_of_bib->holdingbranch; + return 1 if $item_of_bib->holdingbranch eq $to->branchcode; + my $code = $limittype eq 'itemtype' + ? $item_of_bib->effective_itemtype + : $item_of_bib->ccode; + return 1 unless $code; + $items->{$code}->{$item_of_bib->holdingbranch} = 1; + } + + # At this point we will have a HASHref containing each itemtype/ccode that + # this biblio has, inside which are all of the holdingbranches where those + # items are located at. Then, we will query Koha::Item::Transfer::Limits to + # find out whether a transfer limits for such $limittype from any of the + # listed holdingbranches to the given $to library exist. If at least one + # holdingbranch for that $limittype does not have a transfer limit to given + # $to library, then we know that the transfer is possible. + foreach my $code (keys %{$items}) { + my @holdingbranches = keys %{$items->{$code}}; + return 1 if Koha::Item::Transfer::Limits->search({ + toBranch => $to->branchcode, + fromBranch => { 'in' => \@holdingbranches }, + $limittype => $code + }, { + group_by => [qw/fromBranch/] + })->count == scalar(@holdingbranches) ? 0 : 1; + } + + return 0; +} + =head3 article_request_type my $type = $biblio->article_request_type( $borrower ); diff --git a/Koha/Item.pm b/Koha/Item.pm index 890ebbd..37610e3 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -211,6 +211,10 @@ Takes HASHref that can have the following parameters: Returns 1 if item can be transferred to $to_library, otherwise 0. +To find out whether at least one item of a Koha::Biblio can be transferred, please +see Koha::Biblio->can_be_transferred() instead of using this method for +multiple items of the same biblio. + =cut sub can_be_transferred { diff --git a/t/db_dependent/Koha/Biblios.t b/t/db_dependent/Koha/Biblios.t index 9f6a14a..2c7bdbe 100644 --- a/t/db_dependent/Koha/Biblios.t +++ b/t/db_dependent/Koha/Biblios.t @@ -19,8 +19,10 @@ use Modern::Perl; -use Test::More tests => 2; +use Test::More tests => 3; +use C4::Biblio; +use C4::Items; use C4::Reserves; use Koha::DateUtils qw( dt_from_string ); @@ -80,5 +82,80 @@ subtest 'subscriptions' => sub { is( $subscriptions->count, 2, 'Koha::Biblio->subscriptions should return the correct number of subscriptions'); }; +subtest 'can_be_transferred' => sub { + plan tests => 11; + + t::lib::Mocks::mock_preference('UseBranchTransferLimits', 1); + t::lib::Mocks::mock_preference('BranchTransferLimitsType', 'itemtype'); + + my $library1 = $builder->build( { source => 'Branch' } )->{branchcode}; + my $library2 = $builder->build( { source => 'Branch' } )->{branchcode}; + my $library3 = $builder->build( { source => 'Branch' } )->{branchcode}; + my ($bibnum, $title, $bibitemnum) = create_helper_biblio('ONLY1'); + my ($item_bibnum, $item_bibitemnum, $itemnumber) + = AddItem({ homebranch => $library1, holdingbranch => $library1 }, $bibnum); + my $item = Koha::Items->find($itemnumber); + my $biblio = Koha::Biblios->find($bibnum); + + is(Koha::Item::Transfer::Limits->search({ + fromBranch => $library1, + toBranch => $library2, + })->count, 0, 'There are no transfer limits between libraries.'); + ok($biblio->can_be_transferred({ to => $library2 }), + 'Some items of this biblio can be transferred between libraries.'); + + my $limit = Koha::Item::Transfer::Limit->new({ + fromBranch => $library1, + toBranch => $library2, + itemtype => $item->effective_itemtype, + })->store; + is(Koha::Item::Transfer::Limits->search({ + fromBranch => $library1, + toBranch => $library2, + })->count, 1, 'Given we have added a transfer limit that applies for all ' + .'of this biblio\s items,'); + is($biblio->can_be_transferred({ to => $library2 }), 0, + 'None of the items of biblio can no longer be transferred between ' + .'libraries.'); + is($biblio->can_be_transferred({ to => $library2, from => $library1 }), 0, + 'We get the same result also if we pass the from-library parameter.'); + $item->holdingbranch($library2)->store; + is($biblio->can_be_transferred({ to => $library2 }), 1, 'Given one of the ' + .'items is already located at to-library, then the transfer is possible.'); + $item->holdingbranch($library1)->store; + my ($item_bibnum2, $item_bibitemnum2, $itemnumber2) + = AddItem({ homebranch => $library1, holdingbranch => $library3 }, $bibnum); + my $item2 = Koha::Items->find($itemnumber2); + is($biblio->can_be_transferred({ to => $library2 }), 1, 'Given we added ' + .'another item that should have no transfer limits applying on, then ' + .'the transfer is possible.'); + $item2->holdingbranch($library1)->store; + is($biblio->can_be_transferred({ to => $library2 }), 0, 'Given all of items' + .' of the biblio are from same, transfer limited library, then transfer' + .' is not possible.'); + eval { $biblio->can_be_transferred({ to => undef }); }; + is(ref($@), 'Koha::Exceptions::Library::NotFound', 'Exception thrown when no' + .' library given.'); + eval { $biblio->can_be_transferred({ to => 'heaven' }); }; + is(ref($@), 'Koha::Exceptions::Library::NotFound', 'Exception thrown when' + .' invalid library is given.'); + eval { $biblio->can_be_transferred({ to => $library2, from => 'hell' }); }; + is(ref($@), 'Koha::Exceptions::Library::NotFound', 'Exception thrown when' + .' invalid library is given.'); +}; + $schema->storage->txn_rollback; +# Helper method to set up a Biblio. +sub create_helper_biblio { + my $itemtype = shift; + my ($bibnum, $title, $bibitemnum); + my $bib = MARC::Record->new(); + $title = 'Silence in the library'; + $bib->append_fields( + MARC::Field->new('100', ' ', ' ', a => 'Moffat, Steven'), + MARC::Field->new('245', ' ', ' ', a => $title), + MARC::Field->new('942', ' ', ' ', c => $itemtype), + ); + return ($bibnum, $title, $bibitemnum) = AddBiblio($bib, ''); +} -- 2.7.4