(MT 2563) : ILSDI PatronLookUp Problem
[koha.git] / C4 / ILSDI / Services.pm
1 package 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 use strict;
21 use warnings;
22
23 use C4::Members;
24 use C4::Items;
25 use C4::Circulation;
26 use C4::Branch;
27 use C4::Accounts;
28 use C4::Biblio;
29 use C4::Reserves;
30 use C4::Context;
31 use C4::AuthoritiesMarc;
32 use C4::ILSDI::Utility;
33 use XML::Simple;
34 use HTML::Entities;
35 use CGI;
36
37 =head1 NAME
38
39 C4::ILS-DI::Services - ILS-DI Services
40
41 =head1 DESCRIPTION
42
43         Each function in this module represents an ILS-DI service.
44         They all takes a CGI instance as argument and most of them return a 
45         hashref that will be printed by XML::Simple in opac/ilsdi.pl
46
47 =head1 SYNOPSIS
48
49         use C4::ILSDI::Services;
50         use XML::Simple;
51         use CGI;
52
53         my $cgi = new CGI;
54
55         $out = LookupPatron($cgi);
56
57         print CGI::header('text/xml');
58         print XMLout($out,
59                 noattr => 1, 
60                 noescape => 1,
61                 nosort => 1,
62                 xmldecl => '<?xml version="1.0" encoding="ISO-8859-1" ?>', 
63                 RootName => 'LookupPatron', 
64                 SuppressEmpty => 1);
65
66 =cut
67
68 =head2 GetAvailability
69     
70         Given a set of biblionumbers or itemnumbers, returns a list with 
71         availability of the items associated with the identifiers.
72         
73         Parameters :
74
75         - id (Required)
76                 list of either biblionumbers or itemnumbers
77         - id_type (Required)
78                 defines the type of record identifier being used in the request, 
79                 possible values:
80                         - bib
81                         - item
82         - return_type (Optional)
83                 requests a particular level of detail in reporting availability, 
84                 possible values:
85                         - bib
86                         - item
87         - return_fmt (Optional)
88                 requests a particular format or set of formats in reporting 
89                 availability 
90
91 =cut
92
93 sub GetAvailability {
94     my ($cgi) = @_;
95
96     my $out = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
97     $out .= "<dlf:collection\n";
98     $out .= "  xmlns:dlf=\"http://diglib.org/ilsdi/1.1\"\n";
99     $out .= "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n";
100     $out .= "  xsi:schemaLocation=\"http://diglib.org/ilsdi/1.1\n";
101     $out .= "    http://diglib.org/architectures/ilsdi/schemas/1.1/dlfexpanded.xsd\">\n";
102
103     foreach my $id ( split( / /, $cgi->param('id') ) ) {
104         if ( $cgi->param('id_type') eq "item" ) {
105             my ( $biblionumber, $status, $msg, $location ) = Availability($id);
106
107             $out .= "  <dlf:record>\n";
108             $out .= "    <dlf:bibliographic id=\"" . ( $biblionumber || $id ) . "\" />\n";
109             $out .= "    <dlf:items>\n";
110             $out .= "      <dlf:item id=\"" . $id . "\">\n";
111             $out .= "        <dlf:simpleavailability>\n";
112             $out .= "          <dlf:identifier>" . $id . "</dlf:identifier>\n";
113             $out .= "          <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
114             if ($msg)      { $out .= "          <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n"; }
115             if ($location) { $out .= "          <dlf:location>" . $location . "</dlf:location>\n"; }
116             $out .= "        </dlf:simpleavailability>\n";
117             $out .= "      </dlf:item>\n";
118             $out .= "    </dlf:items>\n";
119             $out .= "  </dlf:record>\n";
120         } else {
121             my $status;
122             my $msg;
123             my $biblioitem = ( GetBiblioItemByBiblioNumber( $id, undef ) )[0];
124             if ($biblioitem) {
125
126             } else {
127                 $status = "unknown";
128                 $msg    = "Error: could not retrieve availability for this ID";
129             }
130             $out .= "  <dlf:record>\n";
131             $out .= "    <dlf:bibliographic id=\"" . $id . "\" />\n";
132             $out .= "    <dlf:simpleavailability>\n";
133             $out .= "      <dlf:identifier>" . $id . "</dlf:identifier>\n";
134             $out .= "      <dlf:availabilitystatus>" . $status . "</dlf:availabilitystatus>\n";
135             $out .= "      <dlf:availabilitymsg>" . $msg . "</dlf:availabilitymsg>\n";
136             $out .= "    </dlf:simpleavailability>\n";
137             $out .= "  </dlf:record>\n";
138         }
139     }
140     $out .= "</dlf:collection>\n";
141
142     return $out;
143 }
144
145 =head2 GetRecords
146     
147         Given a list of biblionumbers, returns a list of record objects that 
148         contain bibliographic information, as well as associated holdings and item
149         information. The caller may request a specific metadata schema for the 
150         record objects to be returned.
151         This function behaves similarly to HarvestBibliographicRecords and 
152         HarvestExpandedRecords in Data Aggregation, but allows quick, real time 
153         lookup by bibliographic identifier.
154
155         You can use OAI-PMH ListRecords instead of this service.
156         
157         Parameters:
158
159         - id (Required)
160                 list of system record identifiers
161         - id_type (Optional)
162                 Defines the metadata schema in which the records are returned, 
163                 possible values:
164                         - MARCXML
165
166 =cut
167
168 sub GetRecords {
169     my ($cgi) = @_;
170
171     # Check if the schema is supported. For now, GetRecords only supports MARCXML
172     if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
173         return { code => 'UnsupportedSchema' };
174     }
175
176     my @records;
177
178     # Loop over biblionumbers
179     foreach my $biblionumber ( split( / /, $cgi->param('id') ) ) {
180
181         # Get the biblioitem from the biblionumber
182         my $biblioitem = ( GetBiblioItemByBiblioNumber( $biblionumber, undef ) )[0];
183         if ( not $biblioitem->{'biblionumber'} ) {
184             $biblioitem = "RecordNotFound";
185         }
186
187         # We don't want MARC to be displayed
188         delete $biblioitem->{'marc'};
189
190         # nor the XML declaration of MARCXML
191         $biblioitem->{'marcxml'} =~ s/<\?xml version="1.0" encoding="UTF-8"\?>//go;
192
193         # Get most of the needed data
194         my $biblioitemnumber = $biblioitem->{'biblioitemnumber'};
195         my @reserves         = GetReservesFromBiblionumber( $biblionumber, undef, undef );
196         my $issues           = GetBiblioIssues($biblionumber);
197         my $items            = GetItemsByBiblioitemnumber($biblioitemnumber);
198
199         # We loop over the items to clean them
200         foreach my $item (@$items) {
201
202             # This hides additionnal XML subfields, we don't need these info
203             delete $item->{'more_subfields_xml'};
204
205             # Display branch names instead of branch codes
206             $item->{'homebranchname'}    = GetBranchName( $item->{'homebranch'} );
207             $item->{'holdingbranchname'} = GetBranchName( $item->{'holdingbranch'} );
208         }
209
210         # Hashref building...
211         $biblioitem->{'items'}->{'item'}       = $items;
212         $biblioitem->{'reserves'}->{'reserve'} = $reserves[1];
213         $biblioitem->{'issues'}->{'issue'}     = $issues;
214
215         map { $biblioitem->{$_} = encode_entities( $biblioitem->{$_}, '&' ) } grep( !/marcxml/, keys %$biblioitem );
216
217 <<<<<<< HEAD:C4/ILSDI/Services.pm
218         push @records, $biblioitem;
219 =======
220             $_ = encode_entities( $$biblioitem{$_}, '&' ) for @$biblioitem{ grep {!/marcxml/} keys %$biblioitem };
221             
222             push @records, $biblioitem;
223             
224         } else {
225             push @records, { code => 'RecordNotFound' };
226         }
227 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
228     }
229
230     return { record => \@records };
231 }
232
233 =head2 GetAuthorityRecords
234     
235         Given a list of authority record identifiers, returns a list of record 
236         objects that contain the authority records. The function user may request 
237         a specific metadata schema for the record objects.
238
239         Parameters:
240
241         - id (Required)
242             list of authority record identifiers
243         - schema (Optional)
244             specifies the metadata schema of records to be returned, possible values:
245                   - MARCXML
246
247 =cut
248
249 sub GetAuthorityRecords {
250     my ($cgi) = @_;
251
252     # If the user asks for an unsupported schema, return an error code
253     if ( $cgi->param('schema') and $cgi->param('schema') ne "MARCXML" ) {
254         return { code => 'UnsupportedSchema' };
255     }
256
257     my $records;
258
259     # Let's loop over the authority IDs
260     foreach my $authid ( split( / /, $cgi->param('id') ) ) {
261
262         # Get the record as XML string, or error code
263 <<<<<<< HEAD:C4/ILSDI/Services.pm
264         my $record = GetAuthorityXML($authid) || "<record>RecordNotFound</record>";
265 =======
266         my $record = GetAuthorityXML( $_ ) || "<record><code>RecordNotFound</code></record>";
267 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
268         $record =~ s/<\?xml(.*)\?>//go;
269         $records .= $record;
270     }
271
272     return $records;
273 }
274
275 =head2 LookupPatron
276     
277         Looks up a patron in the ILS by an identifier, and returns the borrowernumber.
278         
279         Parameters:
280
281         - id (Required)
282                 an identifier used to look up the patron in Koha
283         - id_type (Optional)
284                 the type of the identifier, possible values:
285                         - cardnumber
286                         - firstname
287                         - userid
288                         - borrowernumber
289
290 =cut
291
292 sub LookupPatron {
293     my ($cgi) = @_;
294
295     # Get the borrower...
296 <<<<<<< HEAD:C4/ILSDI/Services.pm
297 <<<<<<< HEAD:C4/ILSDI/Services.pm
298     my $borrower = GetMember($cgi->param('id_type') => $cgi->param('id'));
299     if ( not $borrower->{'borrowernumber'} ) {
300         return { message => 'PatronNotFound' };
301     }
302
303     # Build the hashref
304     my $patron->{'id'} = $borrower->{'borrowernumber'};
305 =======
306     my $borrower = GetMember( $cgi->param('id'), $cgi->param('id_type') );
307 =======
308     my $borrower = GetMember( $cgi->param('id_type')||"borrowernumber",$cgi->param('id') );
309 >>>>>>> (MT 2563) : ILSDI PatronLookUp Problem:C4/ILSDI.pm
310     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
311 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
312
313     # ...and return his ID
314     return $patron;
315 }
316
317 =head2 AuthenticatePatron
318
319         Authenticates a user's login credentials and returns the identifier for 
320         the patron.
321         
322         Parameters:
323
324         - username (Required)
325                 user's login identifier
326         - password (Required)
327                 user's password
328                 
329 =cut
330
331 sub AuthenticatePatron {
332     my ($cgi) = @_;
333
334 <<<<<<< HEAD:C4/ILSDI/Services.pm
335     # Check if borrower exists, using a C4::ILSDI::Utility function...
336     if ( not( BorrowerExists( $cgi->param('username'), $cgi->param('password') ) ) ) {
337         return { message => 'PatronNotFound' };
338 =======
339     # Check if borrower exists, using a C4::Auth function...
340     unless( checkpw( C4::Context->dbh, $cgi->param('username'), $cgi->param('password') ) ) {
341         return { code => 'PatronNotFound' };
342 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
343     }
344
345     # Get the borrower
346     my $borrower = GetMember( userid => $cgi->param('username') );
347
348     # Build the hashref
349     my $patron->{'id'} = $borrower->{'borrowernumber'};
350
351     # ... and return his ID
352     return $patron;
353 }
354
355 =head2 GetPatronInfo
356
357         Returns specified information about the patron, based on options in the 
358         request. This function can optionally return patron's contact information, 
359         fine information, hold request information, and loan information.
360         
361         Parameters:
362
363         - patron_id (Required)
364                 the borrowernumber
365         - show_contact (Optional, default 1)
366                 whether or not to return patron's contact information in the response
367         - show_fines (Optional, default 0)
368                 whether or not to return fine information in the response
369         - show_holds (Optional, default 0)
370                 whether or not to return hold request information in the response
371         - show_loans (Optional, default 0)
372                 whether or not to return loan information request information in the response 
373                 
374 =cut
375
376 sub GetPatronInfo {
377     my ($cgi) = @_;
378
379     # Get Member details
380     my $borrowernumber = $cgi->param('patron_id');
381 <<<<<<< HEAD:C4/ILSDI/Services.pm
382     my $borrower = GetMemberDetails( $borrowernumber, undef );
383     if ( not $borrower->{'borrowernumber'} ) {
384         return { message => 'PatronNotFound' };
385     }
386 =======
387     my $borrower = GetMemberDetails( $borrowernumber );
388     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
389 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
390
391     # Cleaning the borrower hashref
392     $borrower->{'charges'}    = $borrower->{'flags'}->{'CHARGES'}->{'amount'};
393     $borrower->{'branchname'} = GetBranchName( $borrower->{'branchcode'} );
394     delete $borrower->{'flags'};
395     delete $borrower->{'userid'};
396     delete $borrower->{'password'};
397
398     # Contact fields management
399     if ( $cgi->param('show_contact') eq "0" ) {
400
401         # Define contact fields
402         my @contactfields = (
403             'email',              'emailpro',           'fax',                 'mobile',          'phone',             'phonepro',
404             'streetnumber',       'zipcode',            'city',                'streettype',      'B_address',         'B_city',
405             'B_email',            'B_phone',            'B_zipcode',           'address',         'address2',          'altcontactaddress1',
406             'altcontactaddress2', 'altcontactaddress3', 'altcontactfirstname', 'altcontactphone', 'altcontactsurname', 'altcontactzipcode'
407         );
408
409         # and delete them
410         foreach my $field (@contactfields) {
411             delete $borrower->{$field};
412         }
413     }
414
415     # Fines management
416     if ( $cgi->param('show_fines') eq "1" ) {
417         my @charges;
418         for ( my $i = 1 ; my @charge = getcharges( $borrowernumber, undef, $i ) ; $i++ ) {
419             push( @charges, @charge );
420         }
421         $borrower->{'fines'}->{'fine'} = \@charges;
422     }
423
424     # Reserves management
425     if ( $cgi->param('show_holds') eq "1" ) {
426
427         # Get borrower's reserves
428         my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
429         foreach my $reserve (@reserves) {
430
431             # Get additional informations
432             my $item = GetBiblioFromItemNumber( $reserve->{'itemnumber'}, undef );
433             my $branchname = GetBranchName( $reserve->{'branchcode'} );
434
435             # Remove unwanted fields
436             delete $item->{'marc'};
437             delete $item->{'marcxml'};
438             delete $item->{'more_subfields_xml'};
439
440             # Add additional fields
441             $reserve->{'item'}       = $item;
442             $reserve->{'branchname'} = $branchname;
443             $reserve->{'title'}      = ( GetBiblio( $reserve->{'biblionumber'} ) )[1]->{'title'};
444         }
445         $borrower->{'holds'}->{'hold'} = \@reserves;
446     }
447
448     # Issues management
449     if ( $cgi->param('show_loans') eq "1" ) {
450         my $issues = GetPendingIssues($borrowernumber);
451         $borrower->{'loans'}->{'loan'} = $issues;
452     }
453
454     return $borrower;
455 }
456
457 =head2 GetPatronStatus
458
459         Returns a patron's status information.
460         
461         Parameters:
462
463         - patron_id (Required)
464                 the borrower ID
465
466 =cut
467
468 sub GetPatronStatus {
469     my ($cgi) = @_;
470
471     # Get Member details
472     my $borrowernumber = $cgi->param('patron_id');
473 <<<<<<< HEAD:C4/ILSDI/Services.pm
474     my $borrower = GetMemberDetails( $borrowernumber, undef );
475     if ( not $borrower->{'borrowernumber'} ) {
476         return { message => 'PatronNotFound' };
477     }
478
479     # Hashref building
480     my $patron;
481     $patron->{'type'}   = $borrower->{'categorycode'};
482     $patron->{'status'} = 0;                             #TODO
483     $patron->{'expiry'} = $borrower->{'dateexpiry'};
484
485     return $patron;
486 =======
487     my $borrower = GetMemberDetails( $borrowernumber );
488     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
489
490     # Return the results
491     return {
492         type   => $$borrower{categorycode},
493         status => 0, # TODO
494         expiry => $$borrower{dateexpiry},
495     };
496 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
497 }
498
499 =head2 GetServices
500
501         Returns information about the services available on a particular item for 
502         a particular patron.
503         
504         Parameters:
505
506         - patron_id (Required)
507                 a borrowernumber
508         - item_id (Required)
509                 an itemnumber
510 =cut
511
512 sub GetServices {
513     my ($cgi) = @_;
514
515     # Get the member, or return an error code if not found
516     my $borrowernumber = $cgi->param('patron_id');
517 <<<<<<< HEAD:C4/ILSDI/Services.pm
518     my $borrower = GetMemberDetails( $borrowernumber, undef );
519     if ( not $borrower->{'borrowernumber'} ) {
520         return { message => 'PatronNotFound' };
521     }
522
523     # Get the item, or return an error code if not found
524     my $itemnumber = $cgi->param('item_id');
525     my $item = GetItem( $itemnumber, undef, undef );
526     if ( not $item->{'itemnumber'} ) {
527         return { message => 'RecordNotFound' };
528     }
529 =======
530     my $borrower = GetMemberDetails( $borrowernumber );
531     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
532
533     # Get the item, or return an error code if not found
534     my $itemnumber = $cgi->param('item_id');
535     my $item = GetItem( $itemnumber );
536     return { code => 'RecordNotFound' } unless $$item{itemnumber};
537 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
538
539     my @availablefor;
540
541     # Reserve level management
542     my $biblionumber = $item->{'biblionumber'};
543     my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
544     if ($canbookbereserved) {
545         push @availablefor, 'title level hold';
546         my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber);
547         if ($canitembereserved) {
548             push @availablefor, 'item level hold';
549         }
550     }
551
552     # Reserve cancellation management
553     my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
554     my @reserveditems;
555     foreach my $reserve (@reserves) {
556         push @reserveditems, $reserve->{'itemnumber'};
557     }
558     if ( grep { $itemnumber eq $_ } @reserveditems ) {
559         push @availablefor, 'hold cancellation';
560     }
561
562     # Renewal management
563     my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
564     if ( $renewal[0] ) {
565         push @availablefor, 'loan renewal';
566     }
567
568     # Issuing management
569     my $barcode = $item->{'barcode'} || '';
570     $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') );
571     if ($barcode) {
572         my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
573
574         # TODO push @availablefor, 'loan';
575     }
576
577     my $out;
578     $out->{'AvailableFor'} = \@availablefor;
579
580     return $out;
581 }
582
583 =head2 RenewLoan
584
585         Extends the due date for a borrower's existing issue.
586         
587         Parameters:
588
589         - patron_id (Required)
590                 a borrowernumber
591         - item_id (Required)
592                 an itemnumber
593         - desired_due_date (Required)
594                 the date the patron would like the item returned by 
595
596 =cut
597
598 sub RenewLoan {
599     my ($cgi) = @_;
600
601     # Get borrower infos or return an error code
602     my $borrowernumber = $cgi->param('patron_id');
603 <<<<<<< HEAD:C4/ILSDI/Services.pm
604     my $borrower = GetMemberDetails( $borrowernumber, undef );
605     if ( not $borrower->{'borrowernumber'} ) {
606         return { message => 'PatronNotFound' };
607     }
608 =======
609     my $borrower = GetMemberDetails( $borrowernumber );
610     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
611 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
612
613     # Get the item, or return an error code
614     my $itemnumber = $cgi->param('item_id');
615 <<<<<<< HEAD:C4/ILSDI/Services.pm
616     my $item = GetItem( $itemnumber, undef, undef );
617     if ( not $item->{'itemnumber'} ) {
618         return { message => 'RecordNotFound' };
619     }
620 =======
621     my $item = GetItem( $itemnumber );
622     return { code => 'RecordNotFound' } unless $$item{itemnumber};
623 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
624
625     # Add renewal if possible
626     my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
627     if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber ); }
628
629     my $issue = GetItemIssue($itemnumber);
630
631     # Hashref building
632     my $out;
633     $out->{'renewals'} = $issue->{'renewals'};
634     $out->{'date_due'} = $issue->{'date_due'};
635     $out->{'success'}  = $renewal[0];
636     $out->{'error'}    = $renewal[1];
637
638     return $out;
639 }
640
641 =head2 HoldTitle
642
643         Creates, for a borrower, a biblio-level hold reserve.
644         
645         Parameters:
646
647         - patron_id (Required)
648                 a borrowernumber
649         - bib_id (Required)
650                 a biblionumber
651         - request_location (Required)
652                 IP address where the end user request is being placed
653         - pickup_location (Optional)
654                 a branch code indicating the location to which to deliver the item for pickup
655         - needed_before_date (Optional)
656                 date after which hold request is no longer needed
657         - pickup_expiry_date (Optional)
658                 date after which item returned to shelf if item is not picked up 
659
660 =cut
661
662 sub HoldTitle {
663     my ($cgi) = @_;
664
665     # Get the borrower or return an error code
666     my $borrowernumber = $cgi->param('patron_id');
667 <<<<<<< HEAD:C4/ILSDI/Services.pm
668     my $borrower = GetMemberDetails( $borrowernumber, undef );
669     if ( not $borrower->{'borrowernumber'} ) {
670         return { message => 'PatronNotFound' };
671     }
672
673     # Get the biblio record, or return an error code
674     my $biblionumber = $cgi->param('bib_id');
675     my ( $count, $biblio ) = GetBiblio($biblionumber);
676     if ( not $biblio->{'biblionumber'} ) {
677         return { message => 'RecordNotFound' };
678     }
679     my $title = $biblio->{'title'};
680
681     # Check if the biblio can be reserved
682     my $canbereserved = CanBookBeReserved( $borrower, $biblionumber );
683     if ( not $canbereserved ) {
684         return { message => 'NotHoldable' };
685     }
686 =======
687     my $borrower = GetMemberDetails( $borrowernumber );
688     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
689
690     # Get the biblio record, or return an error code
691     my $biblionumber = $cgi->param('bib_id');
692     my ( $count, $biblio ) = GetBiblio( $biblionumber );
693     return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
694     
695     my $title = $$biblio{title};
696
697     # Check if the biblio can be reserved
698     return { code => 'NotHoldable' } unless CanBookBeReserved( $borrowernumber, $biblionumber );
699 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
700
701     my $branch;
702
703     # Pickup branch management
704     if ( $cgi->param('pickup_location') ) {
705         $branch = $cgi->param('pickup_location');
706 <<<<<<< HEAD:C4/ILSDI/Services.pm
707         my $branches = GetBranches();
708         if ( not $branches->{$branch} ) {
709             return { message => 'LocationNotFound' };
710         }
711     } else {    # if user provide no branch, use his own
712         $branch = $borrower->{'branchcode'};
713 =======
714         my $branches = GetBranches;
715         return { code => 'LocationNotFound' } unless $$branches{$branch};
716     } else { # if the request provide no branch, use the borrower's branch
717         $branch = $$borrower{branchcode};
718 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
719     }
720
721     # Add the reserve
722     #          $branch, $borrowernumber, $biblionumber, $constraint, $bibitems,  $priority, $notes, $title, $checkitem,  $found
723     AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, 0, undef, $title, undef, undef );
724
725     # Hashref building
726     my $out;
727     $out->{'title'}           = $title;
728     $out->{'pickup_location'} = GetBranchName($branch);
729
730     # TODO $out->{'date_available'}  = '';
731
732     return $out;
733 }
734
735 =head2 HoldItem
736
737         Creates, for a borrower, an item-level hold request on a specific item of 
738         a bibliographic record in Koha.
739
740         Parameters:
741
742         - patron_id (Required)
743                 a borrowernumber
744         - bib_id (Required)
745                 a biblionumber
746         - item_id (Required)
747                 an itemnumber
748         - pickup_location (Optional)
749                 a branch code indicating the location to which to deliver the item for pickup
750         - needed_before_date (Optional)
751                 date after which hold request is no longer needed
752         - pickup_expiry_date (Optional)
753                 date after which item returned to shelf if item is not picked up 
754
755 =cut
756
757 sub HoldItem {
758     my ($cgi) = @_;
759
760     # Get the borrower or return an error code
761     my $borrowernumber = $cgi->param('patron_id');
762 <<<<<<< HEAD:C4/ILSDI/Services.pm
763     my $borrower = GetMemberDetails( $borrowernumber, undef );
764     if ( not $borrower->{'borrowernumber'} ) {
765         return { message => 'PatronNotFound' };
766     }
767 =======
768     my $borrower = GetMemberDetails( $borrowernumber );
769     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
770 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
771
772     # Get the biblio or return an error code
773     my $biblionumber = $cgi->param('bib_id');
774     my ( $count, $biblio ) = GetBiblio($biblionumber);
775 <<<<<<< HEAD:C4/ILSDI/Services.pm
776     if ( not $biblio->{'biblionumber'} ) {
777         return { message => 'RecordNotFound' };
778     }
779     my $title = $biblio->{'title'};
780
781     # Get the item or return an error code
782     my $itemnumber = $cgi->param('item_id');
783     my $item = GetItem( $itemnumber, undef, undef );
784     if ( not $item->{'itemnumber'} ) {
785         return { message => 'RecordNotFound' };
786     }
787
788     # if the biblio does not match the item, return an error code
789     if ( $item->{'biblionumber'} ne $biblio->{'biblionumber'} ) {
790         return { message => 'RecordNotFound' };
791     }
792
793     # Check for item disponibility
794     my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber);
795     my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
796     if ( ( not $canbookbereserved ) or not($canitembereserved) ) {
797         return { message => 'NotHoldable' };
798     }
799 =======
800     return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
801
802     my $title = $$biblio{title};
803
804     # Get the item or return an error code
805     my $itemnumber = $cgi->param('item_id');
806     my $item = GetItem( $itemnumber );
807     return { code => 'RecordNotFound' } unless $$item{itemnumber};
808
809     # If the biblio does not match the item, return an error code
810     return { code => 'RecordNotFound' } if $$item{biblionumber} ne $$biblio{biblionumber};
811
812     # Check for item disponibility
813     my $canitembereserved = CanItemBeReserved( $borrowernumber, $itemnumber );
814     my $canbookbereserved = CanBookBeReserved( $borrowernumber, $biblionumber );
815     return { code => 'NotHoldable' } unless $canbookbereserved and $canitembereserved;
816 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
817
818     my $branch;
819
820     # Pickup branch management
821     if ( $cgi->param('pickup_location') ) {
822         $branch = $cgi->param('pickup_location');
823         my $branches = GetBranches();
824 <<<<<<< HEAD:C4/ILSDI/Services.pm
825         if ( not $branches->{$branch} ) {
826             return { message => 'LocationNotFound' };
827         }
828     } else {    # if user provide no branch, use his own
829         $branch = $borrower->{'branchcode'};
830 =======
831         return { code => 'LocationNotFound' } unless $$branches{$branch};
832     } else { # if the request provide no branch, use the borrower's branch
833         $branch = $$borrower{branchcode};
834 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
835     }
836
837     my $rank;
838     my $found;
839
840     # Get rank and found
841     $rank = '0' unless C4::Context->preference('ReservesNeedReturns');
842     if ( $item->{'holdingbranch'} eq $branch ) {
843         $found = 'W' unless C4::Context->preference('ReservesNeedReturns');
844     }
845
846     # Add the reserve
847     #          $branch, $borrowernumber, $biblionumber, $constraint, $bibitems,  $priority, $notes, $title, $checkitem,  $found
848     AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, $rank, undef, $title, $itemnumber, $found );
849
850     # Hashref building
851     my $out;
852     $out->{'pickup_location'} = GetBranchName($branch);
853
854     # TODO $out->{'date_available'} = '';
855
856     return $out;
857 }
858
859 =head2 CancelHold
860
861         Cancels an active reserve request for the borrower.
862         
863         Parameters:
864
865         - patron_id (Required)
866                 a borrowernumber
867         - item_id (Required)
868                 an itemnumber 
869
870 =cut
871
872 sub CancelHold {
873     my ($cgi) = @_;
874
875     # Get the borrower or return an error code
876     my $borrowernumber = $cgi->param('patron_id');
877 <<<<<<< HEAD:C4/ILSDI/Services.pm
878     my $borrower = GetMemberDetails( $borrowernumber, undef );
879     if ( not $borrower->{'borrowernumber'} ) {
880         return { message => 'PatronNotFound' };
881     }
882
883     # Get the item or return an error code
884     my $itemnumber = $cgi->param('item_id');
885     my $item = GetItem( $itemnumber, undef, undef );
886     if ( not $item->{'itemnumber'} ) {
887         return { message => 'RecordNotFound' };
888     }
889 =======
890     my $borrower = GetMemberDetails( $borrowernumber );
891     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
892
893     # Get the item or return an error code
894     my $itemnumber = $cgi->param('item_id');
895     my $item = GetItem( $itemnumber );
896     return { code => 'RecordNotFound' } unless $$item{itemnumber};
897 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
898
899     # Get borrower's reserves
900     my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
901     my @reserveditems;
902
903     # ...and loop over it to build an array of reserved itemnumbers
904     foreach my $reserve (@reserves) {
905         push @reserveditems, $reserve->{'itemnumber'};
906     }
907
908     # if the item was not reserved by the borrower, returns an error code
909 <<<<<<< HEAD:C4/ILSDI/Services.pm
910     if ( not grep { $itemnumber eq $_ } @reserveditems ) {
911         return { message => 'NotCanceled' };
912     }
913 =======
914     return { code => 'NotCanceled' } unless any { $itemnumber eq $_ } @reserveditemnumbers;
915 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
916
917     # Cancel the reserve
918     CancelReserve( $itemnumber, undef, $borrowernumber );
919
920 <<<<<<< HEAD:C4/ILSDI/Services.pm
921     return { message => 'Canceled' };
922
923 =======
924     return { code => 'Canceled' };
925 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
926 }
927
928 1;