From eeb5e0c27f730ea839604f637843d4328616385c Mon Sep 17 00:00:00 2001 From: Zeno Tajoli Date: Sun, 12 Jul 2015 13:01:54 +0200 Subject: [PATCH] [BUG 14519] Send courtesy notices when sys pref EnhancedMessagingPreferences is OFF To test creation on a new message: -- Insert a new loan with due date tomorrow -- Go to misc/cronjobs/ and on command line do: ./courtesy_notices.pl --day=1 -c -- Go to MySQL and see new lines in table message_queue --- misc/cronjobs/courtesy_notices.pl | 422 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 misc/cronjobs/courtesy_notices.pl diff --git a/misc/cronjobs/courtesy_notices.pl b/misc/cronjobs/courtesy_notices.pl new file mode 100644 index 0000000..94048e7 --- /dev/null +++ b/misc/cronjobs/courtesy_notices.pl @@ -0,0 +1,422 @@ +#!/usr/bin/perl + +# Copyright 2008 LibLime +# Copyright 2015 CINECA +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +=head1 NAME + +courtesy_notices.pl - cron script to put reminders about due date of loans into message queue + +=head1 SYNOPSIS + +./courtesy_notices.pl -c + +or, in crontab: +0 1 * * * courtesy_notices.pl -c + +=head1 DESCRIPTION + +This script prepares pre-due digest reminders to be sent to +patrons. It queues them in the message queue, which is processed by +the process_message_queue.pl cronjob. You can configure the script about: +-- Days before due date (default 7) +-- Limit notices about specific libraris (default all) +-- Name of the letter (default 'PREDUEDGST') +-- Fields to describe loans (default due date,title,author,barcode) + +To be used with EnhancedMessagingPreferences = 'OFF' + +=cut + +use strict; +use warnings; +use Getopt::Long; +use Pod::Usage; +use Data::Dumper; +BEGIN { + # find Koha's Perl modules + # test carefully before changing this + use FindBin; + eval { require "$FindBin::Bin/../kohalib.pl" }; +} +use C4::Biblio; +use C4::Context; +use C4::Letters; +use C4::Members; +use C4::Members::Messaging; +use C4::Overdues; +use Koha::DateUtils; + +=head1 NAME + +courtesy_notices.pl - prepare messages to be sent to patrons for nearly due items + +=head1 SYNOPSIS + +courtesy_notices.pl + [ -n ][ --days ][ --itemscontent ] + [ --libs ][ --notice ][ -c ] + +=head1 OPTIONS + +=over 8 + +=item B<--help> + +Print a brief help message and exits. + +=item B<--man> + +Prints the manual page and exits. + +=item B<-v> + +Verbose. Without this flag set, only fatal errors are reported. + +=item B<-n> + +Do not send any email. Courtesy notices that would have been sent to +the patrons are printed to standard out. + +=item B<--days> + +Defines exact day befoure due date to send courtesy notices. +Default value is 7. + +=item B<--itemscontent> + +Comma separated list of fields that get substituted into templates in +places of the EEitems.contentEE placeholder. This +defaults to due date,title,author,barcode + +Other possible values come from fields in the biblios, items and +issues tables. + +=item B<--libs> + +Comma separated list of libraries's codes. If used, only issues connect with listed +libraries create courtesy notices. If not used, the deafaul is that issues of all libraries +create courtesy notices + +=item B<--notice> + +The code of notice template used. The template need to be a digest. +Default value 'PREDUEDGST' + +=item B<-c> +Confirm the setup. Without this flag the script does nothing and show the help + +=back + +=head1 DESCRIPTION + +This script is designed to alert patrons about coming due + +=head2 Configuration + +This script is to be used when EnhancedMessagingPreferences = 'OFF' and you want to +create courtesy notices with a setup at library level. +You can use the scripts options to setup it. + +=head2 Outgoing emails + +Messages are prepared for each patron with due items a specific day before due date. + +These emails are staged in the outgoing message queue, as are messages +produced by other features of Koha. This message queue must be +processed regularly by the +F program. + +In the event that the C<-n> flag is passed to this program, no emails +are sent. Instead, messages are sent on standard output from this +program. They may be redirected to a file if desired. + +=head2 Templates + +Templates can contain variables enclosed in double angle brackets like +EEthisEE. Those variables will be replaced with values +specific to the overdue items or relevant patron. Available variables +are: + +=over + +=item EEitems.contentEE + +one line for each item, each line containing a tab separated list of +title, author, barcode, issuedate + +=item EEborrowers.*EE + +any field from the borrowers table + +=item EEbranches.*EE + +any field from the branches table + +=back + +=head1 SEE ALSO + +The F program allows you to send +messages to patrons when their messages are overdue. +=cut + +# These are defaults for command line options. +my $confirm; # -c: Confirm that the user has read and configured this script. +my $nomail; # -n: No mail. Will not send any emails. +my $day_all_pre = 7; # --days: When to send (days befoure). +my $verbose = 0; # -v: Verbose. +my $notice_format = 'PREDUEDGST'; # --notice: The code of the notice. +my $libraries; # --libs: Codes of libraries to select issues. +my $itemscontent = join(',',qw( date_due title author barcode )); +my $help = 0; +my $man = 0; + +my $send_all_pre = 'Y'; +my $send_all_format = 'digest'; + +GetOptions( + 'help|?' => \$help, + 'man' => \$man, + 'c' => \$confirm, + 'n' => \$nomail, + 'days:i' => \$day_all_pre, + 'v' => \$verbose, + 'itemscontent=s' => \$itemscontent, + 'libs=s' => \$libraries, + 'notice=s' => \$notice_format, + )or pod2usage(2); +pod2usage(1) if $help; +pod2usage( -verbose => 2 ) if $man;; + +#Stop if EnhancedMessagingPreferences is ON +if ( C4::Context->preference('EnhancedMessagingPreferences') ) { + warn <<'END_WARN'; + +The "EnhancedMessagingPreferences" syspref is ON. +This script is developed to be use when "EnhancedMessagingPreferences" syspref is OFF. +The script stop here. It do nothing. + +END_WARN +} +unless ($confirm) { + pod2usage(1); +} + +#Check on apostrophe in libs +if ($libraries =~ m/'/){ + warn <<'END_WARN'; +Not supported apostrophe on librabry codes. +Script stopped. +END_WARN + exit; +} +#Setup the string to use in the 'IN' clause of MySQL +if ($libraries) { + $libraries = "'$libraries'"; + $libraries=~ s/,/','/g; +} + + + +# The fields that will be substituted into <> +my @item_content_fields = split(/,/,$itemscontent); +my $upcoming_dues =''; +warn 'getting upcoming due issues' if $verbose; + +if ($send_all_pre eq 'Y') { + $upcoming_dues = SpecificDayComingDueIssues( { days_in_advance => $day_all_pre, libs =>$libraries } ); +}else{ + warn <<'END_WARN'; +Config not supported +END_WARN + exit; +} + +warn 'found ' . scalar( @$upcoming_dues ) . ' issues' if $verbose; + +# Force digest and letter format +my $upcoming_digest; +my $due_digest; + +my $admin_adress = C4::Context->preference('KohaAdminEmailAddress'); + +my $borrower_preferences = {}; +$borrower_preferences->{'transports'} = {'email' => $notice_format}; +$borrower_preferences->{'wants_digest'} = 'Y'; + +foreach my $upcoming ( @$upcoming_dues ) { + my $from_address = $upcoming->{branchemail} || $admin_adress; + + my $digest = $upcoming_digest->{$upcoming->{'borrowernumber'}} ||= {}; + $digest->{email} ||= $from_address; + $digest->{count}++; +} + + +# Now, run through all the people, forcing digest and send them +my $dbh = C4::Context->dbh(); + +my $sel_issues = ''; +if ($libraries) { $sel_issues ='AND issues.branchcode IN ('.$libraries.')'}; + +my $sth = $dbh->prepare( qq{ +SELECT biblio.*, items.*, issues.* + FROM issues,items,biblio + WHERE items.itemnumber=issues.itemnumber + AND biblio.biblionumber=items.biblionumber + AND issues.borrowernumber = ? + $sel_issues + AND (TO_DAYS(date_due)-TO_DAYS(NOW()) = ?) +}); + +PATRON: while ( my ( $borrowernumber, $digest ) = each %$upcoming_digest ) { + my $count = $digest->{count}; + my $from_address = $digest->{email}; + my $letter_type = $notice_format; + + $sth->execute($borrowernumber,$day_all_pre); + my $titles = ""; + while ( my $item_info = $sth->fetchrow_hashref()) { + my @item_info = map { $_ =~ /^date|date$/ ? format_date($item_info->{$_}) : $item_info->{$_} || '' } @item_content_fields; + $titles .= join("\t",@item_info) . "\n"; + } + + ## Get branch info for borrowers home library. + my %branch_info = get_branch_info( $borrowernumber ); + + my $letter = parse_letter( { letter_code => $letter_type, + borrowernumber => $borrowernumber, + substitute => { count => $count, + 'items.content' => $titles, + %branch_info, + } + } ) + or die "no letter of type '$letter_type' found. Please see sample_notices.sql"; + if ($nomail) { + local $, = "\f"; + print $letter->{'content'}; + } + else { + foreach my $transport ( keys %{$borrower_preferences->{'transports'}} ) { + C4::Letters::EnqueueLetter( { letter => $letter, + borrowernumber => $borrowernumber, + from_address => $from_address, + message_transport_type => $transport } ); + } + } +} + + +=head1 METHODS + +=head2 parse_letter + +=cut + +sub parse_letter { + my $params = shift; + foreach my $required ( qw( letter_code borrowernumber ) ) { + return unless exists $params->{$required}; + } + + my %table_params = ( 'borrowers' => $params->{'borrowernumber'} ); + + if ( my $p = $params->{'branchcode'} ) { + $table_params{'branches'} = $p; + } + if ( my $p = $params->{'itemnumber'} ) { + $table_params{'issues'} = $p; + $table_params{'items'} = $p; + } + if ( my $p = $params->{'biblionumber'} ) { + $table_params{'biblio'} = $p; + $table_params{'biblioitems'} = $p; + } + + return C4::Letters::GetPreparedLetter ( + module => 'circulation', + letter_code => $params->{'letter_code'}, + branchcode => $table_params{'branches'}, + substitute => $params->{'substitute'}, + tables => \%table_params, + ); +} + +sub format_date { + my $date_string = shift; + my $dt=dt_from_string($date_string); + return output_pref($dt); +} + +=head2 get_branch_info + +=cut + +sub get_branch_info { + my ( $borrowernumber ) = @_; + + ## Get branch info for borrowers home library. + my $borrower_details = C4::Members::GetMember( borrowernumber => $borrowernumber ); + my $borrower_branchcode = $borrower_details->{'branchcode'}; + my $branch = C4::Branch::GetBranchDetail( $borrower_branchcode ); + my %branch_info; + foreach my $key( keys %$branch ) { + $branch_info{"branches.$key"} = $branch->{$key}; + } + + return %branch_info; +} + + +sub SpecificDayComingDueIssues { + my $params = shift; + my $sel_issues = 'returndate is NULL'; + + $params->{'days_in_advance'} = 7 unless exists $params->{'days_in_advance'}; + if ($params->{'libs'}) { + $sel_issues ='returndate is NULL and issues.branchcode IN ('.$params->{'libs'}.') '; + }else{ + $sel_issues = 'returndate is NULL'; + } + + my $dbh = C4::Context->dbh; + + my $statement = <<"END_SQL"; +SELECT issues.*, items.itype as itemtype, items.homebranch, TO_DAYS( date_due )-TO_DAYS( NOW() ) as days_until_due, branches.branchemail +FROM issues +LEFT JOIN items USING (itemnumber) +LEFT OUTER JOIN branches USING (branchcode) +WHERE $sel_issues +HAVING days_until_due > 0 AND days_until_due = ? +END_SQL + + my @bind_parameters = ( $params->{'days_in_advance'} ); + + my $sth = $dbh->prepare( $statement ); + $sth->execute( @bind_parameters ); + my $day_upcoming_dues = $sth->fetchall_arrayref({}); + $sth->finish; + + return $day_upcoming_dues; +} + + +1; + +__END__ -- 1.9.1