@@ -, +, @@ --- Koha/Biblio.pm | 90 +++++++++++++++++++++++++++++++++++++++++++ Koha/Item.pm | 4 ++ t/db_dependent/Koha/Biblios.t | 79 ++++++++++++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 1 deletion(-) --- a/Koha/Biblio.pm +++ a/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 ); --- a/Koha/Item.pm +++ a/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 { --- a/t/db_dependent/Koha/Biblios.t +++ a/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, ''); +} --