ILS-DI Messages uniformization
[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     my $borrower = GetMember($cgi->param('id_type') => $cgi->param('id'));
298     if ( not $borrower->{'borrowernumber'} ) {
299         return { message => 'PatronNotFound' };
300     }
301
302     # Build the hashref
303     my $patron->{'id'} = $borrower->{'borrowernumber'};
304 =======
305     my $borrower = GetMember( $cgi->param('id'), $cgi->param('id_type') );
306     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
307 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
308
309     # ...and return his ID
310     return $patron;
311 }
312
313 =head2 AuthenticatePatron
314
315         Authenticates a user's login credentials and returns the identifier for 
316         the patron.
317         
318         Parameters:
319
320         - username (Required)
321                 user's login identifier
322         - password (Required)
323                 user's password
324                 
325 =cut
326
327 sub AuthenticatePatron {
328     my ($cgi) = @_;
329
330 <<<<<<< HEAD:C4/ILSDI/Services.pm
331     # Check if borrower exists, using a C4::ILSDI::Utility function...
332     if ( not( BorrowerExists( $cgi->param('username'), $cgi->param('password') ) ) ) {
333         return { message => 'PatronNotFound' };
334 =======
335     # Check if borrower exists, using a C4::Auth function...
336     unless( checkpw( C4::Context->dbh, $cgi->param('username'), $cgi->param('password') ) ) {
337         return { code => 'PatronNotFound' };
338 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
339     }
340
341     # Get the borrower
342     my $borrower = GetMember( userid => $cgi->param('username') );
343
344     # Build the hashref
345     my $patron->{'id'} = $borrower->{'borrowernumber'};
346
347     # ... and return his ID
348     return $patron;
349 }
350
351 =head2 GetPatronInfo
352
353         Returns specified information about the patron, based on options in the 
354         request. This function can optionally return patron's contact information, 
355         fine information, hold request information, and loan information.
356         
357         Parameters:
358
359         - patron_id (Required)
360                 the borrowernumber
361         - show_contact (Optional, default 1)
362                 whether or not to return patron's contact information in the response
363         - show_fines (Optional, default 0)
364                 whether or not to return fine information in the response
365         - show_holds (Optional, default 0)
366                 whether or not to return hold request information in the response
367         - show_loans (Optional, default 0)
368                 whether or not to return loan information request information in the response 
369                 
370 =cut
371
372 sub GetPatronInfo {
373     my ($cgi) = @_;
374
375     # Get Member details
376     my $borrowernumber = $cgi->param('patron_id');
377 <<<<<<< HEAD:C4/ILSDI/Services.pm
378     my $borrower = GetMemberDetails( $borrowernumber, undef );
379     if ( not $borrower->{'borrowernumber'} ) {
380         return { message => 'PatronNotFound' };
381     }
382 =======
383     my $borrower = GetMemberDetails( $borrowernumber );
384     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
385 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
386
387     # Cleaning the borrower hashref
388     $borrower->{'charges'}    = $borrower->{'flags'}->{'CHARGES'}->{'amount'};
389     $borrower->{'branchname'} = GetBranchName( $borrower->{'branchcode'} );
390     delete $borrower->{'flags'};
391     delete $borrower->{'userid'};
392     delete $borrower->{'password'};
393
394     # Contact fields management
395     if ( $cgi->param('show_contact') eq "0" ) {
396
397         # Define contact fields
398         my @contactfields = (
399             'email',              'emailpro',           'fax',                 'mobile',          'phone',             'phonepro',
400             'streetnumber',       'zipcode',            'city',                'streettype',      'B_address',         'B_city',
401             'B_email',            'B_phone',            'B_zipcode',           'address',         'address2',          'altcontactaddress1',
402             'altcontactaddress2', 'altcontactaddress3', 'altcontactfirstname', 'altcontactphone', 'altcontactsurname', 'altcontactzipcode'
403         );
404
405         # and delete them
406         foreach my $field (@contactfields) {
407             delete $borrower->{$field};
408         }
409     }
410
411     # Fines management
412     if ( $cgi->param('show_fines') eq "1" ) {
413         my @charges;
414         for ( my $i = 1 ; my @charge = getcharges( $borrowernumber, undef, $i ) ; $i++ ) {
415             push( @charges, @charge );
416         }
417         $borrower->{'fines'}->{'fine'} = \@charges;
418     }
419
420     # Reserves management
421     if ( $cgi->param('show_holds') eq "1" ) {
422
423         # Get borrower's reserves
424         my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
425         foreach my $reserve (@reserves) {
426
427             # Get additional informations
428             my $item = GetBiblioFromItemNumber( $reserve->{'itemnumber'}, undef );
429             my $branchname = GetBranchName( $reserve->{'branchcode'} );
430
431             # Remove unwanted fields
432             delete $item->{'marc'};
433             delete $item->{'marcxml'};
434             delete $item->{'more_subfields_xml'};
435
436             # Add additional fields
437             $reserve->{'item'}       = $item;
438             $reserve->{'branchname'} = $branchname;
439             $reserve->{'title'}      = ( GetBiblio( $reserve->{'biblionumber'} ) )[1]->{'title'};
440         }
441         $borrower->{'holds'}->{'hold'} = \@reserves;
442     }
443
444     # Issues management
445     if ( $cgi->param('show_loans') eq "1" ) {
446         my $issues = GetPendingIssues($borrowernumber);
447         $borrower->{'loans'}->{'loan'} = $issues;
448     }
449
450     return $borrower;
451 }
452
453 =head2 GetPatronStatus
454
455         Returns a patron's status information.
456         
457         Parameters:
458
459         - patron_id (Required)
460                 the borrower ID
461
462 =cut
463
464 sub GetPatronStatus {
465     my ($cgi) = @_;
466
467     # Get Member details
468     my $borrowernumber = $cgi->param('patron_id');
469 <<<<<<< HEAD:C4/ILSDI/Services.pm
470     my $borrower = GetMemberDetails( $borrowernumber, undef );
471     if ( not $borrower->{'borrowernumber'} ) {
472         return { message => 'PatronNotFound' };
473     }
474
475     # Hashref building
476     my $patron;
477     $patron->{'type'}   = $borrower->{'categorycode'};
478     $patron->{'status'} = 0;                             #TODO
479     $patron->{'expiry'} = $borrower->{'dateexpiry'};
480
481     return $patron;
482 =======
483     my $borrower = GetMemberDetails( $borrowernumber );
484     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
485
486     # Return the results
487     return {
488         type   => $$borrower{categorycode},
489         status => 0, # TODO
490         expiry => $$borrower{dateexpiry},
491     };
492 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
493 }
494
495 =head2 GetServices
496
497         Returns information about the services available on a particular item for 
498         a particular patron.
499         
500         Parameters:
501
502         - patron_id (Required)
503                 a borrowernumber
504         - item_id (Required)
505                 an itemnumber
506 =cut
507
508 sub GetServices {
509     my ($cgi) = @_;
510
511     # Get the member, or return an error code if not found
512     my $borrowernumber = $cgi->param('patron_id');
513 <<<<<<< HEAD:C4/ILSDI/Services.pm
514     my $borrower = GetMemberDetails( $borrowernumber, undef );
515     if ( not $borrower->{'borrowernumber'} ) {
516         return { message => 'PatronNotFound' };
517     }
518
519     # Get the item, or return an error code if not found
520     my $itemnumber = $cgi->param('item_id');
521     my $item = GetItem( $itemnumber, undef, undef );
522     if ( not $item->{'itemnumber'} ) {
523         return { message => 'RecordNotFound' };
524     }
525 =======
526     my $borrower = GetMemberDetails( $borrowernumber );
527     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
528
529     # Get the item, or return an error code if not found
530     my $itemnumber = $cgi->param('item_id');
531     my $item = GetItem( $itemnumber );
532     return { code => 'RecordNotFound' } unless $$item{itemnumber};
533 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
534
535     my @availablefor;
536
537     # Reserve level management
538     my $biblionumber = $item->{'biblionumber'};
539     my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
540     if ($canbookbereserved) {
541         push @availablefor, 'title level hold';
542         my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber);
543         if ($canitembereserved) {
544             push @availablefor, 'item level hold';
545         }
546     }
547
548     # Reserve cancellation management
549     my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
550     my @reserveditems;
551     foreach my $reserve (@reserves) {
552         push @reserveditems, $reserve->{'itemnumber'};
553     }
554     if ( grep { $itemnumber eq $_ } @reserveditems ) {
555         push @availablefor, 'hold cancellation';
556     }
557
558     # Renewal management
559     my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
560     if ( $renewal[0] ) {
561         push @availablefor, 'loan renewal';
562     }
563
564     # Issuing management
565     my $barcode = $item->{'barcode'} || '';
566     $barcode = barcodedecode($barcode) if ( $barcode && C4::Context->preference('itemBarcodeInputFilter') );
567     if ($barcode) {
568         my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $borrower, $barcode );
569
570         # TODO push @availablefor, 'loan';
571     }
572
573     my $out;
574     $out->{'AvailableFor'} = \@availablefor;
575
576     return $out;
577 }
578
579 =head2 RenewLoan
580
581         Extends the due date for a borrower's existing issue.
582         
583         Parameters:
584
585         - patron_id (Required)
586                 a borrowernumber
587         - item_id (Required)
588                 an itemnumber
589         - desired_due_date (Required)
590                 the date the patron would like the item returned by 
591
592 =cut
593
594 sub RenewLoan {
595     my ($cgi) = @_;
596
597     # Get borrower infos or return an error code
598     my $borrowernumber = $cgi->param('patron_id');
599 <<<<<<< HEAD:C4/ILSDI/Services.pm
600     my $borrower = GetMemberDetails( $borrowernumber, undef );
601     if ( not $borrower->{'borrowernumber'} ) {
602         return { message => 'PatronNotFound' };
603     }
604 =======
605     my $borrower = GetMemberDetails( $borrowernumber );
606     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
607 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
608
609     # Get the item, or return an error code
610     my $itemnumber = $cgi->param('item_id');
611 <<<<<<< HEAD:C4/ILSDI/Services.pm
612     my $item = GetItem( $itemnumber, undef, undef );
613     if ( not $item->{'itemnumber'} ) {
614         return { message => 'RecordNotFound' };
615     }
616 =======
617     my $item = GetItem( $itemnumber );
618     return { code => 'RecordNotFound' } unless $$item{itemnumber};
619 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
620
621     # Add renewal if possible
622     my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
623     if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber ); }
624
625     my $issue = GetItemIssue($itemnumber);
626
627     # Hashref building
628     my $out;
629     $out->{'renewals'} = $issue->{'renewals'};
630     $out->{'date_due'} = $issue->{'date_due'};
631     $out->{'success'}  = $renewal[0];
632     $out->{'error'}    = $renewal[1];
633
634     return $out;
635 }
636
637 =head2 HoldTitle
638
639         Creates, for a borrower, a biblio-level hold reserve.
640         
641         Parameters:
642
643         - patron_id (Required)
644                 a borrowernumber
645         - bib_id (Required)
646                 a biblionumber
647         - request_location (Required)
648                 IP address where the end user request is being placed
649         - pickup_location (Optional)
650                 a branch code indicating the location to which to deliver the item for pickup
651         - needed_before_date (Optional)
652                 date after which hold request is no longer needed
653         - pickup_expiry_date (Optional)
654                 date after which item returned to shelf if item is not picked up 
655
656 =cut
657
658 sub HoldTitle {
659     my ($cgi) = @_;
660
661     # Get the borrower or return an error code
662     my $borrowernumber = $cgi->param('patron_id');
663 <<<<<<< HEAD:C4/ILSDI/Services.pm
664     my $borrower = GetMemberDetails( $borrowernumber, undef );
665     if ( not $borrower->{'borrowernumber'} ) {
666         return { message => 'PatronNotFound' };
667     }
668
669     # Get the biblio record, or return an error code
670     my $biblionumber = $cgi->param('bib_id');
671     my ( $count, $biblio ) = GetBiblio($biblionumber);
672     if ( not $biblio->{'biblionumber'} ) {
673         return { message => 'RecordNotFound' };
674     }
675     my $title = $biblio->{'title'};
676
677     # Check if the biblio can be reserved
678     my $canbereserved = CanBookBeReserved( $borrower, $biblionumber );
679     if ( not $canbereserved ) {
680         return { message => 'NotHoldable' };
681     }
682 =======
683     my $borrower = GetMemberDetails( $borrowernumber );
684     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
685
686     # Get the biblio record, or return an error code
687     my $biblionumber = $cgi->param('bib_id');
688     my ( $count, $biblio ) = GetBiblio( $biblionumber );
689     return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
690     
691     my $title = $$biblio{title};
692
693     # Check if the biblio can be reserved
694     return { code => 'NotHoldable' } unless CanBookBeReserved( $borrowernumber, $biblionumber );
695 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
696
697     my $branch;
698
699     # Pickup branch management
700     if ( $cgi->param('pickup_location') ) {
701         $branch = $cgi->param('pickup_location');
702 <<<<<<< HEAD:C4/ILSDI/Services.pm
703         my $branches = GetBranches();
704         if ( not $branches->{$branch} ) {
705             return { message => 'LocationNotFound' };
706         }
707     } else {    # if user provide no branch, use his own
708         $branch = $borrower->{'branchcode'};
709 =======
710         my $branches = GetBranches;
711         return { code => 'LocationNotFound' } unless $$branches{$branch};
712     } else { # if the request provide no branch, use the borrower's branch
713         $branch = $$borrower{branchcode};
714 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
715     }
716
717     # Add the reserve
718     #          $branch, $borrowernumber, $biblionumber, $constraint, $bibitems,  $priority, $notes, $title, $checkitem,  $found
719     AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, 0, undef, $title, undef, undef );
720
721     # Hashref building
722     my $out;
723     $out->{'title'}           = $title;
724     $out->{'pickup_location'} = GetBranchName($branch);
725
726     # TODO $out->{'date_available'}  = '';
727
728     return $out;
729 }
730
731 =head2 HoldItem
732
733         Creates, for a borrower, an item-level hold request on a specific item of 
734         a bibliographic record in Koha.
735
736         Parameters:
737
738         - patron_id (Required)
739                 a borrowernumber
740         - bib_id (Required)
741                 a biblionumber
742         - item_id (Required)
743                 an itemnumber
744         - pickup_location (Optional)
745                 a branch code indicating the location to which to deliver the item for pickup
746         - needed_before_date (Optional)
747                 date after which hold request is no longer needed
748         - pickup_expiry_date (Optional)
749                 date after which item returned to shelf if item is not picked up 
750
751 =cut
752
753 sub HoldItem {
754     my ($cgi) = @_;
755
756     # Get the borrower or return an error code
757     my $borrowernumber = $cgi->param('patron_id');
758 <<<<<<< HEAD:C4/ILSDI/Services.pm
759     my $borrower = GetMemberDetails( $borrowernumber, undef );
760     if ( not $borrower->{'borrowernumber'} ) {
761         return { message => 'PatronNotFound' };
762     }
763 =======
764     my $borrower = GetMemberDetails( $borrowernumber );
765     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
766 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
767
768     # Get the biblio or return an error code
769     my $biblionumber = $cgi->param('bib_id');
770     my ( $count, $biblio ) = GetBiblio($biblionumber);
771 <<<<<<< HEAD:C4/ILSDI/Services.pm
772     if ( not $biblio->{'biblionumber'} ) {
773         return { message => 'RecordNotFound' };
774     }
775     my $title = $biblio->{'title'};
776
777     # Get the item or return an error code
778     my $itemnumber = $cgi->param('item_id');
779     my $item = GetItem( $itemnumber, undef, undef );
780     if ( not $item->{'itemnumber'} ) {
781         return { message => 'RecordNotFound' };
782     }
783
784     # if the biblio does not match the item, return an error code
785     if ( $item->{'biblionumber'} ne $biblio->{'biblionumber'} ) {
786         return { message => 'RecordNotFound' };
787     }
788
789     # Check for item disponibility
790     my $canitembereserved = IsAvailableForItemLevelRequest($itemnumber);
791     my $canbookbereserved = CanBookBeReserved( $borrower, $biblionumber );
792     if ( ( not $canbookbereserved ) or not($canitembereserved) ) {
793         return { message => 'NotHoldable' };
794     }
795 =======
796     return { code => 'RecordNotFound' } unless $$biblio{biblionumber};
797
798     my $title = $$biblio{title};
799
800     # Get the item or return an error code
801     my $itemnumber = $cgi->param('item_id');
802     my $item = GetItem( $itemnumber );
803     return { code => 'RecordNotFound' } unless $$item{itemnumber};
804
805     # If the biblio does not match the item, return an error code
806     return { code => 'RecordNotFound' } if $$item{biblionumber} ne $$biblio{biblionumber};
807
808     # Check for item disponibility
809     my $canitembereserved = CanItemBeReserved( $borrowernumber, $itemnumber );
810     my $canbookbereserved = CanBookBeReserved( $borrowernumber, $biblionumber );
811     return { code => 'NotHoldable' } unless $canbookbereserved and $canitembereserved;
812 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
813
814     my $branch;
815
816     # Pickup branch management
817     if ( $cgi->param('pickup_location') ) {
818         $branch = $cgi->param('pickup_location');
819         my $branches = GetBranches();
820 <<<<<<< HEAD:C4/ILSDI/Services.pm
821         if ( not $branches->{$branch} ) {
822             return { message => 'LocationNotFound' };
823         }
824     } else {    # if user provide no branch, use his own
825         $branch = $borrower->{'branchcode'};
826 =======
827         return { code => 'LocationNotFound' } unless $$branches{$branch};
828     } else { # if the request provide no branch, use the borrower's branch
829         $branch = $$borrower{branchcode};
830 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
831     }
832
833     my $rank;
834     my $found;
835
836     # Get rank and found
837     $rank = '0' unless C4::Context->preference('ReservesNeedReturns');
838     if ( $item->{'holdingbranch'} eq $branch ) {
839         $found = 'W' unless C4::Context->preference('ReservesNeedReturns');
840     }
841
842     # Add the reserve
843     #          $branch, $borrowernumber, $biblionumber, $constraint, $bibitems,  $priority, $notes, $title, $checkitem,  $found
844     AddReserve( $branch, $borrowernumber, $biblionumber, 'a', undef, $rank, undef, $title, $itemnumber, $found );
845
846     # Hashref building
847     my $out;
848     $out->{'pickup_location'} = GetBranchName($branch);
849
850     # TODO $out->{'date_available'} = '';
851
852     return $out;
853 }
854
855 =head2 CancelHold
856
857         Cancels an active reserve request for the borrower.
858         
859         Parameters:
860
861         - patron_id (Required)
862                 a borrowernumber
863         - item_id (Required)
864                 an itemnumber 
865
866 =cut
867
868 sub CancelHold {
869     my ($cgi) = @_;
870
871     # Get the borrower or return an error code
872     my $borrowernumber = $cgi->param('patron_id');
873 <<<<<<< HEAD:C4/ILSDI/Services.pm
874     my $borrower = GetMemberDetails( $borrowernumber, undef );
875     if ( not $borrower->{'borrowernumber'} ) {
876         return { message => 'PatronNotFound' };
877     }
878
879     # Get the item or return an error code
880     my $itemnumber = $cgi->param('item_id');
881     my $item = GetItem( $itemnumber, undef, undef );
882     if ( not $item->{'itemnumber'} ) {
883         return { message => 'RecordNotFound' };
884     }
885 =======
886     my $borrower = GetMemberDetails( $borrowernumber );
887     return { code => 'PatronNotFound' } unless $$borrower{borrowernumber};
888
889     # Get the item or return an error code
890     my $itemnumber = $cgi->param('item_id');
891     my $item = GetItem( $itemnumber );
892     return { code => 'RecordNotFound' } unless $$item{itemnumber};
893 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
894
895     # Get borrower's reserves
896     my @reserves = GetReservesFromBorrowernumber( $borrowernumber, undef );
897     my @reserveditems;
898
899     # ...and loop over it to build an array of reserved itemnumbers
900     foreach my $reserve (@reserves) {
901         push @reserveditems, $reserve->{'itemnumber'};
902     }
903
904     # if the item was not reserved by the borrower, returns an error code
905 <<<<<<< HEAD:C4/ILSDI/Services.pm
906     if ( not grep { $itemnumber eq $_ } @reserveditems ) {
907         return { message => 'NotCanceled' };
908     }
909 =======
910     return { code => 'NotCanceled' } unless any { $itemnumber eq $_ } @reserveditemnumbers;
911 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
912
913     # Cancel the reserve
914     CancelReserve( $itemnumber, undef, $borrowernumber );
915
916 <<<<<<< HEAD:C4/ILSDI/Services.pm
917     return { message => 'Canceled' };
918
919 =======
920     return { code => 'Canceled' };
921 >>>>>>> [MT2306_2271] ILS-DI Message codes consistence:C4/ILSDI.pm
922 }
923
924 1;