RSS Git Download  Clone
Raw Blame History
#!/usr/bin/env perl

=begin -------------------------------------------------------------------------
transfers xls file of requests for any auth'd within past 24hrs to
ftp.tdlpathology.com, using Net::SFTP::Foreign
sets uclh database manually, no need for command-line arg
=cut ---------------------------------------------------------------------------

use Getopt::Std;
getopts('d:tq'); # days, testing, query output
our($opt_d,$opt_t,$opt_q); # warn $opt_t; exit;

use strict;
use warnings;
use feature 'say';

my $JUST_TESTING = $opt_t || 0; # dumps xls file in /tmp only

#==============================================================================
my $duration = $opt_d || 1; # days; for DATE(time_col) >= ( now minus 2 days )
#==============================================================================

use lib '/home/raj/perl5/lib/perl5';
use IO::All;
use Try::Tiny;
use Text::CSV;
use File::Temp;
use Data::Printer;
use Net::SFTP::Foreign;
use SQL::Abstract::More;

use FindBin qw($Bin); # warn $Bin;
use lib $Bin . '/../../../lib';
use LIMS::Local::ScriptHelpers;
use Spreadsheet::WriteExcel::Simple;

# get tools from LIMS::Local::ScriptHelpers:
my $tools = LIMS::Local::ScriptHelpers->new();
$tools->test_only($JUST_TESTING);
my $today = $tools->time_now;

my $cfg_file = "$Bin/../lib/settings.cfg";
my $settings = Config::Auto::parse($cfg_file); # p $settings;

my $cfg = $settings->{uclh_tdl_server}; # p $cfg;

#-------------------------------------------------------------------------------
my $ref_date = $today->clone->subtract( days => $duration ); # warn $ref_date;
my $sftphost = $cfg->{remote_address} or die 'remote_address cfg value missing';
my $username = $cfg->{username}       or die 'username cfg value missing';
my $password = $cfg->{password}       or die 'password cfg value missing';
my $remote_path = $cfg->{remote_path} or die 'remote_path cfg value missing';
my $remote_file = 'hsl_hmds_data.xls';
#-------------------------------------------------------------------------------

my $config = $tools->config();
my $dbix   = $tools->dbix();
$dbix->lc_columns = 0; # preserve MixedCase

$dbix->dbh->do('USE uclh');

my ($sql, @bind) = _get_query(); # p $sql; p @bind;
my $query = $dbix->query( $sql, @bind );

my @cols  = $query->columns; # p @cols;
my @data  = $query->arrays;  # p @data;
exit unless @data;

# open my $fh, '>:encoding(utf8)', my \$data or die "IO: $!";
my $fh = File::Temp->new(); # create new fh to tmpfile in /tmp dir
my $xl = Spreadsheet::WriteExcel::Simple->new;

my $local_file = $fh->filename;
$local_file .= '.xls' if $JUST_TESTING; # warn $local_file; # won't auto-delete

$xl->write_bold_row(\@cols);
$xl->write_row($_) for @data;
$xl->save($local_file);

if ($JUST_TESTING) {
    say 'data saved to ' . $local_file;
	exit;
}

{ # sftp file:
    my %args = ( user => $username, password => $password );

	my $sftp = Net::SFTP::Foreign->new($sftphost, %args);
	$sftp->die_on_error('unable to establish SFTP connection');

	# need to manually set remote path:
	$sftp->setcwd($remote_path) or
        msg_and_exit('unable to set cwd: ' . $sftp->error);

	# need to set copy_perm false or get error "put failed: Couldn't setstat
	# remote file: SSH_FILEXFER_ATTR_PERMISSIONS":
    $sftp->put($local_file, $remote_file, copy_perm => 0) or
		msg_and_exit('put failed: ' . $sftp->error);

    # probably caught any error aleady, but just in case:
    if ( my $err = $sftp->error ) {
        msg_and_exit($err);
    }
    else {
		my $script = $tools->script_filename;
        my $date   = $ref_date->dmy; # for cron log
        say "$script reports UCLH data for $date successfully transferred";
    }
}

sub msg_and_exit {
    my $msg = shift;

	my $script = $tools->script_filename;
	say "$script - $msg"; # dump to logs
    $tools->mail_admin({ script => $script, msg => $msg });
	exit;
}

sub _get_query {
    my @cols = (
        'pc.unit_number|PatientNumber',
        q{CONCAT_WS(' ', p.first_name, p.last_name)|PatientName},
        'p.gender|Sex',
        'p.dob|DoB',
        q{DATE_FORMAT(r.created_at,'%Y') - DATE_FORMAT(p.dob,'%Y')
            - (DATE_FORMAT(r.created_at,'00-%m-%d')
                < DATE_FORMAT(p.dob,'00-%m-%d')) AS Age},
        q{MAX(CASE WHEN ao.option_name = 'private'
            THEN 'Private' ELSE 'NHS' END) AS Category},
        'p.nhs_number|NHSNo',
        'pn.detail|PatientNotes',
        'NULL|RefOrdNo',                # referred from another location
        'NULL|ReferringLabNo',          # referred from another location
        'NULL|ReferringClinician',      # referred from another location
        'rs.organisation_code|SourceCode',
        'rs.display_name|SourceName',
        'NULL|SourceClass',
        'ref.national_code|ClinicianCode',
        'ref.name|ClinicianName',
        'DATE(rsd.specimen_date)|SampleDate',
        'TIME(rsd.specimen_date)|SampleTime',
		# assuming received date/time same as registration date/time
        q{MAX(CASE WHEN rh.action = 'registered'
            THEN DATE(rh.time) END) AS ReceivedDate},
        q{MAX(CASE WHEN rh.action = 'registered'
            THEN TIME(rh.time) END) AS ReceivedTime},
        q{MAX(CASE WHEN rh.action = 'registered'
            THEN DATE(rh.time) END) AS BookedDate},
        q{MAX(CASE WHEN rh.action = 'registered'
            THEN TIME(rh.time) END) AS BookedTime},
        q{MAX(CASE WHEN rh.action = 'registered'
            THEN CONCAT_WS(' ', u.first_name, u.last_name) END) AS BookedUser},
        q{MAX(CASE WHEN ao.option_name = 'urgent'
            THEN 'yes' ELSE 'no' END) AS Urgent},
        's.sample_code|SampleType',
        's.description|SampleDesc',
        q{CONCAT('U', r.request_number, '/', r.year - 2000)|LabNo},
        q{IF(lt.test_type = 'panel', lt.field_label, NULL) AS TLC},
        q{IF(lt.test_type = 'test',  lt.field_label, NULL) AS TFC},
        'NULL|Result',          # no results available
        'NULL|ResultDate',      # no results available
        'NULL|ResultTime',      # no results available
		q{MAX(CASE WHEN rh.action = 'authorised'
            THEN DATE(rh.time) END) AS AuthDate},
		q{MAX(CASE WHEN rh.action = 'authorised'
            THEN TIME(rh.time) END) AS AuthTime},
        'NULL|Units',
        'NULL|RangeLo',
        'NULL|RangeHi',
    );
    my @rels = (                              'requests|r'                  ,
        q{r.patient_case_id=pc.id}         => 'patient_case|pc'             ,
        q{pc.patient_id=p.id}              => 'patients|p'                  ,
        q{pc.referral_source_id=rs.id}     => 'referral_sources|rs'         ,
        q{rsv.request_id=r.id}			   => 'request_status_view|rsv'     ,
        q{r.referrer_department_id=rd.id}  => 'referrer_department|rd'      ,
		q{rd.referrer_id=ref.id}		   => 'referrers|ref'               ,
		q{rsd.request_id=r.id}             => 'request_specimen_detail|rsd' ,
        q{rsp.request_id=r.id}             => 'request_specimen|rsp'        ,
        q{rsp.specimen_id=s.id}            => 'specimens|s'                 ,
        q{rh.request_id=r.id}              => 'request_history|rh'          ,
        q{rh.user_id=u.id}                 => 'users|u'                     ,
      # left joins:
        q{=>ts.request_id=r.id}            => 'request_lab_test_status|ts'  ,
        q{=>ts.lab_test_id=lt.id}          => 'lab_tests|lt'                ,
        q{=>ro.request_id=r.id}            => 'request_option|ro'           ,
        q{=>ro.option_id=ao.id}            => 'additional_options|ao'       ,
        q{=>pn.patient_id=p.id}            => 'patient_notes|pn'            ,
    );
    my %where = (
        'DATE(rsv.time)' => $ref_date->ymd,
        'rsv.action'     => 'authorised',
    );
    my @args = (
		-columns  => \@cols,
		-from     => [ -join => @rels ],
		-where    => \%where,
        -group_by => ['lt.id','r.id'],
        -order_by => 'r.id',
    ); # p @args;
    my ($sql, @bind) = SQL::Abstract::More->new->select(@args); # p $sql; p \@bind;
         $dbix->dump_query($sql, @bind) if $opt_q; # exit;
    return ($sql, @bind);
}