From 0bbebced9dd463444cb1d91a60bcf4323e5a721e Mon Sep 17 00:00:00 2001 From: Nick Clemens Date: Mon, 17 Apr 2017 11:20:25 -0400 Subject: [PATCH] Bug 16149: Generate and send custom notices based on report output Ths patch add an EmailReport function to C4::Reports::Guided It accepts a notice (module, code, branch) and a report and attempts to email notices to patron, generating content using report content. Notice must be in template toolkit syntax, only columns in report are available for notice. To test: 1 - Specify various options 2 - Ensure errors are returned if options are incomplete or incorrect 3 - Pass a report containing 'from' and 'email' and 'borrowernumber' columns and ensure message queue populated as expected Signed-off-by: Jessica Ofsa Signed-off-by: Tomas Cohen Arazi Signed-off-by: Nick Clemens --- C4/Reports/Guided.pm | 97 ++++++++++++++++++ misc/cronjobs/patron_emailer.pl | 175 ++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100755 misc/cronjobs/patron_emailer.pl diff --git a/C4/Reports/Guided.pm b/C4/Reports/Guided.pm index c4d783f011..eff3a7c9e6 100644 --- a/C4/Reports/Guided.pm +++ b/C4/Reports/Guided.pm @@ -27,9 +27,13 @@ use C4::Context; use C4::Templates qw/themelanguage/; use C4::Koha; use Koha::DateUtils; +use Koha::Patrons; +use Koha::Reports; use C4::Output; use C4::Debug; use C4::Log; +use Koha::Notice::Templates; +use C4::Letters; use Koha::AuthorisedValues; use Koha::Patron::Categories; @@ -929,6 +933,99 @@ sub ValidateSQLParameters { return \@problematic_parameters; } +=head2 EmailReport + + my ( $emails, $arrayrefs ) = EmailReport($report_id, $letter_code, $module, $branch, $email) + +Take a report and use it to process a Template Toolkit formatted notice +Returns arrayrefs containing prepared letters and errors respectively + +=cut + +sub EmailReport { + + my $params = shift; + my $report_id = $params->{report_id}; + my $from = $params->{from}; + my $email = $params->{email}; + my $module = $params->{module}; + my $code = $params->{code}; + my $branch = $params->{branch} || ""; + + my @errors = (); + my @emails = (); + + return ( undef, [{ FATAL => "MISSING_PARAMS" }] ) unless ($report_id && $module && $code); + + return ( undef, [{ FATAL => "NO_LETTER" }] ) unless + my $letter = Koha::Notice::Templates->find({ + module => $module, + code => $code, + branchcode => $branch, + message_transport_type => 'email', + }); + $letter = $letter->unblessed; + + my $report = Koha::Reports->find( $report_id ); + my $sql = $report->savedsql; + return ( { FATAL => "NO_REPORT" } ) unless $sql; + + my ( $sth, $errors ) = execute_query( $sql ); #don't pass offset or limit, hardcoded limit of 999,999 will be used + return ( undef, [{ FATAL => "REPORT_FAIL" }] ) if $errors; + + my $counter = 1; + my $template = $letter->{content}; + + while ( my $row = $sth->fetchrow_hashref() ) { + my $email; + my $err_count = scalar @errors; + push ( @errors, { NO_BOR_COL => $counter } ) unless defined $row->{borrowernumber}; + push ( @errors, { NO_EMAIL_COL => $counter } ) unless ( (defined $email && defined $row->{$email}) || defined $row->{email} ); + push ( @errors, { NO_FROM_COL => $counter } ) unless defined ( $from || $row->{from} ); + push ( @errors, { NO_BOR => $row->{borrowernumber} } ) unless Koha::Patrons->find({borrowernumber=>$row->{borrowernumber}}); + + my $from_address = $from || $row->{from}; + my $to_address = $email ? $row->{$email} : $row->{email}; + push ( @errors, { NOT_PARSE => $counter } ) unless my $content = _process_row_TT( $row, $template ); + $counter++; + next if scalar @errors > $err_count; #If any problems, try next + + $letter->{content} = $content; + $email->{borrowernumber} = $row->{borrowernumber}; + $email->{letter} = $letter; + $email->{from_address} = $from_address; + $email->{to_address} = $to_address; + + push ( @emails, $email ); + } + + return ( \@emails, \@errors ); + +} + + + +=head2 ProcessRowTT + + my $content = ProcessRowTT($row_hashref, $template); + +Accepts a hashref containing values and processes them against Template Toolkit +to produce content + +=cut + +sub _process_row_TT { + + my ($row, $template) = @_; + + return 0 unless ($row && $template); + my $content; + my $processor = Template->new(); + $processor->process( \$template, $row, \$content); + return $content; + +} + sub _get_display_value { my ( $original_value, $column ) = @_; if ( $column eq 'periodicity' ) { diff --git a/misc/cronjobs/patron_emailer.pl b/misc/cronjobs/patron_emailer.pl new file mode 100755 index 0000000000..dbdf2a5096 --- /dev/null +++ b/misc/cronjobs/patron_emailer.pl @@ -0,0 +1,175 @@ +#!/usr/bin/perl + +# +# 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 . + +use Modern::Perl; + +BEGIN { + # find Koha's Perl modules + # test carefully before changing this + use FindBin; + eval { require "$FindBin::Bin/../kohalib.pl" }; +} + +use Getopt::Long; +use Pod::Usage; + +use C4::Log; +use C4::Reports::Guided; + +cronlogaction(); + +=head1 NAME + +patron_emailer.pl + +=head1 SYNOPSIS + +patron_emailer.pl + [--report ][--notice][--module] --library --from + + Options: + --help brief help + --report report ID to use as data for email template + --notice specific notice code to use + --module which module to find the above notice in + --library specified branch for selecting notice, will use all libraries by default + --from specified email for 'from' address, report column 'from' used if not specified + --email specified column to use as 'to' email address, report column 'email' used if not specified + --verbose increased verbosity, will print notices and errors + --commit send emails, without this script will only report + +head1 OPTIONS + +=over 8 + +=item B<-help> + +Print brief help and exit. + +=item B<-man> + +Print full documentation and exit. + +=item B<-report> + +Specify a saved SQL report id in the Koha system to user for the emails. All, and only, + columns in the report will be available for notice template variables + +=item B<-notice> + +Specific notice (CODE) to select + +=item B<-module> + +Which module to find the specified notice in + +=item B<-library> + +Option to specify which branches notice should be used, 'All libraries' is used if not specified + +=item B<-from> + +Specify the sender address of the email, if not specified a 'from' column in the report will be used. + +=item B<-email> + +Specify the column to find recipient address of the email, if not specified an 'email' column in the report will be used. + +=item B<-verbose> + +Increased verbosity, reports successes and errors. + +=item B<-commit> + +Send emails, if omitted script will report as verbose. + +=back + +=cut + +my $help = 0; +my $report_id; +my $notice; +my $module; #this is only for selecting correct notice - report itself defines available columns, not module +my $library; #as above, determines which notice to use, will use 'all libraries' if not specified +my $email; #to specify which column should be used as email in report will use 'email' from borrwers table +my $from; #to specify from address, will expect 'from' column in report if not specified +my $verbose = 0; +my $commit = 0; + +my $error_msgs = { + MISSING_PARAMS => "You must supply a report ID, letter module and code at minimum\n", + NO_LETTER => "The specified letter was not found, please check your input\n", + NO_REPORT => "The specified report was not found, please check your input\n", + REPORT_FAIL => "There was an error running the report, please check your SQL\n", + NO_BOR_COL => "There was no borrowernumber found for row ", + NO_EMAIL_COL => "There was no email found for row ", + NO_FROM_COL => "No from email was specified for row ", + NO_BOR => "There is no borrower with borrowernumber " +}; + +GetOptions( + 'help|?' => \$help, + 'report=i' => \$report_id, + 'notice=s' => \$notice, + 'module=s' => \$module, + 'library=s' => \$library, + 'email=s' => \$email, + 'from=s' => \$from, + 'verbose' => \$verbose, + 'commit' => \$commit +) or pod2usage(1); +pod2usage(1) if $help; +pod2usage(1) unless $report_id && $notice && $module; + +my ( $emails, $errors ) = C4::Reports::Guided::EmailReport({ + email => $email, + from => $from, + report_id => $report_id, + module => $module, + code => $notice, + branch => $library, + verbose => $verbose, + commit => $commit, +}); + +foreach my $email (@$emails){ + print "No emails will be sent!\n" unless $commit; + if( $verbose || !$commit ){ + print "Email generated to $email->{to_address} from $email->{from_address}\n"; + print "Content:\n"; + print $email->{letter}->{content} ."\n"; + } + C4::Letters::EnqueueLetter({ + letter => $email->{letter}, + borrowernumber => $email->{borrowernumber}, + message_transport_type => 'email', + from_address => $email->{from_address}, + to_address => $email->{to_address}, + }) if $commit; +} + +if( $verbose || !$commit ){ + foreach my $error ( @$errors ){ + foreach ( keys %{$error} ){ + print "$_\n"; + if ( $_ eq 'FATAL' ) { print $error_msgs->{ ${$error}{$_} } } + else { print $error_msgs->{$_} . ${$error}{$_} . "\n" } + } + } +} -- 2.39.5