reserve and virtualshelves (leftovers) - Dates.pm integration and warnings fixes.
[koha.git] / reserve / request.pl
1 #!/usr/bin/perl
2
3
4 #writen 2/1/00 by chris@katipo.oc.nz
5 # Copyright 2000-2002 Katipo Communications
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
12 # version.
13 #
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License along with
19 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 # Suite 330, Boston, MA  02111-1307 USA
21
22 =head1 request.pl
23
24 script to place reserves/requests
25
26 =cut
27
28 use strict;
29 use C4::Branch; # GetBranches get_branchinfos_of
30 use CGI;
31 use List::MoreUtils qw/uniq/;
32 use Date::Calc qw/Today Date_to_Days/;
33 use C4::Output;
34 use C4::Auth;
35 use C4::Reserves;
36 use C4::Biblio;
37 use C4::Koha;
38 use C4::Circulation;
39 use C4::Dates;
40 use C4::Members;
41
42 my $dbh = C4::Context->dbh;
43 my $sth;
44 my $input = new CGI;
45 my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
46     {
47         template_name   => "reserve/request.tmpl",
48         query           => $input,
49         type            => "intranet",
50         authnotrequired => 0,
51         flagsrequired   => { reserveforothers => 1 },
52     }
53 );
54
55 # get biblio information....
56 my $biblionumber = $input->param('biblionumber');
57 my $dat          = GetBiblioData($biblionumber);
58
59 # Select borrowers infos
60 my $findborrower = $input->param('findborrower');
61 $findborrower =~ s|,| |g;
62 my $cardnumber = $input->param('cardnumber');
63 my $borrowerslist;
64 my $messageborrower;
65
66 my $date = sprintf( '%04d-%02d-%02d', Today() );
67
68 if ($findborrower) {
69     my ( $count, $borrowers ) =
70       SearchMember($findborrower, 'cardnumber', 'web' );
71
72     my @borrowers = @$borrowers;
73
74     if ( $#borrowers == -1 ) {
75         $input->param( 'findborrower', '' );
76         $messageborrower = "'$findborrower'";
77     }
78     elsif ( $#borrowers == 0 ) {
79         $input->param( 'cardnumber', $borrowers[0]->{'cardnumber'} );
80         $cardnumber = $borrowers[0]->{'cardnumber'};
81     }
82     else {
83         $borrowerslist = \@borrowers;
84     }
85 }
86
87 if ($cardnumber) {
88     my $borrowerinfo = GetMemberDetails( 0, $cardnumber );
89     my $expiry;
90     my $diffbranch;
91     my @getreservloop;
92     my $count_reserv = 0;
93     my $maxreserves;
94
95 #       we check the reserves of the borrower, and if he can reserv a document
96 # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
97
98     my $number_reserves =
99       GetReserveCount( $borrowerinfo->{'borrowernumber'} );
100
101     if ( $number_reserves > C4::Context->preference('maxreserves') ) {
102         $maxreserves = 1;
103     }
104
105     # we check the date expiricy of the borrower (only if there is an expiry date, otherwise, set to 1 (warn)
106     if ($borrowerinfo->{'dateexpiry'} ne '0000-00-00') {
107         my $warning = (Date_to_Days(split /-/,$date) > Date_to_Days( split /-/,$borrowerinfo->{'dateexpiry'}));
108         if ( $warning > 0 ) {
109             $expiry = 1;
110         }
111     } else {
112         $expiry = 1;
113     }
114      
115
116     # check if the borrower make the reserv in a different branch
117     if ( $borrowerinfo->{'branchcode'} ne C4::Context->userenv->{'branch'} ) {
118         $diffbranch = 1;
119     }
120
121     $template->param(
122                 borrowernumber => $borrowerinfo->{'borrowernumber'},
123                 borrowersurname   => $borrowerinfo->{'surname'},
124                 borrowerfirstname => $borrowerinfo->{'firstname'},
125                 borrowerstreetaddress => $borrowerinfo->{'address'},
126                 borrowercity => $borrowerinfo->{'city'},
127                 borrowerphone => $borrowerinfo->{'phone'},
128                                 borrowermobile => $borrowerinfo->{'mobile'},
129                                 borrowerfax => $borrowerinfo->{'fax'},
130                                 borrowerphonepro => $borrowerinfo->{'phonepro'},
131                 borroweremail => $borrowerinfo->{'email'},
132                 borroweremailpro => $borrowerinfo->{'emailpro'},
133                 borrowercategory => $borrowerinfo->{'category'},
134                 borrowerreservs   => $count_reserv,
135                 maxreserves       => $maxreserves,
136                 expiry            => $expiry,
137                 diffbranch        => $diffbranch
138     );
139 }
140
141 $template->param( messageborrower => $messageborrower );
142
143 my $CGIselectborrower;
144 if ($borrowerslist) {
145     my @values;
146     my %labels;
147
148     foreach my $borrower (
149         sort {
150                 $a->{surname}
151               . $a->{firstname} cmp $b->{surname}
152               . $b->{firstname}
153         } @{$borrowerslist}
154       )
155     {
156         push @values, $borrower->{cardnumber};
157
158         $labels{ $borrower->{cardnumber} } = sprintf(
159             '%s, %s ... (%s - %s) ... %s',
160             $borrower->{surname},    $borrower->{firstname},
161             $borrower->{cardnumber}, $borrower->{categorycode},
162             $borrower->{streetaddress},
163         );
164     }
165
166     $CGIselectborrower = CGI::scrolling_list(
167         -name     => 'cardnumber',
168         -values   => \@values,
169         -labels   => \%labels,
170         -size     => 7,
171         -multiple => 0,
172     );
173 }
174
175 # get existing reserves .....
176 my ( $count, $reserves ) = GetReservesFromBiblionumber($biblionumber);
177 my $totalcount = $count;
178 my $alreadyreserved;
179
180 # FIXME launch another time GetMemberDetails perhaps until
181 my $borrowerinfo = GetMemberDetails( 0, $cardnumber );
182
183 foreach my $res (@$reserves) {
184     if ( ( $res->{found} eq 'W' ) or ( $res->{priority} == 0 ) ) {
185         $count--;
186     }
187
188     if ( $borrowerinfo->{borrowernumber} eq $res->{borrowernumber} ) {
189         $alreadyreserved = 1;
190     }
191 }
192
193 $template->param( alreadyreserved => $alreadyreserved );
194
195 # FIXME think @optionloop, is maybe obsolete, or  must be switchable by a systeme preference fixed rank or not
196 # make priorities options
197
198 my @optionloop;
199 for ( 1 .. $count + 1 ) {
200     push(
201         @optionloop,
202         {
203             num      => $_,
204             selected => ( $_ == $count + 1 ),
205         }
206     );
207 }
208 # adding a fixed value for priority options
209 my $fixedRank = $count+1;
210
211 my @branchcodes;
212 my %itemnumbers_of_biblioitem;
213 my @itemnumbers  = @{ get_itemnumbers_of($biblionumber)->{$biblionumber} };
214 my $iteminfos_of = GetItemInfosOf(@itemnumbers);
215
216 foreach my $itemnumber (@itemnumbers) {
217     push( @branchcodes,
218         $iteminfos_of->{$itemnumber}->{homebranch},
219         $iteminfos_of->{$itemnumber}->{holdingbranch} );
220
221     my $biblioitemnumber = $iteminfos_of->{$itemnumber}->{biblioitemnumber};
222     push( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} }, $itemnumber );
223 }
224
225 # @branchcodes = uniq @branchcodes;
226
227 my @biblioitemnumbers = keys %itemnumbers_of_biblioitem;
228
229 my $branchinfos_of      = get_branchinfos_of(@branchcodes);
230 my $notforloan_label_of = get_notforloan_label_of();
231 my $biblioiteminfos_of  = GetBiblioItemInfosOf(@biblioitemnumbers);
232
233 my @itemtypes;
234 foreach my $biblioitemnumber (@biblioitemnumbers) {
235     push @itemtypes, $biblioiteminfos_of->{$biblioitemnumber}{itemtype};
236 }
237
238 my $itemtypeinfos_of = get_itemtypeinfos_of(@itemtypes);
239
240 my @bibitemloop;
241
242 foreach my $biblioitemnumber (@biblioitemnumbers) {
243     my $biblioitem = $biblioiteminfos_of->{$biblioitemnumber};
244
245     $biblioitem->{description} =
246       $itemtypeinfos_of->{ $biblioitem->{itemtype} }{description};
247
248     foreach
249       my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } )
250     {
251         my $item = $iteminfos_of->{$itemnumber};
252
253         $item->{homebranchname} =
254           $branchinfos_of->{ $item->{homebranch} }{branchname};
255
256         # if the holdingbranch is different than the homebranch, we show the
257         # holdingbranch of the document too
258         if ( $item->{homebranch} ne $item->{holdingbranch} ) {
259             $item->{holdingbranchname} =
260               $branchinfos_of->{ $item->{holdingbranch} }{branchname};
261         }
262         
263 #       add information
264         $item->{itemcallnumber} = $item->{itemcallnumber};
265         
266         # if the item is currently on loan, we display its return date and
267         # change the background color
268         my $issues= GetItemIssue($itemnumber);
269         if ( $issues->{'date_due'} ) {
270             $item->{date_due} = format_date($issues->{'date_due'});
271             $item->{backgroundcolor} = 'onloan';
272         }
273
274         # checking reserve
275         my ($reservedate,$reservedfor,$expectedAt) = GetReservesFromItemnumber($itemnumber);
276         my $ItemBorrowerReserveInfo = GetMemberDetails( $reservedfor, 0);
277
278         if ( defined $reservedate ) {
279             $item->{backgroundcolor} = 'reserved';
280             $item->{reservedate}     = format_date($reservedate);
281             $item->{ReservedForBorrowernumber}     = $reservedfor;
282             $item->{ReservedForSurname}     = $ItemBorrowerReserveInfo->{'surname'};
283             $item->{ReservedForFirstname}     = $ItemBorrowerReserveInfo->{'firstname'};
284             $item->{ExpectedAtLibrary}     = $expectedAt;
285             
286         }
287
288         # Management of the notforloan document
289         if ( $item->{notforloan} ) {
290             $item->{backgroundcolor} = 'other';
291             $item->{notforloanvalue} =
292               $notforloan_label_of->{ $item->{notforloan} };
293         }
294
295         # Management of lost or long overdue items
296         if ( $item->{itemlost} ) {
297
298             # FIXME localized strings should never be in Perl code
299             $item->{message} =
300                 $item->{itemlost} == 1 ? "(lost)"
301               : $item->{itemlost} == 2 ? "(long overdue)"
302               : "";
303             $item->{backgroundcolor} = 'other';
304         }
305
306         # Check of the transfered documents
307         my ( $transfertwhen, $transfertfrom, $transfertto ) =
308           GetTransfers($itemnumber);
309
310         if ( $transfertwhen ne '' ) {
311             $item->{transfertwhen} = format_date($transfertwhen);
312             $item->{transfertfrom} =
313               $branchinfos_of->{$transfertfrom}{branchname};
314             $item->{transfertto} = $branchinfos_of->{$transfertto}{branchname};
315                 $item->{nocancel} = 1;
316         }
317
318         # If there is no loan, return and transfer, we show a checkbox.
319         $item->{notforloan} = $item->{notforloan} || 0;
320         
321         # if independent branches is on we need to check if the person can reserve
322         # for branches they arent logged in to
323         if ( C4::Context->preference("IndependantBranches") ) { 
324             if (! C4::Context->preference("canreservefromotherbranches")){
325                 # cant reserve items so need to check if item homebranch and userenv branch match if not we cant reserve
326                 my $userenv = C4::Context->userenv; 
327                 if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
328                     $item->{cantreserve} = 1 if ( $item->{homebranch} ne $userenv->{branch} );
329                 } 
330             }
331         }
332         # An item is available only if:
333         if (
334             not defined $reservedate    # not reserved yet
335             and $issues->{'date_due'} eq ''         # not currently on loan
336             and not $item->{itemlost}   # not lost
337             and not $item->{notforloan} # not forbidden to loan
338             and not $item->{cantreserve}
339             and $transfertwhen eq ''    # not currently on transfert
340           )
341         {
342             $item->{available} = 1;
343         }
344
345         push @{ $biblioitem->{itemloop} }, $item;
346     }
347
348     push @bibitemloop, $biblioitem;
349 }
350
351 # existingreserves building
352 my @reserveloop;
353 my $branches = GetBranches();
354 ( $count, $reserves ) = GetReservesFromBiblionumber($biblionumber);
355 foreach my $res ( sort { $a->{found} cmp $b->{found} } @$reserves ) {
356     my %reserve;
357     my @optionloop;
358     for ( my $i = 1 ; $i <= $totalcount ; $i++ ) {
359         push(
360             @optionloop,
361             {
362                 num      => $i,
363                 selected => ( $i == $res->{priority} ),
364             }
365         );
366     }
367     my @branchloop;
368     foreach my $br ( keys %$branches ) {
369         my %abranch;
370         $abranch{'selected'}   = ( $br eq $res->{'branchcode'} );
371         $abranch{'branch'}     = $br;
372         $abranch{'branchname'} = $branches->{$br}->{'branchname'};
373         push( @branchloop, \%abranch );
374     }
375
376     if ( ( $res->{'found'} eq 'W' ) or ( $res->{'priority'} eq '0' ) ) {
377         my $item = $res->{'itemnumber'};
378         $item = GetBiblioFromItemNumber($item,undef);
379         $reserve{'wait'}= 1; 
380         $reserve{'holdingbranch'}=$item->{'holdingbranch'};
381         $reserve{'biblionumber'}=$item->{'biblionumber'};
382         $reserve{'barcodenumber'}       = $item->{'barcode'};
383         $reserve{'wbrcode'} = $res->{'branchcode'};
384         $reserve{'itemnumber'}  = $res->{'itemnumber'};
385         $reserve{'wbrname'} = $branches->{$res->{'branchcode'}}->{'branchname'};
386         if($reserve{'holdingbranch'} eq $reserve{'wbrcode'}){
387             $reserve{'atdestination'} = 1;
388         }
389         # set found to 1 if reserve is waiting for patron pickup
390         $reserve{'found'} = 1 if $res->{'found'} eq 'W';
391     }
392     
393 #     get borrowers reserve info
394 my $reserveborrowerinfo = GetMemberDetails( $res->{'borrowernumber'}, 0);
395
396     $reserve{'date'}           = format_date( $res->{'reservedate'} );
397     $reserve{'borrowernumber'} = $res->{'borrowernumber'};
398     $reserve{'biblionumber'}   = $res->{'biblionumber'};
399     $reserve{'borrowernumber'} = $res->{'borrowernumber'};
400     $reserve{'firstname'}      = $reserveborrowerinfo->{'firstname'};
401     $reserve{'surname'}        = $reserveborrowerinfo->{'surname'};
402     $reserve{'notes'}          = $res->{'reservenotes'};
403     $reserve{'wait'}           =
404       ( ( $res->{'found'} eq 'W' ) or ( $res->{'priority'} eq '0' ) );
405     $reserve{'constrainttypea'} = ( $res->{'constrainttype'} eq 'a' );
406     $reserve{'constrainttypeo'} = ( $res->{'constrainttype'} eq 'o' );
407     $reserve{'voldesc'}         = $res->{'volumeddesc'};
408     $reserve{'ccode'}           = $res->{'ccode'};
409     $reserve{'barcode'}         = $res->{'barcode'};
410     $reserve{'priority'}        = $res->{'priority'};
411     $reserve{'branchloop'} = \@branchloop;
412     $reserve{'optionloop'} = \@optionloop;
413
414     push( @reserveloop, \%reserve );
415 }
416
417 my $default = C4::Context->userenv->{branch};
418 my @values;
419 my %label_of;
420
421 foreach my $branchcode ( keys %{$branches} ) {
422     push @values, $branchcode;
423     $label_of{$branchcode} = $branches->{$branchcode}->{branchname};
424 }
425 my $CGIbranch = CGI::scrolling_list(
426     -name     => 'pickup',
427         -id          => 'pickup',
428     -values   => \@values,
429     -default  => $default,
430     -labels   => \%label_of,
431     -size     => 1,
432     -multiple => 0,
433 );
434
435 # get the time for the form name...
436 my $time = time();
437
438 $template->param(
439     CGIbranch   => $CGIbranch,
440     reserveloop => \@reserveloop,
441     time        => $time,
442     fixedRank   => $fixedRank,
443 );
444
445 # display infos
446 $template->param(
447     optionloop        => \@optionloop,
448     bibitemloop       => \@bibitemloop,
449     date              => $date,
450     biblionumber      => $biblionumber,
451     findborrower      => $findborrower,
452     cardnumber        => $cardnumber,
453     CGIselectborrower => $CGIselectborrower,
454     title             => $dat->{title},
455     author            => $dat->{author}
456 );
457
458 # printout the page
459 output_html_with_http_headers $input, $cookie, $template->output;