#!/usr/bin/perl
=begin -------------------------------------------------------------------------
generates NYCRIS data feed for new and revised diagnoses during previous 1 month
creates pipe-delimited rows, one row per request
=cut ---------------------------------------------------------------------------
use strict;
use warnings;
my $JUST_TESTING = 1; # skips ftp, puts data files in /tmp, emails just raj
BEGIN {
use FindBin qw($Bin); # warn $Bin; exit;
use lib "$Bin/../../../lib";
}
use IO::All;
use Config::Auto;
use Data::Dumper;
use DateTime::Format::MySQL;
use LIMS::Local::ScriptHelpers;
use Text::Wrap qw($columns fill); $columns = 68;
#################################
my $delimiter = '|'; #
my $duration = 2; # months ago #
#################################
my $cfg_file = "$Bin/../lib/settings.cfg";
my $settings = Config::Auto::parse($cfg_file); # warn Dumper $settings;
# get tools from LIMS::Local::ScriptHelpers:
my $tools = LIMS::Local::ScriptHelpers->new();
my $sql_lib = $tools->sql_lib();
my $config = $tools->config();
my $dbix = $tools->dbix();
my $today = $tools->time_now();
my $data_filename = sprintf 'hmds_%s', $today->ymd('_');
my @data = ();
# go:
{
# get request ID's for horizontal & vertical tables:
my $request_ids = get_request_ids(); # warn Dumper $request_ids;
# get data maps of vertical tables - much faster than tying into main query:
my $data_map = get_data_map($request_ids); # warn Dumper $data_map;
# get request result 1-to-1 data:
my $query = $sql_lib->retr('nycris_data');
my $result = $dbix->query($query, @$request_ids);
while ( my $vars = $result->hash ) { # warn Dumper $vars; next;
my $row = parse_data($vars, $data_map); # combine horizontal & vertical tbls
push @data, $row; # warn $row;
} # warn Dumper \@data;
}
{ # create file & FTP:
my $file_path = '/tmp/' . $data_filename;
my $contents = join "\n", @data;
$contents > io($file_path); # warn $contents;
# ftp file:
unless ($JUST_TESTING) {
my %args = (
local_filename => $file_path,
remote_filename => $data_filename,
);
ftp_file(\%args);
}
}
# archive results file:
unless ($JUST_TESTING) {}
# combine horizontal & vertical tables:
sub parse_data {
my ($vars, $data_map) = @_;
{ # add data-map fields:
my $request_id = $vars->{request_id};
# specimen code(s):
$vars->{specimen_code}
= $data_map->{specimen}->{$request_id}->{specimen_code};
# result summaries:
map $vars->{$_} = $data_map->{result_summary}->{$request_id}->{$_},
qw(immunocytochemistry flow_cytometry fish cytogenetics molecular);
# reporter:
map $vars->{$_} = $data_map->{reporter_data}->{$request_id}->{$_},
qw(reporter_name reporter_code);
}
# tidy up (trim content & substitute new-line markers):
map { $vars->{$_} = tidy($vars->{$_}) }
grep $vars->{$_},
qw(comment immunocytochemistry flow_cytometry fish cytogenetics
gross_description molecular);
$vars->{gender} ||= 'U';
my @fields = qw(
request_id
labno
request_date
last_name
first_name
middle_name
unit_number
dob
nhs_number
gender
referrer
referrer_code
location
organisation_code
specimen_code
clinical_details
gross_description
specimen_quality
comment
diagnosis
icdo3
flow_cytometry
immunohistochemistry
molecular
cytogenetics
fish
reporter_name
reporter_code
authorisation_date
);
no warnings 'uninitialized'; # lots in $vars
my $row = join $delimiter, map $vars->{$_}, @fields;
# row needs to start with request ID - in case unescaped new-line marker present
die unless $row =~ /\A\d{6,}/;
return $row;
}
sub get_request_ids {
my @request_ids = ();
{ # new diagnoses:
my $sql = $sql_lib->retr('nycris_new_diagnosis_request_ids');
my $request_ids = $dbix->query($sql, $duration, $duration)->flat;
push @request_ids, @$request_ids; # warn Dumper $request_ids;
}
{ # get revised diagnoses:
my $sql = $sql_lib->retr('nycris_revised_diagnosis_request_ids');
my $request_ids = $dbix->query($sql, $duration, $duration)->flat;
push @request_ids, @$request_ids; # warn Dumper $request_ids;
}
# combine & eliminate duplicates
my %request_ids = map { $_ => 1 } @request_ids; # warn Dumper \%request_ids;
return [ keys %request_ids ];
}
sub ftp_file { return 0;
my $args = shift;
my $cfg = $settings->{nycris_server};
my %params = (
local_filename => $args->{local_filename},
remote_filename => $args->{remote_filename},
server_addr => $cfg->{remote_address},
username => $cfg->{username},
password => $cfg->{password},
);
# ftp file (returns str on failure, undef on success):
my $rtn = $tools->ftp_file(\%params);
if ($rtn) {
$tools->mail_admin({ script => $0, msg => $rtn });
warn "$0 - $rtn\n"; # dump to logs but don't die!!
}
else {
io($args->{local_filename})->unlink;
}
}
sub user_codes {
my $username = shift;
my $national_codes = {
swirsky => 'C2202309',
burton => 'C4370806',
tooze => 'C3664265',
cargo => 'C6050871',
jack => 'C2547174',
owen => 'C3271078',
richards => 'CS01892',
rawstron => 'CS01874',
oconnor => 'CS01696',
evans => 'CS09254',
};
return $national_codes->{$username}
|| 'H9999998'; # OTHER HEALTH CARE PROFESSIONAL
}
sub get_data_map {
my $request_ids = shift;
my $map = {};
{ # request_specimens:
my $sql = q!select `request_id`,
group_concat(`description` separator '/') as 'description',
group_concat(`sample_code`) as 'code' from `request_specimen` rs
join `specimens` s on rs.`specimen_id` = s.`id`
where rs.`request_id` in (??) group by `request_id`!;
my $result = $dbix->query($sql, @$request_ids);
while ( my $vars = $result->hash ) { # warn Dumper $vars;
my $request_id = $vars->{request_id};
my %data = (
specimen_code => $vars->{code},
description => $vars->{description},
);
$map->{specimen}->{$request_id} = \%data;
} # warn Dumper $map->{specimen};
}
{ # reporter data:
my $sql = q!select rh.request_id, u.username, u.first_name, u.last_name
from request_history rh join users u on ( rh.user_id = u.id and
action = 'reported' ) where request_id in (??)!;
my $result = $dbix->query($sql, @$request_ids);
while ( my $vars = $result->hash ) { # warn Dumper $vars;
my $request_id = $vars->{request_id};
my $reporter = join ' ',
ucfirst $vars->{first_name},
ucfirst $vars->{last_name};
my $reporter_code = user_codes($vars->{username});
my %data = (
reporter_name => $reporter,
reporter_code => $reporter_code,
);
$map->{reporter_data}->{$request_id} = \%data;
} # warn Dumper $map->{reporter_data};
}
{ # result_summaries:
my $sql = q!select rs.`request_id`, rs.`results_summary`, ls.`section_name`
from `request_result_summaries` rs join `lab_sections` ls on
rs.`lab_section_id` = ls.`id` where rs.`request_id` in (??)!;
my $result = $dbix->query($sql, @$request_ids);
while ( my $vars = $result->hash ) { # warn Dumper $vars;
my $request_id = $vars->{request_id};
my $section = $vars->{section_name};
my $result = $vars->{results_summary};
$section =~ s/ /_/g;
$map->{result_summary}->{$request_id}->{lc $section} = $result;
} # warn Dumper $map->{result_summary};
}
return $map;
}
sub tidy {
my $str = shift;
# trim:
$str =~ s/\A\s+//; # leading
$str =~ s/\s+\Z//; # trailing
$str =~ s/(\r\n)/[NEW_LINE]/g; # substitute new-line marker
return $str;
}
=begin
# format text: indent, replace blanks with N/A, max 68 chars / line:
sub format_text {
my $str = shift || ''; # needs to exist or uninitialized warnings below
# put '07|' after of new-line markers:
my $formatted_newline = $settings->{new_line};
$str =~ s/^(\s+|\t)//; # remove leading spaces or tabs
$str =~ s/\|//g; # remove pipes if used!!
$str ||= 'N/A'; # only applies to @formatted_fields, others already grepped
my $wrapped_text = fill($settings->{indent}, $settings->{indent}, $str); # Text::Wrap function
# new 07| in front of newly-wrapped lines:
$wrapped_text =~ s/\n/$formatted_newline/g; # print $wrapped_text;
return $wrapped_text;
}
sub specimen_summary {
local $_ = shift; # specimen string
my @title;
push @title, 'peripheral blood' if /PB|CMP/; # CMP excluded
push @title, 'chimerism' if /CHI/; # currently excluding chimerism screen
push @title, 'bone marrow aspirate' if /BMA$|BMA\,/; # BMA[^T] doesn't work
push @title, 'bone marrow biopsy' if /BMAT|T[B|S][L|P]/;
push @title, 'tissue biopsy' if /[DGLRX][BL|F|SL|U|A]/;
push @title, 'effusion' if /EF/;
push @title, 'CSF' if /CF/;
push @title, 'slide' if /HS/;
push @title, 'serum' if /SE/;
push @title, 'urine' if /URI/;
# my $title = @title > 1 ? join (' & ' => join (', ' => @title[ 0 .. @title - 2 ]), $title[-1]) : $title[0];
my $title = join '/', @title; # print Dumper ($title, length $title) if length $title > 40;
$title ||= $_; # so var not empty if specimen doesn't match in regex's
return ( length $title < 41 )
? $title
: 'multiple blood/marrow/tissue specimens';
}
=cut