# find Koha's Perl modules
# test carefully before changing this
- use FindBin;
+ use FindBin ();
eval { require "$FindBin::Bin/../kohalib.pl" };
}
-use Getopt::Long;
-use Pod::Usage;
+use Getopt::Long qw( GetOptions );
+use Pod::Usage qw( pod2usage );
use Text::CSV_XS;
use DateTime;
use DateTime::Duration;
+use Koha::Script -cron;
use C4::Context;
use C4::Letters;
-use C4::Overdues qw(GetFine GetOverdueMessageTransportTypes parse_overdues_letter);
-use C4::Log;
-use Koha::Patron::Debarments qw(AddUniqueDebarment);
-use Koha::DateUtils;
+use C4::Overdues qw( GetOverdueMessageTransportTypes parse_overdues_letter );
+use C4::Log qw( cronlogaction );
+use Koha::Patron::Debarments qw( AddUniqueDebarment );
+use Koha::DateUtils qw( dt_from_string output_pref );
use Koha::Calendar;
use Koha::Libraries;
use Koha::Acquisition::Currencies;
+use Koha::Patrons;
=head1 NAME
[ -email <email_type> ... ]
Options:
- -help brief help message
- -man full documentation
- -v verbose
- -n No email will be sent
- -max <days> maximum days overdue to deal with
- -library <branchname> only deal with overdues from this library (repeatable : several libraries can be given)
- -csv <filename> populate CSV file
- -html <directory> Output html to a file in the given directory
- -text <directory> Output plain text to a file in the given directory
- -itemscontent <list of fields> item information in templates
- -borcat <categorycode> category code that must be included
- -borcatout <categorycode> category code that must be excluded
- -t only include triggered overdues
+ -help Brief help message.
+ -man Full documentation.
+ -v Verbose mode.
+ -n No email will be sent.
+ -max <days> Maximum days overdue to deal with.
+ -library <branchcode> Only deal with overdues from this library.
+ (repeatable : several libraries can be given)
+ -csv <filename> Populate CSV file.
+ -html <directory> Output html to a file in the given directory.
+ -text <directory> Output plain text to a file in the given directory.
+ -itemscontent <list of fields> Item information in templates.
+ -borcat <categorycode> Category code that must be included.
+ -borcatout <categorycode> Category code that must be excluded.
+ -t Only include triggered overdues.
--test Run in test mode. No changes will be made on the DB.
- -list-all list all overdues
- -date <yyyy-mm-dd> emulate overdues run for this date
- -email <email_type> type of email that will be used. Can be 'email', 'emailpro' or 'B_email'. Repeatable.
+ -list-all List all overdues.
+ -date <yyyy-mm-dd> Emulate overdues run for this date.
+ -email <email_type> Type of email that will be used.
+ Can be 'email', 'emailpro' or 'B_email'. Repeatable.
+ --frombranch Set the from address for the notice to one of 'item-homebranch' or 'item-issuebranch'.
=head1 OPTIONS
Allows to specify which type of email will be used. Can be email, emailpro or B_email. Repeatable.
+=item B<--frombranch>
+
+Use the address information from the item homebranch library instead of the issuing library.
+
+Defaults to 'item-issuebranch'
+
=back
=head1 DESCRIPTION
my $nomail = 0;
my $MAX = 90;
my $test_mode = 0;
+my $frombranch = 'item-issuebranch';
my @branchcodes; # Branch(es) passed as parameter
my @emails_to_use; # Emails to use for messaging
my @emails; # Emails given in command-line parameters
'borcat=s' => \@myborcat,
'borcatout=s' => \@myborcatout,
'email=s' => \@emails,
+ 'frombranch=s' => \$frombranch,
) or pod2usage(2);
pod2usage(1) if $help;
pod2usage( -verbose => 2 ) if $man;
-
cronlogaction() unless $test_mode;
if ( defined $csvfilename && $csvfilename =~ /^-/ ) {
warn qq(using "$csvfilename" as filename, that seems odd);
}
-my @overduebranches = C4::Overdues::GetBranchcodesWithOverdueRules(); # Branches with overdue rules
-my @branches; # Branches passed as parameter with overdue rules
+die "--frombranch takes item-homebranch or item-issuebranch only"
+ unless ( $frombranch eq 'item-issuebranch'
+ || $frombranch eq 'item-homebranch' );
+my $owning_library = ( $frombranch eq 'item-homebranch' ) ? 1 : 0;
+
+my @overduebranches = C4::Overdues::GetBranchcodesWithOverdueRules(); # Branches with overdue rules
+my @branches; # Branches passed as parameter with overdue rules
my $branchcount = scalar(@overduebranches);
my $overduebranch_word = scalar @overduebranches > 1 ? 'branches' : 'branch';
if (@branches) {
- my $branch_word = scalar @branches > 1 ? 'branches' : 'branch';
- $verbose and warn "$branch_word @branches have overdue rules\n";
+ my $branch_word = scalar @branches > 1 ? 'branches' : 'branch';
+ $verbose and warn "$branch_word @branches have overdue rules\n";
} else {
our $csv; # the Text::CSV_XS object
our $csv_fh; # the filehandle to the CSV file.
if ( defined $csvfilename ) {
- my $sep_char = C4::Context->preference('delimiter') || ';';
+ my $sep_char = C4::Context->preference('CSVDelimiter') || ';';
$sep_char = "\t" if ($sep_char eq 'tabulation');
$csv = Text::CSV_XS->new( { binary => 1 , sep_char => $sep_char } );
if ( $csvfilename eq '' ) {
if ( $htmlfilename eq '' ) {
$fh = *STDOUT;
} else {
- my $today = DateTime->now(time_zone => C4::Context->tz );
+ my $today = dt_from_string();
open $fh, ">:encoding(UTF-8)",File::Spec->catdir ($htmlfilename,"notices-".$today->ymd().".html");
}
if ( $text_filename eq '' ) {
$fh = *STDOUT;
} else {
- my $today = DateTime->now(time_zone => C4::Context->tz );
- open $fh, ">",File::Spec->catdir ($text_filename,"notices-".$today->ymd().".txt");
+ my $today = dt_from_string();
+ open $fh, ">:encoding(UTF-8)",File::Spec->catdir ($text_filename,"notices-".$today->ymd().".txt");
}
}
foreach my $branchcode (@branches) {
+ my $calendar;
if ( C4::Context->preference('OverdueNoticeCalendar') ) {
- my $calendar = Koha::Calendar->new( branchcode => $branchcode );
+ $calendar = Koha::Calendar->new( branchcode => $branchcode );
if ( $calendar->is_holiday($date_to_run) ) {
next;
}
}
my $library = Koha::Libraries->find($branchcode);
- my $admin_email_address = $library->branchemail
- || C4::Context->preference('KohaAdminEmailAddress');
+ my $admin_email_address = $library->from_email_address;
+ my $branch_email_address = C4::Context->preference('AddressForFailedOverdueNotices')
+ || $library->inbound_email_address;
my @output_chunks; # may be sent to mail or stdout or csv file.
- $verbose and warn sprintf "branchcode : '%s' using %s\n", $branchcode, $admin_email_address;
+ $verbose and warn sprintf "branchcode : '%s' using %s\n", $branchcode, $branch_email_address;
- my $sth2 = $dbh->prepare( <<"END_SQL" );
+ my $sql2 = <<"END_SQL";
SELECT biblio.*, items.*, issues.*, biblioitems.itemtype, branchname
FROM issues,items,biblio, biblioitems, branches b
WHERE items.itemnumber=issues.itemnumber
AND b.branchcode = items.homebranch
AND biblio.biblionumber = biblioitems.biblionumber
AND issues.borrowernumber = ?
+ AND items.itemlost = 0
AND TO_DAYS($date)-TO_DAYS(issues.date_due) >= 0
END_SQL
+ if($owning_library) {
+ $sql2 .= ' AND items.homebranch = ? ';
+ } else {
+ $sql2 .= ' AND issues.branchcode = ? ';
+ }
+ my $sth2 = $dbh->prepare($sql2);
+
my $query = "SELECT * FROM overduerules WHERE delay1 IS NOT NULL AND branchcode = ? ";
$query .= " AND categorycode IN (".join( ',' , ('?') x @myborcat ).") " if (@myborcat);
$query .= " AND categorycode NOT IN (".join( ',' , ('?') x @myborcatout ).") " if (@myborcatout);
# $letter->{'content'} is the text of the mail that is sent.
# this text contains fields that are replaced by their value. Those fields must be written between brackets
# The following fields are available :
- # 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).
+ # 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).
# <date> <itemcount> <firstname> <lastname> <address1> <address2> <address3> <city> <postcode> <country>
my $borrower_sql = <<"END_SQL";
SELECT issues.borrowernumber, firstname, surname, address, address2, city, zipcode, country, email, emailpro, B_email, smsalertnumber, phone, cardnumber, date_due
-FROM issues,borrowers,categories
+FROM issues,borrowers,categories,items
WHERE issues.borrowernumber=borrowers.borrowernumber
AND borrowers.categorycode=categories.categorycode
+AND issues.itemnumber = items.itemnumber
+AND items.itemlost = 0
AND TO_DAYS($date)-TO_DAYS(issues.date_due) >= 0
END_SQL
my @borrower_parameters;
if ($branchcode) {
- $borrower_sql .= ' AND issues.branchcode=? ';
+ if($owning_library) {
+ $borrower_sql .= ' AND items.homebranch=? ';
+ } else {
+ $borrower_sql .= ' AND issues.branchcode=? ';
+ }
push @borrower_parameters, $branchcode;
}
if ( $overdue_rules->{categorycode} ) {
$borrower_sql .= ' AND categories.overduenoticerequired=1 ORDER BY issues.borrowernumber';
# $sth gets borrower info iff at least one overdue item has triggered the overdue action.
- my $sth = $dbh->prepare($borrower_sql);
+ my $sth = $dbh->prepare($borrower_sql);
$sth->execute(@borrower_parameters);
$verbose and warn $borrower_sql . "\n $branchcode | " . $overdue_rules->{'categorycode'} . "\n ($mindays, $maxdays, ". $date_to_run->datetime() .")\nreturns " . $sth->rows . " rows";
my $days_between;
if ( C4::Context->preference('OverdueNoticeCalendar') )
{
- my $calendar =
- Koha::Calendar->new( branchcode => $branchcode );
$days_between =
$calendar->days_between( dt_from_string($data->{date_due}),
$date_to_run );
next;
}
$borrowernumber = $data->{'borrowernumber'};
- my $borr =
- $data->{'firstname'} . ', '
- . $data->{'surname'} . ' ('
- . $borrowernumber . ')';
+ my $borr = sprintf( "%s%s%s (%s)",
+ $data->{'surname'} || '',
+ $data->{'firstname'} && $data->{'surname'} ? ', ' : '',
+ $data->{'firstname'} || '',
+ $borrowernumber );
$verbose
and warn "borrower $borr has items triggering level $i.";
+ my $patron = Koha::Patrons->find( $borrowernumber );
@emails_to_use = ();
- my $notice_email =
- C4::Members::GetNoticeEmailAddress($borrowernumber);
+ my $notice_email = $patron->notice_email_address;
unless ($nomail) {
if (@emails) {
foreach (@emails) {
}
}
- my $letter = C4::Letters::getletter( 'circulation', $overdue_rules->{"letter$i"}, $branchcode );
+ my $letter = Koha::Notice::Templates->find_effective_template(
+ {
+ module => 'circulation',
+ code => $overdue_rules->{"letter$i"},
+ branchcode => $branchcode,
+ lang => $patron->lang
+ }
+ );
unless ($letter) {
$verbose and warn qq|Message '$overdue_rules->{"letter$i"}' content not found|;
) unless $test_mode;
$verbose and warn "debarring $borr\n";
}
- my @params = ($borrowernumber);
+ my @params = ($borrowernumber,$branchcode);
$verbose and warn "STH2 PARAMS: borrowernumber = $borrowernumber";
$sth2->execute(@params);
my $exceededPrintNoticesMaxLines = 0;
while ( my $item_info = $sth2->fetchrow_hashref() ) {
if ( C4::Context->preference('OverdueNoticeCalendar') ) {
- my $calendar =
- Koha::Calendar->new( branchcode => $branchcode );
$days_between =
$calendar->days_between(
dt_from_string( $item_info->{date_due} ), $date_to_run );
last;
}
$j++;
- my @item_info = map { $_ =~ /^date|date$/ ?
- eval { output_pref( { dt => dt_from_string( $item_info->{$_} ), dateonly => 1 } ); }
- :
- $item_info->{$_} || '' } @item_content_fields;
- $titles .= join("\t", @item_info) . "\n";
+
+ $titles .= C4::Letters::get_item_content( { item => $item_info, item_content_fields => \@item_content_fields, dateonly => 1 } );
$itemcount++;
push @items, $item_info;
}
# email or sms is requested but not exist, do a print.
$effective_mtt = 'print';
}
+ splice @items, $PrintNoticesMaxLines if $effective_mtt eq 'print' && $PrintNoticesMaxLines && scalar @items > $PrintNoticesMaxLines;
+ #catch the case where we are sending a print to someone with an email
+
+ my $letter_exists = Koha::Notice::Templates->find_effective_template(
+ {
+ module => 'circulation',
+ code => $overdue_rules->{"letter$i"},
+ message_transport_type => $effective_mtt,
+ branchcode => $branchcode,
+ lang => $patron->lang
+ }
+ );
- my $letter_exists = C4::Letters::getletter( 'circulation', $overdue_rules->{"letter$i"}, $branchcode, $effective_mtt ) ? 1 : 0;
my $letter = parse_overdues_letter(
{ letter_code => $overdue_rules->{"letter$i"},
borrowernumber => $borrowernumber,
'count' => $itemcount,
},
# If there is no template defined for the requested letter
- # Fallback on email
- message_transport_type => $letter_exists ? $effective_mtt : 'email',
+ # Fallback on the original type
+ message_transport_type => $letter_exists ? $effective_mtt : $mtt,
}
);
- unless ($letter) {
+ unless ($letter && $letter->{content}) {
$verbose and warn qq|Message '$overdue_rules->{"letter$i"}' content not found|;
# this transport doesn't have a configured notice, so try another
next;
# Generate the content of the csv with headers
my $content;
if ( defined $csvfilename ) {
- my $delimiter = C4::Context->preference('delimiter') || ';';
+ my $delimiter = C4::Context->preference('CSVDelimiter') || ';';
$content = join($delimiter, qw(title name surname address1 address2 zipcode city country email itemcount itemsinfo due_date issue_date)) . "\n";
}
else {
title => 'Overdue Notices',
content => 'These messages were not sent directly to the patrons.',
};
+
C4::Letters::EnqueueLetter(
{ letter => $letter,
borrowernumber => undef,
message_transport_type => 'email',
attachments => [$attachment],
- to_address => $admin_email_address,
+ to_address => $branch_email_address,
}
) unless $test_mode;
}