Bug 17736: [Follow-up] Rename to current_holds
[koha.git] / C4 / ILSDI / Services.pm
blob287ac0287bf90f2a5c3dd9708afda5f12dd8e2be
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>.
20 use strict;
21 use warnings;
23 use C4::Members;
24 use C4::Items;
25 use C4::Circulation;
26 use C4::Accounts;
27 use C4::Biblio;
28 use C4::Reserves qw(AddReserve GetReservesFromBorrowernumber CanBookBeReserved CanItemBeReserved IsAvailableForItemLevelRequest);
29 use C4::Context;
30 use C4::AuthoritiesMarc;
31 use XML::Simple;
32 use HTML::Entities;
33 use CGI qw ( -utf8 );
34 use DateTime;
35 use C4::Auth;
36 use C4::Members::Attributes qw(GetBorrowerAttributes);
38 use Koha::Biblios;
39 use Koha::Libraries;
41 =head1 NAME
43 C4::ILS-DI::Services - ILS-DI Services
45 =head1 DESCRIPTION
47 Each function in this module represents an ILS-DI service.
48 They all takes a CGI instance as argument and most of them return a
49 hashref that will be printed by XML::Simple in opac/ilsdi.pl
51 =head1 SYNOPSIS
53 use C4::ILSDI::Services;
54 use XML::Simple;
55 use CGI qw ( -utf8 );
57 my $cgi = new CGI;
59 $out = LookupPatron($cgi);
61 print CGI::header('text/xml');
62 print XMLout($out,
63 noattr => 1,
64 noescape => 1,
65 nosort => 1,
66 xmldecl => '<?xml version="1.0" encoding="UTF-8" ?>',
67 RootName => 'LookupPatron',
68 SuppressEmpty => 1);
70 =cut
72 =head1 FUNCTIONS
74 =head2 GetAvailability
76 Given a set of biblionumbers or itemnumbers, returns a list with
77 availability of the items associated with the identifiers.
79 Parameters:
81 =head3 id (Required)
83 list of either biblionumbers or itemnumbers
85 =head3 id_type (Required)
87 defines the type of record identifier being used in the request,
88 possible values:
90 - bib
91 - item
93 =head3 return_type (Optional)
95 requests a particular level of detail in reporting availability,
96 possible values:
98 - bib
99 - item
101 =head3 return_fmt (Optional)
103 requests a particular format or set of formats in reporting
104 availability
106 =cut
108 sub GetAvailability {
109 my ($cgi) = @_;
111 my $out = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
112 $out .= "<dlf:collection\n";
113 $out .= " xmlns:dlf=\"http://diglib.org/ilsdi/1.1\"\n";
114 $out .= " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
115 $out .= " xsi:schemaLocation=\"http://diglib.org/ilsdi/1.1\n";
116 $out .= " http://diglib.org/architectures/ilsdi/schemas/1.1/dlfexpanded.xsd\">\n";
118 foreach my $id ( split( / /, $cgi->param('id') ) ) {
119 if ( $cgi->param('id_type') eq "item" ) {
120 my ( $biblionumber, $status, $msg, $location ) = _availability($id);
122 $out .= " <dlf:record>\n";
123 $out .= " <dlf:bibliographic id=\"" . ( $biblionumber || $id ) . "\" />\n";
124 $out .= " <dlf:items>\n";
125 $out .= " <dlf:item id=\"" . $id . "\">\n";
126 $out .= " <dlf:simpleavailability>\n";
127 $out .= " <dlf:identifier>" . $id . "</dlf:identifier>\n";
128 $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
129 if ($msg) { $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
130 if ($location) { $out .= " <dlf:location>" . $location . "</dlf:location>\n"; }
131 $out .= " </dlf:simpleavailability>\n";
132 $out .= " </dlf:item>\n";
133 $out .= " </dlf:items>\n";
134 $out .= " </dlf:record>\n";
135 } else {
136 my $status;
137 my $msg;
138 my $items = GetItemnumbersForBiblio($id);
139 if ($items) {
140 # Open XML
141 $out .= " <dlf:record>\n";
142 $out .= " <dlf:bibliographic id=\"" .$id. "\" />\n";
143 $out .= " <dlf:items>\n";
144 # We loop over the items to clean them
145 foreach my $itemnumber (@$items) {
146 my ( $biblionumber, $status, $msg, $location ) = _availability($itemnumber);
147 $out .= " <dlf:item id=\"" . $itemnumber . "\">\n";
148 $out .= " <dlf:simpleavailability>\n";
149 $out .= " <dlf:identifier>" . $itemnumber . "</dlf:identifier>\n";
150 $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
151 if ($msg) { $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
152 if ($location) { $out .= " <dlf:location>" . $location . "</dlf:location>\n"; }
153 $out .= " </dlf:simpleavailability>\n";
154 $out .= " </dlf:item>\n";
156 # Close XML
157 $out .= " </dlf:items>\n";
158 $out .= " </dlf:record>\n";
159 } else {
160 $status = "unknown";
161 $msg = "Error: could not retrieve availability for this ID";
165 $out .= "</dlf:collection>\n";
167 return $out;
170 =head2 GetRecords
172 Given a list of biblionumbers, returns a list of record objects that
173 contain bibliographic information, as well as associated holdings and item
174 information. The caller may request a specific metadata schema for the
175 record objects to be returned.
177 This function behaves similarly to HarvestBibliographicRecords and
178 HarvestExpandedRecords in Data Aggregation, but allows quick, real time
179 lookup by bibliographic identifier.
181 You can use OAI-PMH ListRecords instead of this service.
183 Parameters:
185 - id (Required)
186 list of system record identifiers
187 - id_type (Optional)
188 Defines the metadata schema in which the records are returned,
189 possible values:
190 - MARCXML
192 =cut
194 sub GetRecords {
195 my ($cgi) = @_;
197 # Check if the schema is supported. For now, GetRecords only supports MARCXML
198 if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
199 return { code => 'UnsupportedSchema' };
202 my @records;
204 # Loop over biblionumbers
205 foreach my $biblionumber ( split( / /, $cgi->param('id') ) ) {
207 # Get the biblioitem from the biblionumber
208 my $biblioitem = ( GetBiblioItemByBiblioNumber( $biblionumber, undef ) )[0];
209 if ( not $biblioitem->{'biblionumber'} ) {
210 $biblioitem->{code} = "RecordNotFound";
213 my $embed_items = 1;
214 my $record = GetMarcBiblio($biblionumber, $embed_items);
215 if ($record) {
216 $biblioitem->{marcxml} = $record->as_xml_record();
219 # Get most of the needed data
220 my $biblioitemnumber = $biblioitem->{'biblioitemnumber'};
221 my $biblio = Koha::Biblios->find( $biblionumber );
222 my $holds = $biblio->current_holds->unblessed;
223 my $issues = GetBiblioIssues($biblionumber);
224 my $items = GetItemsByBiblioitemnumber($biblioitemnumber);
226 # We loop over the items to clean them
227 foreach my $item (@$items) {
229 # This hides additionnal XML subfields, we don't need these info
230 delete $item->{'more_subfields_xml'};
232 # Display branch names instead of branch codes
233 my $home_library = Koha::Libraries->find( $item->{homebranch} );
234 my $holding_library = Koha::Libraries->find( $item->{holdingbranch} );
235 $item->{'homebranchname'} = $home_library ? $home_library->branchname : '';
236 $item->{'holdingbranchname'} = $holding_library ? $holding_library->branchname : '';
239 # Hashref building...
240 $biblioitem->{'items'}->{'item'} = $items;
241 $biblioitem->{'reserves'}->{'reserve'} = $holds;
242 $biblioitem->{'issues'}->{'issue'} = $issues;
244 push @records, $biblioitem;
247 return { record => \@records };
250 =head2 GetAuthorityRecords
252 Given a list of authority record identifiers, returns a list of record
253 objects that contain the authority records. The function user may request
254 a specific metadata schema for the record objects.
256 Parameters:
258 - id (Required)
259 list of authority record identifiers
260 - schema (Optional)
261 specifies the metadata schema of records to be returned, possible values:
262 - MARCXML
264 =cut
266 sub GetAuthorityRecords {
267 my ($cgi) = @_;
269 # If the user asks for an unsupported schema, return an error code
270 if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
271 return { code => 'UnsupportedSchema' };
274 my @records;
276 # Let's loop over the authority IDs
277 foreach my $authid ( split( / /, $cgi->param('id') ) ) {
279 # Get the record as XML string, or error code
280 push @records, GetAuthorityXML($authid) || { code => 'RecordNotFound' };
283 return { record => \@records };
286 =head2 LookupPatron
288 Looks up a patron in the ILS by an identifier, and returns the borrowernumber.
290 Parameters:
292 - id (Required)
293 an identifier used to look up the patron in Koha
294 - id_type (Optional)
295 the type of the identifier, possible values:
296 - cardnumber
297 - firstname
298 - userid
299 - borrowernumber
301 =cut
303 sub LookupPatron {
304 my ($cgi) = @_;
306 # Get the borrower...
307 my $borrower = GetMember($cgi->param('id_type') => $cgi->param('id'));
308 if ( not $borrower->{'borrowernumber'} ) {
309 return { message => 'PatronNotFound' };
312 # Build the hashref
313 my $patron->{'id'} = $borrower->{'borrowernumber'};
314 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
316 # ...and return his ID
317 return $patron;
320 =head2 AuthenticatePatron
322 Authenticates a user's login credentials and returns the identifier for
323 the patron.
325 Parameters:
327 - username (Required)
328 user's login identifier (userid or cardnumber)
329 - password (Required)
330 user's password
332 =cut
334 sub AuthenticatePatron {
335 my ($cgi) = @_;
336 my $username = $cgi->param('username');
337 my $password = $cgi->param('password');
338 my ($status, $cardnumber, $userid) = C4::Auth::checkpw( C4::Context->dbh, $username, $password );
339 if ( $status ) {
340 # Get the borrower
341 my $borrower = GetMember( cardnumber => $cardnumber );
342 my $patron->{'id'} = $borrower->{'borrowernumber'};
343 return $patron;
345 else {
346 return { code => 'PatronNotFound' };
350 =head2 GetPatronInfo
352 Returns specified information about the patron, based on options in the
353 request. This function can optionally return patron's contact information,
354 fine information, hold request information, and loan information.
356 Parameters:
358 - patron_id (Required)
359 the borrowernumber
360 - show_contact (Optional, default 1)
361 whether or not to return patron's contact information in the response
362 - show_fines (Optional, default 0)
363 whether or not to return fine information in the response
364 - show_holds (Optional, default 0)
365 whether or not to return hold request information in the response
366 - show_loans (Optional, default 0)
367 whether or not to return loan information request information in the response
369 =cut
371 sub GetPatronInfo {
372 my ($cgi) = @_;
374 # Get Member details
375 my $borrowernumber = $cgi->param('patron_id');
376 my $borrower = GetMember( borrowernumber => $borrowernumber );
377 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
379 # Cleaning the borrower hashref
380 my $flags = C4::Members::patronflags( $borrower );
381 $borrower->{'charges'} = $flags->{'CHARGES'}->{'amount'};
382 my $library = Koha::Libraries->find( $borrower->{branchcode} );
383 $borrower->{'branchname'} = $library ? $library->branchname : '';
384 delete $borrower->{'userid'};
385 delete $borrower->{'password'};
387 # Contact fields management
388 if ( defined $cgi->param('show_contact') && $cgi->param('show_contact') eq "0" ) {
390 # Define contact fields
391 my @contactfields = (
392 'email', 'emailpro', 'fax', 'mobile', 'phone', 'phonepro',
393 'streetnumber', 'zipcode', 'city', 'streettype', 'B_address', 'B_city',
394 'B_email', 'B_phone', 'B_zipcode', 'address', 'address2', 'altcontactaddress1',
395 'altcontactaddress2', 'altcontactaddress3', 'altcontactfirstname', 'altcontactphone', 'altcontactsurname', 'altcontactzipcode'
398 # and delete them
399 foreach my $field (@contactfields) {
400 delete $borrower->{$field};
404 # Fines management
405 if ( $cgi->param('show_fines') && $cgi->param('show_fines') eq "1" ) {
406 my @charges;
407 for ( my $i = 1 ; my @charge = getcharges( $borrowernumber, undef, $i ) ; $i++ ) {
408 push( @charges, @charge );
410 $borrower->{'fines'}->{'fine'} = \@charges;
413 # Reserves management
414 if ( $cgi->param('show_holds') && $cgi->param('show_holds') eq "1" ) {
416 # Get borrower's reserves
417 my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
418 foreach my $reserve (@reserves) {
420 # Get additional informations
421 my $item = GetBiblioFromItemNumber( $reserve->{'itemnumber'}, undef );
422 my $library = Koha::Libraries->find( $reserve->{branchcode} );
423 my $branchname = $library ? $library->branchname : '';
425 # Remove unwanted fields
426 delete $item->{'more_subfields_xml'};
428 # Add additional fields
429 $reserve->{'item'} = $item;
430 $reserve->{'branchname'} = $branchname;
431 $reserve->{'title'} = GetBiblio( $reserve->{'biblionumber'} )->{'title'};
433 $borrower->{'holds'}->{'hold'} = \@reserves;
436 # Issues management
437 if ( $cgi->param('show_loans') && $cgi->param('show_loans') eq "1" ) {
438 my $issues = GetPendingIssues($borrowernumber);
439 foreach my $issue ( @$issues ){
440 $issue->{'issuedate'} = $issue->{'issuedate'}->strftime('%Y-%m-%d %H:%M');
441 $issue->{'date_due'} = $issue->{'date_due'}->strftime('%Y-%m-%d %H:%M');
443 $borrower->{'loans'}->{'loan'} = $issues;
446 if ( $cgi->param('show_attributes') eq "1" ) {
447 my $attrs = GetBorrowerAttributes( $borrowernumber, 0, 1 );
448 $borrower->{'attributes'} = $attrs;
451 return $borrower;
454 =head2 GetPatronStatus
456 Returns a patron's status information.
458 Parameters:
460 - patron_id (Required)
461 the borrower ID
463 =cut
465 sub GetPatronStatus {
466 my ($cgi) = @_;
468 # Get Member details
469 my $borrowernumber = $cgi->param('patron_id');
470 my $borrower = GetMember( borrowernumber => $borrowernumber );
471 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
473 # Return the results
474 return {
475 type => $$borrower{categorycode},
476 status => 0, # TODO
477 expiry => $$borrower{dateexpiry},
481 =head2 GetServices
483 Returns information about the services available on a particular item for
484 a particular patron.
486 Parameters:
488 - patron_id (Required)
489 a borrowernumber
490 - item_id (Required)
491 an itemnumber
493 =cut
495 sub GetServices {
496 my ($cgi) = @_;
498 # Get the member, or return an error code if not found
499 my $borrowernumber = $cgi->param('patron_id');
500 my $borrower = GetMember( borrowernumber => $borrowernumber );
501 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
503 # Get the item, or return an error code if not found
504 my $itemnumber = $cgi->param('item_id');
505 my $item = GetItem( $itemnumber );
506 return { code => 'RecordNotFound' } unless $$item{itemnumber};
508 my @availablefor;
510 # Reserve level management
511 my $biblionumber = $item->{'biblionumber'};
512 my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
513 if ($canbookbereserved eq 'OK') {
514 push @availablefor, 'title level hold';
515 my $canitembereserved = IsAvailableForItemLevelRequest($item, $borrower);
516 if ($canitembereserved) {
517 push @availablefor, 'item level hold';
521 # Reserve cancellation management
522 my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
523 my @reserveditems;
524 foreach my $reserve (@reserves) {
525 push @reserveditems, $reserve->{'itemnumber'};
527 if ( grep { $itemnumber eq $_ } @reserveditems ) {
528 push @availablefor, 'hold cancellation';
531 # Renewal management
532 my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
533 if ( $renewal[0] ) {
534 push @availablefor, 'loan renewal';
537 # Issuing management
538 my $barcode = $item->{'barcode'} || '';
539 $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') );
540 if ($barcode) {
541 my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
543 # TODO push @availablefor, 'loan';
546 my $out;
547 $out->{'AvailableFor'} = \@availablefor;
549 return $out;
552 =head2 RenewLoan
554 Extends the due date for a borrower's existing issue.
556 Parameters:
558 - patron_id (Required)
559 a borrowernumber
560 - item_id (Required)
561 an itemnumber
562 - desired_due_date (Required)
563 the date the patron would like the item returned by
565 =cut
567 sub RenewLoan {
568 my ($cgi) = @_;
570 # Get borrower infos or return an error code
571 my $borrowernumber = $cgi->param('patron_id');
572 my $borrower = GetMember( borrowernumber => $borrowernumber );
573 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
575 # Get the item, or return an error code
576 my $itemnumber = $cgi->param('item_id');
577 my $item = GetItem( $itemnumber );
578 return { code => 'RecordNotFound' } unless $$item{itemnumber};
580 # Add renewal if possible
581 my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
582 if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber ); }
584 my $issue = GetItemIssue($itemnumber);
586 # Hashref building
587 my $out;
588 $out->{'renewals'} = $issue->{'renewals'};
589 $out->{date_due} = $issue->{date_due}->strftime('%Y-%m-%d %H:%S');
590 $out->{'success'} = $renewal[0];
591 $out->{'error'} = $renewal[1];
593 return $out;
596 =head2 HoldTitle
598 Creates, for a borrower, a biblio-level hold reserve.
600 Parameters:
602 - patron_id (Required)
603 a borrowernumber
604 - bib_id (Required)
605 a biblionumber
606 - request_location (Required)
607 IP address where the end user request is being placed
608 - pickup_location (Optional)
609 a branch code indicating the location to which to deliver the item for pickup
610 - needed_before_date (Optional)
611 date after which hold request is no longer needed
612 - pickup_expiry_date (Optional)
613 date after which item returned to shelf if item is not picked up
615 =cut
617 sub HoldTitle {
618 my ($cgi) = @_;
620 # Get the borrower or return an error code
621 my $borrowernumber = $cgi->param('patron_id');
622 my $borrower = GetMember( borrowernumber => $borrowernumber );
623 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
625 # Get the biblio record, or return an error code
626 my $biblionumber = $cgi->param('bib_id');
627 my $biblio = GetBiblio( $biblionumber );
628 return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
630 my $title = $$biblio{title};
632 # Check if the biblio can be reserved
633 return { code => 'NotHoldable' } unless CanBookBeReserved( $borrowernumber, $biblionumber ) eq 'OK';
635 my $branch;
637 # Pickup branch management
638 if ( $cgi->param('pickup_location') ) {
639 $branch = $cgi->param('pickup_location');
640 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
641 } else { # if the request provide no branch, use the borrower's branch
642 $branch = $$borrower{branchcode};
645 # Add the reserve
646 # $branch, $borrowernumber, $biblionumber,
647 # $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
648 # $title, $checkitem, $found
649 my $priority= C4::Reserves::CalculatePriority( $biblionumber );
650 AddReserve( $branch, $borrowernumber, $biblionumber, undef, $priority, undef, undef, undef, $title, undef, undef );
652 # Hashref building
653 my $out;
654 $out->{'title'} = $title;
655 my $library = Koha::Libraries->find( $branch );
656 $out->{'pickup_location'} = $library ? $library->branchname : '';
658 # TODO $out->{'date_available'} = '';
660 return $out;
663 =head2 HoldItem
665 Creates, for a borrower, an item-level hold request on a specific item of
666 a bibliographic record in Koha.
668 Parameters:
670 - patron_id (Required)
671 a borrowernumber
672 - bib_id (Required)
673 a biblionumber
674 - item_id (Required)
675 an itemnumber
676 - pickup_location (Optional)
677 a branch code indicating the location to which to deliver the item for pickup
678 - needed_before_date (Optional)
679 date after which hold request is no longer needed
680 - pickup_expiry_date (Optional)
681 date after which item returned to shelf if item is not picked up
683 =cut
685 sub HoldItem {
686 my ($cgi) = @_;
688 # Get the borrower or return an error code
689 my $borrowernumber = $cgi->param('patron_id');
690 my $borrower = GetMember( borrowernumber => $borrowernumber );
691 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
693 # Get the biblio or return an error code
694 my $biblionumber = $cgi->param('bib_id');
695 my $biblio = GetBiblio($biblionumber);
696 return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
698 my $title = $$biblio{title};
700 # Get the item or return an error code
701 my $itemnumber = $cgi->param('item_id');
702 my $item = GetItem( $itemnumber );
703 return { code => 'RecordNotFound' } unless $$item{itemnumber};
705 # If the biblio does not match the item, return an error code
706 return { code => 'RecordNotFound' } if $$item{biblionumber} ne $$biblio{biblionumber};
708 # Check for item disponibility
709 my $canitembereserved = C4::Reserves::CanItemBeReserved( $borrowernumber, $itemnumber );
710 my $canbookbereserved = C4::Reserves::CanBookBeReserved( $borrowernumber, $biblionumber );
711 return { code => 'NotHoldable' } unless $canbookbereserved eq 'OK' and $canitembereserved eq 'OK';
713 # Pickup branch management
714 my $branch;
715 if ( $cgi->param('pickup_location') ) {
716 $branch = $cgi->param('pickup_location');
717 return { code => 'LocationNotFound' } unless Koha::Libraries->find($branch);
718 } else { # if the request provide no branch, use the borrower's branch
719 $branch = $$borrower{branchcode};
722 # Add the reserve
723 # $branch, $borrowernumber, $biblionumber,
724 # $constraint, $bibitems, $priority, $resdate, $expdate, $notes,
725 # $title, $checkitem, $found
726 my $priority= C4::Reserves::CalculatePriority( $biblionumber );
727 AddReserve( $branch, $borrowernumber, $biblionumber, undef, $priority, undef, undef, undef, $title, $itemnumber, undef );
729 # Hashref building
730 my $out;
731 my $library = Koha::Libraries->find( $branch );
732 $out->{'pickup_location'} = $library ? $library->branchname : '';
734 # TODO $out->{'date_available'} = '';
736 return $out;
739 =head2 CancelHold
741 Cancels an active reserve request for the borrower.
743 Parameters:
745 - patron_id (Required)
746 a borrowernumber
747 - item_id (Required)
748 a reserve_id
750 =cut
752 sub CancelHold {
753 my ($cgi) = @_;
755 # Get the borrower or return an error code
756 my $borrowernumber = $cgi->param('patron_id');
757 my $borrower = GetMember( borrowernumber => $borrowernumber );
758 return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
760 # Get the reserve or return an error code
761 my $reserve_id = $cgi->param('item_id');
762 my $reserve = C4::Reserves::GetReserve($reserve_id);
763 return { code => 'RecordNotFound' } unless $reserve;
764 return { code => 'RecordNotFound' } unless ($reserve->{borrowernumber} == $borrowernumber);
766 C4::Reserves::CancelReserve({reserve_id => $reserve_id});
768 return { code => 'Canceled' };
771 =head2 _availability
773 Returns, for an itemnumber, an array containing availability information.
775 my ($biblionumber, $status, $msg, $location) = _availability($id);
777 =cut
779 sub _availability {
780 my ($itemnumber) = @_;
781 my $item = GetItem( $itemnumber, undef, undef );
783 if ( not $item->{'itemnumber'} ) {
784 return ( undef, 'unknown', 'Error: could not retrieve availability for this ID', undef );
787 my $biblionumber = $item->{'biblioitemnumber'};
788 my $library = Koha::Libraries->find( $item->{holdingbranch} );
789 my $location = $library ? $library->branchname : '';
791 if ( $item->{'notforloan'} ) {
792 return ( $biblionumber, 'not available', 'Not for loan', $location );
793 } elsif ( $item->{'onloan'} ) {
794 return ( $biblionumber, 'not available', 'Checked out', $location );
795 } elsif ( $item->{'itemlost'} ) {
796 return ( $biblionumber, 'not available', 'Item lost', $location );
797 } elsif ( $item->{'withdrawn'} ) {
798 return ( $biblionumber, 'not available', 'Item withdrawn', $location );
799 } elsif ( $item->{'damaged'} ) {
800 return ( $biblionumber, 'not available', 'Item damaged', $location );
801 } else {
802 return ( $biblionumber, 'available', undef, $location );