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

(-)a/misc/cronjobs/automatic_renewals.pl (-167 / +173 lines)
Lines 88-101 use Koha::Checkouts; Link Here
88
use Koha::Libraries;
88
use Koha::Libraries;
89
use Koha::Patrons;
89
use Koha::Patrons;
90
90
91
my $command_line_options = join(" ",@ARGV);
91
my $command_line_options = join( " ", @ARGV );
92
92
93
my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
93
my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
94
GetOptions(
94
GetOptions(
95
    'h|help' => \$help,
95
    'h|help'              => \$help,
96
    's|send-notices' => \$send_notices,
96
    's|send-notices'      => \$send_notices,
97
    'v|verbose'    => \$verbose,
97
    'v|verbose'           => \$verbose,
98
    'c|confirm'     => \$confirm,
98
    'c|confirm'           => \$confirm,
99
    'b|digest-per-branch' => \$digest_per_branch,
99
    'b|digest-per-branch' => \$digest_per_branch,
100
) || pod2usage(1);
100
) || pod2usage(1);
101
101
Lines 111-116 to 'Never send emails' or 'Follow patron messaging preferences' Link Here
111
111
112
END_WARN
112
END_WARN
113
} else {
113
} else {
114
114
    # If not following cron then:
115
    # If not following cron then:
115
    # - we should not send if set to never
116
    # - we should not send if set to never
116
    # - we will send any notice generated according to preferences if following those
117
    # - we will send any notice generated according to preferences if following those
Lines 120-126 END_WARN Link Here
120
# Since advance notice options are not visible in the web-interface
121
# Since advance notice options are not visible in the web-interface
121
# unless EnhancedMessagingPreferences is on, let the user know that
122
# unless EnhancedMessagingPreferences is on, let the user know that
122
# this script probably isn't going to do much
123
# this script probably isn't going to do much
123
if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
124
if ( !C4::Context->preference('EnhancedMessagingPreferences') ) {
124
    warn <<'END_WARN';
125
    warn <<'END_WARN';
125
126
126
The "EnhancedMessagingPreferences" syspref is off.
127
The "EnhancedMessagingPreferences" syspref is off.
Lines 130-138 To change this, edit the "EnhancedMessagingPreferences" syspref. Link Here
130
END_WARN
131
END_WARN
131
}
132
}
132
133
133
cronlogaction({ info => $command_line_options });
134
cronlogaction( { info => $command_line_options } );
134
135
135
$verbose = 1 unless $verbose or $confirm;
136
$verbose = 1            unless $verbose or $confirm;
136
print "Test run only\n" unless $confirm;
137
print "Test run only\n" unless $confirm;
137
138
138
print "getting auto renewals\n" if $verbose;
139
print "getting auto renewals\n" if $verbose;
Lines 141-154 my @auto_renews = Koha::Checkouts->search( Link Here
141
        auto_renew                   => 1,
142
        auto_renew                   => 1,
142
        'patron.autorenew_checkouts' => 1,
143
        'patron.autorenew_checkouts' => 1,
143
    },
144
    },
144
    {
145
    { join => [ 'patron', 'item' ] }
145
        join => ['patron','item']
146
    }
147
)->as_list;
146
)->as_list;
148
print "found " . scalar @auto_renews . " auto renewals\n" if $verbose;
147
print "found " . scalar @auto_renews . " auto renewals\n" if $verbose;
149
148
150
my $cron_options = C4::Context->config('auto_renew_cronjob');
149
my $cron_options = C4::Context->config('auto_renew_cronjob');
151
my $loops = $cron_options ? $cron_options->{parallel_loops_count} // 1 : 1;
150
my $loops        = $cron_options ? $cron_options->{parallel_loops_count} // 1 : 1;
152
151
153
# Split the list of issues into chunks to run in parallel
152
# Split the list of issues into chunks to run in parallel
154
my @chunks;
153
my @chunks;
Lines 165-184 if ( $loops > 1 ) { Link Here
165
        push( @{ $chunks[$i] }, $auto_renew );
164
        push( @{ $chunks[$i] }, $auto_renew );
166
    }
165
    }
167
    my $pm = Parallel::ForkManager->new($loops);
166
    my $pm = Parallel::ForkManager->new($loops);
168
  DATA_LOOP:
167
DATA_LOOP:
169
    foreach my $chunk (@chunks) {
168
    foreach my $chunk (@chunks) {
170
        my $pid = $pm->start and next DATA_LOOP;
169
        my $pid = $pm->start and next DATA_LOOP;
171
        _ProcessRenewals($chunk);
170
        _ProcessRenewals($chunk);
172
        $pm->finish;
171
        $pm->finish;
173
    }
172
    }
174
    $pm->wait_all_children;
173
    $pm->wait_all_children;
175
}
174
} else {
176
else {
177
    _ProcessRenewals( \@auto_renews );
175
    _ProcessRenewals( \@auto_renews );
178
}
176
}
179
177
180
cronlogaction({ action => 'End', info => "COMPLETED" });
178
cronlogaction( { action => 'End', info => "COMPLETED" } );
181
182
179
183
=head1 METHODS
180
=head1 METHODS
184
181
Lines 191-345 cronlogaction({ action => 'End', info => "COMPLETED" }); Link Here
191
sub _ProcessRenewals {
188
sub _ProcessRenewals {
192
    my $auto_renew_issues = shift;
189
    my $auto_renew_issues = shift;
193
190
194
my $renew_digest = {};
191
    my $renew_digest = {};
195
my %report;
192
    my %report;
196
my @item_renewal_ids;
193
    my @item_renewal_ids;
197
194
198
    foreach my $auto_renew (@$auto_renew_issues) {
195
    foreach my $auto_renew (@$auto_renew_issues) {
199
    print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
196
        print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
200
197
201
    my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
198
        my ( $borrower_preferences, $wants_messages, $wants_digest ) = ( undef, 0, 0 );
202
    if ( $send_notices_pref eq 'preferences' ) {
199
        if ( $send_notices_pref eq 'preferences' ) {
203
        $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
200
            $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
204
            {
201
                {
205
                borrowernumber => $auto_renew->borrowernumber,
202
                    borrowernumber => $auto_renew->borrowernumber,
206
                message_name   => 'auto_renewals'
203
                    message_name   => 'auto_renewals'
207
            }
204
                }
208
        );
205
            );
209
        $wants_messages = 1
206
            $wants_messages = 1
210
            if $borrower_preferences
207
                if $borrower_preferences
211
            && $borrower_preferences->{transports};
208
                && $borrower_preferences->{transports};
212
        $wants_digest = 1
209
            $wants_digest = 1
213
            if $wants_messages
210
                if $wants_messages
214
            && $borrower_preferences->{wants_digest};
211
                && $borrower_preferences->{wants_digest};
215
    } else {    # Preference is never or cron
212
        } else {    # Preference is never or cron
216
        $wants_messages = $send_notices;
213
            $wants_messages = $send_notices;
217
        $wants_digest   = 0;
214
            $wants_digest   = 0;
218
    }
219
220
    my ( $success, $error, $updated ) = $auto_renew->attempt_auto_renew( { confirm => $confirm } );
221
    if ($success) {
222
        if ($verbose) {
223
            say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
224
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
225
                $confirm ? 'will' : 'would';
226
        }
227
        if ($confirm) {
228
            push @item_renewal_ids, $auto_renew->itemnumber;
229
        }
230
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
231
            if ($wants_messages) && !$wants_digest;
232
    } elsif (
233
234
        # FIXME Do we need to list every status? Why not simply else?
235
           $error eq 'too_many'
236
        || $error eq 'on_reserve'
237
        || $error eq 'restriction'
238
        || $error eq 'overdue'
239
        || $error eq 'too_unseen'
240
        || $error eq 'auto_account_expired'
241
        || $error eq 'auto_too_late'
242
        || $error eq 'auto_too_much_oweing'
243
        || $error eq 'auto_too_soon'
244
        || $error eq 'item_denied_renewal'
245
        || $error eq 'item_issued_to_other_patron'
246
        )
247
    {
248
        if ($verbose) {
249
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
250
                $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
251
                $confirm ? 'will' : 'would', $error;
252
        }
215
        }
253
        if ($updated) {
216
217
        my ( $success, $error, $updated ) = $auto_renew->attempt_auto_renew( { confirm => $confirm } );
218
        if ($success) {
219
            if ($verbose) {
220
                say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
221
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
222
                    $confirm ? 'will' : 'would';
223
            }
224
            if ($confirm) {
225
                push @item_renewal_ids, $auto_renew->itemnumber;
226
            }
254
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
227
            push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
255
                if $error ne 'auto_too_soon' && ( $wants_messages && !$wants_digest );  # Do not notify if it's too soon
228
                if ($wants_messages) && !$wants_digest;
229
        } elsif (
230
231
            # FIXME Do we need to list every status? Why not simply else?
232
               $error eq 'too_many'
233
            || $error eq 'on_reserve'
234
            || $error eq 'restriction'
235
            || $error eq 'overdue'
236
            || $error eq 'too_unseen'
237
            || $error eq 'auto_account_expired'
238
            || $error eq 'auto_too_late'
239
            || $error eq 'auto_too_much_oweing'
240
            || $error eq 'auto_too_soon'
241
            || $error eq 'item_denied_renewal'
242
            || $error eq 'item_issued_to_other_patron'
243
            )
244
        {
245
            if ($verbose) {
246
                say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
247
                    $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber,
248
                    $confirm ? 'will' : 'would', $error;
249
            }
250
            if ($updated) {
251
                push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
252
                    if $error ne 'auto_too_soon'
253
                    && ( $wants_messages && !$wants_digest );    # Do not notify if it's too soon
254
            }
256
        }
255
        }
257
    }
258
256
259
    if ( $wants_digest ) {
257
        if ($wants_digest) {
260
        # cache this one to process after we've run through all of the items.
258
261
        if ($digest_per_branch) {
259
            # cache this one to process after we've run through all of the items.
262
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $success;
260
            if ($digest_per_branch) {
263
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
261
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $success;
264
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}->{defined $error ? $error : 'auto-renew'}++ ;
262
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++
265
            push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
263
                    unless $success || $error eq 'auto_too_soon';
266
            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && (!$error || $error ne 'auto_too_soon');
264
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{results}
267
        } else {
265
                    ->{ defined $error ? $error : 'auto-renew' }++;
268
            $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $success;
266
                push @{ $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues} },
269
            $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
267
                    $auto_renew->itemnumber;
270
            $renew_digest->{ $auto_renew->borrowernumber }->{results}->{defined $error ? $error : 'auto-renew'}++ ;
268
                $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{updated} = 1
271
            $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1 if $updated && (!$error || $error ne 'auto_too_soon');
269
                    if $updated && ( !$error || $error ne 'auto_too_soon' );
272
            push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
270
            } else {
271
                $renew_digest->{ $auto_renew->borrowernumber }->{success}++ if $success;
272
                $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $success || $error eq 'auto_too_soon';
273
                $renew_digest->{ $auto_renew->borrowernumber }->{results}->{ defined $error ? $error : 'auto-renew' }++;
274
                $renew_digest->{ $auto_renew->borrowernumber }->{updated} = 1
275
                    if $updated && ( !$error || $error ne 'auto_too_soon' );
276
                push @{ $renew_digest->{ $auto_renew->borrowernumber }->{issues} }, $auto_renew->itemnumber;
277
            }
273
        }
278
        }
274
    }
275
279
276
}
280
    }
277
281
278
if( @item_renewal_ids ){
282
    if (@item_renewal_ids) {
279
    my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
283
        my $indexer = Koha::SearchEngine::Indexer->new( { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
280
    $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
284
        $indexer->index_records( \@item_renewal_ids, "specialUpdate", "biblioserver" );
281
}
285
    }
282
286
283
if ( $send_notices && $confirm ) {
287
    if ( $send_notices && $confirm ) {
284
    for my $borrowernumber ( keys %report ) {
288
        for my $borrowernumber ( keys %report ) {
285
        my $patron = Koha::Patrons->find($borrowernumber);
289
            my $patron               = Koha::Patrons->find($borrowernumber);
286
        my $borrower_preferences =
290
            my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences(
287
            C4::Members::Messaging::GetMessagingPreferences(
288
                {
291
                {
289
                    borrowernumber => $borrowernumber,
292
                    borrowernumber => $borrowernumber,
290
                    message_name   => 'auto_renewals'
293
                    message_name   => 'auto_renewals'
291
                }
294
                }
292
            );
295
            );
293
        for my $issue ( @{ $report{$borrowernumber} } ) {
296
            for my $issue ( @{ $report{$borrowernumber} } ) {
294
            my $item = $issue->item;
297
                my $item = $issue->item;
295
            # Force sending of email and only email if pref is set to "cron"
298
296
            my @transports = $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
299
                # Force sending of email and only email if pref is set to "cron"
297
            foreach my $transport ( @transports ) {
300
                my @transports =
298
                my $letter = C4::Letters::GetPreparedLetter (
301
                    $send_notices_pref eq 'preferences' ? keys %{ $borrower_preferences->{'transports'} } : 'email';
299
                    module      => 'circulation',
302
                foreach my $transport (@transports) {
300
                    letter_code => 'AUTO_RENEWALS',
303
                    my $letter = C4::Letters::GetPreparedLetter(
301
                    tables      => {
304
                        module      => 'circulation',
302
                        borrowers => $patron->borrowernumber,
305
                        letter_code => 'AUTO_RENEWALS',
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