|
Lines 26-32
use C4::Koha qw( getitemtypeimagelocation getitemtypeimagesrc );
Link Here
|
| 26 |
use C4::Circulation qw( GetBranchItemRule GetTransfers ); |
26 |
use C4::Circulation qw( GetBranchItemRule GetTransfers ); |
| 27 |
use C4::Reserves qw( CanItemBeReserved CanBookBeReserved AddReserve GetReservesControlBranch ItemsAnyAvailableAndNotRestricted IsAvailableForItemLevelRequest ); |
27 |
use C4::Reserves qw( CanItemBeReserved CanBookBeReserved AddReserve GetReservesControlBranch ItemsAnyAvailableAndNotRestricted IsAvailableForItemLevelRequest ); |
| 28 |
use C4::Biblio qw( GetBiblioData GetFrameworkCode ); |
28 |
use C4::Biblio qw( GetBiblioData GetFrameworkCode ); |
| 29 |
use C4::Items qw( GetHostItemsInfo GetItemsInfo ); |
|
|
| 30 |
use C4::Output qw( output_html_with_http_headers ); |
29 |
use C4::Output qw( output_html_with_http_headers ); |
| 31 |
use C4::Context; |
30 |
use C4::Context; |
| 32 |
use C4::Members; |
31 |
use C4::Members; |
|
Lines 142-171
$template->param( branch => $branch );
Link Here
|
| 142 |
# |
141 |
# |
| 143 |
|
142 |
|
| 144 |
my %biblioDataHash; # Hash of biblionumber to biblio/biblioitems record. |
143 |
my %biblioDataHash; # Hash of biblionumber to biblio/biblioitems record. |
| 145 |
my %itemInfoHash; # Hash of itemnumber to item info. |
|
|
| 146 |
foreach my $biblioNumber (@biblionumbers) { |
144 |
foreach my $biblioNumber (@biblionumbers) { |
| 147 |
|
145 |
|
| 148 |
my $biblioData = GetBiblioData($biblioNumber); |
146 |
my $biblioData = GetBiblioData($biblioNumber); |
| 149 |
$biblioDataHash{$biblioNumber} = $biblioData; |
147 |
$biblioDataHash{$biblioNumber} = $biblioData; |
| 150 |
|
148 |
|
| 151 |
my @itemInfos = GetItemsInfo($biblioNumber); |
|
|
| 152 |
|
| 153 |
my $biblio = Koha::Biblios->find( $biblioNumber ); |
149 |
my $biblio = Koha::Biblios->find( $biblioNumber ); |
| 154 |
next unless $biblio; |
150 |
next unless $biblio; |
| 155 |
|
151 |
|
| 156 |
my $marcrecord = $biblio->metadata->record; |
152 |
my $marcrecord = $biblio->metadata->record; |
| 157 |
|
153 |
|
| 158 |
# flag indicating existence of at least one item linked via a host record |
154 |
my $items = |
| 159 |
# adding items linked via host biblios |
155 |
$biblio->items->filter_by_visible_in_opac( { patron => $patron } ); |
| 160 |
my @hostitemInfos = GetHostItemsInfo($marcrecord); |
156 |
my $host_items = |
| 161 |
if (@hostitemInfos){ |
157 |
$biblio->host_items->filter_by_visible_in_opac( { patron => $patron } ); |
| 162 |
push (@itemInfos,@hostitemInfos); |
158 |
$items = $biblio->items->search( |
| 163 |
} |
159 |
{ |
|
|
160 |
itemnumber => { |
| 161 |
-in => [ |
| 162 |
$items->get_column('itemnumber'), |
| 163 |
$host_items->get_column('itemnumber') |
| 164 |
] |
| 165 |
} |
| 166 |
} |
| 167 |
); |
| 164 |
|
168 |
|
| 165 |
$biblioData->{itemInfos} = \@itemInfos; |
169 |
$biblioData->{items} = [$items->as_list]; # FIXME Potentially a lot in memory here! |
| 166 |
foreach my $itemInfo (@itemInfos) { |
|
|
| 167 |
$itemInfoHash{$itemInfo->{itemnumber}} = $itemInfo; |
| 168 |
} |
| 169 |
|
170 |
|
| 170 |
# Compute the priority rank. |
171 |
# Compute the priority rank. |
| 171 |
$biblioData->{object} = $biblio; |
172 |
$biblioData->{object} = $biblio; |
|
Lines 237-242
if ( $query->param('place_reserve') ) {
Link Here
|
| 237 |
$branch = $patron->branchcode; |
238 |
$branch = $patron->branchcode; |
| 238 |
} |
239 |
} |
| 239 |
|
240 |
|
|
|
241 |
# FIXME We shouldn't need to fetch the item here |
| 240 |
my $item = $itemNum ? Koha::Items->find( $itemNum ) : undef; |
242 |
my $item = $itemNum ? Koha::Items->find( $itemNum ) : undef; |
| 241 |
# When choosing a specific item, the default pickup library should be dictated by the default hold policy |
243 |
# When choosing a specific item, the default pickup library should be dictated by the default hold policy |
| 242 |
if ( ! C4::Context->preference("OPACAllowUserToChooseBranch") && $item ) { |
244 |
if ( ! C4::Context->preference("OPACAllowUserToChooseBranch") && $item ) { |
|
Lines 411-416
my $itemLevelTypes = C4::Context->preference('item-level_itypes');
Link Here
|
| 411 |
my $pickup_locations = Koha::Libraries->search({ pickup_location => 1 }); |
413 |
my $pickup_locations = Koha::Libraries->search({ pickup_location => 1 }); |
| 412 |
$template->param('item_level_itypes' => $itemLevelTypes); |
414 |
$template->param('item_level_itypes' => $itemLevelTypes); |
| 413 |
|
415 |
|
|
|
416 |
my $patron_unblessed = $patron->unblessed; |
| 414 |
foreach my $biblioNum (@biblionumbers) { |
417 |
foreach my $biblioNum (@biblionumbers) { |
| 415 |
|
418 |
|
| 416 |
# Init the bib item with the choices for branch pickup |
419 |
# Init the bib item with the choices for branch pickup |
|
Lines 448-472
foreach my $biblioNum (@biblionumbers) {
Link Here
|
| 448 |
$biblioLoopIter{imageurl} = getitemtypeimagesrc() . "/". $itemtypes->{$biblioData->{itemtype}}{imageurl}; |
451 |
$biblioLoopIter{imageurl} = getitemtypeimagesrc() . "/". $itemtypes->{$biblioData->{itemtype}}{imageurl}; |
| 449 |
} |
452 |
} |
| 450 |
|
453 |
|
| 451 |
foreach my $itemInfo (@{$biblioData->{itemInfos}}) { |
|
|
| 452 |
if ($itemLevelTypes && $itemInfo->{itype}) { |
| 453 |
$itemInfo->{translated_description} = $itemtypes->{$itemInfo->{itype}}{translated_description}; |
| 454 |
$itemInfo->{imageurl} = getitemtypeimagesrc() . "/". $itemtypes->{$itemInfo->{itype}}{imageurl}; |
| 455 |
} |
| 456 |
|
| 457 |
if (!$itemInfo->{'notforloan'} && !($itemInfo->{'itemnotforloan'} > 0)) { |
| 458 |
$biblioLoopIter{forloan} = 1; |
| 459 |
} |
| 460 |
} |
| 461 |
|
| 462 |
my @notforloan_avs = Koha::AuthorisedValues->search_by_koha_field({ kohafield => 'items.notforloan', frameworkcode => $frameworkcode })->as_list; |
| 463 |
my $notforloan_label_of = { map { $_->authorised_value => $_->opac_description } @notforloan_avs }; |
| 464 |
|
| 465 |
my $visible_items = { map { $_->itemnumber => $_ } $biblio->items->filter_by_visible_in_opac( { patron => $patron } )->as_list }; |
| 466 |
|
454 |
|
| 467 |
# Only keep the items that are visible in the opac (i.e. those in %visible_items) |
|
|
| 468 |
# FIXME: We should get rid of itemInfos altogether and use $visible_items |
| 469 |
$biblioData->{itemInfos} = [ grep { $visible_items->{ $_->{itemnumber} } } @{ $biblioData->{itemInfos} } ]; |
| 470 |
|
455 |
|
| 471 |
$biblioLoopIter{itemLoop} = []; |
456 |
$biblioLoopIter{itemLoop} = []; |
| 472 |
my $numCopiesAvailable = 0; |
457 |
my $numCopiesAvailable = 0; |
|
Lines 477-567
foreach my $biblioNum (@biblionumbers) {
Link Here
|
| 477 |
# (before this loop was inside that sub loop so it was O(n^2) ) |
462 |
# (before this loop was inside that sub loop so it was O(n^2) ) |
| 478 |
my $items_any_available; |
463 |
my $items_any_available; |
| 479 |
$items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $biblioNum, patron => $patron }) if $patron; |
464 |
$items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $biblioNum, patron => $patron }) if $patron; |
| 480 |
foreach my $itemInfo (@{$biblioData->{itemInfos}}) { |
465 |
foreach my $item (@{$biblioData->{items}}) { |
| 481 |
my $itemNum = $itemInfo->{itemnumber}; |
|
|
| 482 |
my $item = $visible_items->{$itemNum}; |
| 483 |
my $itemLoopIter = {}; |
| 484 |
|
| 485 |
$itemLoopIter->{itemnumber} = $itemNum; |
| 486 |
$itemLoopIter->{barcode} = $itemInfo->{barcode}; |
| 487 |
$itemLoopIter->{homeBranchName} = $itemInfo->{homebranch}; |
| 488 |
$itemLoopIter->{callNumber} = $itemInfo->{itemcallnumber}; |
| 489 |
$itemLoopIter->{enumchron} = $itemInfo->{enumchron}; |
| 490 |
$itemLoopIter->{ccode} = $itemInfo->{ccode}; |
| 491 |
$itemLoopIter->{copynumber} = $itemInfo->{copynumber}; |
| 492 |
$itemLoopIter->{itemnotes} = $itemInfo->{itemnotes}; |
| 493 |
if ($itemLevelTypes) { |
| 494 |
$itemLoopIter->{translated_description} = $itemInfo->{translated_description}; |
| 495 |
$itemLoopIter->{itype} = $itemInfo->{itype}; |
| 496 |
$itemLoopIter->{imageurl} = $itemInfo->{imageurl}; |
| 497 |
} |
| 498 |
|
| 499 |
# If the holdingbranch is different than the homebranch, we show the |
| 500 |
# holdingbranch of the document too. |
| 501 |
if ( $itemInfo->{homebranch} ne $itemInfo->{holdingbranch} ) { |
| 502 |
$itemLoopIter->{holdingBranchName} = $itemInfo->{holdingbranch}; |
| 503 |
} |
| 504 |
|
466 |
|
| 505 |
# If the item is currently on loan, we display its return date and |
467 |
my $item_info = $item->unblessed; |
| 506 |
# change the background color. |
468 |
$item_info->{holding_branch} = $item->holding_branch; |
| 507 |
my $issue = Koha::Checkouts->find( { itemnumber => $itemNum } ); |
469 |
$item_info->{home_branch} = $item->home_branch; |
| 508 |
if ( $issue ) { |
470 |
if ($itemLevelTypes) { |
| 509 |
$itemLoopIter->{dateDue} = $issue->date_due; |
471 |
my $itemtype = $item->itemtype; |
| 510 |
$itemLoopIter->{onloan} = 'onloan'; |
472 |
$item_info->{'imageurl'} = getitemtypeimagelocation( 'opac', |
|
|
473 |
$itemtypes->{ $itemtype->itemtype }->{'imageurl'} ); |
| 474 |
$item_info->{'translated_description'} = |
| 475 |
$itemtypes->{ $itemtype->itemtype }->{translated_description}; |
| 511 |
} |
476 |
} |
| 512 |
|
477 |
|
| 513 |
# checking reserve |
478 |
# checking for holds |
| 514 |
my $holds = $item->current_holds; |
479 |
my $holds = $item->current_holds; |
| 515 |
|
|
|
| 516 |
if ( my $first_hold = $holds->next ) { |
480 |
if ( my $first_hold = $holds->next ) { |
| 517 |
$itemLoopIter->{backgroundcolor} = 'reserved'; |
481 |
$item_info->{first_hold} = $first_hold; |
| 518 |
$itemLoopIter->{reservedate} = $first_hold->reservedate, |
|
|
| 519 |
$itemLoopIter->{ExpectedAtLibrary} = $first_hold->branchcode; |
| 520 |
$itemLoopIter->{waitingdate} = $first_hold->waitingdate; |
| 521 |
} |
482 |
} |
| 522 |
|
483 |
|
| 523 |
$itemLoopIter->{notforloan} = $itemInfo->{notforloan}; |
484 |
$item_info->{checkout} = $item->checkout; |
| 524 |
$itemLoopIter->{itemnotforloan} = $itemInfo->{itemnotforloan}; |
|
|
| 525 |
|
| 526 |
# Management of the notforloan document |
| 527 |
if ( $itemLoopIter->{notforloan} || $itemLoopIter->{itemnotforloan}) { |
| 528 |
$itemLoopIter->{backgroundcolor} = 'other'; |
| 529 |
$itemLoopIter->{notforloanvalue} = |
| 530 |
$notforloan_label_of->{ $itemLoopIter->{notforloan} }; |
| 531 |
} |
| 532 |
|
| 533 |
# Management of lost or long overdue items |
| 534 |
if ( $itemInfo->{itemlost} ) { |
| 535 |
|
| 536 |
# FIXME localized strings should never be in Perl code |
| 537 |
$itemLoopIter->{message} = |
| 538 |
$itemInfo->{itemlost} == 1 ? "(lost)" |
| 539 |
: $itemInfo->{itemlost} == 2 ? "(long overdue)" |
| 540 |
: ""; |
| 541 |
$itemInfo->{backgroundcolor} = 'other'; |
| 542 |
} |
| 543 |
|
485 |
|
| 544 |
# Check of the transferred documents |
486 |
# Check of the transferred documents |
| 545 |
my ( $transfertwhen, $transfertfrom, $transfertto ) = |
487 |
my ( $transfertwhen, $transfertfrom, $transfertto ) = |
| 546 |
GetTransfers($itemNum); |
488 |
GetTransfers($item->itemnumber); |
| 547 |
if ( $transfertwhen && ($transfertwhen ne '') ) { |
489 |
if ( $transfertwhen && ($transfertwhen ne '') ) { |
| 548 |
$itemLoopIter->{transfertwhen} = output_pref({ dt => dt_from_string($transfertwhen), dateonly => 1 }); |
490 |
$item_info->{transfertwhen} = $transfertwhen; |
| 549 |
$itemLoopIter->{transfertfrom} = $transfertfrom; |
491 |
$item_info->{transfertfrom} = $transfertfrom; |
| 550 |
$itemLoopIter->{transfertto} = $transfertto; |
492 |
$item_info->{transfertto} = $transfertto; |
| 551 |
$itemLoopIter->{nocancel} = 1; |
493 |
$item_info->{nocancel} = 1; |
| 552 |
} |
494 |
} |
| 553 |
|
495 |
|
| 554 |
# if the items belongs to a host record, show link to host record |
496 |
# if the items belongs to a host record, show link to host record |
| 555 |
if ( $itemInfo->{biblionumber} ne $biblioNum ) { |
497 |
if ( $item_info->{biblionumber} ne $biblioNum ) { |
| 556 |
$itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; |
498 |
$item_info->{hostbiblionumber} = $item->biblionumber; |
| 557 |
$itemLoopIter->{hosttitle} = Koha::Biblios->find( $itemInfo->{biblionumber} )->title; |
499 |
$item_info->{hosttitle} = Koha::Biblios->find( $item_info->{biblionumber} )->title; |
| 558 |
} |
500 |
} |
| 559 |
|
501 |
|
| 560 |
# If there is no loan, return and transfer, we show a checkbox. |
502 |
my $branch = GetReservesControlBranch( $item_info, $patron_unblessed ); |
| 561 |
$itemLoopIter->{notforloan} = $itemLoopIter->{notforloan} || 0; |
|
|
| 562 |
|
| 563 |
my $patron_unblessed = $patron->unblessed; |
| 564 |
my $branch = GetReservesControlBranch( $itemInfo, $patron_unblessed ); |
| 565 |
|
503 |
|
| 566 |
# items_any_available defined outside of the current loop, |
504 |
# items_any_available defined outside of the current loop, |
| 567 |
# so we avoiding loop inside IsAvailableForItemLevelRequest: |
505 |
# so we avoiding loop inside IsAvailableForItemLevelRequest: |
|
Lines 572-604
foreach my $biblioNum (@biblionumbers) {
Link Here
|
| 572 |
if ($policy_holdallowed) { |
510 |
if ($policy_holdallowed) { |
| 573 |
my $opac_hold_policy = Koha::CirculationRules->get_opacitemholds_policy( { item => $item, patron => $patron } ); |
511 |
my $opac_hold_policy = Koha::CirculationRules->get_opacitemholds_policy( { item => $item, patron => $patron } ); |
| 574 |
if ( $opac_hold_policy ne 'N' ) { # If Y or F |
512 |
if ( $opac_hold_policy ne 'N' ) { # If Y or F |
| 575 |
$itemLoopIter->{available} = 1; |
513 |
$item_info->{available} = 1; |
| 576 |
$numCopiesOPACAvailable++; |
514 |
$numCopiesOPACAvailable++; |
| 577 |
$biblioLoopIter{force_hold} = 1 if $opac_hold_policy eq 'F'; |
515 |
$biblioLoopIter{force_hold} = 1 if $opac_hold_policy eq 'F'; |
| 578 |
} |
516 |
} |
| 579 |
$numCopiesAvailable++; |
517 |
$numCopiesAvailable++; |
| 580 |
|
518 |
|
| 581 |
unless ( $can_place_hold_if_available_at_pickup ) { |
519 |
unless ( $can_place_hold_if_available_at_pickup ) { |
| 582 |
my $items_in_this_library = Koha::Items->search({ biblionumber => $itemInfo->{biblionumber}, holdingbranch => $itemInfo->{holdingbranch} }); |
520 |
my $items_in_this_library = Koha::Items->search({ biblionumber => $item->biblionumber, holdingbranch => $item->holdingbranch }); |
| 583 |
my $nb_of_items_issued = $items_in_this_library->search({ 'issue.itemnumber' => { not => undef }}, { join => 'issue' })->count; |
521 |
my $nb_of_items_issued = $items_in_this_library->search({ 'issue.itemnumber' => { not => undef }}, { join => 'issue' })->count; |
| 584 |
if ( $items_in_this_library->count > $nb_of_items_issued ) { |
522 |
if ( $items_in_this_library->count > $nb_of_items_issued ) { |
| 585 |
push @not_available_at, $itemInfo->{holdingbranch}; |
523 |
push @not_available_at, $item->holdingbranch; |
| 586 |
} |
524 |
} |
| 587 |
} |
525 |
} |
| 588 |
} |
526 |
} |
| 589 |
|
527 |
|
| 590 |
$itemLoopIter->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes->{ $itemInfo->{itype} }{imageurl} ); |
528 |
# Show serial enumeration when needed |
| 591 |
|
529 |
if ($item_info->{enumchron}) { |
| 592 |
# Show serial enumeration when needed |
|
|
| 593 |
if ($itemLoopIter->{enumchron}) { |
| 594 |
$itemdata_enumchron = 1; |
530 |
$itemdata_enumchron = 1; |
| 595 |
} |
531 |
} |
| 596 |
# Show collection when needed |
532 |
# Show collection when needed |
| 597 |
if ($itemLoopIter->{ccode}) { |
533 |
if ($item_info->{ccode}) { |
| 598 |
$itemdata_ccode = 1; |
534 |
$itemdata_ccode = 1; |
| 599 |
} |
535 |
} |
| 600 |
|
536 |
|
| 601 |
push @{$biblioLoopIter{itemLoop}}, $itemLoopIter; |
537 |
push @{$biblioLoopIter{itemLoop}}, $item_info; |
| 602 |
} |
538 |
} |
| 603 |
$template->param( |
539 |
$template->param( |
| 604 |
itemdata_enumchron => $itemdata_enumchron, |
540 |
itemdata_enumchron => $itemdata_enumchron, |
| 605 |
- |
|
|