Bug 19287: Use the notice defined for the homebranch of the patron
[koha.git] / circ / pendingreserves.pl
1 #!/usr/bin/perl
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use constant PULL_INTERVAL => 2;
23
24 use C4::Context;
25 use C4::Output;
26 use CGI qw ( -utf8 );
27 use C4::Auth;
28 use C4::Debug;
29 use C4::Items qw( ModItem ModItemTransfer );
30 use C4::Reserves qw( ModReserveCancelAll );
31 use Koha::Biblios;
32 use Koha::DateUtils;
33 use Koha::Holds;
34 use DateTime::Duration;
35
36 my $input = new CGI;
37 my $startdate = $input->param('from');
38 my $enddate = $input->param('to');
39 my $theme = $input->param('theme');    # only used if allowthemeoverride is set
40 my $op         = $input->param('op') || '';
41 my $borrowernumber = $input->param('borrowernumber');
42 my $reserve_id = $input->param('reserve_id');
43
44 my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
45     {
46         template_name   => "circ/pendingreserves.tt",
47         query           => $input,
48         type            => "intranet",
49         authnotrequired => 0,
50         flagsrequired   => { circulate => "circulate_remaining_permissions" },
51         debug           => 1,
52     }
53 );
54
55 my @messages;
56 if ( $op eq 'cancel_reserve' and $reserve_id ) {
57     my $hold = Koha::Holds->find( $reserve_id );
58     if ( $hold ) {
59         $hold->cancel;
60         push @messages, { type => 'message', code => 'hold_cancelled' };
61     }
62 } elsif ( $op =~ m|^mark_as_lost| ) {
63     my $hold = Koha::Holds->find( $reserve_id );
64     die "wrong reserve_id" unless $hold; # This is a bit rude, but we are not supposed to get a wrong reserve_id
65     my $item = $hold->item;
66     if ( $item and C4::Context->preference('CanMarkHoldsToPullAsLost') =~ m|^allow| ) {
67         my $patron = $hold->borrower;
68         C4::Circulation::LostItem( $item->itemnumber, "pendingreserves" );
69         if ( $op eq 'mark_as_lost_and_notify' and C4::Context->preference('CanMarkHoldsToPullAsLost') eq 'allow_and_notify' ) {
70             my $library = $hold->branch;
71             my $letter = C4::Letters::GetPreparedLetter(
72                 module => 'reserves',
73                 letter_code => 'CANCEL_HOLD_ON_LOST',
74                 branchcode => $patron->homebranch,
75                 lang => $patron->lang,
76                 tables => {
77                     branches    => $library->branchcode,
78                     borrowers   => $patron->borrowernumber,
79                     items       => $item->itemnumber,
80                     biblio      => $hold->biblionumber,
81                     biblioitems => $hold->biblionumber,
82                     reserves    => $hold->unblessed,
83                 },
84             );
85             if ( $letter ) {
86                 my $admin_email_address = $library->branchemail || C4::Context->preference('KohaAdminEmailAddress');
87
88                 C4::Letters::EnqueueLetter(
89                     {   letter                 => $letter,
90                         borrowernumber         => $patron->borrowernumber,
91                         message_transport_type => 'email',
92                         from_address           => $admin_email_address,
93                     }
94                 );
95                 unless ( $patron->notice_email_address ) {
96                     push @messages, {type => 'alert', code => 'no_email_address', };
97                 }
98                 push @messages, { type => 'message', code => 'letter_enqueued' };
99             } else {
100                 push @messages, { type => 'error', code => 'no_template_notice' };
101             }
102         }
103         $hold->cancel;
104         if ( $item->homebranch ne $item->holdingbranch ) {
105             C4::Items::ModItemTransfer( $item->itemnumber, $item->holdingbranch, $item->homebranch );
106         }
107
108         if ( my $yaml = C4::Context->preference('UpdateItemWhenLostFromHoldList') ) {
109             $yaml = "$yaml\n\n";  # YAML is anal on ending \n. Surplus does not hurt
110             my $assignments;
111             eval { $assignments = YAML::Load($yaml); };
112             if ($@) {
113                 warn "Unable to parse UpdateItemWhenLostFromHoldList syspref : $@" if $@;
114             }
115             else {
116                 eval {
117                     C4::Items::ModItem( $assignments, undef, $item->itemnumber );
118                 };
119                 warn "Unable to modify item itemnumber=" . $item->itemnumber . ": $@" if $@;
120             }
121         }
122
123     } elsif ( not $item ) {
124         push @messages, { type => 'alert', code => 'hold_placed_at_biblio_level'};
125     } # else the url parameters have been modified and the user is not allowed to continue
126 }
127
128
129 my $today = dt_from_string;
130
131 if ( $startdate ) {
132     $startdate =~ s/^\s+//;
133     $startdate =~ s/\s+$//;
134     $startdate = eval{dt_from_string( $startdate )};
135 }
136 unless ( $startdate ){
137     # changed from delivered range of 10 years-yesterday to 2 days ago-today
138     # Find two days ago for the default shelf pull start date, unless HoldsToPullStartDate sys pref is set.
139     $startdate = $today - DateTime::Duration->new( days => C4::Context->preference('HoldsToPullStartDate') || PULL_INTERVAL );
140 }
141
142 if ( $enddate ) {
143     $enddate =~ s/^\s+//;
144     $enddate =~ s/\s+$//;
145     $enddate = eval{dt_from_string( $enddate )};
146 }
147 unless ( $enddate ) {
148     #similarly: calculate end date with ConfirmFutureHolds (days)
149     $enddate = $today + DateTime::Duration->new( days => C4::Context->preference('ConfirmFutureHolds') || 0 );
150 }
151
152 my @reservedata;
153 my $dbh = C4::Context->dbh;
154 my $sqldatewhere = "";
155 my $startdate_iso = output_pref({ dt => $startdate, dateformat => 'iso', dateonly => 1 });
156 my $enddate_iso   = output_pref({ dt => $enddate, dateformat => 'iso', dateonly => 1 });
157
158 $debug and warn $startdate_iso. "\n" . $enddate_iso;
159
160 my @query_params = ();
161
162 if ($startdate_iso) {
163     $sqldatewhere .= " AND reservedate >= ?";
164     push @query_params, $startdate_iso;
165 }
166 if ($enddate_iso) {
167     $sqldatewhere .= " AND reservedate <= ?";
168     push @query_params, $enddate_iso;
169 }
170
171 my $strsth =
172     "SELECT min(reservedate) as l_reservedate,
173             reserves.reserve_id,
174             reserves.borrowernumber as borrowernumber,
175
176             GROUP_CONCAT(DISTINCT items.holdingbranch 
177                     ORDER BY items.itemnumber SEPARATOR '|') l_holdingbranch,
178             reserves.biblionumber,
179             reserves.branchcode as l_branch,
180             items.itemnumber,
181             items.holdingbranch,
182             items.homebranch,
183             GROUP_CONCAT(DISTINCT items.itype 
184                     ORDER BY items.itemnumber SEPARATOR '|') l_itype,
185             GROUP_CONCAT(DISTINCT items.location 
186                     ORDER BY items.itemnumber SEPARATOR '|') l_location,
187             GROUP_CONCAT(DISTINCT items.itemcallnumber 
188                     ORDER BY items.itemnumber SEPARATOR '<br/>') l_itemcallnumber,
189             GROUP_CONCAT(DISTINCT items.enumchron
190                     ORDER BY items.itemnumber SEPARATOR '<br/>') l_enumchron,
191             GROUP_CONCAT(DISTINCT items.copynumber
192                     ORDER BY items.itemnumber SEPARATOR '<br/>') l_copynumber,
193             biblio.title,
194             biblio.author,
195             count(DISTINCT items.itemnumber) as icount,
196             count(DISTINCT reserves.borrowernumber) as rcount,
197             borrowers.firstname,
198             borrowers.surname
199     FROM  reserves
200         LEFT JOIN items ON items.biblionumber=reserves.biblionumber 
201         LEFT JOIN biblio ON reserves.biblionumber=biblio.biblionumber
202         LEFT JOIN branchtransfers ON items.itemnumber=branchtransfers.itemnumber
203         LEFT JOIN issues ON items.itemnumber=issues.itemnumber
204         LEFT JOIN borrowers ON reserves.borrowernumber=borrowers.borrowernumber
205     WHERE
206     reserves.found IS NULL
207     $sqldatewhere
208     AND (reserves.itemnumber IS NULL OR reserves.itemnumber = items.itemnumber)
209     AND items.itemnumber NOT IN (SELECT itemnumber FROM branchtransfers where datearrived IS NULL)
210     AND items.itemnumber NOT IN (select itemnumber FROM reserves where found IS NOT NULL)
211     AND issues.itemnumber IS NULL
212     AND reserves.priority <> 0 
213     AND reserves.suspend = 0
214     AND notforloan = 0 AND damaged = 0 AND itemlost = 0 AND withdrawn = 0
215     ";
216     # GROUP BY reserves.biblionumber allows only items that are not checked out, else multiples occur when 
217     #    multiple patrons have a hold on an item
218
219
220 if (C4::Context->preference('IndependentBranches')){
221     $strsth .= " AND items.holdingbranch=? ";
222     push @query_params, C4::Context->userenv->{'branch'};
223 }
224 $strsth .= " GROUP BY reserves.biblionumber ORDER BY biblio.title ";
225
226 my $sth = $dbh->prepare($strsth);
227 $sth->execute(@query_params);
228
229 while ( my $data = $sth->fetchrow_hashref ) {
230     my $record = Koha::Biblios->find($data->{biblionumber});
231     if ($record){
232         $data->{subtitle} = [ $record->subtitles ];
233     }
234     push(
235         @reservedata, {
236             reservedate     => $data->{l_reservedate},
237             firstname       => $data->{firstname} || '',
238             surname         => $data->{surname},
239             title           => $data->{title},
240             subtitle        => $data->{subtitle},
241             author          => $data->{author},
242             borrowernumber  => $data->{borrowernumber},
243             biblionumber    => $data->{biblionumber},
244             holdingbranches => [split('\|', $data->{l_holdingbranch})],
245             branch          => $data->{l_branch},
246             itemcallnumber  => $data->{l_itemcallnumber},
247             enumchron       => $data->{l_enumchron},
248             copyno          => $data->{l_copynumber},
249             count           => $data->{icount},
250             rcount          => $data->{rcount},
251             pullcount       => $data->{icount} <= $data->{rcount} ? $data->{icount} : $data->{rcount},
252             itypes          => [split('\|', $data->{l_itype})],
253             locations       => [split('\|', $data->{l_location})],
254             reserve_id      => $data->{reserve_id},
255             holdingbranch   => $data->{holdingbranch},
256             homebranch      => $data->{homebranch},
257             itemnumber      => $data->{itemnumber},
258         }
259     );
260 }
261 $sth->finish;
262
263 $template->param(
264     todaysdate          => $today,
265     from                => $startdate,
266     to                  => $enddate,
267     reserveloop         => \@reservedata,
268     "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1,
269     HoldsToPullStartDate => C4::Context->preference('HoldsToPullStartDate') || PULL_INTERVAL,
270     HoldsToPullEndDate  => C4::Context->preference('ConfirmFutureHolds') || 0,
271     messages            => \@messages,
272 );
273
274 output_html_with_http_headers $input, $cookie, $template->output;