|
Lines 2-8
Link Here
|
| 2 |
|
2 |
|
| 3 |
# This file is part of Koha. |
3 |
# This file is part of Koha. |
| 4 |
# |
4 |
# |
| 5 |
# Copyright (C) 2014 Hochschule für Gesundheit (hsg), Germany |
5 |
# Copyright (C) 2014 Hochschule f�r Gesundheit (hsg), Germany |
| 6 |
# |
6 |
# |
| 7 |
# Koha is free software; you can redistribute it and/or modify it |
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 |
8 |
# under the terms of the GNU General Public License as published by |
|
Lines 23-32
automatic_renewals.pl - cron script to renew loans
Link Here
|
| 23 |
|
23 |
|
| 24 |
=head1 SYNOPSIS |
24 |
=head1 SYNOPSIS |
| 25 |
|
25 |
|
| 26 |
./automatic_renewals.pl [-c|--confirm] [--send-notices] |
26 |
./automatic_renewals.pl [-c|--confirm] [-s|--send-notices] [-d|--digest] [-b|--digest-per-branch] [-v|--verbose] |
| 27 |
|
27 |
|
| 28 |
or, in crontab: |
28 |
or, in crontab: |
| 29 |
0 3 * * * automatic_renewals.pl -c |
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 |
| 30 |
|
33 |
|
| 31 |
=head1 DESCRIPTION |
34 |
=head1 DESCRIPTION |
| 32 |
|
35 |
|
|
Lines 38-49
and the renewal isn't premature (No Renewal before) the issue is renewed.
Link Here
|
| 38 |
|
41 |
|
| 39 |
=over |
42 |
=over |
| 40 |
|
43 |
|
| 41 |
=item B<--send-notices> |
44 |
=item B<-s|--send-notices> |
| 42 |
|
45 |
|
| 43 |
Send AUTO_RENEWALS notices to patrons if the auto renewal has been done. |
46 |
Send AUTO_RENEWALS notices to patrons if the auto renewal has been done. |
| 44 |
|
47 |
|
| 45 |
Note that this option does not support digest yet. |
|
|
| 46 |
|
| 47 |
=item B<-v|--verbose> |
48 |
=item B<-v|--verbose> |
| 48 |
|
49 |
|
| 49 |
Print report to standard out. |
50 |
Print report to standard out. |
|
Lines 52-57
Print report to standard out.
Link Here
|
| 52 |
|
53 |
|
| 53 |
Without this parameter no changes will be made |
54 |
Without this parameter no changes will be made |
| 54 |
|
55 |
|
|
|
56 |
=item B<-d|--digest> |
| 57 |
|
| 58 |
Flag to indicate that this script should process digest messages. |
| 59 |
|
| 60 |
=item B<-b|--digest-per-branch> |
| 61 |
|
| 62 |
Flag to indicate that generation of message digests should be |
| 63 |
performed separately for each branch. Needs --digest option. |
| 64 |
|
| 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. |
| 70 |
|
| 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. |
| 74 |
|
| 55 |
=back |
75 |
=back |
| 56 |
|
76 |
|
| 57 |
=cut |
77 |
=cut |
|
Lines 69-104
use Koha::Checkouts;
Link Here
|
| 69 |
use Koha::Libraries; |
89 |
use Koha::Libraries; |
| 70 |
use Koha::Patrons; |
90 |
use Koha::Patrons; |
| 71 |
|
91 |
|
| 72 |
my ( $help, $send_notices, $verbose, $confirm ); |
92 |
my ( $help, $send_notices, $verbose, $confirm, $digest, $digest_per_branch ); |
| 73 |
GetOptions( |
93 |
GetOptions( |
| 74 |
'h|help' => \$help, |
94 |
'h|help' => \$help, |
| 75 |
'send-notices' => \$send_notices, |
95 |
's|send-notices' => \$send_notices, |
| 76 |
'v|verbose' => \$verbose, |
96 |
'v|verbose' => \$verbose, |
| 77 |
'c|confirm' => \$confirm, |
97 |
'c|confirm' => \$confirm, |
|
|
98 |
'd|digest|' => \$digest, |
| 99 |
'b|digest-per-branch' => \$digest_per_branch, |
| 78 |
) || pod2usage(1); |
100 |
) || pod2usage(1); |
| 79 |
|
101 |
|
| 80 |
pod2usage(0) if $help; |
102 |
pod2usage(0) if $help; |
|
|
103 |
|
| 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') ) { |
| 108 |
warn <<'END_WARN'; |
| 109 |
|
| 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. |
| 113 |
|
| 114 |
END_WARN |
| 115 |
} |
| 116 |
|
| 81 |
cronlogaction(); |
117 |
cronlogaction(); |
| 82 |
|
118 |
|
|
|
119 |
$verbose = 1 unless $verbose or $confirm; |
| 120 |
print "Test run only\n" unless $confirm; |
| 121 |
|
| 122 |
print "getting auto renewals\n" if $verbose; |
| 83 |
my $auto_renews = Koha::Checkouts->search({ auto_renew => 1 }); |
123 |
my $auto_renews = Koha::Checkouts->search({ auto_renew => 1 }); |
|
|
124 |
print "found " . $auto_renews->count . " auto renewals\n" if $verbose; |
| 84 |
|
125 |
|
|
|
126 |
my $renew_digest = {}; |
| 85 |
my %report; |
127 |
my %report; |
| 86 |
$verbose = 1 unless $verbose or $confirm; |
|
|
| 87 |
print "Test run only\n" unless $confirm; |
| 88 |
while ( my $auto_renew = $auto_renews->next ) { |
128 |
while ( my $auto_renew = $auto_renews->next ) { |
|
|
129 |
print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose; |
| 130 |
|
| 131 |
my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $auto_renew->borrowernumber, |
| 132 |
message_name => 'auto_renewals' } ); |
| 133 |
|
| 134 |
next if !$digest && $borrower_preferences && $borrower_preferences->{'wants_digest'}; |
| 89 |
|
135 |
|
| 90 |
# CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script |
136 |
# CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script |
| 91 |
my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber ); |
137 |
my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber ); |
| 92 |
if ( $error eq 'auto_renew' ) { |
138 |
if ( $error eq 'auto_renew' ) { |
| 93 |
if ($verbose) { |
139 |
if ($verbose) { |
| 94 |
say sprintf "Issue id: %s for borrower: %s and item: %s ". ( $confirm ? 'will' : 'would') . " be renewed.", |
140 |
say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.", |
| 95 |
$auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber; |
141 |
$auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would'; |
| 96 |
} |
142 |
} |
| 97 |
if ($confirm){ |
143 |
if ($confirm){ |
| 98 |
my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode ); |
144 |
my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode ); |
| 99 |
$auto_renew->auto_renew_error(undef)->store; |
145 |
$auto_renew->auto_renew_error(undef)->store; |
| 100 |
} |
146 |
} |
| 101 |
push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew; |
147 |
push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew unless $borrower_preferences && (!$borrower_preferences->{transports} || !$borrower_preferences->{transports}->{email} || $borrower_preferences->{'wants_digest'}); |
| 102 |
} elsif ( $error eq 'too_many' |
148 |
} elsif ( $error eq 'too_many' |
| 103 |
or $error eq 'on_reserve' |
149 |
or $error eq 'on_reserve' |
| 104 |
or $error eq 'restriction' |
150 |
or $error eq 'restriction' |
|
Lines 109-126
while ( my $auto_renew = $auto_renews->next ) {
Link Here
|
| 109 |
or $error eq 'auto_too_soon' |
155 |
or $error eq 'auto_too_soon' |
| 110 |
or $error eq 'item_denied_renewal' ) { |
156 |
or $error eq 'item_denied_renewal' ) { |
| 111 |
if ( $verbose ) { |
157 |
if ( $verbose ) { |
| 112 |
say sprintf "Issue id: %s for borrower: %s and item: %s ". ( $confirm ? 'will' : 'would') . " not be renewed. (%s)", |
158 |
say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)", |
| 113 |
$auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $error; |
159 |
$auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error; |
| 114 |
} |
160 |
} |
| 115 |
if ( not $auto_renew->auto_renew_error or $error ne $auto_renew->auto_renew_error ) { |
161 |
if ( not $auto_renew->auto_renew_error or $error ne $auto_renew->auto_renew_error ) { |
| 116 |
$auto_renew->auto_renew_error($error)->store if $confirm; |
162 |
$auto_renew->auto_renew_error($error)->store if $confirm; |
| 117 |
push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew |
163 |
push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew |
| 118 |
if $error ne 'auto_too_soon'; # Do not notify if it's too soon |
164 |
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 |
| 119 |
} |
165 |
} |
| 120 |
} |
166 |
} |
|
|
167 |
|
| 168 |
if ( $borrower_preferences && $borrower_preferences->{transports} && $borrower_preferences->{transports}->{email} && $borrower_preferences->{'wants_digest'} ) { |
| 169 |
# cache this one to process after we've run through all of the items. |
| 170 |
if ($digest_per_branch) { |
| 171 |
$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew'; |
| 172 |
$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error == 'auto_too_soon' ; |
| 173 |
} else { |
| 174 |
$renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew'; |
| 175 |
$renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon' ; |
| 176 |
} |
| 177 |
} |
| 178 |
|
| 121 |
} |
179 |
} |
| 122 |
|
180 |
|
| 123 |
if ( $send_notices ) { |
181 |
if ( $send_notices && $confirm ) { |
| 124 |
for my $borrowernumber ( keys %report ) { |
182 |
for my $borrowernumber ( keys %report ) { |
| 125 |
my $patron = Koha::Patrons->find($borrowernumber); |
183 |
my $patron = Koha::Patrons->find($borrowernumber); |
| 126 |
for my $issue ( @{ $report{$borrowernumber} } ) { |
184 |
for my $issue ( @{ $report{$borrowernumber} } ) { |
|
Lines 146-152
if ( $send_notices ) {
Link Here
|
| 146 |
message_transport_type => 'email', |
204 |
message_transport_type => 'email', |
| 147 |
from_address => $admin_email_address, |
205 |
from_address => $admin_email_address, |
| 148 |
} |
206 |
} |
| 149 |
) if $confirm; |
207 |
); |
|
|
208 |
} |
| 209 |
} |
| 210 |
|
| 211 |
if ($digest_per_branch) { |
| 212 |
while (my ($branchcode, $digests) = each %$renew_digest) { |
| 213 |
send_digests({ |
| 214 |
digests => $digests, |
| 215 |
branchcode => $branchcode, |
| 216 |
letter_code => 'AUTO_RENEWALS_DGST', |
| 217 |
}); |
| 218 |
} |
| 219 |
} else { |
| 220 |
send_digests({ |
| 221 |
digests => $renew_digest, |
| 222 |
letter_code => 'AUTO_RENEWALS_DGST', |
| 223 |
}); |
| 224 |
} |
| 225 |
} |
| 226 |
|
| 227 |
=head1 METHODS |
| 228 |
|
| 229 |
=head2 send_digests |
| 230 |
|
| 231 |
send_digests({ |
| 232 |
digests => ..., |
| 233 |
letter_code => ..., |
| 234 |
}) |
| 235 |
|
| 236 |
Enqueue digested letters. |
| 237 |
|
| 238 |
Parameters: |
| 239 |
|
| 240 |
=over 4 |
| 241 |
|
| 242 |
=item C<$digests> |
| 243 |
|
| 244 |
Reference to the array of digested messages. |
| 245 |
|
| 246 |
=item C<$letter_code> |
| 247 |
|
| 248 |
String that denote the letter code. |
| 249 |
|
| 250 |
=back |
| 251 |
|
| 252 |
=cut |
| 253 |
|
| 254 |
sub send_digests { |
| 255 |
my $params = shift; |
| 256 |
|
| 257 |
my $admin_email_address = C4::Context->preference('KohaAdminEmailAddress'); |
| 258 |
|
| 259 |
PATRON: while ( my ( $borrowernumber, $digest ) = each %{$params->{digests}} ) { |
| 260 |
my $borrower_preferences = |
| 261 |
C4::Members::Messaging::GetMessagingPreferences( |
| 262 |
{ |
| 263 |
borrowernumber => $borrowernumber, |
| 264 |
message_name => 'auto_renewals' |
| 265 |
} |
| 266 |
); |
| 267 |
|
| 268 |
next PATRON unless $borrower_preferences; # how could this happen? |
| 269 |
|
| 270 |
my $patron = Koha::Patrons->find( $borrowernumber ); |
| 271 |
my $library = Koha::Libraries->find( $params->{branchcode} ); |
| 272 |
my $from_address = $library->{branchemail} || $admin_email_address; |
| 273 |
|
| 274 |
foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) { |
| 275 |
my $letter = C4::Letters::GetPreparedLetter ( |
| 276 |
module => 'circulation', |
| 277 |
letter_code => $params->{letter_code}, |
| 278 |
branchcode => $params->{branchcode}, |
| 279 |
lang => $patron->lang, |
| 280 |
substitute => { |
| 281 |
error => $digest->{error}||0, |
| 282 |
success => $digest->{success}||0, |
| 283 |
}, |
| 284 |
tables => { |
| 285 |
borrowers => $patron->borrowernumber, |
| 286 |
}, |
| 287 |
message_transport_type => $transport, |
| 288 |
) || warn "no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql"; |
| 289 |
|
| 290 |
next unless $letter; |
| 291 |
|
| 292 |
C4::Letters::EnqueueLetter({ |
| 293 |
letter => $letter, |
| 294 |
borrowernumber => $borrowernumber, |
| 295 |
from_address => $from_address, |
| 296 |
message_transport_type => $transport |
| 297 |
}); |
| 150 |
} |
298 |
} |
| 151 |
} |
299 |
} |
| 152 |
} |
300 |
} |
| 153 |
- |
|
|