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

(-)a/misc/cronjobs/overdue_notices.pl (-289 / +313 lines)
Lines 108-114 any CSV files. Defaults to 90 to match F<longoverdues.pl>. Link Here
108
=item B<--library>
108
=item B<--library>
109
109
110
select overdues for one specific library. Use the value in the
110
select overdues for one specific library. Use the value in the
111
branches.branchcode table. This option can be repeated in order 
111
branches.branchcode table. This option can be repeated in order
112
to select overdues for a group of libraries.
112
to select overdues for a group of libraries.
113
113
114
=item B<--csv>
114
=item B<--csv>
Lines 142-147 defaults to due date,title,barcode,author Link Here
142
Other possible values come from fields in the biblios, items and
142
Other possible values come from fields in the biblios, items and
143
issues tables.
143
issues tables.
144
144
145
=item B<--itemtypes>
146
147
Repeatable field, that permits to select only some item types.
148
149
=item B<--itemtypesout>
150
151
Repeatable field, that permits to exclude some item types.
152
145
=item B<--borcat>
153
=item B<--borcat>
146
154
147
Repeatable field, that permits to select only some patron categories.
155
Repeatable field, that permits to select only some patron categories.
Lines 152-164 Repeatable field, that permits to exclude some patron categories. Link Here
152
160
153
=item B<-t> | B<--triggered>
161
=item B<-t> | B<--triggered>
154
162
155
This option causes a notice to be generated if and only if 
163
This option causes a notice to be generated if and only if
156
an item is overdue by the number of days defined in a notice trigger.
164
an item is overdue by the number of days defined in a notice trigger.
157
165
158
By default, a notice is sent each time the script runs, which is suitable for 
166
By default, a notice is sent each time the script runs, which is suitable for
159
less frequent run cron script, but requires syncing notice triggers with 
167
less frequent run cron script, but requires syncing notice triggers with
160
the  cron schedule to ensure proper behavior.
168
the  cron schedule to ensure proper behavior.
161
Add the --triggered option for daily cron, at the risk of no notice 
169
Add the --triggered option for daily cron, at the risk of no notice
162
being generated if the cron fails to run on time.
170
being generated if the cron fails to run on time.
163
171
164
=item B<--test>
172
=item B<--test>
Lines 170-176 for debugging configuration. Link Here
170
178
171
=item B<--list-all>
179
=item B<--list-all>
172
180
173
Default items.content lists only those items that fall in the 
181
Default items.content lists only those items that fall in the
174
range of the currently processing notice.
182
range of the currently processing notice.
175
Choose --list-all to include all overdue items in the list (limited by B<--max> setting).
183
Choose --list-all to include all overdue items in the list (limited by B<--max> setting).
176
184
Lines 307-312 my $text_filename; Link Here
307
my $triggered = 0;
315
my $triggered = 0;
308
my $listall = 0;
316
my $listall = 0;
309
my $itemscontent = join( ',', qw( date_due title barcode author itemnumber ) );
317
my $itemscontent = join( ',', qw( date_due title barcode author itemnumber ) );
318
my @myitemtypes;
319
my @myitemtypesout;
310
my @myborcat;
320
my @myborcat;
311
my @myborcatout;
321
my @myborcatout;
312
my ( $date_input, $today );
322
my ( $date_input, $today );
Lines 320-329 GetOptions( Link Here
320
    'n|nomail'       => \$nomail,
330
    'n|nomail'       => \$nomail,
321
    'max=s'          => \$MAX,
331
    'max=s'          => \$MAX,
322
    'library=s'      => \@branchcodes,
332
    'library=s'      => \@branchcodes,
323
    'csv:s'          => \$csvfilename,    # this optional argument gets '' if not supplied.
333
    'csv:s'          => \$csvfilename,      # this optional argument gets '' if not supplied.
324
    'html:s'         => \$htmlfilename,    # this optional argument gets '' if not supplied.
334
    'html:s'         => \$htmlfilename,     # this optional argument gets '' if not supplied.
325
    'text:s'         => \$text_filename,    # this optional argument gets '' if not supplied.
335
    'text:s'         => \$text_filename,    # this optional argument gets '' if not supplied.
326
    'itemscontent=s' => \$itemscontent,
336
    'itemscontent=s' => \$itemscontent,
337
    'itemtypes=s'    => \@myitemtypes,
338
    'itemtypeouts=s' => \@myitemtypesout,
327
    'list-all'       => \$listall,
339
    'list-all'       => \$listall,
328
    't|triggered'    => \$triggered,
340
    't|triggered'    => \$triggered,
329
    'test'           => \$test_mode,
341
    'test'           => \$test_mode,
Lines 333-341 GetOptions( Link Here
333
    'email=s'        => \@emails,
345
    'email=s'        => \@emails,
334
    'frombranch=s'   => \$frombranch,
346
    'frombranch=s'   => \$frombranch,
335
) or pod2usage(2);
347
) or pod2usage(2);
336
pod2usage(1) if $help;
348
pod2usage(1)               if $help;
337
pod2usage( -verbose => 2 ) if $man;
349
pod2usage( -verbose => 2 ) if $man;
338
cronlogaction({ info => $command_line_options });
350
cronlogaction( { info => $command_line_options } );
339
351
340
if ( defined $csvfilename && $csvfilename =~ /^-/ ) {
352
if ( defined $csvfilename && $csvfilename =~ /^-/ ) {
341
    warn qq(using "$csvfilename" as filename, that seems odd);
353
    warn qq(using "$csvfilename" as filename, that seems odd);
Lines 367-385 if ($branchcount) { Link Here
367
379
368
if (@branchcodes) {
380
if (@branchcodes) {
369
    $verbose and warn "$branchcodes_word @branchcodes passed on parameter\n";
381
    $verbose and warn "$branchcodes_word @branchcodes passed on parameter\n";
370
    
382
371
    # Getting libraries which have overdue rules
383
    # Getting libraries which have overdue rules
372
    my %seen = map { $_ => 1 } @branchcodes;
384
    my %seen = map { $_ => 1 } @branchcodes;
373
    @branches = grep { $seen{$_} } @overduebranches;
385
    @branches = grep { $seen{$_} } @overduebranches;
374
    
386
375
    
387
376
    if (@branches) {
388
    if (@branches) {
377
389
378
        my $branch_word = scalar @branches > 1 ? 'branches' : 'branch';
390
        my $branch_word = scalar @branches > 1 ? 'branches' : 'branch';
379
    $verbose and warn "$branch_word @branches have overdue rules\n";
391
    $verbose and warn "$branch_word @branches have overdue rules\n";
380
392
381
    } else {
393
    } else {
382
    
394
383
        $verbose and warn "No active overduerules for $branchcodes_word  '@branchcodes'\n";
395
        $verbose and warn "No active overduerules for $branchcodes_word  '@branchcodes'\n";
384
        ( scalar grep { '' eq $_ } @branches )
396
        ( scalar grep { '' eq $_ } @branches )
385
          or die "No active overduerules for DEFAULT either!";
397
          or die "No active overduerules for DEFAULT either!";
Lines 437-443 if ( defined $htmlfilename ) { Link Here
437
    my $today = dt_from_string();
449
    my $today = dt_from_string();
438
    open $fh, ">:encoding(UTF-8)",File::Spec->catdir ($htmlfilename,"notices-".$today->ymd().".html");
450
    open $fh, ">:encoding(UTF-8)",File::Spec->catdir ($htmlfilename,"notices-".$today->ymd().".html");
439
  }
451
  }
440
  
452
441
  print $fh _get_html_start();
453
  print $fh _get_html_start();
442
}
454
}
443
elsif ( defined $text_filename ) {
455
elsif ( defined $text_filename ) {
Lines 498-547 END_SQL Link Here
498
        @categories = Koha::Patron::Categories->search()->get_column('categorycode');
510
        @categories = Koha::Patron::Categories->search()->get_column('categorycode');
499
    }
511
    }
500
512
513
    my @itemtypes;
514
    if (@myitemtypes) {
515
        @itemtypes = @myitemtypes;
516
    } elsif (@myitemtypesout) {
517
        @itemtypes =
518
            Koha::ItemTypes->search( { itemtype => { 'not_in' => \@myitemtypesout } } )->get_column('itemtype');
519
    } else {
520
        @itemtypes = Koha::ItemTypes->search()->get_column('itemtype');
521
    }
522
501
    for my $category (@categories) {
523
    for my $category (@categories) {
502
        my $i = 0;
524
        for my $itemtype (@itemtypes) {
503
        PERIOD: while (1) {
525
            my $i = 0;
504
            $i++;
526
            PERIOD: while (1) {
505
            my $j = $i + 1;
527
                $i++;
506
            my $overdue_rules = Koha::CirculationRules->get_effective_rules(
528
                my $j = $i + 1;
507
                {
529
                my $overdue_rules = Koha::CirculationRules->get_effective_rules(
508
                    rules => [
530
                    {
509
                        "overdue_$i" . '_delay',    "overdue_$i" . '_notice', "overdue_$i" . '_mtt',
531
                        rules => [
510
                        "overdue_$i" . '_restrict', "overdue_$j" . '_delay'
532
                            "overdue_$i" . '_delay',    "overdue_$i" . '_notice', "overdue_$i" . '_mtt',
511
                    ],
533
                            "overdue_$i" . '_restrict', "overdue_$j" . '_delay'
512
                    categorycode => $category,
534
                        ],
513
                    branchcode   => $branchcode
535
                        categorycode => $category,
514
                }
536
                        branchcode   => $branchcode,
515
            );
537
                        itemtype     => $itemtype,
516
            $verbose and warn "branch '$branchcode', categorycode = $category pass $i\n";
538
                    }
539
                );
540
                $verbose and warn "branch '$branchcode', categorycode = $category, itemtype = $itemtype, pass $i\n";
517
541
518
            if (!$overdue_rules->{"overdue_$i".'_delay'}) {
542
                if ( !defined( $overdue_rules->{ "overdue_$i" . '_delay' } ) ) {
519
                last PERIOD;
543
                    last PERIOD;
520
            }
544
                }
521
545
522
            my $mindays =
546
                my $mindays =
523
                $overdue_rules->{ "overdue_$i" . '_delay' }; # the notice will be sent after mindays days (grace period)
547
                    $overdue_rules->{ "overdue_$i" . '_delay' }; # the notice will be sent after mindays days (grace period)
524
            my $maxdays = (
548
                my $maxdays = (
525
                  $overdue_rules->{ "overdue_$j" . '_delay' }
549
                      $overdue_rules->{ "overdue_$j" . '_delay' }
526
                ? $overdue_rules->{ "overdue_$j" . '_delay' } - 1
550
                    ? $overdue_rules->{ "overdue_$j" . '_delay' } - 1
527
                : ($MAX)
551
                    : ($MAX)
528
            );    # issues being more than maxdays late are managed somewhere else. (borrower probably suspended)
552
                );    # issues being more than maxdays late are managed somewhere else. (borrower probably suspended)
529
553
530
            next unless defined $mindays;
554
                next unless defined $mindays;
531
555
532
            if ( !$overdue_rules->{"overdue_$i".'_notice'} ) {
556
                if ( !$overdue_rules->{"overdue_$i".'_notice'} ) {
533
                $verbose and warn sprintf "No letter code found for pass %s\n", $i;
557
                    $verbose and warn sprintf "No letter code found for pass %s\n", $i;
534
                next PERIOD;
558
                    next PERIOD;
535
            }
559
                }
536
            $verbose and warn sprintf "Using letter code '%s' for pass %s\n", $overdue_rules->{"overdue_$i".'_notice'}, $i;
560
                $verbose and warn sprintf "Using letter code '%s' for pass %s\n", $overdue_rules->{"overdue_$i".'_notice'}, $i;
537
561
538
            # $letter->{'content'} is the text of the mail that is sent.
562
                # $letter->{'content'} is the text of the mail that is sent.
539
            # this text contains fields that are replaced by their value. Those fields must be written between brackets
563
                # this text contains fields that are replaced by their value. Those fields must be written between brackets
540
            # The following fields are available :
564
                # The following fields are available :
541
        # itemcount is interpreted here as the number of items in the overdue range defined by the current notice or all overdues < max if(-list-all).
565
            # itemcount is interpreted here as the number of items in the overdue range defined by the current notice or all overdues < max if(-list-all).
542
            # <date> <itemcount> <firstname> <lastname> <address1> <address2> <address3> <city> <postcode> <country>
566
                # <date> <itemcount> <firstname> <lastname> <address1> <address2> <address3> <city> <postcode> <country>
543
567
544
            my $borrower_sql = <<"END_SQL";
568
                my $borrower_sql = <<"END_SQL";
545
SELECT issues.borrowernumber, firstname, surname, address, address2, city, zipcode, country, email, emailpro, B_email, smsalertnumber, phone, cardnumber, date_due
569
SELECT issues.borrowernumber, firstname, surname, address, address2, city, zipcode, country, email, emailpro, B_email, smsalertnumber, phone, cardnumber, date_due
546
FROM   issues,borrowers,categories,items
570
FROM   issues,borrowers,categories,items
547
WHERE  issues.borrowernumber=borrowers.borrowernumber
571
WHERE  issues.borrowernumber=borrowers.borrowernumber
Lines 550-806 AND issues.itemnumber = items.itemnumber Link Here
550
AND    items.itemlost = 0
574
AND    items.itemlost = 0
551
AND    TO_DAYS($date)-TO_DAYS(issues.date_due) >= 0
575
AND    TO_DAYS($date)-TO_DAYS(issues.date_due) >= 0
552
END_SQL
576
END_SQL
553
            my @borrower_parameters;
577
                my @borrower_parameters;
554
            if ($branchcode) {
578
                if ($branchcode) {
555
        if($owning_library) {
579
            if($owning_library) {
556
            $borrower_sql .= ' AND items.homebranch=? ';
580
                $borrower_sql .= ' AND items.homebranch=? ';
557
        } else {
581
            } else {
558
            $borrower_sql .= ' AND issues.branchcode=? ';
582
                $borrower_sql .= ' AND issues.branchcode=? ';
559
        }
560
                push @borrower_parameters, $branchcode;
561
            }
562
            if ( $category ) {
563
                $borrower_sql .= ' AND borrowers.categorycode=? ';
564
                push @borrower_parameters, $category;
565
            }
583
            }
566
            $borrower_sql .= '  AND categories.overduenoticerequired=1 ORDER BY issues.borrowernumber';
584
                    push @borrower_parameters, $branchcode;
567
568
            # $sth gets borrower info iff at least one overdue item has triggered the overdue action.
569
            my $sth = $dbh->prepare($borrower_sql);
570
            $sth->execute(@borrower_parameters);
571
572
            if ( $verbose > 1 ){
573
                warn sprintf "--------Borrower SQL------\n";
574
                warn $borrower_sql . "\n $branchcode | " . $category . "\n ($mindays, $maxdays, ".  $date_to_run->datetime() .")\n";
575
                warn sprintf "--------------------------\n";
576
            }
577
            $verbose and warn sprintf "Found %s borrowers with overdues\n", $sth->rows;
578
            my $borrowernumber;
579
            while ( my $data = $sth->fetchrow_hashref ) {
580
581
                # check the borrower has at least one item that matches
582
                my $days_between;
583
                if ( C4::Context->preference('OverdueNoticeCalendar') )
584
                {
585
                    $days_between =
586
                      $calendar->days_between( dt_from_string($data->{date_due}),
587
                        $date_to_run );
588
                }
585
                }
589
                else {
586
                if ( $category ) {
590
                    $days_between =
587
                    $borrower_sql .= ' AND borrowers.categorycode=? ';
591
                      $date_to_run->delta_days( dt_from_string($data->{date_due}) );
588
                    push @borrower_parameters, $category;
592
                }
589
                }
593
                $days_between = $days_between->in_units('days');
590
                $borrower_sql .= '  AND categories.overduenoticerequired=1 ORDER BY issues.borrowernumber';
594
                if ($triggered) {
595
                    if ( $mindays != $days_between ) {
596
                        next;
597
                    }
598
                }
599
                else {
600
                    unless (   $days_between >= $mindays
601
                        && $days_between <= $maxdays )
602
                    {
603
                        next;
604
                    }
605
                }
606
                if (defined $borrowernumber && $borrowernumber eq $data->{'borrowernumber'}){
607
# we have already dealt with this borrower
608
                    $verbose and warn "already dealt with this borrower $borrowernumber";
609
                    next;
610
                }
611
                $borrowernumber = $data->{'borrowernumber'};
612
                next if ( $patron_homelibrary && $already_queued{"$borrowernumber$i"} );
613
                my $borr = sprintf( "%s%s%s (%s)",
614
                    $data->{'surname'} || '',
615
                    $data->{'firstname'} && $data->{'surname'} ? ', ' : '',
616
                    $data->{'firstname'} || '',
617
                    $borrowernumber );
618
                $verbose and warn "borrower $borr has items triggering level $i.\n";
619
620
                my $patron = Koha::Patrons->find( $borrowernumber );
621
                if ($patron_homelibrary) {
622
                    $branchcode           = $patron->branchcode;
623
                    $library              = Koha::Libraries->find($branchcode);
624
                    $admin_email_address  = $library->from_email_address;
625
                    $branch_email_address = C4::Context->preference('AddressForFailedOverdueNotices')
626
                        || $library->inbound_email_address;
627
                }
628
                @emails_to_use = ();
629
                my $notice_email = $patron->notice_email_address;
630
                unless ($nomail) {
631
                    if (@emails) {
632
                        foreach (@emails) {
633
                            push @emails_to_use, $data->{$_} if ( $data->{$_} );
634
                        }
635
                    }
636
                    else {
637
                        push @emails_to_use, $notice_email if ($notice_email);
638
                    }
639
                }
640
641
                my $letter = Koha::Notice::Templates->find_effective_template(
642
                    {
643
                        module     => 'circulation',
644
                        code       => $overdue_rules->{"overdue_$i".'_notice'},
645
                        branchcode => $branchcode,
646
                        lang       => $patron->lang
647
                    }
648
                );
649
591
650
                unless ($letter) {
592
                # $sth gets borrower info iff at least one overdue item has triggered the overdue action.
651
                    $verbose and warn qq|Message '$overdue_rules->{"overdue_$i"."_notice"}' content not found|;
593
                my $sth = $dbh->prepare($borrower_sql);
594
                $sth->execute(@borrower_parameters);
652
595
653
                    # might as well skip while PERIOD, no other borrowers are going to work.
596
                if ( $verbose > 1 ){
654
                    # FIXME : Does this mean a letter must be defined in order to trigger a debar ?
597
                    warn sprintf "--------Borrower SQL------\n";
655
                    next PERIOD;
598
                    warn $borrower_sql . "\n $branchcode | " . $category . "\n ($mindays, $maxdays, ".  $date_to_run->datetime() .")\n";
656
                }
599
                    warn sprintf "--------------------------\n";
657
    
658
                if ( $overdue_rules->{"overdue_$i".'_restrict'} ) {
659
    
660
                    #action taken is debarring
661
                    AddUniqueDebarment(
662
                        {
663
                            borrowernumber => $borrowernumber,
664
                            type           => 'OVERDUES',
665
                            comment => "OVERDUES_PROCESS " .  output_pref( dt_from_string() ),
666
                        }
667
                    ) unless $test_mode;
668
                    $verbose and warn "debarring $borr\n";
669
                }
600
                }
670
                my @params = $patron_homelibrary ? ($borrowernumber) : ( $borrowernumber, $branchcode );
601
                $verbose and warn sprintf "Found %s borrowers with overdues\n", $sth->rows;
671
602
                my $borrowernumber;
672
                $sth2->execute(@params);
603
                while ( my $data = $sth->fetchrow_hashref ) {
673
                my $itemcount = 0;
604
674
                my $titles = "";
605
                    # check the borrower has at least one item that matches
675
                my @items = ();
606
                    my $days_between;
676
                
607
                    if ( C4::Context->preference('OverdueNoticeCalendar') )
677
                my $j = 0;
608
                    {
678
                my $exceededPrintNoticesMaxLines = 0;
679
                while ( my $item_info = $sth2->fetchrow_hashref() ) {
680
                    if ( C4::Context->preference('OverdueNoticeCalendar') ) {
681
                        $days_between =
609
                        $days_between =
682
                          $calendar->days_between(
610
                          $calendar->days_between( dt_from_string($data->{date_due}),
683
                            dt_from_string( $item_info->{date_due} ), $date_to_run );
611
                            $date_to_run );
684
                    }
612
                    }
685
                    else {
613
                    else {
686
                        $days_between =
614
                        $days_between =
687
                          $date_to_run->delta_days(
615
                          $date_to_run->delta_days( dt_from_string($data->{date_due}) );
688
                            dt_from_string( $item_info->{date_due} ) );
689
                    }
616
                    }
690
                    $days_between = $days_between->in_units('days');
617
                    $days_between = $days_between->in_units('days');
691
                    if ($listall){
618
                    if ($triggered) {
692
                        unless ($days_between >= 1 and $days_between <= $MAX){
619
                        if ( $mindays != $days_between ) {
693
                            next;
620
                            next;
694
                        }
621
                        }
695
                    }
622
                    }
696
                    else {
623
                    else {
697
                        if ($triggered) {
624
                        unless (   $days_between >= $mindays
698
                            if ( $mindays != $days_between ) {
625
                            && $days_between <= $maxdays )
699
                                next;
626
                        {
627
                            next;
628
                        }
629
                    }
630
                    if (defined $borrowernumber && $borrowernumber eq $data->{'borrowernumber'}){
631
# we have already dealt with this borrower
632
                        $verbose and warn "already dealt with this borrower $borrowernumber";
633
                        next;
634
                    }
635
                    $borrowernumber = $data->{'borrowernumber'};
636
                    next if ( $patron_homelibrary && $already_queued{"$borrowernumber$i"} );
637
                    my $borr = sprintf( "%s%s%s (%s)",
638
                        $data->{'surname'} || '',
639
                        $data->{'firstname'} && $data->{'surname'} ? ', ' : '',
640
                        $data->{'firstname'} || '',
641
                        $borrowernumber );
642
                    $verbose and warn "borrower $borr has items triggering level $i.\n";
643
644
                    my $patron = Koha::Patrons->find( $borrowernumber );
645
                    if ($patron_homelibrary) {
646
                        $branchcode           = $patron->branchcode;
647
                        $library              = Koha::Libraries->find($branchcode);
648
                        $admin_email_address  = $library->from_email_address;
649
                        $branch_email_address = C4::Context->preference('AddressForFailedOverdueNotices')
650
                            || $library->inbound_email_address;
651
                    }
652
                    @emails_to_use = ();
653
                    my $notice_email = $patron->notice_email_address;
654
                    unless ($nomail) {
655
                        if (@emails) {
656
                            foreach (@emails) {
657
                                push @emails_to_use, $data->{$_} if ( $data->{$_} );
700
                            }
658
                            }
701
                        }
659
                        }
702
                        else {
660
                        else {
703
                            unless ( $days_between >= $mindays
661
                            push @emails_to_use, $notice_email if ($notice_email);
704
                                && $days_between <= $maxdays )
705
                            {
706
                                next;
707
                            }
708
                        }
662
                        }
709
                    }
663
                    }
710
664
711
                    if ( ( scalar(@emails_to_use) == 0 || $nomail ) && $PrintNoticesMaxLines && $j >= $PrintNoticesMaxLines ) {
665
                    my $letter = Koha::Notice::Templates->find_effective_template(
712
                      $exceededPrintNoticesMaxLines = 1;
713
                      last;
714
                    }
715
                    next if $patron_homelibrary and !grep { $seen{ $item_info->{branchcode} } } @branches;
716
                    $j++;
717
718
                    $titles .= C4::Letters::get_item_content( { item => $item_info, item_content_fields => \@item_content_fields, dateonly => 1 } );
719
                    $itemcount++;
720
                    push @items, $item_info;
721
                }
722
                $sth2->finish;
723
724
                my @message_transport_types = split( /,/, $overdue_rules->{ "overdue_$i" . '_mtt' } );
725
726
                my $print_sent = 0; # A print notice is not yet sent for this patron
727
                for my $mtt ( @message_transport_types ) {
728
                    next if $mtt eq 'itiva';
729
                    my $effective_mtt = $mtt;
730
                    if ( ($mtt eq 'email' and not scalar @emails_to_use) or ($mtt eq 'sms' and not $data->{smsalertnumber}) ) {
731
                        # email or sms is requested but not exist, do a print.
732
                        $effective_mtt = 'print';
733
                    }
734
                    splice @items, $PrintNoticesMaxLines if $effective_mtt eq 'print' && $PrintNoticesMaxLines && scalar @items > $PrintNoticesMaxLines;
735
                    #catch the case where we are sending a print to someone with an email
736
737
                    my $letter_exists = Koha::Notice::Templates->find_effective_template(
738
                        {
666
                        {
739
                            module                 => 'circulation',
667
                            module     => 'circulation',
740
                            code                   => $overdue_rules->{ "overdue_$i" . '_notice' },
668
                            code       => $overdue_rules->{"overdue_$i".'_notice'},
741
                            message_transport_type => $effective_mtt,
669
                            branchcode => $branchcode,
742
                            branchcode             => $branchcode,
670
                            lang       => $patron->lang
743
                            lang                   => $patron->lang
744
                        }
671
                        }
745
                    );
672
                    );
746
673
747
                    my $letter = parse_overdues_letter(
674
                    unless ($letter) {
748
                        {
749
                            letter_code    => $overdue_rules->{ "overdue_$i" . '_notice' },
750
                            borrowernumber => $borrowernumber,
751
                            branchcode     => $branchcode,
752
                            items          => \@items,
753
                            substitute => {    # this appears to be a hack to overcome incomplete features in this code.
754
                                bib             => $library->branchname,    # maybe 'bib' is a typo for 'lib<rary>'?
755
                                'items.content' => $titles,
756
                                'count'         => $itemcount,
757
                            },
758
759
                            # If there is no template defined for the requested letter
760
                            # Fallback on the original type
761
                            message_transport_type => $letter_exists ? $effective_mtt : $mtt,
762
                        }
763
                    );
764
                    unless ( $letter && $letter->{content} ) {
765
                        $verbose and warn qq|Message '$overdue_rules->{"overdue_$i"."_notice"}' content not found|;
675
                        $verbose and warn qq|Message '$overdue_rules->{"overdue_$i"."_notice"}' content not found|;
766
676
767
                        # this transport doesn't have a configured notice, so try another
677
                        # might as well skip while PERIOD, no other borrowers are going to work.
768
                        next;
678
                        # FIXME : Does this mean a letter must be defined in order to trigger a debar ?
679
                        next PERIOD;
769
                    }
680
                    }
770
681
771
                    if ( $exceededPrintNoticesMaxLines ) {
682
                    if ( $overdue_rules->{"overdue_$i".'_restrict'} ) {
772
                      $letter->{'content'} .= "List too long for form; please check your account online for a complete list of your overdue items.";
683
684
                        #action taken is debarring
685
                        AddUniqueDebarment(
686
                            {
687
                                borrowernumber => $borrowernumber,
688
                                type           => 'OVERDUES',
689
                                comment => "OVERDUES_PROCESS " .  output_pref( dt_from_string() ),
690
                            }
691
                        ) unless $test_mode;
692
                        $verbose and warn "debarring $borr\n";
773
                    }
693
                    }
694
                    my @params = $patron_homelibrary ? ($borrowernumber) : ( $borrowernumber, $branchcode );
695
696
                    $sth2->execute(@params);
697
                    my $itemcount = 0;
698
                    my $titles = "";
699
                    my @items = ();
700
701
                    my $j = 0;
702
                    my $exceededPrintNoticesMaxLines = 0;
703
                    while ( my $item_info = $sth2->fetchrow_hashref() ) {
704
                        if ( C4::Context->preference('OverdueNoticeCalendar') ) {
705
                            $days_between =
706
                              $calendar->days_between(
707
                                dt_from_string( $item_info->{date_due} ), $date_to_run );
708
                        }
709
                        else {
710
                            $days_between =
711
                              $date_to_run->delta_days(
712
                                dt_from_string( $item_info->{date_due} ) );
713
                        }
714
                        $days_between = $days_between->in_units('days');
715
                        if ($listall){
716
                            unless ($days_between >= 1 and $days_between <= $MAX){
717
                                next;
718
                            }
719
                        }
720
                        else {
721
                            if ($triggered) {
722
                                if ( $mindays != $days_between ) {
723
                                    next;
724
                                }
725
                            }
726
                            else {
727
                                unless ( $days_between >= $mindays
728
                                    && $days_between <= $maxdays )
729
                                {
730
                                    next;
731
                                }
732
                            }
733
                        }
734
735
                        if ( ( scalar(@emails_to_use) == 0 || $nomail ) && $PrintNoticesMaxLines && $j >= $PrintNoticesMaxLines ) {
736
                          $exceededPrintNoticesMaxLines = 1;
737
                          last;
738
                        }
739
                        next if $patron_homelibrary and !grep { $seen{ $item_info->{branchcode} } } @branches;
740
                        $j++;
774
741
775
                    my @misses = grep { /./ } map { /^([^>]*)[>]+/; ( $1 || '' ); } split /\</, $letter->{'content'};
742
                        $titles .= C4::Letters::get_item_content( { item => $item_info, item_content_fields => \@item_content_fields, dateonly => 1 } );
776
                    if (@misses) {
743
                        $itemcount++;
777
                        $verbose and warn "The following terms were not matched and replaced: \n\t" . join "\n\t", @misses;
744
                        push @items, $item_info;
778
                    }
745
                    }
746
                    $sth2->finish;
779
747
780
                    if ($nomail) {
748
                    my @message_transport_types = split( /,/, $overdue_rules->{ "overdue_$i" . '_mtt' } );
781
                        push @output_chunks,
749
782
                          prepare_letter_for_printing(
750
                    my $print_sent = 0; # A print notice is not yet sent for this patron
783
                          {   letter         => $letter,
751
                    for my $mtt ( @message_transport_types ) {
784
                              borrowernumber => $borrowernumber,
752
                        next if $mtt eq 'itiva';
785
                              firstname      => $data->{'firstname'},
753
                        my $effective_mtt = $mtt;
786
                              lastname       => $data->{'surname'},
787
                              address1       => $data->{'address'},
788
                              address2       => $data->{'address2'},
789
                              city           => $data->{'city'},
790
                              phone          => $data->{'phone'},
791
                              cardnumber     => $data->{'cardnumber'},
792
                              branchname     => $library->branchname,
793
                              letternumber   => $i,
794
                              postcode       => $data->{'zipcode'},
795
                              country        => $data->{'country'},
796
                              email          => $notice_email,
797
                              itemcount      => $itemcount,
798
                              titles         => $titles,
799
                              outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
800
                            }
801
                          );
802
                    } else {
803
                        if ( ($mtt eq 'email' and not scalar @emails_to_use) or ($mtt eq 'sms' and not $data->{smsalertnumber}) ) {
754
                        if ( ($mtt eq 'email' and not scalar @emails_to_use) or ($mtt eq 'sms' and not $data->{smsalertnumber}) ) {
755
                            # email or sms is requested but not exist, do a print.
756
                            $effective_mtt = 'print';
757
                        }
758
                        splice @items, $PrintNoticesMaxLines if $effective_mtt eq 'print' && $PrintNoticesMaxLines && scalar @items > $PrintNoticesMaxLines;
759
                        #catch the case where we are sending a print to someone with an email
760
761
                        my $letter_exists = Koha::Notice::Templates->find_effective_template(
762
                            {
763
                                module                 => 'circulation',
764
                                code                   => $overdue_rules->{ "overdue_$i" . '_notice' },
765
                                message_transport_type => $effective_mtt,
766
                                branchcode             => $branchcode,
767
                                lang                   => $patron->lang
768
                            }
769
                        );
770
771
                        my $letter = parse_overdues_letter(
772
                            {
773
                                letter_code    => $overdue_rules->{ "overdue_$i" . '_notice' },
774
                                borrowernumber => $borrowernumber,
775
                                branchcode     => $branchcode,
776
                                items          => \@items,
777
                                substitute => {    # this appears to be a hack to overcome incomplete features in this code.
778
                                    bib             => $library->branchname,    # maybe 'bib' is a typo for 'lib<rary>'?
779
                                    'items.content' => $titles,
780
                                    'count'         => $itemcount,
781
                                },
782
783
                                # If there is no template defined for the requested letter
784
                                # Fallback on the original type
785
                                message_transport_type => $letter_exists ? $effective_mtt : $mtt,
786
                            }
787
                        );
788
                        unless ( $letter && $letter->{content} ) {
789
                            $verbose and warn qq|Message '$overdue_rules->{"overdue_$i"."_notice"}' content not found|;
790
791
                            # this transport doesn't have a configured notice, so try another
792
                            next;
793
                        }
794
795
                        if ( $exceededPrintNoticesMaxLines ) {
796
                          $letter->{'content'} .= "List too long for form; please check your account online for a complete list of your overdue items.";
797
                        }
798
799
                        my @misses = grep { /./ } map { /^([^>]*)[>]+/; ( $1 || '' ); } split /\</, $letter->{'content'};
800
                        if (@misses) {
801
                            $verbose and warn "The following terms were not matched and replaced: \n\t" . join "\n\t", @misses;
802
                        }
803
804
                        if ($nomail) {
804
                            push @output_chunks,
805
                            push @output_chunks,
805
                              prepare_letter_for_printing(
806
                              prepare_letter_for_printing(
806
                              {   letter         => $letter,
807
                              {   letter         => $letter,
Lines 810-815 END_SQL Link Here
810
                                  address1       => $data->{'address'},
811
                                  address1       => $data->{'address'},
811
                                  address2       => $data->{'address2'},
812
                                  address2       => $data->{'address2'},
812
                                  city           => $data->{'city'},
813
                                  city           => $data->{'city'},
814
                                  phone          => $data->{'phone'},
815
                                  cardnumber     => $data->{'cardnumber'},
816
                                  branchname     => $library->branchname,
817
                                  letternumber   => $i,
813
                                  postcode       => $data->{'zipcode'},
818
                                  postcode       => $data->{'zipcode'},
814
                                  country        => $data->{'country'},
819
                                  country        => $data->{'country'},
815
                                  email          => $notice_email,
820
                                  email          => $notice_email,
Lines 818-856 END_SQL Link Here
818
                                  outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
823
                                  outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
819
                                }
824
                                }
820
                              );
825
                              );
821
                        }
826
                        } else {
822
                        unless ( $effective_mtt eq 'print' and $print_sent == 1 ) {
827
                            if ( ($mtt eq 'email' and not scalar @emails_to_use) or ($mtt eq 'sms' and not $data->{smsalertnumber}) ) {
823
                            # Just sent a print if not already done.
828
                                push @output_chunks,
824
                            C4::Letters::EnqueueLetter(
829
                                  prepare_letter_for_printing(
825
                                {   letter                 => $letter,
830
                                  {   letter         => $letter,
826
                                    borrowernumber         => $borrowernumber,
831
                                      borrowernumber => $borrowernumber,
827
                                    message_transport_type => $effective_mtt,
832
                                      firstname      => $data->{'firstname'},
828
                                    from_address           => $admin_email_address,
833
                                      lastname       => $data->{'surname'},
829
                                    to_address             => join(',', @emails_to_use),
834
                                      address1       => $data->{'address'},
830
                                    reply_address          => $library->inbound_email_address,
835
                                      address2       => $data->{'address2'},
831
                                }
836
                                      city           => $data->{'city'},
832
                            ) unless $test_mode;
837
                                      postcode       => $data->{'zipcode'},
833
                            # A print notice should be sent only once per overdue level.
838
                                      country        => $data->{'country'},
834
                            # Without this check, a print could be sent twice or more if the library checks sms and email and print and the patron has no email or sms number.
839
                                      email          => $notice_email,
835
                            $print_sent = 1 if $effective_mtt eq 'print';
840
                                      itemcount      => $itemcount,
841
                                      titles         => $titles,
842
                                      outputformat   => defined $csvfilename ? 'csv' : defined $htmlfilename ? 'html' : defined $text_filename ? 'text' : '',
843
                                    }
844
                                  );
845
                            }
846
                            unless ( $effective_mtt eq 'print' and $print_sent == 1 ) {
847
                                # Just sent a print if not already done.
848
                                C4::Letters::EnqueueLetter(
849
                                    {   letter                 => $letter,
850
                                        borrowernumber         => $borrowernumber,
851
                                        message_transport_type => $effective_mtt,
852
                                        from_address           => $admin_email_address,
853
                                        to_address             => join(',', @emails_to_use),
854
                                        reply_address          => $library->inbound_email_address,
855
                                    }
856
                                ) unless $test_mode;
857
                                # A print notice should be sent only once per overdue level.
858
                                # Without this check, a print could be sent twice or more if the library checks sms and email and print and the patron has no email or sms number.
859
                                $print_sent = 1 if $effective_mtt eq 'print';
860
                            }
836
                        }
861
                        }
837
                    }
862
                    }
863
                    $already_queued{"$borrowernumber$i"} = 1;
838
                }
864
                }
839
                $already_queued{"$borrowernumber$i"} = 1;
865
                $sth->finish;
840
            }
866
            }
841
            $sth->finish;
842
        }
867
        }
843
    }
868
    }
844
869
845
    if (@output_chunks) {
870
    if (@output_chunks) {
846
        if ( defined $csvfilename ) {
871
        if ( defined $csvfilename ) {
847
            print $csv_fh @output_chunks;        
872
            print $csv_fh @output_chunks;
848
        }
873
        }
849
        elsif ( defined $htmlfilename ) {
874
        elsif ( defined $htmlfilename ) {
850
            print $fh @output_chunks;        
875
            print $fh @output_chunks;
851
        }
876
        }
852
        elsif ( defined $text_filename ) {
877
        elsif ( defined $text_filename ) {
853
            print $fh @output_chunks;        
878
            print $fh @output_chunks;
854
        }
879
        }
855
        elsif ($nomail){
880
        elsif ($nomail){
856
                local $, = "\f";    # pagebreak
881
                local $, = "\f";    # pagebreak
857
- 

Return to bug 10190