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 <jofsa@vt.edu>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
Nick Clemens 2017-04-17 11:20:25 -04:00
parent f751423d15
commit 0bbebced9d
2 changed files with 272 additions and 0 deletions

View File

@ -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' ) {

175
misc/cronjobs/patron_emailer.pl Executable file
View File

@ -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 <http://www.gnu.org/licenses>.
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" }
}
}
}