Bug 30222: Remove warning
[koha.git] / misc / cronjobs / automatic_renewals.pl
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Copyright (C) 2014 Hochschule für Gesundheit (hsg), Germany
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 =head1 NAME
21
22 automatic_renewals.pl - cron script to renew loans
23
24 =head1 SYNOPSIS
25
26 ./automatic_renewals.pl [-c|--confirm] [-s|--send-notices] [-d|--digest] [-b|--digest-per-branch] [-v|--verbose]
27
28 or, in crontab:
29 # Once every day for digest messages
30 0 3 * * * automatic_renewals.pl -c -d
31 # Three times a day for non digest messages
32 0 0,8,16 * * * automatic_renewals.pl -c
33
34 =head1 DESCRIPTION
35
36 This script searches for issues scheduled for automatic renewal
37 (issues.auto_renew). If there are still renews left (Renewals allowed)
38 and the renewal isn't premature (No Renewal before) the issue is renewed.
39
40 =head1 OPTIONS
41
42 =over
43
44 =item B<-s|--send-notices>
45
46 DEPRECATED: The system preference AutoRenewalNotices should be used to determine
47 whether notices are sent or not
48 Send AUTO_RENEWALS notices to patrons if the auto renewal has been done.
49
50 =item B<-v|--verbose>
51
52 Print report to standard out.
53
54 =item B<-c|--confirm>
55
56 Without this parameter no changes will be made
57
58 =item B<-b|--digest-per-branch>
59
60 Flag to indicate that generation of message digests should be
61 performed separately for each branch.
62
63 A patron could potentially have loans at several different branches
64 There is no natural branch to set as the sender on the aggregated
65 message in this situation so the default behavior is to use the
66 borrowers home branch.  This could surprise to the borrower when
67 message sender is a library where they have not borrowed anything.
68
69 Enabling this flag ensures that the issuing library is the sender of
70 the digested message.  It has no effect unless the borrower has
71 chosen 'Digests only' on the advance messages.
72
73 =back
74
75 =cut
76
77 use Modern::Perl;
78 use Pod::Usage qw( pod2usage );
79 use Getopt::Long qw( GetOptions );
80
81 use Koha::Script -cron;
82 use C4::Circulation qw( CanBookBeRenewed AddRenewal );
83 use C4::Context;
84 use C4::Log qw( cronlogaction );
85 use C4::Letters;
86 use Koha::Checkouts;
87 use Koha::Libraries;
88 use Koha::Patrons;
89
90 my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
91 GetOptions(
92     'h|help' => \$help,
93     's|send-notices' => \$send_notices,
94     'v|verbose'    => \$verbose,
95     'c|confirm'     => \$confirm,
96     'b|digest-per-branch' => \$digest_per_branch,
97 ) || pod2usage(1);
98
99 pod2usage(0) if $help;
100
101 my $send_notices_pref = C4::Context->preference('AutoRenewalNotices');
102 if ( $send_notices_pref eq 'cron' ) {
103     warn <<'END_WARN';
104
105 The "AutoRenewalNotices" syspref is set to 'Follow the cron switch'.
106 The send_notices switch for this script is deprecated, you should either set the preference
107 to 'Never send emails' or 'Follow patron messaging preferences'
108
109 END_WARN
110 } else {
111     # If not following cron then:
112     # - we should not send if set to never
113     # - we will send any notice generated according to preferences if following those
114     $send_notices = $send_notices_pref eq 'never' ? 0 : 1;
115 }
116
117 # Since advance notice options are not visible in the web-interface
118 # unless EnhancedMessagingPreferences is on, let the user know that
119 # this script probably isn't going to do much
120 if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
121     warn <<'END_WARN';
122
123 The "EnhancedMessagingPreferences" syspref is off.
124 Therefore, it is unlikely that this script will actually produce any messages to be sent.
125 To change this, edit the "EnhancedMessagingPreferences" syspref.
126
127 END_WARN
128 }
129
130 cronlogaction();
131
132 $verbose = 1 unless $verbose or $confirm;
133 print "Test run only\n" unless $confirm;
134
135 print "getting auto renewals\n" if $verbose;
136 my $auto_renews = Koha::Checkouts->search({ auto_renew => 1, 'patron.autorenew_checkouts' => 1 },{ join => 'patron'});
137 print "found " . $auto_renews->count . " auto renewals\n" if $verbose;
138
139 my $renew_digest = {};
140 my %report;
141 while ( my $auto_renew = $auto_renews->next ) {
142     print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
143
144     my ( $borrower_preferences, $wants_email, $wants_digest ) = ( undef, 0, 0 );
145     if ( $send_notices_pref eq 'preferences' ){
146         $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
147             {
148                 borrowernumber => $auto_renew->borrowernumber,
149                 message_name   => 'auto_renewals'
150             }
151         );
152         $wants_email = 1
153             if $borrower_preferences
154             && $borrower_preferences->{transports}
155             && $borrower_preferences->{transports}->{email};
156         $wants_digest = 1
157             if $wants_email
158             && $borrower_preferences->{wants_digest};
159     } else { # Preference is never or cron
160         $wants_email = $send_notices;
161         $wants_digest = 0;
162     }
163
164     # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
165     my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber, undef, 1 );
166     my $updated;
167     if ( $error eq 'auto_renew' ) {
168         $updated = 1;
169         if ($verbose) {
170             say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
171               $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would';
172         }
173         if ($confirm){
174             my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode, undef, undef, undef, 0 );
175             $auto_renew->auto_renew_error(undef)->store;
176         }
177         push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
178             if ( $wants_email ) && !$wants_digest;
179     } elsif ( $error eq 'too_many'
180         or $error eq 'on_reserve'
181         or $error eq 'restriction'
182         or $error eq 'overdue'
183         or $error eq 'too_unseen'
184         or $error eq 'auto_account_expired'
185         or $error eq 'auto_too_late'
186         or $error eq 'auto_too_much_oweing'
187         or $error eq 'auto_too_soon'
188         or $error eq 'item_denied_renewal' ) {
189         if ( $verbose ) {
190             say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
191               $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
192         }
193         $updated = 1 if (!$auto_renew->auto_renew_error || $error ne $auto_renew->auto_renew_error);
194         if ( $updated ) {
195             $auto_renew->auto_renew_error($error)->store if $confirm;
196             push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
197               if $error ne 'auto_too_soon' && ( $wants_email  && !$wants_digest );    # Do not notify if it's too soon
198         }
199     }
200
201     if ( $wants_digest ) {
202         # cache this one to process after we've run through all of the items.
203         if ($digest_per_branch) {
204             $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew';
205             $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew';
206             push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
207             $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
208         } else {
209             $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew';
210             $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew';
211             $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
212             push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
213         }
214     }
215
216 }
217
218 if ( $send_notices && $confirm ) {
219     for my $borrowernumber ( keys %report ) {
220         my $patron = Koha::Patrons->find($borrowernumber);
221         for my $issue ( @{ $report{$borrowernumber} } ) {
222             my $item   = Koha::Items->find( $issue->itemnumber );
223             my $letter = C4::Letters::GetPreparedLetter(
224                 module      => 'circulation',
225                 letter_code => 'AUTO_RENEWALS',
226                 tables      => {
227                     borrowers => $patron->borrowernumber,
228                     issues    => $issue->itemnumber,
229                     items     => $issue->itemnumber,
230                     biblio    => $item->biblionumber,
231                 },
232                 lang => $patron->lang,
233             );
234
235             my $library = Koha::Libraries->find( $patron->branchcode );
236             my $admin_email_address = $library->from_email_address;
237
238             C4::Letters::EnqueueLetter(
239                 {   letter                 => $letter,
240                     borrowernumber         => $borrowernumber,
241                     message_transport_type => 'email',
242                     from_address           => $admin_email_address,
243                 }
244             );
245         }
246     }
247
248     if ($digest_per_branch) {
249         while (my ($branchcode, $digests) = each %$renew_digest) {
250             send_digests({
251                 digests => $digests,
252                 branchcode => $branchcode,
253                 letter_code => 'AUTO_RENEWALS_DGST',
254             });
255         }
256     } else {
257         send_digests({
258             digests => $renew_digest,
259             letter_code => 'AUTO_RENEWALS_DGST',
260         });
261     }
262 }
263
264 =head1 METHODS
265
266 =head2 send_digests
267
268     send_digests({
269         digests => ...,
270         letter_code => ...,
271     })
272
273 Enqueue digested letters.
274
275 Parameters:
276
277 =over 4
278
279 =item C<$digests>
280
281 Reference to the array of digested messages.
282
283 =item C<$letter_code>
284
285 String that denote the letter code.
286
287 =back
288
289 =cut
290
291 sub send_digests {
292     my $params = shift;
293
294     PATRON: while ( my ( $borrowernumber, $digest ) = each %{$params->{digests}} ) {
295         next unless defined $digest->{updated} && $digest->{updated} == 1;
296         my $borrower_preferences =
297             C4::Members::Messaging::GetMessagingPreferences(
298                 {
299                     borrowernumber => $borrowernumber,
300                     message_name   => 'auto_renewals'
301                 }
302             );
303
304         next PATRON unless $borrower_preferences; # how could this happen?
305
306         my $patron = Koha::Patrons->find( $borrowernumber );
307         my $branchcode;
308         if ( defined $params->{branchcode} ) {
309             $branchcode = $params->{branchcode};
310         } else {
311             $branchcode = $patron->branchcode;
312         }
313         my $library = Koha::Libraries->find( $branchcode );
314         my $from_address = $library->from_email_address;
315
316         foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
317             my $letter = C4::Letters::GetPreparedLetter (
318                 module => 'circulation',
319                 letter_code => $params->{letter_code},
320                 branchcode => $branchcode,
321                 lang => $patron->lang,
322                 substitute => {
323                     error => $digest->{error}||0,
324                     success => $digest->{success}||0,
325                 },
326                 loops => { issues => \@{$digest->{issues}} },
327                 tables      => {
328                     borrowers => $patron->borrowernumber,
329                 },
330                 message_transport_type => $transport,
331             ) || warn "no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
332
333             next unless $letter;
334
335             C4::Letters::EnqueueLetter({
336                 letter                 => $letter,
337                 borrowernumber         => $borrowernumber,
338                 from_address           => $from_address,
339                 message_transport_type => $transport
340             });
341         }
342     }
343 }