1 package C4::ILSDI::Services;
3 # Copyright 2009 SARL Biblibre
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use C4::Items qw( get_hostitemnumbers_of );
25 use C4::Circulation qw( CanBookBeRenewed barcodedecode CanBookBeIssued AddRenewal );
27 use C4::Biblio qw( GetMarcBiblio );
28 use C4::Reserves qw( CanBookBeReserved IsAvailableForItemLevelRequest CalculatePriority AddReserve CanItemBeReserved );
34 use Koha::DateUtils qw( dt_from_string );
35 use C4::AuthoritiesMarc qw( GetAuthorityXML );
45 C4::ILS-DI::Services - ILS-DI Services
49 Each function in this module represents an ILS-DI service.
50 They all takes a CGI instance as argument and most of them return a
51 hashref that will be printed by XML::Simple in opac/ilsdi.pl
55 use C4::ILSDI::Services;
61 $out = LookupPatron($cgi);
63 print CGI::header('text/xml');
68 xmldecl => '<?xml version="1.0" encoding="UTF-8" ?>',
69 RootName => 'LookupPatron',
76 =head2 GetAvailability
78 Given a set of biblionumbers or itemnumbers, returns a list with
79 availability of the items associated with the identifiers.
85 list of either biblionumbers or itemnumbers
87 =head3 id_type (Required)
89 defines the type of record identifier being used in the request,
95 =head3 return_type (Optional)
97 requests a particular level of detail in reporting availability,
103 =head3 return_fmt (Optional)
105 requests a particular format or set of formats in reporting
110 sub GetAvailability {
113 my $out = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
114 $out .= "<dlf:collection\n";
115 $out .= " xmlns:dlf=\"http://diglib.org/ilsdi/1.1\"\n";
116 $out .= " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
117 $out .= " xsi:schemaLocation=\"http://diglib.org/ilsdi/1.1\n";
118 $out .= " http://diglib.org/architectures/ilsdi/schemas/1.1/dlfexpanded.xsd\">\n";
120 foreach my $id ( split( / /, $cgi->param('id') ) ) {
121 if ( $cgi->param('id_type') eq "item" ) {
122 my ( $biblionumber, $status, $msg, $location, $itemcallnumber ) = _availability($id);
124 $out .= " <dlf:record>\n";
125 $out .= " <dlf:bibliographic id=\"" . ( $biblionumber || $id ) . "\" />\n";
126 $out .= " <dlf:items>\n";
127 $out .= " <dlf:item id=\"" . $id . "\">\n";
128 $out .= " <dlf:simpleavailability>\n";
129 $out .= " <dlf:identifier>" . $id . "</dlf:identifier>\n";
130 $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
131 if ($msg) { $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
132 if ($location) { $out .= " <dlf:location>" . $location . "</dlf:location>\n"; }
133 if ($itemcallnumber) { $out .= " <dlf:itemcallnumber>" . $itemcallnumber. "</dlf:itemcallnumber>\n"; }
134 $out .= " </dlf:simpleavailability>\n";
135 $out .= " </dlf:item>\n";
136 $out .= " </dlf:items>\n";
137 $out .= " </dlf:record>\n";
141 my $items = Koha::Items->search({ biblionumber => $id });
144 $out .= " <dlf:record>\n";
145 $out .= " <dlf:bibliographic id=\"" .$id. "\" />\n";
146 $out .= " <dlf:items>\n";
147 # We loop over the items to clean them
148 while ( my $item = $items->next ) {
149 my $itemnumber = $item->itemnumber;
150 my ( $biblionumber, $status, $msg, $location, $itemcallnumber ) = _availability($itemnumber);
151 $out .= " <dlf:item id=\"" . $itemnumber . "\">\n";
152 $out .= " <dlf:simpleavailability>\n";
153 $out .= " <dlf:identifier>" . $itemnumber . "</dlf:identifier>\n";
154 $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
155 if ($msg) { $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
156 if ($location) { $out .= " <dlf:location>" . $location . "</dlf:location>\n"; }
157 if ($itemcallnumber) { $out .= " <dlf:itemcallnumber>" . $itemcallnumber. "</dlf:itemcallnumber>\n"; }
158 $out .= " </dlf:simpleavailability>\n";
159 $out .= " </dlf:item>\n";
162 $out .= " </dlf:items>\n";
163 $out .= " </dlf:record>\n";
166 $msg = "Error: could not retrieve availability for this ID";
170 $out .= "</dlf:collection>\n";
177 Given a list of biblionumbers, returns a list of record objects that
178 contain bibliographic information, as well as associated holdings and item
179 information. The caller may request a specific metadata schema for the
180 record objects to be returned.
182 This function behaves similarly to HarvestBibliographicRecords and
183 HarvestExpandedRecords in Data Aggregation, but allows quick, real time
184 lookup by bibliographic identifier.
186 You can use OAI-PMH ListRecords instead of this service.
191 list of system record identifiers
193 Defines the metadata schema in which the records are returned,
202 # Check if the schema is supported. For now, GetRecords only supports MARCXML
203 if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
204 return { code => 'UnsupportedSchema' };
209 # Loop over biblionumbers
210 foreach my $biblionumber ( split( / /, $cgi->param('id') ) ) {
212 # Get the biblioitem from the biblionumber
213 my $biblio = Koha::Biblios->find( $biblionumber );
215 push @records, { code => "RecordNotFound" };
219 my $biblioitem = $biblio->biblioitem->unblessed;
222 my $record = GetMarcBiblio({
223 biblionumber => $biblionumber,
224 embed_items => $embed_items });
226 $biblioitem->{marcxml} = $record->as_xml_record();
229 # Get most of the needed data
230 my $biblioitemnumber = $biblioitem->{'biblioitemnumber'};
231 my $checkouts = Koha::Checkouts->search(
232 { biblionumber => $biblionumber },
235 '+select' => ['item.barcode'],
236 '+as' => ['barcode'],
239 foreach my $checkout (@$checkouts) {
240 delete $checkout->{'borrowernumber'};
242 my @items = $biblio->items->as_list;
244 $biblioitem->{items}->{item} = [];
246 # We loop over the items to clean them
247 foreach my $item (@items) {
248 my %item = %{ $item->unblessed };
250 # This hides additionnal XML subfields, we don't need these info
251 delete $item{'more_subfields_xml'};
253 # Display branch names instead of branch codes
254 my $home_library = $item->home_branch;
255 my $holding_library = $item->holding_branch;
256 $item{'homebranchname'} = $home_library ? $home_library->branchname : '';
257 $item{'holdingbranchname'} = $holding_library ? $holding_library->branchname : '';
259 if ($item->location) {
260 my $authorised_value = Koha::AuthorisedValues->find_by_koha_field({ kohafield => 'items.location', authorised_value => $item->location });
261 if ($authorised_value) {
262 $item{location_description} = $authorised_value->opac_description;
267 my $itemtype = Koha::ItemTypes->find($item->itype);
269 $item{itype_description} = $itemtype->description;
273 my $transfer = $item->get_transfer;
276 datesent => $transfer->datesent,
277 frombranch => $transfer->frombranch,
278 tobranch => $transfer->tobranch,
282 push @{ $biblioitem->{items}->{item} }, \%item;
286 my $holds = $biblio->current_holds->unblessed;
287 foreach my $hold (@$holds) {
288 delete $hold->{'borrowernumber'};
291 # Hashref building...
292 $biblioitem->{'reserves'}->{'reserve'} = $holds;
293 $biblioitem->{'issues'}->{'issue'} = $checkouts;
295 push @records, $biblioitem;
298 return { record => \@records };
301 =head2 GetAuthorityRecords
303 Given a list of authority record identifiers, returns a list of record
304 objects that contain the authority records. The function user may request
305 a specific metadata schema for the record objects.
310 list of authority record identifiers
312 specifies the metadata schema of records to be returned, possible values:
317 sub GetAuthorityRecords {
320 # If the user asks for an unsupported schema, return an error code
321 if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
322 return { code => 'UnsupportedSchema' };
327 # Let's loop over the authority IDs
328 foreach my $authid ( split( / /, $cgi->param('id') ) ) {
330 # Get the record as XML string, or error code
331 push @records, GetAuthorityXML($authid) || { code => 'RecordNotFound' };
334 return { record => \@records };
339 Looks up a patron in the ILS by an identifier, and returns the borrowernumber.
344 an identifier used to look up the patron in Koha
346 the type of the identifier, possible values:
359 my $id = $cgi->param('id');
361 return { message => 'PatronNotFound' };
365 my $passed_id_type = $cgi->param('id_type');
366 if($passed_id_type) {
367 $patrons = Koha::Patrons->search( { $passed_id_type => $id } );
369 foreach my $id_type ('cardnumber', 'userid', 'email', 'borrowernumber',
370 'surname', 'firstname') {
371 $patrons = Koha::Patrons->search( { $id_type => $id } );
372 last if($patrons->count);
375 unless ( $patrons->count ) {
376 return { message => 'PatronNotFound' };
379 return { id => $patrons->next->borrowernumber };
382 =head2 AuthenticatePatron
384 Authenticates a user's login credentials and returns the identifier for
389 - username (Required)
390 user's login identifier (userid or cardnumber)
391 - password (Required)
396 sub AuthenticatePatron {
398 my $username = $cgi->param('username');
399 my $password = $cgi->param('password');
400 my ($status, $cardnumber, $userid) = C4::Auth::checkpw( C4::Context->dbh, $username, $password );
403 C4::Auth::track_login_daily( $userid );
405 my $patron = Koha::Patrons->find( { userid => $userid } );
406 return { id => $patron->borrowernumber };
409 return { code => 'PatronNotFound' };
415 Returns specified information about the patron, based on options in the
416 request. This function can optionally return patron's contact information,
417 fine information, hold request information, and loan information.
421 - patron_id (Required)
423 - show_contact (Optional, default 1)
424 whether or not to return patron's contact information in the response
425 - show_fines (Optional, default 0)
426 whether or not to return fine information in the response
427 - show_holds (Optional, default 0)
428 whether or not to return hold request information in the response
429 - show_loans (Optional, default 0)
430 whether or not to return loan information request information in the response
431 - show_attributes (Optional, default 0)
432 whether or not to return additional patron attributes, when enabled the attributes
433 are limited to those marked as opac visible only.
441 my $borrowernumber = $cgi->param('patron_id');
442 my $patron = Koha::Patrons->find( $borrowernumber );
443 return { code => 'PatronNotFound' } unless $patron;
445 # Cleaning the borrower hashref
446 my $borrower = $patron->unblessed;
447 $borrower->{charges} = sprintf "%.02f", $patron->account->non_issues_charges; # FIXME Formatting should not be done here
448 my $library = Koha::Libraries->find( $borrower->{branchcode} );
449 $borrower->{'branchname'} = $library ? $library->branchname : '';
450 delete $borrower->{'userid'};
451 delete $borrower->{'password'};
453 # Contact fields management
454 if ( defined $cgi->param('show_contact') && $cgi->param('show_contact') eq "0" ) {
456 # Define contact fields
457 my @contactfields = (
458 'email', 'emailpro', 'fax', 'mobile', 'phone', 'phonepro',
459 'streetnumber', 'zipcode', 'city', 'streettype', 'B_address', 'B_city',
460 'B_email', 'B_phone', 'B_zipcode', 'address', 'address2', 'altcontactaddress1',
461 'altcontactaddress2', 'altcontactaddress3', 'altcontactfirstname', 'altcontactphone', 'altcontactsurname', 'altcontactzipcode'
465 foreach my $field (@contactfields) {
466 delete $borrower->{$field};
471 if ( $cgi->param('show_fines') && $cgi->param('show_fines') eq "1" ) {
472 $borrower->{fines}{fine} = $patron->account->lines->unblessed;
475 # Reserves management
476 if ( $cgi->param('show_holds') && $cgi->param('show_holds') eq "1" ) {
478 # Get borrower's reserves
479 my $holds = $patron->holds;
480 while ( my $hold = $holds->next ) {
482 my ( $item, $biblio, $biblioitem ) = ( {}, {}, {} );
483 # Get additional informations
484 if ( $hold->itemnumber ) { # item level holds
485 $item = Koha::Items->find( $hold->itemnumber );
486 $biblio = $item->biblio;
487 $biblioitem = $biblio->biblioitem;
489 # Remove unwanted fields
490 $item = $item->unblessed;
491 delete $item->{more_subfields_xml};
492 $biblio = $biblio->unblessed;
493 $biblioitem = $biblioitem->unblessed;
496 # Add additional fields
497 my $unblessed_hold = $hold->unblessed;
498 $unblessed_hold->{item} = { %$item, %$biblio, %$biblioitem };
499 my $library = Koha::Libraries->find( $hold->branchcode );
500 my $branchname = $library ? $library->branchname : '';
501 $unblessed_hold->{branchname} = $branchname;
502 $biblio = Koha::Biblios->find( $hold->biblionumber ); # Should be $hold->get_biblio
503 $unblessed_hold->{title} = $biblio ? $biblio->title : ''; # Just in case, but should not be needed
505 push @{ $borrower->{holds}{hold} }, $unblessed_hold;
511 if ( $cgi->param('show_loans') && $cgi->param('show_loans') eq "1" ) {
512 my $per_page = $cgi->param('loans_per_page');
513 my $page = $cgi->param('loans_page');
515 my $pending_checkouts = $patron->pending_checkouts;
517 if ($page || $per_page) {
520 $borrower->{total_loans} = $pending_checkouts->count();
521 $pending_checkouts = $pending_checkouts->search(undef, {
528 while ( my $c = $pending_checkouts->next ) {
529 # FIXME We should only retrieve what is needed in the template
530 my $issue = $c->unblessed_all_relateds;
531 delete $issue->{'more_subfields_xml'};
532 push @checkouts, $issue
534 $borrower->{'loans'}->{'loan'} = \@checkouts;
537 my $show_attributes = $cgi->param('show_attributes');
538 if ( $show_attributes && $show_attributes eq "1" ) {
539 # FIXME Regression expected here, we do not retrieve the same field as previously
540 # Waiting for answer on bug 14257 comment 15
541 $borrower->{'attributes'} = [
543 $_->type->opac_display
546 %{ $_->type->unblessed },
547 value => $_->attribute, # Backward compatibility
548 value_description => $_->description, # Awkward retro-compability...
551 } $patron->extended_attributes->search
555 # Add is expired information
556 $borrower->{'is_expired'} = $patron->is_expired ? 1 : 0;
561 =head2 GetPatronStatus
563 Returns a patron's status information.
567 - patron_id (Required)
572 sub GetPatronStatus {
576 my $borrowernumber = $cgi->param('patron_id');
577 my $patron = Koha::Patrons->find( $borrowernumber );
578 return { code => 'PatronNotFound' } unless $patron;
582 type => $patron->categorycode,
584 expiry => $patron->dateexpiry,
590 Returns information about the services available on a particular item for
595 - patron_id (Required)
605 # Get the member, or return an error code if not found
606 my $borrowernumber = $cgi->param('patron_id');
607 my $patron = Koha::Patrons->find( $borrowernumber );
608 return { code => 'PatronNotFound' } unless $patron;
610 my $borrower = $patron->unblessed;
611 # Get the item, or return an error code if not found
612 my $itemnumber = $cgi->param('item_id');
613 my $item = Koha::Items->find($itemnumber);
614 return { code => 'RecordNotFound' } unless $item;
618 # Reserve level management
619 my $biblionumber = $item->biblionumber;
620 my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
621 if ($canbookbereserved->{status} eq 'OK') {
622 push @availablefor, 'title level hold';
623 my $canitembereserved = IsAvailableForItemLevelRequest($item, $patron);
624 if ($canitembereserved) {
625 push @availablefor, 'item level hold';
629 # Reserve cancellation management
630 my $holds = $patron->holds;
632 while ( my $hold = $holds->next ) { # FIXME This could be improved
633 push @reserveditems, $hold->itemnumber;
635 if ( grep { $itemnumber eq $_ } @reserveditems ) {
636 push @availablefor, 'hold cancellation';
640 my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
642 push @availablefor, 'loan renewal';
646 my $barcode = $item->barcode || '';
647 $barcode = barcodedecode($barcode) if $barcode;
649 my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $barcode );
651 # TODO push @availablefor, 'loan';
655 $out->{'AvailableFor'} = \@availablefor;
662 Extends the due date for a borrower's existing issue.
666 - patron_id (Required)
670 - desired_due_date (Required)
671 the date the patron would like the item returned by
678 # Get borrower infos or return an error code
679 my $borrowernumber = $cgi->param('patron_id');
680 my $patron = Koha::Patrons->find( $borrowernumber );
681 return { code => 'PatronNotFound' } unless $patron;
683 # Get the item, or return an error code
684 my $itemnumber = $cgi->param('item_id');
685 my $item = Koha::Items->find($itemnumber);
686 return { code => 'RecordNotFound' } unless $item;
688 # Add renewal if possible
689 my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
690 if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 ); }
692 my $issue = $item->checkout;
693 return unless $issue; # FIXME should be handled
697 $out->{'renewals'} = $issue->renewals;
698 $out->{date_due} = dt_from_string($issue->date_due)->strftime('%Y-%m-%d %H:%M');
699 $out->{'success'} = $renewal[0];
700 $out->{'error'} = $renewal[1];
707 Creates, for a borrower, a biblio-level hold reserve.
711 - patron_id (Required)
715 - request_location (Required)
716 IP address where the end user request is being placed
717 - pickup_location (Optional)
718 a branch code indicating the location to which to deliver the item for pickup
719 - start_date (Optional)
720 date after which hold request is no longer needed if the document has not been made available
721 - expiry_date (Optional)
722 date after which item returned to shelf if item is not picked up
729 # Get the borrower or return an error code
730 my $borrowernumber = $cgi->param('patron_id');
731 my $patron = Koha::Patrons->find( $borrowernumber );
732 return { code => 'PatronNotFound' } unless $patron;
735 # If borrower is restricted return an error code
736 return { code => 'PatronRestricted' } if $patron->is_debarred;
738 # Check for patron expired, category and syspref settings
739 return { code => 'PatronExpired' } if ($patron->category->effective_BlockExpiredPatronOpacActions && $patron->is_expired);
741 # Get the biblio record, or return an error code
742 my $biblionumber = $cgi->param('bib_id');
743 my $biblio = Koha::Biblios->find( $biblionumber );
744 return { code => 'RecordNotFound' } unless $biblio;
746 my @hostitems = get_hostitemnumbers_of($biblionumber);
749 push(@itemnumbers, @hostitems);
752 my $items = Koha::Items->search({ -or => { biblionumber => $biblionumber, itemnumber => { in => \@itemnumbers } } });
754 unless ( $items->count ) {
755 return { code => 'NoItems' };
758 my $title = $biblio ? $biblio->title : '';
760 # Check if the biblio can be reserved
761 my $code = CanBookBeReserved( $borrowernumber, $biblionumber )->{status};
762 return { code => $code } unless ( $code eq 'OK' );
766 # Pickup branch management
767 if ( $cgi->param('pickup_location') ) {
768 $branch = $cgi->param('pickup_location');
769 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
770 } else { # if the request provide no branch, use the borrower's branch
771 $branch = $patron->branchcode;
774 my $destination = Koha::Libraries->find($branch);
775 return { code => 'libraryNotPickupLocation' } unless $destination->pickup_location;
776 return { code => 'cannotBeTransferred' } unless $biblio->can_be_transferred({ to => $destination });
779 if ( $cgi->param('start_date') ) {
780 $resdate = $cgi->param('start_date');
784 if ( $cgi->param('expiry_date') ) {
785 $expdate = $cgi->param('expiry_date');
789 # $branch, $borrowernumber, $biblionumber,
790 # $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
791 # $title, $checkitem, $found
792 my $priority= C4::Reserves::CalculatePriority( $biblionumber );
795 branchcode => $branch,
796 borrowernumber => $borrowernumber,
797 biblionumber => $biblionumber,
798 priority => $priority,
799 reservation_date => $resdate,
800 expiration_date => $expdate,
807 $out->{'title'} = $title;
808 my $library = Koha::Libraries->find( $branch );
809 $out->{'pickup_location'} = $library ? $library->branchname : '';
811 # TODO $out->{'date_available'} = '';
818 Creates, for a borrower, an item-level hold request on a specific item of
819 a bibliographic record in Koha.
823 - patron_id (Required)
829 - pickup_location (Optional)
830 a branch code indicating the location to which to deliver the item for pickup
831 - start_date (Optional)
832 date after which hold request is no longer needed if the item has not been made available
833 - expiry_date (Optional)
834 date after which item returned to shelf if item is not picked up
841 # Get the borrower or return an error code
842 my $borrowernumber = $cgi->param('patron_id');
843 my $patron = Koha::Patrons->find( $borrowernumber );
844 return { code => 'PatronNotFound' } unless $patron;
846 # If borrower is restricted return an error code
847 return { code => 'PatronRestricted' } if $patron->is_debarred;
849 # Check for patron expired, category and syspref settings
850 return { code => 'PatronExpired' } if ($patron->category->effective_BlockExpiredPatronOpacActions && $patron->is_expired);
852 # Get the biblio or return an error code
853 my $biblionumber = $cgi->param('bib_id');
854 my $biblio = Koha::Biblios->find( $biblionumber );
855 return { code => 'RecordNotFound' } unless $biblio;
857 my $title = $biblio ? $biblio->title : '';
859 # Get the item or return an error code
860 my $itemnumber = $cgi->param('item_id');
861 my $item = Koha::Items->find($itemnumber);
862 return { code => 'RecordNotFound' } unless $item;
864 # If the biblio does not match the item, return an error code
865 return { code => 'RecordNotFound' } if $item->biblionumber ne $biblio->biblionumber;
867 # Pickup branch management
869 if ( $cgi->param('pickup_location') ) {
870 $branch = $cgi->param('pickup_location');
871 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
872 } else { # if the request provide no branch, use the borrower's branch
873 $branch = $patron->branchcode;
876 # Check for item disponibility
877 my $canitembereserved = C4::Reserves::CanItemBeReserved( $patron, $item, $branch )->{status};
878 return { code => $canitembereserved } unless $canitembereserved eq 'OK';
881 if ( $cgi->param('start_date') ) {
882 $resdate = $cgi->param('start_date');
886 if ( $cgi->param('expiry_date') ) {
887 $expdate = $cgi->param('expiry_date');
891 my $priority = C4::Reserves::CalculatePriority($biblionumber);
894 branchcode => $branch,
895 borrowernumber => $borrowernumber,
896 biblionumber => $biblionumber,
897 priority => $priority,
898 reservation_date => $resdate,
899 expiration_date => $expdate,
901 itemnumber => $itemnumber,
907 my $library = Koha::Libraries->find( $branch );
908 $out->{'pickup_location'} = $library ? $library->branchname : '';
910 # TODO $out->{'date_available'} = '';
917 Cancels an active reserve request for the borrower.
921 - patron_id (Required)
931 # Get the borrower or return an error code
932 my $borrowernumber = $cgi->param('patron_id');
933 my $patron = Koha::Patrons->find( $borrowernumber );
934 return { code => 'PatronNotFound' } unless $patron;
936 # Get the reserve or return an error code
937 my $reserve_id = $cgi->param('item_id');
938 my $hold = Koha::Holds->find( $reserve_id );
939 return { code => 'RecordNotFound' } unless $hold;
940 return { code => 'RecordNotFound' } unless ($hold->borrowernumber == $borrowernumber);
944 return { code => 'Canceled' };
949 Returns, for an itemnumber, an array containing availability information.
951 my ($biblionumber, $status, $msg, $location) = _availability($id);
956 my ($itemnumber) = @_;
957 my $item = Koha::Items->find($itemnumber);
960 return ( undef, 'unknown', 'Error: could not retrieve availability for this ID', undef );
963 my $biblionumber = $item->biblioitemnumber;
964 my $library = Koha::Libraries->find( $item->holdingbranch );
965 my $location = $library ? $library->branchname : '';
966 my $itemcallnumber = $item->itemcallnumber;
968 if ( $item->notforloan ) {
969 return ( $biblionumber, 'not available', 'Not for loan', $location, $itemcallnumber );
970 } elsif ( $item->onloan ) {
971 return ( $biblionumber, 'not available', 'Checked out', $location, $itemcallnumber );
972 } elsif ( $item->itemlost ) {
973 return ( $biblionumber, 'not available', 'Item lost', $location, $itemcallnumber );
974 } elsif ( $item->withdrawn ) {
975 return ( $biblionumber, 'not available', 'Item withdrawn', $location, $itemcallnumber );
976 } elsif ( $item->damaged ) {
977 return ( $biblionumber, 'not available', 'Item damaged', $location, $itemcallnumber );
979 return ( $biblionumber, 'available', undef, $location, $itemcallnumber );