3 # This file is part of Koha.
5 # Copyright (C) 2014 Hochschule für Gesundheit (hsg), Germany
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.
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.
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>.
22 automatic_renewals.pl - cron script to renew loans
26 ./automatic_renewals.pl [-c|--confirm] [-s|--send-notices] [-d|--digest] [-b|--digest-per-branch] [-v|--verbose]
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
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.
44 =item B<-s|--send-notices>
46 Send AUTO_RENEWALS notices to patrons if the auto renewal has been done.
50 Print report to standard out.
54 Without this parameter no changes will be made
58 Flag to indicate that this script should process digest messages.
60 =item B<-b|--digest-per-branch>
62 Flag to indicate that generation of message digests should be
63 performed separately for each branch. Needs --digest option.
65 A patron could potentially have loans at several different branches
66 There is no natural branch to set as the sender on the aggregated
67 message in this situation so the default behavior is to use the
68 borrowers home branch. This could surprise to the borrower when
69 message sender is a library where they have not borrowed anything.
71 Enabling this flag ensures that the issuing library is the sender of
72 the digested message. It has no effect unless the borrower has
73 chosen 'Digests only' on the advance messages.
83 use Koha::Script -cron;
92 my ( $help, $send_notices, $verbose, $confirm, $digest, $digest_per_branch );
95 's|send-notices' => \$send_notices,
96 'v|verbose' => \$verbose,
97 'c|confirm' => \$confirm,
98 'd|digest|' => \$digest,
99 'b|digest-per-branch' => \$digest_per_branch,
102 pod2usage(0) if $help;
104 # Since advance notice options are not visible in the web-interface
105 # unless EnhancedMessagingPreferences is on, let the user know that
106 # this script probably isn't going to do much
107 if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
110 The "EnhancedMessagingPreferences" syspref is off.
111 Therefore, it is unlikely that this script will actually produce any messages to be sent.
112 To change this, edit the "EnhancedMessagingPreferences" syspref.
119 $verbose = 1 unless $verbose or $confirm;
120 print "Test run only\n" unless $confirm;
122 print "getting auto renewals\n" if $verbose;
123 my $auto_renews = Koha::Checkouts->search({ auto_renew => 1, 'borrower.autorenew_checkouts' => 1 },{ join => 'borrower'});
124 print "found " . $auto_renews->count . " auto renewals\n" if $verbose;
126 my $renew_digest = {};
128 while ( my $auto_renew = $auto_renews->next ) {
129 print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
131 my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $auto_renew->borrowernumber,
132 message_name => 'auto_renewals' } );
134 next if !$digest && $borrower_preferences && $borrower_preferences->{'wants_digest'};
136 # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
137 my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber, undef, 1 );
138 if ( $error eq 'auto_renew' ) {
140 say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
141 $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would';
144 my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode, undef, undef, undef, 0 );
145 $auto_renew->auto_renew_error(undef)->store;
147 push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew unless $borrower_preferences && (!$borrower_preferences->{transports} || !$borrower_preferences->{transports}->{email} || $borrower_preferences->{'wants_digest'});
148 } elsif ( $error eq 'too_many'
149 or $error eq 'on_reserve'
150 or $error eq 'restriction'
151 or $error eq 'overdue'
152 or $error eq 'too_unseen'
153 or $error eq 'auto_account_expired'
154 or $error eq 'auto_too_late'
155 or $error eq 'auto_too_much_oweing'
156 or $error eq 'auto_too_soon'
157 or $error eq 'item_denied_renewal' ) {
159 say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
160 $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
162 if ( not $auto_renew->auto_renew_error or $error ne $auto_renew->auto_renew_error ) {
163 $auto_renew->auto_renew_error($error)->store if $confirm;
164 push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
165 if $error ne 'auto_too_soon' && (!$borrower_preferences || ($borrower_preferences->{transports} && $borrower_preferences->{transports}->{email} && !$borrower_preferences->{'wants_digest'})); # Do not notify if it's too soon
169 if ( $borrower_preferences && $borrower_preferences->{transports} && $borrower_preferences->{transports}->{email} && $borrower_preferences->{'wants_digest'} ) {
170 # cache this one to process after we've run through all of the items.
171 if ($digest_per_branch) {
172 $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew';
173 $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error == 'auto_too_soon' ;
175 $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew';
176 $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon' ;
182 if ( $send_notices && $confirm ) {
183 for my $borrowernumber ( keys %report ) {
184 my $patron = Koha::Patrons->find($borrowernumber);
185 for my $issue ( @{ $report{$borrowernumber} } ) {
186 my $item = Koha::Items->find( $issue->itemnumber );
187 my $letter = C4::Letters::GetPreparedLetter(
188 module => 'circulation',
189 letter_code => 'AUTO_RENEWALS',
191 borrowers => $patron->borrowernumber,
192 issues => $issue->itemnumber,
193 items => $issue->itemnumber,
194 biblio => $item->biblionumber,
196 lang => $patron->lang,
199 my $library = Koha::Libraries->find( $patron->branchcode );
200 my $admin_email_address = $library->branchemail || C4::Context->preference('KohaAdminEmailAddress');
202 C4::Letters::EnqueueLetter(
204 borrowernumber => $borrowernumber,
205 message_transport_type => 'email',
206 from_address => $admin_email_address,
212 if ($digest_per_branch) {
213 while (my ($branchcode, $digests) = each %$renew_digest) {
216 branchcode => $branchcode,
217 letter_code => 'AUTO_RENEWALS_DGST',
222 digests => $renew_digest,
223 letter_code => 'AUTO_RENEWALS_DGST',
237 Enqueue digested letters.
245 Reference to the array of digested messages.
247 =item C<$letter_code>
249 String that denote the letter code.
258 my $admin_email_address = C4::Context->preference('KohaAdminEmailAddress');
260 PATRON: while ( my ( $borrowernumber, $digest ) = each %{$params->{digests}} ) {
261 my $borrower_preferences =
262 C4::Members::Messaging::GetMessagingPreferences(
264 borrowernumber => $borrowernumber,
265 message_name => 'auto_renewals'
269 next PATRON unless $borrower_preferences; # how could this happen?
271 my $patron = Koha::Patrons->find( $borrowernumber );
272 my $library = Koha::Libraries->find( $params->{branchcode} );
273 my $from_address = $library->{branchemail} || $admin_email_address;
275 foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
276 my $letter = C4::Letters::GetPreparedLetter (
277 module => 'circulation',
278 letter_code => $params->{letter_code},
279 branchcode => $params->{branchcode},
280 lang => $patron->lang,
282 error => $digest->{error}||0,
283 success => $digest->{success}||0,
286 borrowers => $patron->borrowernumber,
288 message_transport_type => $transport,
289 ) || warn "no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
293 C4::Letters::EnqueueLetter({
295 borrowernumber => $borrowernumber,
296 from_address => $from_address,
297 message_transport_type => $transport