#!/usr/bin/env perl =begin ------------------------------------------------------------------------- function to email reports to: 1) location options: * specific hospital department (eg Pinderfields/Haem) * specific organisation department (eg Leeds/Haem) * a hospital (all departments) * an organisation (all departments) 2) request status options: * new * all only using basic DBIx::Simple methods (hashes) so son't need Local::DB how to deal with reports where a departmental contact exists, and a hospital/organisation contact (do they also get the dept report?), and also a CWT contact (usually needs all 'new' reports) * can manually run script using --re-run flag to dispatch any unsent reports on same day: CENTRE=xxxx perl email_reports.pl --re-run >> ~/crons/cron.log 2>&1 -------------------------------------------------------------------------------- =cut BEGIN { use lib '/home/raj/perl5/lib/perl5'; # *must* come before FindBin($Bin) use FindBin qw($Bin); # warn $Bin; exit; use lib ("$Bin/../../../lib", '/home/raj/perl-lib'); # override default db test: $ENV{ROSEDB_DEVINIT} = "$Bin/../../../config/rosedb_devinit_prod.pl"; } my($opt_d,$opt_t,$rerun); use Getopt::Long; GetOptions ( "days|d=s" => \$opt_d, # string "testing|t" => \$opt_t, # flag "re-run" => \$rerun, # flag ); # warn $opt_d; warn $opt_t; warn $rerun; exit; # emails only 'service_email' addr in config, dumps history data to lims_test db: my $JUST_TESTING = $opt_t || 0; my $delta = $opt_d || 1; # warn $delta; # days ago (1 for production) use IO::All; use File::Slurp; use Config::Auto; use Modern::Perl; use Data::Printer; use SQL::Abstract::More; use DateTime::Format::MySQL; use LIMS::Local::Reports; use LIMS::Local::ScriptHelpers; my $cfg_file = "$Bin/../lib/settings.cfg"; my $settings = Config::Auto::parse($cfg_file); # p $settings; # get tools from LIMS::Local::ScriptHelpers: my $tools = LIMS::Local::ScriptHelpers->new(); $tools->test_only($JUST_TESTING); my $sql_lib = $tools->sql_lib(); my $config = $tools->config(); my $today = $tools->time_now(); my $dbix = $tools->dbix; my $sqla = SQL::Abstract::More->new; my $date = $tools->date_subtract( days => $delta )->ymd; # warn $date; # substitutes LIMS methods required by Role::RecordHandler: my $lims = LIMS::Local::Reports->new({tools => $tools}); # localhost http address - for charts; is_print_request for tt formatting: $lims->tt_params( app_url => 'http://localhost/hilis4', is_print_request => 1, # otherwise it loads guest view template by default ); # load exemptions: my $skip_reports = $tools->get_yaml_file('skip_email_reports') || {}; # hashref or 0 #=============================================================================== # get all requests authorised/modified yesterday as AoH: # [request_id, status, referral_source_id, parent_organisation_id & department_id] my @requests = do { my @cols = qw( r.id rr.status rs.id|referral_source_id|ref_src_id hd.id|department_code rs.parent_organisation_id|parent_id ); my @rels = ( 'requests|r' => 'ris.request_id=r.id' , 'request_initial_screen|ris' => 'ris.screen_id=s.id' , 'screens|s' => 'r.patient_case_id=pc.id' , 'patient_case|pc' => 'pc.referral_source_id=rs.id' , 'referral_sources|rs' => 'r.referrer_department_id=rd.id' , 'referrer_department|rd' => 'rd.hospital_department_code=hd.id' , 'hospital_departments|hd' => 'rr.request_id=r.id' , 'request_report_view|rr' => 'r.status_option_id=so.id' , 'status_options|so' => '=>rt.request_id=r.id' , 'request_trial|rt' => '=>rt.trial_id=ct.id' , 'clinical_trials|ct' ); my @status = ( 'complete' ); push @status, $tools->does_authorisation ? 'authorised' : 'reported'; my %where = ( 'DATE(rr.updated_at)' => $date, 'so.description' => { -in => \@status }, ); # skip screened_as/presentation: if ( my $presentation = $skip_reports->{presentation} ) { # aref $where{'s.description'} = { -not_in => $presentation }; } # skip clinical trials: if ( my $trials = $skip_reports->{clinical_trial} ) { # aref $where{'ct.trial_name'} = # needs an undef or lose all non-ct entries [ -or => { -not_in => $trials }, undef ]; } my @args = ( -columns => \@cols, -from => [ -join => @rels ], -where => \%where, ); my ($sql, @bind) = $sqla->select(@args); # p $sql; # p \@bind; # $dbix->dump_query($sql, @bind); exit; $dbix->query($sql, @bind)->hashes; # AoH }; # p \@requests; #=============================================================================== # get list of report email contact details as AoH: my @contacts = do { my @cols = qw( ec.display_name ec.referral_source_id|source_id rs.parent_organisation_id|parent_id ec.scope ec.department_id ec.contact_address ec.status ); my @rels = ( 'email_contacts|ec' => 'ec.referral_source_id=rs.id', 'referral_sources|rs' ); my @args = ( -columns => \@cols, -from => [ -join => @rels ], -where => { 'ec.type' => 'report', 'ec.is_active' => 'yes' }, ); # p @args; my ($sql, @bind) = $sqla->select(@args); # p $sql; # p \@bind; # $dbix->dump_query($sql, @bind); exit; $dbix->query($sql, @bind)->hashes; # AoH }; # p \@contacts; my %reports; # hash of contact addresses => [ request.ids ] my @request_cols = qw( id status ref_src_id department_code parent_id ); my @contact_cols = qw( scope contact_address parent_id department_id source_id status ); # for each contact address, assign any matching request ids from $requests # involves looping through each request for each contact (but very fast): for my $contact (@contacts) { my ($scope, $email, $parent_id, $department_id, $location_id, $want_status) = @{$contact}{@contact_cols}; REQ: for my $req (@requests) { my ($req_id, $req_status, $req_refsrc_id, $req_department_code, $req_parent_id) = @{$req}{@request_cols}; # first deal with request status (requires new diagnoses or not): if ( $want_status eq 'new' ) { next REQ unless $req_status eq 'new'; } # next deal with contacts for specific departments: if ( $department_id ) { # 823, 824, etc next REQ unless $req_department_code == $department_id; } # contact 'scope' is either hospital or organisation: if ( $scope eq 'hospital' ) { next REQ unless $req_refsrc_id == $location_id; } else { # scope = 'organisation' next REQ unless $req_parent_id == $parent_id; } if ($rerun) { # manual command using --re-run flag # has report already been sent today? my $dispatched = $dbix->select('request_dispatch_log', 1, { 'DATE(time)' => $today->ymd, request_id => $req_id, recipient => $email, })->list; next REQ if $dispatched; } # now have required combination of hospital/organisation + optional dept: # my $label = join '::', $email, $contact->{display_name}; # for debug use only # push @{ $reports{$label} }, $req_id; push @{ $reports{$email} }, $req_id; } } # p \%reports; exit; =begin #======================================================================== # for testing using known requests: %reports = ( 'hmds.lth@nhs.net' => [ # 307257 # NEQAS request - anonymised patient # 308979 # PenENRICH trial - unknown referrer # 309256 # Imatinib chart 308502 # Outreach ]); #=============================================================================== =cut # common vars for email message: my %mail = ( config => $config ); # now get pdf's as in-memory object for each contact - may involve compiling # some reports more than once but alternative is save to disk and clean up after while ( my ($email, $ref) = each %reports ) { # aref of request_id's REQ: for my $req_id (@$ref) { my $pdf = $lims->format_report($req_id); # L::C::Roles::RecordHandler # $pdf > io("$Bin/$req_id.pdf"); warn 'for test only'; next REQ; $mail{attachment} = $pdf; # retrieve request data object stashed in Recordhandler::_format_report(): my $data = $lims->stash->{request_data}; { # add subject line: my $referrer_department = $data->referrer_department; my $subject = sprintf 'HMDS Report for %s / %s', $referrer_department->hospital_department->display_name, # speciality $referrer_department->referrer->name; # referrer # doesn't work properly if unknown clinician - uses referrer_department.id 31116: if ( $subject =~ /Unknown clinician/ ) { # "Unknown/Other / Unknown clinician" $subject = 'HMDS Report [referrer unknown]' } $mail{subject} = $subject; } { # add filename: my $filename = sprintf '%02d_%05d.pdf', $data->year - 2000, $data->request_number; $mail{filename} = $filename; } # p \%mail; # send report to recipient: $mail{recipient} = $email; # p \%mail; dispatch_report({ request_id => $req_id, message => \%mail }); } } sub dispatch_report { my $args = shift; my $request_id = $args->{request_id}; my $message = $args->{message}; # substitute recipient address here if $JUST_TESTING (L::L::Mail doesn't any more): if ($JUST_TESTING) { my $safe_address = $config->{service_email}; die "unsafe recipient address $safe_address" unless $safe_address =~ /\@nhs.net\Z/; $message->{recipient} = $safe_address; } my $result = LIMS::Model::Email->send_message($message); # Return::Value my $centre = $ENV{CENTRE} || 'leeds'; if ( $result->type eq 'success' ) { my $recipient = $message->{recipient}; my $filename = $message->{filename}; my $str = $result->string; # rs = 'message sent'; can't substitute direct on rs, so: $str =~ s/message/$filename [$centre]/i; # str = eg '12_01234.pdf [uclh] sent' printf "%s %s to %s\n", $tools->script_filename, $str, $recipient; my %data = ( request_id => $request_id, recipient => $recipient, ); # log details in request_dispatch_log & request_history tables: unless ($JUST_TESTING) { my $rtn = $lims->model('Request')->update_request_dispatch_log(\%data); warn "Error in $0: $rtn" if $rtn; } else { # manual input into lims_test db: $dbix->insert('lims_test.request_dispatch_log', \%data); my $service_user = $tools->get_server_user_details(); $data{user_id} = $service_user->{id}; $data{action} = 'dispatched report to ' . $recipient; delete $data{recipient}; $dbix->insert('lims_test.request_history', \%data); } } else { warn $result->string; $tools->mail_admin({ script => $0, msg => $result->string }); } }