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::Reserves qw( CanBookBeReserved IsAvailableForItemLevelRequest CalculatePriority AddReserve CanItemBeReserved CanReserveBeCanceledFromOpac );
33 use Koha::DateUtils qw( dt_from_string );
34 use C4::AuthoritiesMarc qw( GetAuthorityXML );
38 use Koha::I18N qw(__);
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;
221 my $record = $biblio->metadata->record({ embed_items => 1 });
223 $biblioitem->{marcxml} = $record->as_xml_record();
226 # Get most of the needed data
227 my $biblioitemnumber = $biblioitem->{'biblioitemnumber'};
228 my $checkouts = Koha::Checkouts->search(
229 { biblionumber => $biblionumber },
232 '+select' => ['item.barcode'],
233 '+as' => ['barcode'],
236 foreach my $checkout (@$checkouts) {
237 delete $checkout->{'borrowernumber'};
239 my @items = $biblio->items->as_list;
241 $biblioitem->{items}->{item} = [];
243 # We loop over the items to clean them
244 foreach my $item (@items) {
245 my %item = %{ $item->unblessed };
247 # This hides additionnal XML subfields, we don't need these info
248 delete $item{'more_subfields_xml'};
250 # Display branch names instead of branch codes
251 my $home_library = $item->home_branch;
252 my $holding_library = $item->holding_branch;
253 $item{'homebranchname'} = $home_library ? $home_library->branchname : '';
254 $item{'holdingbranchname'} = $holding_library ? $holding_library->branchname : '';
256 if ($item->location) {
257 my $authorised_value = Koha::AuthorisedValues->find_by_koha_field({ kohafield => 'items.location', authorised_value => $item->location });
258 if ($authorised_value) {
259 $item{location_description} = $authorised_value->opac_description;
264 my $itemtype = Koha::ItemTypes->find($item->itype);
266 $item{itype_description} = $itemtype->description;
270 my $transfer = $item->get_transfer;
273 datesent => $transfer->datesent,
274 frombranch => $transfer->frombranch,
275 tobranch => $transfer->tobranch,
279 push @{ $biblioitem->{items}->{item} }, \%item;
283 my $holds = $biblio->current_holds->unblessed;
284 foreach my $hold (@$holds) {
285 delete $hold->{'borrowernumber'};
288 # Hashref building...
289 $biblioitem->{'reserves'}->{'reserve'} = $holds;
290 $biblioitem->{'issues'}->{'issue'} = $checkouts;
292 push @records, $biblioitem;
295 return { record => \@records };
298 =head2 GetAuthorityRecords
300 Given a list of authority record identifiers, returns a list of record
301 objects that contain the authority records. The function user may request
302 a specific metadata schema for the record objects.
307 list of authority record identifiers
309 specifies the metadata schema of records to be returned, possible values:
314 sub GetAuthorityRecords {
317 # If the user asks for an unsupported schema, return an error code
318 if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
319 return { code => 'UnsupportedSchema' };
324 # Let's loop over the authority IDs
325 foreach my $authid ( split( / /, $cgi->param('id') ) ) {
327 # Get the record as XML string, or error code
328 push @records, GetAuthorityXML($authid) || { code => 'RecordNotFound' };
331 return { record => \@records };
336 Looks up a patron in the ILS by an identifier, and returns the borrowernumber.
341 an identifier used to look up the patron in Koha
343 the type of the identifier, possible values:
356 my $id = $cgi->param('id');
358 return { message => 'PatronNotFound' };
362 my $passed_id_type = $cgi->param('id_type');
363 if($passed_id_type) {
364 $patrons = Koha::Patrons->search( { $passed_id_type => $id } );
366 foreach my $id_type ('cardnumber', 'userid', 'email', 'borrowernumber',
367 'surname', 'firstname') {
368 $patrons = Koha::Patrons->search( { $id_type => $id } );
369 last if($patrons->count);
372 unless ( $patrons->count ) {
373 return { message => 'PatronNotFound' };
376 return { id => $patrons->next->borrowernumber };
379 =head2 AuthenticatePatron
381 Authenticates a user's login credentials and returns the identifier for
386 - username (Required)
387 user's login identifier (userid or cardnumber)
388 - password (Required)
393 sub AuthenticatePatron {
395 my $username = $cgi->param('username');
396 my $password = $cgi->param('password');
397 my ($status, $cardnumber, $userid) = C4::Auth::checkpw( $username, $password );
398 if ( $status == 1 ) {
400 my $patron = Koha::Patrons->find( { userid => $userid } );
402 $patron->update_lastseen('connection');
403 return { id => $patron->borrowernumber };
405 elsif ( $status == -2 ){
406 return { code => 'PasswordExpired' };
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'};
533 # Is the item already on hold by another user?
534 $issue->{'holds_on_item'} = Koha::Holds->search( { itemnumber => $issue->{'itemnumber'} } )->count;
536 # Is the record (next available item) on hold by another user?
537 $issue->{'holds_on_record'} = Koha::Holds->search( { biblionumber => $issue->{'biblionumber'} } )->count;
539 push @checkouts, $issue
541 $borrower->{'loans'}->{'loan'} = \@checkouts;
544 my $show_attributes = $cgi->param('show_attributes');
545 if ( $show_attributes && $show_attributes eq "1" ) {
546 # FIXME Regression expected here, we do not retrieve the same field as previously
547 # Waiting for answer on bug 14257 comment 15
548 $borrower->{'attributes'} = [
550 $_->type->opac_display
553 %{ $_->type->unblessed },
554 value => $_->attribute, # Backward compatibility
555 value_description => $_->description, # Awkward retro-compability...
558 } $patron->extended_attributes->search->as_list
562 # Add is expired information
563 $borrower->{'is_expired'} = $patron->is_expired ? 1 : 0;
568 =head2 GetPatronStatus
570 Returns a patron's status information.
574 - patron_id (Required)
579 sub GetPatronStatus {
583 my $borrowernumber = $cgi->param('patron_id');
584 my $patron = Koha::Patrons->find( $borrowernumber );
585 return { code => 'PatronNotFound' } unless $patron;
589 type => $patron->categorycode,
591 expiry => $patron->dateexpiry,
597 Returns information about the services available on a particular item for
602 - patron_id (Required)
612 # Get the member, or return an error code if not found
613 my $borrowernumber = $cgi->param('patron_id');
614 my $patron = Koha::Patrons->find( $borrowernumber );
615 return { code => 'PatronNotFound' } unless $patron;
617 my $borrower = $patron->unblessed;
618 # Get the item, or return an error code if not found
619 my $itemnumber = $cgi->param('item_id');
620 my $item = Koha::Items->find($itemnumber);
621 return { code => 'RecordNotFound' } unless $item;
625 # Reserve level management
626 my $biblionumber = $item->biblionumber;
627 my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
628 if ($canbookbereserved->{status} eq 'OK') {
629 push @availablefor, 'title level hold';
630 my $canitembereserved = IsAvailableForItemLevelRequest($item, $patron);
631 if ($canitembereserved) {
632 push @availablefor, 'item level hold';
636 # Reserve cancellation management
637 my $holds = $patron->holds;
639 while ( my $hold = $holds->next ) { # FIXME This could be improved
640 push @reserveditems, $hold->itemnumber;
642 if ( grep { $itemnumber eq $_ } @reserveditems ) {
643 push @availablefor, 'hold cancellation';
647 my @renewal = CanBookBeRenewed( $patron, $item->checkout ); # TODO: Error if issue not found?
649 push @availablefor, 'loan renewal';
653 my $barcode = $item->barcode || '';
654 $barcode = barcodedecode($barcode) if $barcode;
656 my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $barcode );
658 # TODO push @availablefor, 'loan';
662 $out->{'AvailableFor'} = \@availablefor;
669 Extends the due date for a borrower's existing issue.
673 - patron_id (Required)
677 - desired_due_date (Required)
678 the date the patron would like the item returned by
685 # Get borrower infos or return an error code
686 my $borrowernumber = $cgi->param('patron_id');
687 my $patron = Koha::Patrons->find( $borrowernumber );
688 return { code => 'PatronNotFound' } unless $patron;
690 # Get the item, or return an error code
691 my $itemnumber = $cgi->param('item_id'); # TODO: Refactor and send issue_id instead?
692 my $item = Koha::Items->find($itemnumber);
694 return { code => 'RecordNotFound' } unless $item;
696 my $issue = $item->checkout;
697 return unless $issue; # FIXME should be handled
699 # Add renewal if possible
700 my @renewal = CanBookBeRenewed( $patron, $issue );
704 borrowernumber => $borrowernumber,
705 itemnumber => $itemnumber,
713 $out->{'renewals'} = $issue->renewals_count;
714 # FIXME Unusual date formatting
715 $out->{date_due} = dt_from_string($issue->date_due)->strftime('%Y-%m-%d %H:%M');
716 $out->{'success'} = $renewal[0];
717 $out->{'error'} = $renewal[1];
724 Creates, for a borrower, a biblio-level hold reserve.
728 - patron_id (Required)
732 - request_location (Required)
733 IP address where the end user request is being placed
734 - pickup_location (Optional)
735 a branch code indicating the location to which to deliver the item for pickup
736 - start_date (Optional)
737 date after which hold request is no longer needed if the document has not been made available
738 - expiry_date (Optional)
739 date after which item returned to shelf if item is not picked up
746 # Get the borrower or return an error code
747 my $borrowernumber = $cgi->param('patron_id');
748 my $patron = Koha::Patrons->find( $borrowernumber );
749 return { code => 'PatronNotFound' } unless $patron;
752 # If borrower is restricted return an error code
753 return { code => 'PatronRestricted' } if $patron->is_debarred;
755 # Check for patron expired, category and syspref settings
756 return { code => 'PatronExpired' } if ($patron->category->effective_BlockExpiredPatronOpacActions && $patron->is_expired);
758 # Get the biblio record, or return an error code
759 my $biblionumber = $cgi->param('bib_id');
760 my $biblio = Koha::Biblios->find( $biblionumber );
761 return { code => 'RecordNotFound' } unless $biblio;
763 my @hostitems = get_hostitemnumbers_of($biblionumber);
766 push(@itemnumbers, @hostitems);
769 my $items = Koha::Items->search({ -or => { biblionumber => $biblionumber, itemnumber => { in => \@itemnumbers } } });
771 unless ( $items->count ) {
772 return { code => 'NoItems' };
775 my $title = $biblio ? $biblio->title : '';
777 # Check if the biblio can be reserved
778 my $code = CanBookBeReserved( $borrowernumber, $biblionumber )->{status};
779 return { code => $code } unless ( $code eq 'OK' );
783 # Pickup branch management
784 if ( $cgi->param('pickup_location') ) {
785 $branch = $cgi->param('pickup_location');
786 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
787 } else { # if the request provide no branch, use the borrower's branch
788 $branch = $patron->branchcode;
791 my $destination = Koha::Libraries->find($branch);
792 return { code => 'libraryNotPickupLocation' } unless $destination->pickup_location;
793 return { code => 'cannotBeTransferred' } unless $biblio->can_be_transferred({ to => $destination });
795 my $resdate = $cgi->param('start_date');
796 my $expdate = $cgi->param('expiry_date');
799 # $branch, $borrowernumber, $biblionumber,
800 # $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
801 # $title, $checkitem, $found
802 my $priority= C4::Reserves::CalculatePriority( $biblionumber );
805 branchcode => $branch,
806 borrowernumber => $borrowernumber,
807 biblionumber => $biblionumber,
808 priority => $priority,
809 reservation_date => $resdate,
810 expiration_date => $expdate,
817 $out->{'title'} = $title;
818 my $library = Koha::Libraries->find( $branch );
819 $out->{'pickup_location'} = $library ? $library->branchname : '';
821 # TODO $out->{'date_available'} = '';
828 Creates, for a borrower, an item-level hold request on a specific item of
829 a bibliographic record in Koha.
833 - patron_id (Required)
839 - pickup_location (Optional)
840 a branch code indicating the location to which to deliver the item for pickup
841 - start_date (Optional)
842 date after which hold request is no longer needed if the item has not been made available
843 - expiry_date (Optional)
844 date after which item returned to shelf if item is not picked up
851 # Get the borrower or return an error code
852 my $borrowernumber = $cgi->param('patron_id');
853 my $patron = Koha::Patrons->find( $borrowernumber );
854 return { code => 'PatronNotFound' } unless $patron;
856 # If borrower is restricted return an error code
857 return { code => 'PatronRestricted' } if $patron->is_debarred;
859 # Check for patron expired, category and syspref settings
860 return { code => 'PatronExpired' } if ($patron->category->effective_BlockExpiredPatronOpacActions && $patron->is_expired);
862 # Get the biblio or return an error code
863 my $biblionumber = $cgi->param('bib_id');
864 my $biblio = Koha::Biblios->find( $biblionumber );
865 return { code => 'RecordNotFound' } unless $biblio;
867 my $title = $biblio ? $biblio->title : '';
869 # Get the item or return an error code
870 my $itemnumber = $cgi->param('item_id');
871 my $item = Koha::Items->find($itemnumber);
872 return { code => 'RecordNotFound' } unless $item;
874 # If the biblio does not match the item, return an error code
875 return { code => 'RecordNotFound' } if $item->biblionumber ne $biblio->biblionumber;
877 # Pickup branch management
879 if ( $cgi->param('pickup_location') ) {
880 $branch = $cgi->param('pickup_location');
881 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
882 } else { # if the request provide no branch, use the borrower's branch
883 $branch = $patron->branchcode;
886 # Check for item disponibility
887 my $canitembereserved = C4::Reserves::CanItemBeReserved( $patron, $item, $branch )->{status};
888 return { code => $canitembereserved } unless $canitembereserved eq 'OK';
890 my $resdate = $cgi->param('start_date');
891 my $expdate = $cgi->param('expiry_date');
894 my $priority = C4::Reserves::CalculatePriority($biblionumber);
897 branchcode => $branch,
898 borrowernumber => $borrowernumber,
899 biblionumber => $biblionumber,
900 priority => $priority,
901 reservation_date => $resdate,
902 expiration_date => $expdate,
904 itemnumber => $itemnumber,
910 my $library = Koha::Libraries->find( $branch );
911 $out->{'pickup_location'} = $library ? $library->branchname : '';
913 # TODO $out->{'date_available'} = '';
920 Cancels an active reserve request for the borrower.
924 - patron_id (Required)
934 # Get the borrower or return an error code
935 my $borrowernumber = $cgi->param('patron_id');
936 my $patron = Koha::Patrons->find( $borrowernumber );
937 return { code => 'PatronNotFound' } unless $patron;
939 # Get the reserve or return an error code
940 my $reserve_id = $cgi->param('item_id');
941 my $hold = Koha::Holds->find( $reserve_id );
942 return { code => 'RecordNotFound' } unless $hold;
944 # Check if reserve belongs to the borrower and if it is in a state which allows cancellation
945 return { code => 'BorrowerCannotCancelHold' } unless CanReserveBeCanceledFromOpac( $reserve_id, $borrowernumber );
949 return { code => 'Canceled' };
954 Returns, for an itemnumber, an array containing availability information.
956 my ($biblionumber, $status, $msg, $location) = _availability($id);
961 my ($itemnumber) = @_;
962 my $item = Koha::Items->find($itemnumber);
965 return ( undef, __('unknown'), __('Error: could not retrieve availability for this ID'), undef );
968 my $biblionumber = $item->biblioitemnumber;
969 my $library = Koha::Libraries->find( $item->holdingbranch );
970 my $location = $library ? $library->branchname : '';
971 my $itemcallnumber = $item->itemcallnumber;
973 if ( $item->is_notforloan ) {
974 return ( $biblionumber, __('not available'), __('Not for loan'), $location, $itemcallnumber );
975 } elsif ( $item->onloan ) {
976 return ( $biblionumber, __('not available'), __('Checked out'), $location, $itemcallnumber );
977 } elsif ( $item->itemlost ) {
978 return ( $biblionumber, __('not available'), __('Item lost'), $location, $itemcallnumber );
979 } elsif ( $item->withdrawn ) {
980 return ( $biblionumber, __('not available'), __('Item withdrawn'), $location, $itemcallnumber );
981 } elsif ( $item->damaged ) {
982 return ( $biblionumber, __('not available'), __('Item damaged'), $location, $itemcallnumber );
984 return ( $biblionumber, __('available'), undef, $location, $itemcallnumber );