View | Details | Raw Unified | Return to bug 29507
Collapse All | Expand All

(-)a/debian/templates/koha-conf-site.xml.in (+4 lines)
Lines 459-464 __END_SRU_PUBLICSERVER__ Link Here
459
   <vhost>__MESSAGE_BROKER_VHOST__</vhost>
459
   <vhost>__MESSAGE_BROKER_VHOST__</vhost>
460
 </message_broker>
460
 </message_broker>
461
461
462
 <auto_renew_cronjob>
463
   <parallel_loops_count>1</parallel_loops_count>
464
 </auto_renew_cronjob>
465
462
 <background_jobs_worker>
466
 <background_jobs_worker>
463
     <!-- Max simultaneous processes per worker -->
467
     <!-- Max simultaneous processes per worker -->
464
     <max_processes>1</max_processes>
468
     <max_processes>1</max_processes>
(-)a/etc/koha-conf.xml (+4 lines)
Lines 271-276 Link Here
271
   <vhost></vhost>
271
   <vhost></vhost>
272
 </message_broker>
272
 </message_broker>
273
273
274
 <auto_renew_cronjob>
275
   <parallel_loops_count>1</parallel_loops_count>
276
 </auto_renew_cronjob>
277
274
 <background_jobs_worker>
278
 <background_jobs_worker>
275
     <!-- Max simultaneous processes per worker -->
279
     <!-- Max simultaneous processes per worker -->
276
     <max_processes>1</max_processes>
280
     <max_processes>1</max_processes>
(-)a/misc/cronjobs/automatic_renewals.pl (-139 / +182 lines)
Lines 76-81 chosen 'Digests only' on the advance messages. Link Here
76
76
77
use Modern::Perl;
77
use Modern::Perl;
78
use Pod::Usage qw( pod2usage );
78
use Pod::Usage qw( pod2usage );
79
use Parallel::ForkManager;
79
use Getopt::Long qw( GetOptions );
80
use Getopt::Long qw( GetOptions );
80
81
81
use Koha::Script -cron;
82
use Koha::Script -cron;
Lines 135-141 $verbose = 1 unless $verbose or $confirm; Link Here
135
print "Test run only\n" unless $confirm;
136
print "Test run only\n" unless $confirm;
136
137
137
print "getting auto renewals\n" if $verbose;
138
print "getting auto renewals\n" if $verbose;
138
my $auto_renews = Koha::Checkouts->search(
139
my @auto_renews = Koha::Checkouts->search(
139
    {
140
    {
140
        auto_renew                   => 1,
141
        auto_renew                   => 1,
141
        'patron.autorenew_checkouts' => 1,
142
        'patron.autorenew_checkouts' => 1,
Lines 143-315 my $auto_renews = Koha::Checkouts->search( Link Here
143
    {
144
    {
144
        join => ['patron','item']
145
        join => ['patron','item']
145
    }
146
    }
146
);
147
)->as_list;
147
print "found " . $auto_renews->count . " auto renewals\n" if $verbose;
148
print "found " . scalar @auto_renews . " auto renewals\n" if $verbose;
148
149
149
my $renew_digest = {};
150
my $renew_digest = {};
150
my %report;
151
my %report;
151
my @item_renewal_ids;
152
my @item_renewal_ids;
152
while ( my $auto_renew = $auto_renews->next ) {
153
    print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
154
155
    my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
156
    if ( $send_notices_pref eq 'preferences' ){
157
        $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
158
            {
159
                borrowernumber => $auto_renew->borrowernumber,
160
                message_name   => 'auto_renewals'
161
            }
162
        );
163
        $wants_messages = 1
164
            if $borrower_preferences
165
            && $borrower_preferences->{transports};
166
        $wants_digest = 1
167
            if $wants_messages
168
            && $borrower_preferences->{wants_digest};
169
    } else { # Preference is never or cron
170
        $wants_messages = $send_notices;
171
        $wants_digest = 0;
172
    }
173
153
174
    # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
154
my $cron_options = C4::Context->config('auto_renew_cronjob');
175
    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->patron, $auto_renew, undef, 1 );
155
my $loops = $cron_options ? $cron_options->{parallel_loops_count} // 1 : 1;
176
    my $updated;
156
177
    if ( $error eq 'auto_renew' ) {
157
# Split the list of issues into chunks to run in parallel
178
        $updated = 1;
158
my @chunks;
179
        if ($verbose) {
159
if ( $loops > 1 ) {
180
            say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
160
    my $i              = 0;
181
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
161
    my $borrowernumber = 0;
182
                $confirm ? 'will' : 'would';
162
    while (@auto_renews) {
163
        my $auto_renew = pop(@auto_renews);
164
        if ( $borrowernumber != $auto_renew->borrowernumber ) {
165
            $i++ if $borrowernumber;
166
            $borrowernumber = $auto_renew->borrowernumber;
183
        }
167
        }
184
        if ($confirm) {
168
        $i = 0 if $i >= $loops;
185
            my $date_due = AddRenewal(
169
        push( @{ $chunks[$i] }, $auto_renew );
170
    }
171
    my $pm = Parallel::ForkManager->new($loops);
172
  DATA_LOOP:
173
    foreach my $chunk (@chunks) {
174
        my $pid = $pm->start and next DATA_LOOP;
175
        _ProcessRenewals($chunk);
176
        $pm->finish;
177
    }
178
    $pm->wait_all_children;
179
}
180
else {
181
    _ProcessRenewals( \@auto_renews );
182
}
183
184
cronlogaction({ action => 'End', info => "COMPLETED" });
185
186
=head1 METHODS
187
188
=head2 _ProcessRenewals
189
190
    Internal method to process the queue in chunks
191
192
=cut
193
194
sub _ProcessRenewals {
195
196
    my $auto_renew_issues = shift;
197
198
    foreach my $auto_renew (@$auto_renew_issues) {
199
        print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
200
201
        my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
202
        if ( $send_notices_pref eq 'preferences' ){
203
            $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
186
                {
204
                {
187
                    borrowernumber => $auto_renew->borrowernumber,
205
                    borrowernumber => $auto_renew->borrowernumber,
188
                    itemnumber     => $auto_renew->itemnumber,
206
                    message_name   => 'auto_renewals'
189
                    branch         => $auto_renew->branchcode,
190
                    seen           => 0,
191
                    automatic      => 1,
192
                }
207
                }
193
            );
208
            );
194
            push @item_renewal_ids, $auto_renew->itemnumber;
209
            $wants_messages = 1
195
            $auto_renew->auto_renew_error(undef)->store;
210
                if $borrower_preferences
211
                && $borrower_preferences->{transports};
212
            $wants_digest = 1
213
                if $wants_messages
214
                && $borrower_preferences->{wants_digest};
215
        } else { # Preference is never or cron
216
            $wants_messages = $send_notices;
217
            $wants_digest = 0;
196
        }
218
        }
197
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
219
198
            if ($wants_messages) && !$wants_digest;
220
        # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
199
    } elsif ( $error eq 'too_many'
221
        my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->patron, $auto_renew, undef, 1 );
200
        || $error eq 'on_reserve'
222
        my $updated;
201
        || $error eq 'restriction'
223
        if ( $error eq 'auto_renew' ) {
202
        || $error eq 'overdue'
224
            $updated = 1;
203
        || $error eq 'too_unseen'
225
            if ($verbose) {
204
        || $error eq 'auto_account_expired'
226
                say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
205
        || $error eq 'auto_too_late'
227
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
206
        || $error eq 'auto_too_much_oweing'
228
                    $confirm ? 'will' : 'would';
207
        || $error eq 'auto_too_soon'
229
            }
208
        || $error eq 'too_soon'
230
            if ($confirm) {
209
        || $error eq 'item_denied_renewal'
231
                my $date_due = AddRenewal(
210
        || $error eq 'item_issued_to_other_patron' )
232
                    {
211
    {
233
                        borrowernumber => $auto_renew->borrowernumber,
212
        if ($verbose) {
234
                        itemnumber     => $auto_renew->itemnumber,
213
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
235
                        branch         => $auto_renew->branchcode,
214
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
236
                        seen           => 0,
215
                $confirm ? 'will' : 'would', $error;
237
                        automatic      => 1,
216
        }
238
                    }
217
        $updated = 1 if ( !$auto_renew->auto_renew_error || $error ne $auto_renew->auto_renew_error );
239
                );
218
        if ($updated) {
240
                push @item_renewal_ids, $auto_renew->itemnumber;
219
            $auto_renew->auto_renew_error($error)->store if $confirm;
241
                $auto_renew->auto_renew_error(undef)->store;
242
            }
220
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
243
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
221
                if $error ne 'auto_too_soon' && ( $wants_messages && !$wants_digest );  # Do not notify if it's too soon
244
                if ($wants_messages) && !$wants_digest;
245
        } elsif ( $error eq 'too_many'
246
            || $error eq 'on_reserve'
247
            || $error eq 'restriction'
248
            || $error eq 'overdue'
249
            || $error eq 'too_unseen'
250
            || $error eq 'auto_account_expired'
251
            || $error eq 'auto_too_late'
252
            || $error eq 'auto_too_much_oweing'
253
            || $error eq 'auto_too_soon'
254
            || $error eq 'too_soon'
255
            || $error eq 'item_denied_renewal'
256
            || $error eq 'item_issued_to_other_patron' )
257
        {
258
            if ($verbose) {
259
                say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
260
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
261
                    $confirm ? 'will' : 'would', $error;
262
            }
263
            $updated = 1 if ( !$auto_renew->auto_renew_error || $error ne $auto_renew->auto_renew_error );
264
            if ($updated) {
265
                $auto_renew->auto_renew_error($error)->store if $confirm;
266
                push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
267
                    if $error ne 'auto_too_soon' && ( $wants_messages && !$wants_digest );  # Do not notify if it's too soon
268
            }
222
        }
269
        }
223
    }
224
270
225
    if ( $wants_digest ) {
271
        if ( $wants_digest ) {
226
        # cache this one to process after we've run through all of the items.
272
            # cache this one to process after we've run through all of the items.
227
        if ($digest_per_branch) {
273
            if ($digest_per_branch) {
228
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew';
274
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew';
229
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon';
275
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon';
230
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}->{$error}++ ;
276
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}->{$error}++ ;
231
            push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
277
                push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
232
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
278
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
233
        } else {
279
            } else {
234
            $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew';
280
                $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew';
235
            $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon';
281
                $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon';
236
            $renew_digest->{ $auto_renew->borrowernumber }->{results}->{$error}++ ;
282
                $renew_digest->{ $auto_renew->borrowernumber }->{results}->{$error}++ ;
237
            $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
283
                $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && $error ne 'auto_too_soon';
238
            push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
284
                push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
285
            }
239
        }
286
        }
240
    }
241
287
242
}
288
    }
243
289
244
if( @item_renewal_ids ){
290
    if( @item_renewal_ids ){
245
    my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
291
        my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
246
    $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
292
        $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
247
}
293
    }
248
294
249
if ( $send_notices && $confirm ) {
295
    if ( $send_notices && $confirm ) {
250
    for my $borrowernumber ( keys %report ) {
296
        for my $borrowernumber ( keys %report ) {
251
        my $patron = Koha::Patrons->find($borrowernumber);
297
            my $patron = Koha::Patrons->find($borrowernumber);
252
        my $borrower_preferences =
298
            my $borrower_preferences =
253
            C4::Members::Messaging::GetMessagingPreferences(
299
                C4::Members::Messaging::GetMessagingPreferences(
254
                {
300
                    {
255
                    borrowernumber => $borrowernumber,
301
                        borrowernumber => $borrowernumber,
256
                    message_name   => 'auto_renewals'
302
                        message_name   => 'auto_renewals'
257
                }
303
                    }
258
            );
259
        for my $issue ( @{ $report{$borrowernumber} } ) {
260
            my $item = $issue->item;
261
            # Force sending of email and only email if pref is set to "cron"
262
            my @transports = $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
263
            foreach my $transport ( @transports ) {
264
                my $letter = C4::Letters::GetPreparedLetter (
265
                    module      => 'circulation',
266
                    letter_code => 'AUTO_RENEWALS',
267
                    tables      => {
268
                        borrowers => $patron->borrowernumber,
269
                        issues    => $issue->itemnumber,
270
                        items     => $issue->itemnumber,
271
                        biblio    => $item->biblionumber,
272
                    },
273
                    lang => $patron->lang,
274
                    message_transport_type => $transport,
275
                );
304
                );
276
305
            for my $issue ( @{ $report{$borrowernumber} } ) {
277
                if ($letter) {
306
                my $item = $issue->item;
278
                    my $library = $patron->library;
307
                # Force sending of email and only email if pref is set to "cron"
279
                    my $admin_email_address = $library->from_email_address;
308
                my @transports = $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
280
309
                foreach my $transport ( @transports ) {
281
                    C4::Letters::EnqueueLetter(
310
                    my $letter = C4::Letters::GetPreparedLetter (
282
                        {
311
                        module      => 'circulation',
283
                            letter                 => $letter,
312
                        letter_code => 'AUTO_RENEWALS',
284
                            borrowernumber         => $borrowernumber,
313
                        tables      => {
285
                            from_address           => $admin_email_address,
314
                            borrowers => $patron->borrowernumber,
286
                            message_transport_type => $transport
315
                            issues    => $issue->itemnumber,
287
                        }
316
                            items     => $issue->itemnumber,
317
                            biblio    => $item->biblionumber,
318
                        },
319
                        lang => $patron->lang,
320
                        message_transport_type => $transport,
288
                    );
321
                    );
322
323
                    if ($letter) {
324
                        my $library = $patron->library;
325
                        my $admin_email_address = $library->from_email_address;
326
327
                        C4::Letters::EnqueueLetter(
328
                            {
329
                                letter                 => $letter,
330
                                borrowernumber         => $borrowernumber,
331
                                from_address           => $admin_email_address,
332
                                message_transport_type => $transport
333
                            }
334
                        );
335
                    }
289
                }
336
                }
290
            }
337
            }
291
        }
338
        }
292
    }
293
339
294
    if ($digest_per_branch) {
340
        if ($digest_per_branch) {
295
        while (my ($branchcode, $digests) = each %$renew_digest) {
341
            while (my ($branchcode, $digests) = each %$renew_digest) {
342
                send_digests({
343
                    digests => $digests,
344
                    branchcode => $branchcode,
345
                    letter_code => 'AUTO_RENEWALS_DGST',
346
                });
347
            }
348
        } else {
296
            send_digests({
349
            send_digests({
297
                digests => $digests,
350
                digests => $renew_digest,
298
                branchcode => $branchcode,
299
                letter_code => 'AUTO_RENEWALS_DGST',
351
                letter_code => 'AUTO_RENEWALS_DGST',
300
            });
352
            });
301
        }
353
        }
302
    } else {
303
        send_digests({
304
            digests => $renew_digest,
305
            letter_code => 'AUTO_RENEWALS_DGST',
306
        });
307
    }
354
    }
308
}
309
355
310
cronlogaction({ action => 'End', info => "COMPLETED" });
356
}
311
312
=head1 METHODS
313
357
314
=head2 send_digests
358
=head2 send_digests
315
359
316
- 

Return to bug 29507