File Coverage

File:C4/ILSDI/Services.pm
Coverage:14.4%

linestmtbrancondsubtimecode
1package C4::ILSDI::Services;
2
3# Copyright 2009 SARL Biblibre
4#
5# This file is part of Koha.
6#
7# Koha is free software; you can redistribute it and/or modify it under the
8# terms of the GNU General Public License as published by the Free Software
9# Foundation; either version 2 of the License, or (at your option) any later
10# version.
11#
12# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with Koha; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
4
4
4
49283
43
171
use strict;
21
4
4
4
46
33
162
use warnings;
22
23
4
4
4
406
7
1986
use C4::Members;
24
4
4
4
34
4
827
use C4::Items;
25
4
4
4
16
3
908
use C4::Circulation;
26
4
4
4
15
3
454
use C4::Branch;
27
4
4
4
21
10
710
use C4::Accounts;
28
4
4
4
25
9
1945
use C4::Biblio;
29
4
4
4
24
8
407
use C4::Reserves qw(AddReserve CancelReserve GetReservesFromBiblionumber GetReservesFromBorrowernumber);
30
4
4
4
21
9
53
use C4::Context;
31
4
4
4
636
10
1178
use C4::AuthoritiesMarc;
32
4
4
4
899
9
438
use C4::ILSDI::Utility;
33
4
4
4
21
6
47
use XML::Simple;
34
4
4
4
29554
20306
331
use HTML::Entities;
35
4
4
4
520
33074
168
use CGI;
36
37 - 66
=head1 NAME

C4::ILS-DI::Services - ILS-DI Services

=head1 DESCRIPTION

Each function in this module represents an ILS-DI service.
They all takes a CGI instance as argument and most of them return a 
hashref that will be printed by XML::Simple in opac/ilsdi.pl

=head1 SYNOPSIS

	use C4::ILSDI::Services;
	use XML::Simple;
	use CGI;

	my $cgi = new CGI;

	$out = LookupPatron($cgi);

	print CGI::header('text/xml');
	print XMLout($out,
		noattr => 1, 
		noescape => 1,
		nosort => 1,
		xmldecl => '<?xml version="1.0" encoding="ISO-8859-1" ?>', 
		RootName => 'LookupPatron', 
		SuppressEmpty => 1);

=cut
67
68 - 102
=head1 FUNCTIONS

=head2 GetAvailability

Given a set of biblionumbers or itemnumbers, returns a list with 
availability of the items associated with the identifiers.

Parameters:

=head3 id (Required)

list of either biblionumbers or itemnumbers

=head3 id_type (Required)

defines the type of record identifier being used in the request, 
possible values:

  - bib
  - item

=head3 return_type (Optional)

requests a particular level of detail in reporting availability, 
possible values:

  - bib
  - item

=head3 return_fmt (Optional)

requests a particular format or set of formats in reporting 
availability 

=cut
103
104sub GetAvailability {
105
0
    my ($cgi) = @_;
106
107
0
    my $out = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
108
0
    $out .= "<dlf:collection\n";
109
0
    $out .= " xmlns:dlf=\"http://diglib.org/ilsdi/1.1\"\n";
110
0
    $out .= " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
111
0
    $out .= " xsi:schemaLocation=\"http://diglib.org/ilsdi/1.1\n";
112
0
    $out .= " http://diglib.org/architectures/ilsdi/schemas/1.1/dlfexpanded.xsd\">\n";
113
114
0
    foreach my $id ( split( / /, $cgi->param('id') ) ) {
115
0
        if ( $cgi->param('id_type') eq "item" ) {
116
0
            my ( $biblionumber, $status, $msg, $location ) = Availability($id);
117
118
0
            $out .= " <dlf:record>\n";
119
0
            $out .= " <dlf:bibliographic id=\"" . ( $biblionumber || $id ) . "\" />\n";
120
0
            $out .= " <dlf:items>\n";
121
0
            $out .= " <dlf:item id=\"" . $id . "\">\n";
122
0
            $out .= " <dlf:simpleavailability>\n";
123
0
            $out .= " <dlf:identifier>" . $id . "</dlf:identifier>\n";
124
0
            $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
125
0
0
            if ($msg) { $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
126
0
0
            if ($location) { $out .= " <dlf:location>" . $location . "</dlf:location>\n"; }
127
0
            $out .= " </dlf:simpleavailability>\n";
128
0
            $out .= " </dlf:item>\n";
129
0
            $out .= " </dlf:items>\n";
130
0
            $out .= " </dlf:record>\n";
131        } else {
132
0
            my $status;
133
0
            my $msg;
134
0
            my $biblioitem = ( GetBiblioItemByBiblioNumber( $id, undef ) )[0];
135
0
            if ($biblioitem) {
136
137            } else {
138
0
                $status = "unknown";
139
0
                $msg = "Error: could not retrieve availability for this ID";
140            }
141
0
            $out .= " <dlf:record>\n";
142
0
            $out .= " <dlf:bibliographic id=\"" . $id . "\" />\n";
143
0
            $out .= " <dlf:simpleavailability>\n";
144
0
            $out .= " <dlf:identifier>" . $id . "</dlf:identifier>\n";
145
0
            $out .= " <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
146
0
            $out .= " <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n";
147
0
            $out .= " </dlf:simpleavailability>\n";
148
0
            $out .= " </dlf:record>\n";
149        }
150    }
151
0
    $out .= "</dlf:collection>\n";
152
153
0
    return $out;
154}
155
156 - 178
=head2 GetRecords

Given a list of biblionumbers, returns a list of record objects that 
contain bibliographic information, as well as associated holdings and item
information. The caller may request a specific metadata schema for the 
record objects to be returned.

This function behaves similarly to HarvestBibliographicRecords and 
HarvestExpandedRecords in Data Aggregation, but allows quick, real time 
lookup by bibliographic identifier.

You can use OAI-PMH ListRecords instead of this service.

Parameters:

  - id (Required)
	list of system record identifiers
  - id_type (Optional)
	Defines the metadata schema in which the records are returned, 
	possible values:
  	  - MARCXML

=cut
179
180sub GetRecords {
181
0
    my ($cgi) = @_;
182
183    # Check if the schema is supported. For now, GetRecords only supports MARCXML
184
0
    if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
185
0
        return { code => 'UnsupportedSchema' };
186    }
187
188
0
    my @records;
189
190    # Loop over biblionumbers
191
0
    foreach my $biblionumber ( split( / /, $cgi->param('id') ) ) {
192
193        # Get the biblioitem from the biblionumber
194
0
        my $biblioitem = ( GetBiblioItemByBiblioNumber( $biblionumber, undef ) )[0];
195
0
        if ( not $biblioitem->{'biblionumber'} ) {
196
0
            $biblioitem->{code} = "RecordNotFound";
197        }
198
199        # We don't want MARC to be displayed
200
0
        delete $biblioitem->{'marc'};
201
202        # Get most of the needed data
203
0
        my $biblioitemnumber = $biblioitem->{'biblioitemnumber'};
204
0
        my @reserves = GetReservesFromBiblionumber( $biblionumber, undef, undef );
205
0
        my $issues = GetBiblioIssues($biblionumber);
206
0
        my $items = GetItemsByBiblioitemnumber($biblioitemnumber);
207
208        # We loop over the items to clean them
209
0
        foreach my $item (@$items) {
210
211            # This hides additionnal XML subfields, we don't need these info
212
0
            delete $item->{'more_subfields_xml'};
213
214            # Display branch names instead of branch codes
215
0
            $item->{'homebranchname'} = GetBranchName( $item->{'homebranch'} );
216
0
            $item->{'holdingbranchname'} = GetBranchName( $item->{'holdingbranch'} );
217        }
218
219        # Hashref building...
220
0
        $biblioitem->{'items'}->{'item'} = $items;
221
0
        $biblioitem->{'reserves'}->{'reserve'} = $reserves[1];
222
0
        $biblioitem->{'issues'}->{'issue'} = $issues;
223
224
0
        push @records, $biblioitem;
225    }
226
227
0
    return { record => \@records };
228}
229
230 - 244
=head2 GetAuthorityRecords

Given a list of authority record identifiers, returns a list of record 
objects that contain the authority records. The function user may request 
a specific metadata schema for the record objects.

Parameters:

  - id (Required)
    list of authority record identifiers
  - schema (Optional)
    specifies the metadata schema of records to be returned, possible values:
      - MARCXML

=cut
245
246sub GetAuthorityRecords {
247
0
    my ($cgi) = @_;
248
249    # If the user asks for an unsupported schema, return an error code
250
0
    if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
251
0
        return { code => 'UnsupportedSchema' };
252    }
253
254
0
    my @records;
255
256    # Let's loop over the authority IDs
257
0
    foreach my $authid ( split( / /, $cgi->param('id') ) ) {
258
259        # Get the record as XML string, or error code
260
0
        push @records, GetAuthorityXML($authid) || { code => 'RecordNotFound' };
261    }
262
263
0
    return { record => \@records };
264}
265
266 - 281
=head2 LookupPatron

Looks up a patron in the ILS by an identifier, and returns the borrowernumber.

Parameters:

  - id (Required)
	an identifier used to look up the patron in Koha
  - id_type (Optional)
	the type of the identifier, possible values:
	- cardnumber
	- firstname
	- userid
	- borrowernumber

=cut
282
283sub LookupPatron {
284
0
    my ($cgi) = @_;
285
286    # Get the borrower...
287
0
    my $borrower = GetMember($cgi->param('id_type') => $cgi->param('id'));
288
0
    if ( not $borrower->{'borrowernumber'} ) {
289
0
        return { message => 'PatronNotFound' };
290    }
291
292    # Build the hashref
293
0
    my $patron->{'id'} = $borrower->{'borrowernumber'};
294
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
295
296    # ...and return his ID
297
0
    return $patron;
298}
299
300 - 312
=head2 AuthenticatePatron

Authenticates a user's login credentials and returns the identifier for 
the patron.

Parameters:

  - username (Required)
	user's login identifier
  - password (Required)
	user's password

=cut
313
314sub AuthenticatePatron {
315
0
    my ($cgi) = @_;
316
317    # Check if borrower exists, using a C4::Auth function...
318
0
    unless( C4::Auth::checkpw( C4::Context->dbh, $cgi->param('username'), $cgi->param('password') ) ) {
319
0
        return { code => 'PatronNotFound' };
320    }
321
322    # Get the borrower
323
0
    my $borrower = GetMember( userid => $cgi->param('username') );
324
325    # Build the hashref
326
0
    my $patron->{'id'} = $borrower->{'borrowernumber'};
327
328    # ... and return his ID
329
0
    return $patron;
330}
331
332 - 351
=head2 GetPatronInfo

Returns specified information about the patron, based on options in the 
request. This function can optionally return patron's contact information, 
fine information, hold request information, and loan information.

Parameters:

  - patron_id (Required)
	the borrowernumber
  - show_contact (Optional, default 1)
	whether or not to return patron's contact information in the response
  - show_fines (Optional, default 0)
	whether or not to return fine information in the response
  - show_holds (Optional, default 0)
	whether or not to return hold request information in the response
  - show_loans (Optional, default 0)
	whether or not to return loan information request information in the response 

=cut
352
353sub GetPatronInfo {
354
0
    my ($cgi) = @_;
355
356    # Get Member details
357
0
    my $borrowernumber = $cgi->param('patron_id');
358
0
    my $borrower = GetMemberDetails( $borrowernumber );
359
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
360
361    # Cleaning the borrower hashref
362
0
    $borrower->{'charges'} = $borrower->{'flags'}->{'CHARGES'}->{'amount'};
363
0
    $borrower->{'branchname'} = GetBranchName( $borrower->{'branchcode'} );
364
0
    delete $borrower->{'flags'};
365
0
    delete $borrower->{'userid'};
366
0
    delete $borrower->{'password'};
367
368    # Contact fields management
369
0
    if ( $cgi->param('show_contact') eq "0" ) {
370
371        # Define contact fields
372
0
        my @contactfields = (
373            'email', 'emailpro', 'fax', 'mobile', 'phone', 'phonepro',
374            'streetnumber', 'zipcode', 'city', 'streettype', 'B_address', 'B_city',
375            'B_email', 'B_phone', 'B_zipcode', 'address', 'address2', 'altcontactaddress1',
376            'altcontactaddress2', 'altcontactaddress3', 'altcontactfirstname', 'altcontactphone', 'altcontactsurname', 'altcontactzipcode'
377        );
378
379        # and delete them
380
0
        foreach my $field (@contactfields) {
381
0
            delete $borrower->{$field};
382        }
383    }
384
385    # Fines management
386
0
    if ( $cgi->param('show_fines') eq "1" ) {
387
0
        my @charges;
388        for ( my $i = 1 ; my @charge = getcharges( $borrowernumber, undef, $i ) ; $i++ ) {
389
0
            push( @charges, @charge );
390
0
        }
391
0
        $borrower->{'fines'}->{'fine'} = \@charges;
392    }
393
394    # Reserves management
395
0
    if ( $cgi->param('show_holds') eq "1" ) {
396
397        # Get borrower's reserves
398
0
        my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
399
0
        foreach my $reserve (@reserves) {
400
401            # Get additional informations
402
0
            my $item = GetBiblioFromItemNumber( $reserve->{'itemnumber'}, undef );
403
0
            my $branchname = GetBranchName( $reserve->{'branchcode'} );
404
405            # Remove unwanted fields
406
0
            delete $item->{'marc'};
407
0
            delete $item->{'marcxml'};
408
0
            delete $item->{'more_subfields_xml'};
409
410            # Add additional fields
411
0
            $reserve->{'item'} = $item;
412
0
            $reserve->{'branchname'} = $branchname;
413
0
            $reserve->{'title'} = ( GetBiblio( $reserve->{'biblionumber'} ) )[1]->{'title'};
414        }
415
0
        $borrower->{'holds'}->{'hold'} = \@reserves;
416    }
417
418    # Issues management
419
0
    if ( $cgi->param('show_loans') eq "1" ) {
420
0
        my $issues = GetPendingIssues($borrowernumber);
421
0
        $borrower->{'loans'}->{'loan'} = $issues;
422    }
423
424
0
    return $borrower;
425}
426
427 - 436
=head2 GetPatronStatus

Returns a patron's status information.

Parameters:

  - patron_id (Required)
	the borrower ID

=cut
437
438sub GetPatronStatus {
439
0
    my ($cgi) = @_;
440
441    # Get Member details
442
0
    my $borrowernumber = $cgi->param('patron_id');
443
0
    my $borrower = GetMemberDetails( $borrowernumber );
444
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
445
446    # Return the results
447    return {
448
0
        type => $$borrower{categorycode},
449        status => 0, # TODO
450        expiry => $$borrower{dateexpiry},
451    };
452}
453
454 - 465
=head2 GetServices

Returns information about the services available on a particular item for 
a particular patron.

Parameters:

  - patron_id (Required)
	a borrowernumber
  - item_id (Required)
	an itemnumber
=cut
466
467sub GetServices {
468
0
    my ($cgi) = @_;
469
470    # Get the member, or return an error code if not found
471
0
    my $borrowernumber = $cgi->param('patron_id');
472
0
    my $borrower = GetMemberDetails( $borrowernumber );
473
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
474
475    # Get the item, or return an error code if not found
476
0
    my $itemnumber = $cgi->param('item_id');
477
0
    my $item = GetItem( $itemnumber );
478
0
    return { code => 'RecordNotFound' } unless $$item{itemnumber};
479
480
0
    my @availablefor;
481
482    # Reserve level management
483
0
    my $biblionumber = $item->{'biblionumber'};
484
0
    my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
485
0
    if ($canbookbereserved) {
486
0
        push @availablefor, 'title level hold';
487
0
        my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber);
488
0
        if ($canitembereserved) {
489
0
            push @availablefor, 'item level hold';
490        }
491    }
492
493    # Reserve cancellation management
494
0
    my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
495
0
    my @reserveditems;
496
0
    foreach my $reserve (@reserves) {
497
0
        push @reserveditems, $reserve->{'itemnumber'};
498    }
499
0
0
    if ( grep { $itemnumber eq $_ } @reserveditems ) {
500
0
        push @availablefor, 'hold cancellation';
501    }
502
503    # Renewal management
504
0
    my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
505
0
    if ( $renewal[0] ) {
506
0
        push @availablefor, 'loan renewal';
507    }
508
509    # Issuing management
510
0
    my $barcode = $item->{'barcode'} || '';
511
0
    $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') );
512
0
    if ($barcode) {
513
0
        my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
514
515        # TODO push @availablefor, 'loan';
516    }
517
518
0
    my $out;
519
0
    $out->{'AvailableFor'} = \@availablefor;
520
521
0
    return $out;
522}
523
524 - 537
=head2 RenewLoan

Extends the due date for a borrower's existing issue.

Parameters:

  - patron_id (Required)
	a borrowernumber
  - item_id (Required)
	an itemnumber
  - desired_due_date (Required)
	the date the patron would like the item returned by 

=cut
538
539sub RenewLoan {
540
0
    my ($cgi) = @_;
541
542    # Get borrower infos or return an error code
543
0
    my $borrowernumber = $cgi->param('patron_id');
544
0
    my $borrower = GetMemberDetails( $borrowernumber );
545
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
546
547    # Get the item, or return an error code
548
0
    my $itemnumber = $cgi->param('item_id');
549
0
    my $item = GetItem( $itemnumber );
550
0
    return { code => 'RecordNotFound' } unless $$item{itemnumber};
551
552    # Add renewal if possible
553
0
    my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
554
0
0
    if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber ); }
555
556
0
    my $issue = GetItemIssue($itemnumber);
557
558    # Hashref building
559
0
    my $out;
560
0
    $out->{'renewals'} = $issue->{'renewals'};
561
0
    $out->{'date_due'} = $issue->{'date_due'};
562
0
    $out->{'success'} = $renewal[0];
563
0
    $out->{'error'} = $renewal[1];
564
565
0
    return $out;
566}
567
568 - 587
=head2 HoldTitle

Creates, for a borrower, a biblio-level hold reserve.

Parameters:

  - patron_id (Required)
	a borrowernumber
  - bib_id (Required)
	a biblionumber
  - request_location (Required)
	IP address where the end user request is being placed
  - pickup_location (Optional)
	a branch code indicating the location to which to deliver the item for pickup
  - needed_before_date (Optional)
	date after which hold request is no longer needed
  - pickup_expiry_date (Optional)
	date after which item returned to shelf if item is not picked up 

=cut
588
589sub HoldTitle {
590
0
    my ($cgi) = @_;
591
592    # Get the borrower or return an error code
593
0
    my $borrowernumber = $cgi->param('patron_id');
594
0
    my $borrower = GetMemberDetails( $borrowernumber );
595
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
596
597    # Get the biblio record, or return an error code
598
0
    my $biblionumber = $cgi->param('bib_id');
599
0
    my ( $count, $biblio ) = GetBiblio( $biblionumber );
600
0
    return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
601
602
0
    my $title = $$biblio{title};
603
604    # Check if the biblio can be reserved
605
0
    return { code => 'NotHoldable' } unless CanBookBeReserved( $borrowernumber, $biblionumber );
606
607
0
    my $branch;
608
609    # Pickup branch management
610
0
    if ( $cgi->param('pickup_location') ) {
611
0
        $branch = $cgi->param('pickup_location');
612
0
        my $branches = GetBranches;
613
0
        return { code => 'LocationNotFound' } unless $$branches{$branch};
614    } else { # if the request provide no branch, use the borrower's branch
615
0
        $branch = $$borrower{branchcode};
616    }
617
618    # Add the reserve
619    # $branch, $borrowernumber, $biblionumber, $constraint, $bibitems, $priority, $notes, $title, $checkitem, $found
620
0
    AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, 0, undef, $title, undef, undef );
621
622    # Hashref building
623
0
    my $out;
624
0
    $out->{'title'} = $title;
625
0
    $out->{'pickup_location'} = GetBranchName($branch);
626
627    # TODO $out->{'date_available'} = '';
628
629
0
    return $out;
630}
631
632 - 652
=head2 HoldItem

Creates, for a borrower, an item-level hold request on a specific item of 
a bibliographic record in Koha.

Parameters:

  - patron_id (Required)
	a borrowernumber
  - bib_id (Required)
	a biblionumber
  - item_id (Required)
	an itemnumber
  - pickup_location (Optional)
	a branch code indicating the location to which to deliver the item for pickup
  - needed_before_date (Optional)
	date after which hold request is no longer needed
  - pickup_expiry_date (Optional)
	date after which item returned to shelf if item is not picked up 

=cut
653
654sub HoldItem {
655
0
    my ($cgi) = @_;
656
657    # Get the borrower or return an error code
658
0
    my $borrowernumber = $cgi->param('patron_id');
659
0
    my $borrower = GetMemberDetails( $borrowernumber );
660
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
661
662    # Get the biblio or return an error code
663
0
    my $biblionumber = $cgi->param('bib_id');
664
0
    my ( $count, $biblio ) = GetBiblio($biblionumber);
665
0
    return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
666
667
0
    my $title = $$biblio{title};
668
669    # Get the item or return an error code
670
0
    my $itemnumber = $cgi->param('item_id');
671
0
    my $item = GetItem( $itemnumber );
672
0
    return { code => 'RecordNotFound' } unless $$item{itemnumber};
673
674    # If the biblio does not match the item, return an error code
675
0
    return { code => 'RecordNotFound' } if $$item{biblionumber} ne $$biblio{biblionumber};
676
677    # Check for item disponibility
678
0
    my $canitembereserved = CanItemBeReserved( $borrowernumber, $itemnumber );
679
0
    my $canbookbereserved = CanBookBeReserved( $borrowernumber, $biblionumber );
680
0
    return { code => 'NotHoldable' } unless $canbookbereserved and $canitembereserved;
681
682
0
    my $branch;
683
684    # Pickup branch management
685
0
    if ( $cgi->param('pickup_location') ) {
686
0
        $branch = $cgi->param('pickup_location');
687
0
        my $branches = GetBranches();
688
0
        return { code => 'LocationNotFound' } unless $$branches{$branch};
689    } else { # if the request provide no branch, use the borrower's branch
690
0
        $branch = $$borrower{branchcode};
691    }
692
693
0
    my $rank;
694
0
    my $found;
695
696    # Get rank and found
697
0
    $rank = '0' unless C4::Context->preference('ReservesNeedReturns');
698
0
    if ( $item->{'holdingbranch'} eq $branch ) {
699
0
        $found = 'W' unless C4::Context->preference('ReservesNeedReturns');
700    }
701
702    # Add the reserve
703    # $branch, $borrowernumber, $biblionumber, $constraint, $bibitems, $priority, $notes, $title, $checkitem, $found
704
0
    AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, $rank, undef, $title, $itemnumber, $found );
705
706    # Hashref building
707
0
    my $out;
708
0
    $out->{'pickup_location'} = GetBranchName($branch);
709
710    # TODO $out->{'date_available'} = '';
711
712
0
    return $out;
713}
714
715 - 726
=head2 CancelHold

Cancels an active reserve request for the borrower.

Parameters:

  - patron_id (Required)
	a borrowernumber
  - item_id (Required)
	an itemnumber 

=cut
727
728sub CancelHold {
729
0
    my ($cgi) = @_;
730
731    # Get the borrower or return an error code
732
0
    my $borrowernumber = $cgi->param('patron_id');
733
0
    my $borrower = GetMemberDetails( $borrowernumber );
734
0
    return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
735
736    # Get the item or return an error code
737
0
    my $itemnumber = $cgi->param('item_id');
738
0
    my $item = GetItem( $itemnumber );
739
0
    return { code => 'RecordNotFound' } unless $$item{itemnumber};
740
741    # Get borrower's reserves
742
0
    my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
743
0
    my @reserveditems;
744
745    # ...and loop over it to build an array of reserved itemnumbers
746
0
    foreach my $reserve (@reserves) {
747
0
        push @reserveditems, $reserve->{'itemnumber'};
748    }
749
750    # if the item was not reserved by the borrower, returns an error code
751
0
0
    return { code => 'NotCanceled' } unless any { $itemnumber eq $_ } @reserveditems;
752
753    # Cancel the reserve
754
0
    CancelReserve( $itemnumber, undef, $borrowernumber );
755
756
0
    return { code => 'Canceled' };
757}
758
7591;