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

(-)a/misc/cronjobs/automatic_renewals.pl (-168 / +174 lines)
Lines 87-100 use Koha::Checkouts; Link Here
87
use Koha::Libraries;
87
use Koha::Libraries;
88
use Koha::Patrons;
88
use Koha::Patrons;
89
89
90
my $command_line_options = join(" ",@ARGV);
90
my $command_line_options = join( " ", @ARGV );
91
91
92
my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
92
my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
93
GetOptions(
93
GetOptions(
94
    'h|help' => \$help,
94
    'h|help'              => \$help,
95
    's|send-notices' => \$send_notices,
95
    's|send-notices'      => \$send_notices,
96
    'v|verbose'    => \$verbose,
96
    'v|verbose'           => \$verbose,
97
    'c|confirm'     => \$confirm,
97
    'c|confirm'           => \$confirm,
98
    'b|digest-per-branch' => \$digest_per_branch,
98
    'b|digest-per-branch' => \$digest_per_branch,
99
) || pod2usage(1);
99
) || pod2usage(1);
100
100
Lines 110-115 to 'Never send emails' or 'Follow patron messaging preferences' Link Here
110
110
111
END_WARN
111
END_WARN
112
} else {
112
} else {
113
113
    # If not following cron then:
114
    # If not following cron then:
114
    # - we should not send if set to never
115
    # - we should not send if set to never
115
    # - we will send any notice generated according to preferences if following those
116
    # - we will send any notice generated according to preferences if following those
Lines 119-125 END_WARN Link Here
119
# Since advance notice options are not visible in the web-interface
120
# Since advance notice options are not visible in the web-interface
120
# unless EnhancedMessagingPreferences is on, let the user know that
121
# unless EnhancedMessagingPreferences is on, let the user know that
121
# this script probably isn't going to do much
122
# this script probably isn't going to do much
122
if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
123
if ( !C4::Context->preference('EnhancedMessagingPreferences') ) {
123
    warn <<'END_WARN';
124
    warn <<'END_WARN';
124
125
125
The "EnhancedMessagingPreferences" syspref is off.
126
The "EnhancedMessagingPreferences" syspref is off.
Lines 129-137 To change this, edit the "EnhancedMessagingPreferences" syspref. Link Here
129
END_WARN
130
END_WARN
130
}
131
}
131
132
132
cronlogaction({ info => $command_line_options });
133
cronlogaction( { info => $command_line_options } );
133
134
134
$verbose = 1 unless $verbose or $confirm;
135
$verbose = 1            unless $verbose or $confirm;
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;
Lines 140-153 my @auto_renews = Koha::Checkouts->search( Link Here
140
        auto_renew                   => 1,
141
        auto_renew                   => 1,
141
        'patron.autorenew_checkouts' => 1,
142
        'patron.autorenew_checkouts' => 1,
142
    },
143
    },
143
    {
144
    { join => [ 'patron', 'item' ] }
144
        join => ['patron','item']
145
    }
146
)->as_list;
145
)->as_list;
147
print "found " . scalar @auto_renews . " auto renewals\n" if $verbose;
146
print "found " . scalar @auto_renews . " auto renewals\n" if $verbose;
148
147
149
my $cron_options = C4::Context->config('auto_renew_cronjob');
148
my $cron_options = C4::Context->config('auto_renew_cronjob');
150
my $loops = $cron_options ? $cron_options->{parallel_loops_count} // 1 : 1;
149
my $loops        = $cron_options ? $cron_options->{parallel_loops_count} // 1 : 1;
151
150
152
# Split the list of issues into chunks to run in parallel
151
# Split the list of issues into chunks to run in parallel
153
my @chunks;
152
my @chunks;
Lines 164-183 if ( $loops > 1 ) { Link Here
164
        push( @{ $chunks[$i] }, $auto_renew );
163
        push( @{ $chunks[$i] }, $auto_renew );
165
    }
164
    }
166
    my $pm = Parallel::ForkManager->new($loops);
165
    my $pm = Parallel::ForkManager->new($loops);
167
  DATA_LOOP:
166
DATA_LOOP:
168
    foreach my $chunk (@chunks) {
167
    foreach my $chunk (@chunks) {
169
        my $pid = $pm->start and next DATA_LOOP;
168
        my $pid = $pm->start and next DATA_LOOP;
170
        _ProcessRenewals($chunk);
169
        _ProcessRenewals($chunk);
171
        $pm->finish;
170
        $pm->finish;
172
    }
171
    }
173
    $pm->wait_all_children;
172
    $pm->wait_all_children;
174
}
173
} else {
175
else {
176
    _ProcessRenewals( \@auto_renews );
174
    _ProcessRenewals( \@auto_renews );
177
}
175
}
178
176
179
cronlogaction({ action => 'End', info => "COMPLETED" });
177
cronlogaction( { action => 'End', info => "COMPLETED" } );
180
181
178
182
=head1 METHODS
179
=head1 METHODS
183
180
Lines 190-345 cronlogaction({ action => 'End', info => "COMPLETED" }); Link Here
190
sub _ProcessRenewals {
187
sub _ProcessRenewals {
191
    my $auto_renew_issues = shift;
188
    my $auto_renew_issues = shift;
192
189
193
my $renew_digest = {};
190
    my $renew_digest = {};
194
my %report;
191
    my %report;
195
my @item_renewal_ids;
192
    my @item_renewal_ids;
196
193
197
    foreach my $auto_renew (@$auto_renew_issues) {
194
    foreach my $auto_renew (@$auto_renew_issues) {
198
    print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
195
        print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
199
196
200
    my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
197
        my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
201
    if ( $send_notices_pref eq 'preferences' ) {
198
        if ( $send_notices_pref eq 'preferences' ) {
202
        $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
199
            $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
203
            {
200
                {
204
                borrowernumber => $auto_renew->borrowernumber,
201
                    borrowernumber => $auto_renew->borrowernumber,
205
                message_name   => 'auto_renewals'
202
                    message_name   => 'auto_renewals'
206
            }
203
                }
207
        );
204
            );
208
        $wants_messages = 1
205
            $wants_messages = 1
209
            if $borrower_preferences
206
                if $borrower_preferences
210
            && $borrower_preferences->{transports};
207
                && $borrower_preferences->{transports};
211
        $wants_digest = 1
208
            $wants_digest = 1
212
            if $wants_messages
209
                if $wants_messages
213
            && $borrower_preferences->{wants_digest};
210
                && $borrower_preferences->{wants_digest};
214
    } else {    # Preference is never or cron
211
        } else {    # Preference is never or cron
215
        $wants_messages = $send_notices;
212
            $wants_messages = $send_notices;
216
        $wants_digest   = 0;
213
            $wants_digest   = 0;
217
    }
218
219
    my ( $success, $error, $updated ) = $auto_renew->attempt_auto_renew( { confirm => $confirm } );
220
    if ($success) {
221
        if ($verbose) {
222
            say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
223
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
224
                $confirm ? 'will' : 'would';
225
        }
226
        if ($confirm) {
227
            push @item_renewal_ids, $auto_renew->itemnumber;
228
        }
229
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
230
            if ($wants_messages) && !$wants_digest;
231
    } elsif (
232
233
        # FIXME Do we need to list every status? Why not simply else?
234
           $error eq 'too_many'
235
        || $error eq 'on_reserve'
236
        || $error eq 'restriction'
237
        || $error eq 'overdue'
238
        || $error eq 'too_unseen'
239
        || $error eq 'auto_account_expired'
240
        || $error eq 'auto_too_late'
241
        || $error eq 'auto_too_much_oweing'
242
        || $error eq 'auto_too_soon'
243
        || $error eq 'item_denied_renewal'
244
        || $error eq 'item_issued_to_other_patron'
245
        )
246
    {
247
        if ($verbose) {
248
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
249
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
250
                $confirm ? 'will' : 'would', $error;
251
        }
214
        }
252
        if ($updated) {
215
216
        my ( $success, $error, $updated ) = $auto_renew->attempt_auto_renew( { confirm => $confirm } );
217
        if ($success) {
218
            if ($verbose) {
219
                say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
220
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
221
                    $confirm ? 'will' : 'would';
222
            }
223
            if ($confirm) {
224
                push @item_renewal_ids, $auto_renew->itemnumber;
225
            }
253
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
226
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
254
                if $error ne 'auto_too_soon' && ( $wants_messages && !$wants_digest );  # Do not notify if it's too soon
227
                if ($wants_messages) && !$wants_digest;
228
        } elsif (
229
230
            # FIXME Do we need to list every status? Why not simply else?
231
               $error eq 'too_many'
232
            || $error eq 'on_reserve'
233
            || $error eq 'restriction'
234
            || $error eq 'overdue'
235
            || $error eq 'too_unseen'
236
            || $error eq 'auto_account_expired'
237
            || $error eq 'auto_too_late'
238
            || $error eq 'auto_too_much_oweing'
239
            || $error eq 'auto_too_soon'
240
            || $error eq 'item_denied_renewal'
241
            || $error eq 'item_issued_to_other_patron'
242
            )
243
        {
244
            if ($verbose) {
245
                say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
246
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
247
                    $confirm ? 'will' : 'would', $error;
248
            }
249
            if ($updated) {
250
                push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
251
                    if $error ne 'auto_too_soon'
252
                    && ( $wants_messages && !$wants_digest );    # Do not notify if it's too soon
253
            }
255
        }
254
        }
256
    }
257
255
258
    if ( $wants_digest ) {
256
        if ($wants_digest) {
259
        # cache this one to process after we've run through all of the items.
257
260
        if ($digest_per_branch) {
258
            # cache this one to process after we've run through all of the items.
261
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $success;
259
            if ($digest_per_branch) {
262
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
260
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $success;
263
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}->{defined $error ? $error : 'auto-renew'}++ ;
261
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++
264
            push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
262
                    unless $success || $error eq 'auto_too_soon';
265
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && (!$error || $error ne 'auto_too_soon');
263
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}
266
        } else {
264
                    ->{ defined $error ? $error : 'auto-renew' }++;
267
            $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $success;
265
                push @{ $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues} },
268
            $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
266
                    $auto_renew->itemnumber;
269
            $renew_digest->{ $auto_renew->borrowernumber }->{results}->{defined $error ? $error : 'auto-renew'}++ ;
267
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1
270
            $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && (!$error || $error ne 'auto_too_soon');
268
                    if $updated && ( !$error || $error ne 'auto_too_soon' );
271
            push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
269
            } else {
270
                $renew_digest->{ $auto_renew->borrowernumber }->{success}++ if $success;
271
                $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
272
                $renew_digest->{ $auto_renew->borrowernumber }->{results}->{ defined $error ? $error : 'auto-renew' }++;
273
                $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1
274
                    if $updated && ( !$error || $error ne 'auto_too_soon' );
275
                push @{ $renew_digest->{ $auto_renew->borrowernumber }->{issues} }, $auto_renew->itemnumber;
276
            }
272
        }
277
        }
273
    }
274
278
275
}
279
    }
276
280
277
if( @item_renewal_ids ){
281
    if (@item_renewal_ids) {
278
    my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
282
        my $indexer = Koha::SearchEngine::Indexer->new( { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
279
    $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
283
        $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
280
}
284
    }
281
285
282
if ( $send_notices && $confirm ) {
286
    if ( $send_notices && $confirm ) {
283
    for my $borrowernumber ( keys %report ) {
287
        for my $borrowernumber ( keys %report ) {
284
        my $patron = Koha::Patrons->find($borrowernumber);
288
            my $patron               = Koha::Patrons->find($borrowernumber);
285
        my $borrower_preferences =
289
            my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
286
            C4::Members::Messaging::GetMessagingPreferences(
287
                {
290
                {
288
                    borrowernumber => $borrowernumber,
291
                    borrowernumber => $borrowernumber,
289
                    message_name   => 'auto_renewals'
292
                    message_name   => 'auto_renewals'
290
                }
293
                }
291
            );
294
            );
292
        for my $issue ( @{ $report{$borrowernumber} } ) {
295
            for my $issue ( @{ $report{$borrowernumber} } ) {
293
            my $item = $issue->item;
296
                my $item = $issue->item;
294
            # Force sending of email and only email if pref is set to "cron"
297
295
            my @transports = $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
298
                # Force sending of email and only email if pref is set to "cron"
296
            foreach my $transport ( @transports ) {
299
                my @transports =
297
                my $letter = C4::Letters::GetPreparedLetter (
300
                    $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
298
                    module      => 'circulation',
301
                foreach my $transport (@transports) {
299
                    letter_code => 'AUTO_RENEWALS',
302
                    my $letter = C4::Letters::GetPreparedLetter(
300
                    branchcode  => $patron->branchcode,
303
                        module      => 'circulation',
301
                    tables      => {
304
                        letter_code => 'AUTO_RENEWALS',
302
                        borrowers => $patron->borrowernumber,
305
                        branchcode  => $patron->branchcode,
303
                        issues    => $issue->itemnumber,
306
                        tables      => {
304
                        items     => $issue->itemnumber,
307
                            borrowers => $patron->borrowernumber,
305
                        biblio    => $item->biblionumber,
308
                            issues    => $issue->itemnumber,
306
                    },
309
                            items     => $issue->itemnumber,
307
                    lang => $patron->lang,
310
                            biblio    => $item->biblionumber,
308
                    message_transport_type => $transport,
311
                        },
309
                );
312
                        lang                   => $patron->lang,
310
313
                        message_transport_type => $transport,
311
                if ($letter) {
312
                    my $library = $patron->library;
313
                    my $admin_email_address = $library->from_email_address;
314
315
                    C4::Letters::EnqueueLetter(
316
                        {
317
                            letter                 => $letter,
318
                            borrowernumber         => $borrowernumber,
319
                            from_address           => $admin_email_address,
320
                            message_transport_type => $transport
321
                        }
322
                    );
314
                    );
315
316
                    if ($letter) {
317
                        my $library             = $patron->library;
318
                        my $admin_email_address = $library->from_email_address;
319
320
                        C4::Letters::EnqueueLetter(
321
                            {
322
                                letter                 => $letter,
323
                                borrowernumber         => $borrowernumber,
324
                                from_address           => $admin_email_address,
325
                                message_transport_type => $transport
326
                            }
327
                        );
328
                    }
323
                }
329
                }
324
            }
330
            }
325
        }
331
        }
326
    }
327
332
328
    if ($digest_per_branch) {
333
        if ($digest_per_branch) {
329
        while (my ($branchcode, $digests) = each %$renew_digest) {
334
            while ( my ( $branchcode, $digests ) = each %$renew_digest ) {
330
            send_digests({
335
                send_digests(
331
                digests => $digests,
336
                    {
332
                branchcode => $branchcode,
337
                        digests     => $digests,
333
                letter_code => 'AUTO_RENEWALS_DGST',
338
                        branchcode  => $branchcode,
334
            });
339
                        letter_code => 'AUTO_RENEWALS_DGST',
340
                    }
341
                );
342
            }
343
        } else {
344
            send_digests(
345
                {
346
                    digests     => $renew_digest,
347
                    letter_code => 'AUTO_RENEWALS_DGST',
348
                }
349
            );
335
        }
350
        }
336
    } else {
337
        send_digests({
338
            digests => $renew_digest,
339
            letter_code => 'AUTO_RENEWALS_DGST',
340
        });
341
    }
351
    }
342
}
343
352
344
}
353
}
345
354
Lines 371-411 String that denote the letter code. Link Here
371
sub send_digests {
380
sub send_digests {
372
    my $params = shift;
381
    my $params = shift;
373
382
374
    PATRON: while ( my ( $borrowernumber, $digest ) = each %{$params->{digests}} ) {
383
PATRON: while ( my ( $borrowernumber, $digest ) = each %{ $params->{digests} } ) {
375
        next unless defined $digest->{updated} && $digest->{updated} == 1;
384
        next unless defined $digest->{updated} && $digest->{updated} == 1;
376
        my $borrower_preferences =
385
        my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
377
            C4::Members::Messaging::GetMessagingPreferences(
386
            {
378
                {
387
                borrowernumber => $borrowernumber,
379
                    borrowernumber => $borrowernumber,
388
                message_name   => 'auto_renewals'
380
                    message_name   => 'auto_renewals'
389
            }
381
                }
390
        );
382
            );
383
391
384
        next PATRON unless $borrower_preferences; # how could this happen?
392
        next PATRON unless $borrower_preferences;    # how could this happen?
385
393
386
        my $patron = Koha::Patrons->find( $borrowernumber );
394
        my $patron = Koha::Patrons->find($borrowernumber);
387
        my $branchcode;
395
        my $branchcode;
388
        if ( defined $params->{branchcode} ) {
396
        if ( defined $params->{branchcode} ) {
389
            $branchcode = $params->{branchcode};
397
            $branchcode = $params->{branchcode};
390
        } else {
398
        } else {
391
            $branchcode = $patron->branchcode;
399
            $branchcode = $patron->branchcode;
392
        }
400
        }
393
        my $library = Koha::Libraries->find( $branchcode );
401
        my $library      = Koha::Libraries->find($branchcode);
394
        my $from_address = $library->from_email_address;
402
        my $from_address = $library->from_email_address;
395
403
396
        foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
404
        foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
397
            my $letter = C4::Letters::GetPreparedLetter (
405
            my $letter = C4::Letters::GetPreparedLetter(
398
                module => 'circulation',
406
                module      => 'circulation',
399
                letter_code => $params->{letter_code},
407
                letter_code => $params->{letter_code},
400
                branchcode => $branchcode,
408
                branchcode  => $branchcode,
401
                lang => $patron->lang,
409
                lang        => $patron->lang,
402
                substitute => {
410
                substitute  => {
403
                    error => $digest->{error}||0,
411
                    error   => $digest->{error}   || 0,
404
                    success => $digest->{success}||0,
412
                    success => $digest->{success} || 0,
405
                    results => $digest->{results},
413
                    results => $digest->{results},
406
                },
414
                },
407
                loops => { issues => \@{$digest->{issues}} },
415
                loops  => { issues => \@{ $digest->{issues} } },
408
                tables      => {
416
                tables => {
409
                    borrowers => $patron->borrowernumber,
417
                    borrowers => $patron->borrowernumber,
410
                },
418
                },
411
                message_transport_type => $transport,
419
                message_transport_type => $transport,
Lines 420-429 sub send_digests { Link Here
420
                        message_transport_type => $transport
428
                        message_transport_type => $transport
421
                    }
429
                    }
422
                );
430
                );
423
            }
431
            } else {
424
            else {
425
                warn
432
                warn
426
"no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
433
                    "no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
427
            }
434
            }
428
435
429
        }
436
        }
430
- 

Return to bug 29507