package Test;
use Data::Dumper;
use Moose;
with qw(
Role::User
Role::RebuildTables
);
use namespace::clean -except => 'meta';
has db => (is => 'ro', isa => 'HashRef', required => 1);
has sql => (is => 'ro', isa => 'HashRef', required => 1);
has unknown_referrers => ( is => 'ro', isa => 'HashRef', default => sub { {} } );
# need to force delay until after db passed in from new():
has specimen_map => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has options_map => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has known_referrers => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has diagnosis_map => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has private_referrers => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has known_location_referrers => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
has known_location_screen_referrers => ( is => 'ro', isa => 'HashRef', lazy_build => 1 );
no Moose;
__PACKAGE__->meta->make_immutable;
my $total_unknowns = 0;
=begin
sub run {
my $self = shift; # warn 'HERE'; # appears after _build_specimen_map if lazy_build = 1
my @specimens = qw(BMAT PB LBL PB XB);
my @unique = keys %{
{ map { $_ => 1 } @specimens }
};
my $specimen_map = $self->specimen_map; # print Dumper $specimen_map;
SPECIMEN: foreach my $specimen(@unique) {
if ( my $specimen_id = $specimen_map->{$specimen} ) {
warn "$specimen = $specimen_id";
}
else {
print "no such sample_code: $specimen\n";
next SPECIMEN;
}
}
}
=cut
sub run {
my $self = shift;
my $dbix4 = $self->db->{dbix4};
my $dbix3 = $self->db->{dbix3};
my $REQ = q!
SELECT m.`DBID`, YEAR(m.`Date`) as 'year', m.`HMDS`, p.`LName`, p.`FName`,
p.`DoB`, p.`Sex`, p.`PatNo`, p.`NHSNo`, m.`Source`, m.`Specimen`,
s.`OrgCode`,m.`Clinician`, c.`cons_code`, c.`last_name`,
m.`TimeStamp` as 'main_time', p.`TimeStamp` as 'pid_time',
r.`InitialDiag` as 'screen'
FROM Main m, Report r, Source s, PID p, Clinician c
WHERE cons_code IS NULL
AND m.DBID = r.Rpt_ID
AND m.Source = s.Src_ID
AND m.Pat_ID = p.P_ID
AND m.Clinician = c.c_id
ORDER BY m.DBID!;
my $hilis3 = $dbix3->query($REQ);
while ( my $vals = $hilis3->hash ) {
$self->_get_referrer_code($vals);
}
}
sub test_diagnosis {
my $self = shift;
my $dbix3 = $self->db->{dbix3};
my $dbix4 = $self->db->{dbix4};
my $hilis3_sql = q!select HMDS, year(Date) as 'year', if(FinalDiag is not null,
FinalDiag, if(ReviseDiag is not null, ReviseDiag, Diagnosis)) as 'diagnosis'
from Main, Report where DBID = Rpt_ID!;
my $hilis4_diagnosis_sql = q!select t3.name from requests t1 join request_report
t2 on t2.request_id = t1.id join diagnoses t3 on t2.diagnosis_id = t3.id
where t1.request_number = ? and t1.year = ?!;
my $hilis3 = $dbix3->query($hilis3_sql);
while ( my $vals = $hilis3->hash ) { # warn $diagnosis;
my $hilis3_diagnosis = $vals->{diagnosis};
my $hilis4_diagnosis
= $dbix4->query( $hilis4_diagnosis_sql, $vals->{hmds}, $vals->{year} )->list;
{
no warnings 'uninitialized'; # some records without diagnosis
if ( $hilis3_diagnosis ne $hilis4_diagnosis ) {
warn "$hilis3_diagnosis ne $hilis4_diagnosis for $vals->{hmds} / $vals->{year}";
}
}
}
}
sub phonelog {
my $self = shift;
my $dbix3 = $self->db->{dbix3};
my $dbix4 = $self->db->{dbix4};
my $hilis3 = $dbix3->query(q!select * from PhoneLog!);
my $users_map = $dbix4->query('select username, id from users')->map;
LOG:
while ( my $vals = $hilis3->hash ) { # warn $diagnosis;
my ($hmds, $yr) = $vals->{labno} =~ m!H(\d+)/(\d{2})!;
my $request_id = $dbix4->query( q!select id from requests where request_number
= ? and year = ?!, $hmds, $yr + 2000 )->list;
if (! $request_id ) {
warn "no request_id for $vals->{labno}";
next LOG;
}
my $user_id = $vals->{userid} eq 'ADMIN' ?
# substitute RAJ for ADMIN
$users_map->{raj}
: $users_map->{ lc $vals->{userid} };
if (! $user_id ) {
warn "no user_id for $vals->{userid}";
next LOG;
}
my %data = (
request_id => $request_id,
user_id => $user_id,
status => lc $vals->{direction} . 'bound',
contact => $vals->{contact},
details => $vals->{summary},
time => $vals->{datetime},
);
$dbix4->insert('request_phone_log', \%data);
}
}
sub clinical_trials {
my $self = shift;
my $dbh3 = $self->db->{dbix3};
my $dbh4 = $self->db->{dbix4};
my $hilis3_trials = $dbh3->query('select TrialName, id from Trials')->map;
my $hilis4_trials = $dbh4->query('select trial_name, id from clinical_trials')->map;
{ # 'Community monitoring' changed to 'HMDS outreach'
my $cmp_id = $hilis3_trials->{'Community monitoring'};
delete $hilis3_trials->{'Community monitoring'};
$hilis3_trials->{'HMDS outreach'} = $cmp_id;
}
# map hilis3 Trials.id => hilis4 clinical_trials.id
my %map = map {
my $hilis3_trial_name = $_; # warn $hilis3_trial_name;
my $hilis3_trial_id = $hilis3_trials->{$hilis3_trial_name};
my $hilis4_trial_id = $hilis4_trials->{$hilis3_trial_name};
$hilis3_trial_id => $hilis4_trial_id;
} keys %$hilis3_trials;
# warn Dumper \%map;
my $sql = q!select HMDS, year(Date) as 'year', Study from Main where Study is not null!;
my $hilis3_trial_cases = $dbh3->query( $sql );
while ( my $vals = $hilis3_trial_cases->hash ) {
my $request_id = $dbh4->query( q!select id from requests where request_number
= ? and year = ?!, $vals->{hmds}, $vals->{year})->list;
my $hilis3_trial_id = $vals->{study};
my %data = (
request_id => $request_id,
trial_id => $map{$hilis3_trial_id},
);
$dbh4->insert( 'request_trial', \%data );
}
}
sub request_diagnosis_history {
my $self = shift;
my $dbix3 = $self->db->{dbix3};
my $dbix4 = $self->db->{dbix4};
$self->rebuild_tables(['request_diagnosis_history']);
my $REQ = q!
SELECT
m.`DBID`,
m.`HMDS`,
YEAR(m.`Date`) as 'year',
r.`Diagnosis`,
r.`ReportBy`,
r.`ReportDate`,
r.`ReviseDiag`,
r.`RevisedBy`,
r.`ReviseDate`,
r.`FinalDiag`,
r.`FinalBy`,
r.`FinalDate`
FROM Main m
LEFT JOIN Report r on m.DBID = r.Rpt_ID
WHERE `ReviseDiag` IS NOT NULL OR `FinalDiag` IS NOT NULL
ORDER BY m.DBID!;
my $hilis3 = $dbix3->query($REQ);
while ( my $vals = $hilis3->hash ) {
my $request_id =
$dbix4->query( q!SELECT id FROM requests WHERE request_number = ?
AND year = ?!, $vals->{hmds}, $vals->{year} )->list;
$vals->{_request_id} = $request_id
|| die "Cannot find request_id for $vals->{hmds}, $vals->{year}";
if ( $vals->{finaldiag} ) {
if ($vals->{revisediag}) {
if ( $vals->{revisediag} ne $vals->{diagnosis} ) {
# diagnosis-that-got-changed, who-changed-it, date, reason:
my %data = (
diagnosis => $vals->{diagnosis},
username => $vals->{revisedby},
datetime => $vals->{revisedate},
request_id => $vals->{_request_id},
reason => 'error',
);
$self->_do_diagnosis_history(\%data);
}
if ( $vals->{finaldiag} ne $vals->{revisediag} ) {
# diagnosis-that-got-changed, who-changed-it, date, reason:
my %data = (
diagnosis => $vals->{revisediag},
username => $vals->{finalby},
datetime => $vals->{finaldate},
request_id => $vals->{_request_id},
reason => 'update',
);
$self->_do_diagnosis_history(\%data);
}
}
elsif ( $vals->{finaldiag} ne $vals->{diagnosis} ) {
# diagnosis-that-got-changed, who-changed-it, date, reason:
my %data = (
diagnosis => $vals->{diagnosis},
username => $vals->{finalby},
datetime => $vals->{finaldate},
request_id => $vals->{_request_id},
reason => 'update',
);
$self->_do_diagnosis_history(\%data);
}
}
elsif ( $vals->{revisediag} ) {
if ( $vals->{revisediag} ne $vals->{diagnosis} ) {
# diagnosis-that-got-changed, who-changed-it, date, reason:
my %data = (
diagnosis => $vals->{diagnosis},
username => $vals->{revisedby},
datetime => $vals->{revisedate},
request_id => $vals->{_request_id},
reason => 'error',
);
$self->_do_diagnosis_history(\%data);
}
}
}
$self->do_update_from_history_file;
}
sub _do_diagnosis_history {
my $self = shift;
my $data = shift;
my $dbh = $self->db->{dbix4};
my $diagnosis = $data->{diagnosis}; # original diagnosis
my $signature = $data->{username}; # who changed it
my $date = $data->{datetime} || '0000-00-00'; # early data didn't record date
my $diagnosis_map = $self->diagnosis_map;
my $user_id = $self->_get_user_id_from_sig($signature)
|| die "Cannot find users.id for $signature";
my $diagnosis_id = $diagnosis_map->{$diagnosis}
|| die "Cannot find diagnosis_id for $diagnosis";
my %data = (
request_id => $data->{request_id},
diagnosis_id => $diagnosis_id,
user_id => $user_id,
reason => $data->{reason},
time => join ' ', $date, '00:00:00',
);
$dbh->insert('request_diagnosis_history', \%data);
}
sub additional_options {
my $self = shift;
my $dbh3 = $self->db->{dbix3};
my $dbh4 = $self->db->{dbix4};
# urgent, private, copy_to, doi, teaching:
my $options = $self->options_map;
my $sql = q!select HMDS, year(Date) as 'year', Urgent, DoI, Teaching, Private,
CopyTo from Main!;
my $src = $dbh3->query( $sql );
while ( my $vals = $src->hash ) {
next unless grep $vals->{$_}, qw(urgent private teaching copyto doi);
my $request_id = $dbh4->query( q!select id from requests where request_number
= ? and year = ?!, $vals->{hmds}, $vals->{year})->list;
foreach my $opt( keys %$options ) {
next unless $vals->{$opt};
my %data = (
request_id => $request_id,
option_id => $options->{$opt},
);
$dbh4->insert('request_option', \%data);
}
}
}
sub block_ref {
my $self = shift;
my $dbh3 = $self->db->{dbix3};
my $dbh4 = $self->db->{dbix4};
$self->clear_table('request_external_ref');
my $sql = q!select HMDS, year(Date) as 'year', BlockRef from Main where
BlockRef is not null!;
my $src = $dbh3->query( $sql );
while ( my $vals = $src->hash ) {
my $request_id = $dbh4->query( q!select id from requests where request_number
= ? and year = ?!, $vals->{hmds}, $vals->{year})->list;
my ($ref, $status) = $vals->{blockref} =~ /(.*)\[(.*)\]\Z/; # foo [bar]
if ($ref) { $ref =~ s/\s+$// }; # remove trailing space(s)
# set external ref to $ref if exists, or $block_ref:
my $external_ref = $status ? $ref : $vals->{blockref};
my %data = (
request_id => $request_id,
external_reference => $external_ref,
);
if ($status) { $data{status} = $status }
$dbh4->insert('request_external_ref', \%data);
}
}
sub general_notes {
my $self = shift;
my $dbh3 = $self->db->{dbix3};
my $dbh4 = $self->db->{dbix4};
my $sql = q!select HMDS, year(Date) as 'year', Notes from Main join Others
on O_ID = DBID where length(Notes) > 1!; # exclude crap
my $src = $dbh3->query( $sql );
while ( my $vals = $src->hash ) {
my $request_id = $dbh4->query( q!select id from requests where request_number
= ? and year = ?!, $vals->{hmds}, $vals->{year})->list;
my %data = (
request_id => $request_id,
detail => $vals->{notes},
);
$dbh4->insert('request_general_notes', \%data);
}
}
sub do_update_from_history_file {
my $self = shift;
my $dbix3 = $self->db->{dbix3};
my $dbix4 = $self->db->{dbix4};
my $REQ = q!
SELECT
request_id,
action,
user_id,
time
FROM request_history
WHERE action regexp 'FinalDiag|ReviseDiag'
ORDER BY time!;
my $query = $dbix4->query($REQ);
while ( my $vals = $query->hash ) {
# both if's in case both entered together:
if ($vals->{action} =~ /ReviseDiag/) {
$dbix4->update('request_diagnosis_history',
{ time => $vals->{time} }, # set
{ # where:
request_id => $vals->{request_id},
user_id => $vals->{user_id},
reason => 'error',
}
);
}
if ($vals->{action} =~ /FinalDiag/) {
$dbix4->update('request_diagnosis_history',
{ time => $vals->{time} }, # set
{ # where:
request_id => $vals->{request_id},
user_id => $vals->{user_id},
reason => 'update',
}
);
}
}
}
sub resolved_nhsno {
my $self = shift;
my $dbh4 = $self->db->{dbix4};
my $dbh3 = $self->db->{dbix3};
{ # split mname from fname:
my $sql = q!SELECT fname, nhsno FROM test.ResolvedNHSNo where fname like '% %'!;
for my $row ( $dbh4->query($sql)->hashes ) {
my ($fname, $mname) = split ' ', $row->{fname};
$dbh4->update(
'test.ResolvedNHSNo',
{ fname => $fname, mname => $mname },
{ nhsno => $row->{nhsno} },
);
}
}
{ # update timestamp:
my @list = $dbh4->query('SELECT nhsno FROM test.ResolvedNHSNo')->flat;
foreach my $nhsno (@list) { # 1st one will do if >1:
$dbh3->query('SELECT TimeStamp FROM PID WHERE NHSNo = ?', $nhsno)->into(my $time);
$dbh4->update(
'test.ResolvedNHSNo',
{ pid_time => $time },
{ nhsno => $nhsno },
);
}
}
}
sub _build_specimen_map { # warn 'HERE'; # to check it only loads once
my $self = shift;
my $dbh = $self->db->{dbix4};
my $specimen_map = $dbh->query('SELECT sample_code, id FROM specimens')->map;
# ->map_hashes('sample_code');
return $specimen_map;
}
sub _build_options_map {
my $self = shift;
my $dbh4 = $self->db->{dbix4};
my $options = $dbh4->query( 'select option_name, id from additional_options')->map;
{ # 'CopyTo' => 'copy_to'
my $cc_id = $options->{copy_to};
delete $options->{copy_to};
$options->{copyto} = $cc_id;
}
return $options;
}
sub _build_diagnosis_map {
my $self = shift;
my $dbh = $self->db->{dbix4};
my $map = $dbh->query( 'select name, id from diagnoses ')->map;
return $map;
}
sub _get_referrer_code {
my $self = shift;
my $vals = shift;
my $dbh = $self->db->{dbix4};
my $clinician_code = $vals->{clinician};
my $clinician_name = $vals->{last_name};
if ( my ($g_id) = $clinician_code =~ /\A(G\d+)/ ) {
return $self->gp_practice->{$g_id}->{gp_code} || 'G9999998';
}
# Clinician = 'General Practitioner' & Source = 'Surgery/Medical Centre':
elsif ( $clinician_code == 25 && $vals->{source} == 78 ) { #
return 'G9999998';
}
# Clinician = 'Not stated/known' or 'Unknown':
elsif ( grep $clinician_code == $_, (62, 643) ) { #
return 'C9999998';
}
# known referrers list:
elsif ( $self->known_referrers->{$clinician_name} ) { # warn 'known referrer';
return $self->known_referrers->{$clinician_name}{ref_code};
}
if ( $vals->{orgcode} ) { # null if Source = 54, 57, 78
my ($org_code) = $vals->{orgcode} =~ /\A(...)/; # just need 1st 3 chars
{ # known private referrers:
my $referrers = $self->private_referrers;
if ( $referrers->{$clinician_name} ) { # warn 'private referrer';
return $referrers->{$clinician_name}{ref_code}
if $org_code =~ /$referrers->{$clinician_name}{org_code}/;
}
}
{ # known location referrers:
my $referrers = $self->known_location_referrers;
if ( $referrers->{$clinician_name} ) { # warn 'known location referrer';
return $referrers->{$clinician_name}{ref_code}
if $org_code eq $referrers->{$clinician_name}{org_code};
}
}
{ # known location & initialdiag/screen referrers:
my $referrers = $self->known_location_screen_referrers;
if ( $referrers->{$clinician_name} ) { # warn 'known location screen referrer';
return $referrers->{$clinician_name}{ref_code}
if $org_code eq $referrers->{$clinician_name}{org_code}
&& $vals->{screen} eq $referrers->{$clinician_name}{screen};
}
}
{ # if clinician name unique to location:
my $sql = q!select national_code from clinicians c join clinician_organisation
co on (co.clinician_id = c.id) where `surname` = ? and `region_prefix` = ?
having count(*) = 1!;
if ( my $referrer_code =
$dbh->query($sql, $vals->{last_name}, $org_code)->list ) {
# add it to $self->known_location_referrers: ? IS THIS SAFE - NO!!!!!
# overwrites existing Clinician entries:
# $self->known_location_referrers->{$clinician_name} =
# { org_code => $org_code, ref_code => $referrer_code };
return $referrer_code if $referrer_code;
}
}
}
# warn Dumper [ $vals->{dbid}, $clinician_name, $vals->{orgcode} || 'NULL ORG_CODE' ];
$self->unknown_referrers->{$clinician_name}{ $vals->{orgcode} || 'UNKNOWN' }++;
$total_unknowns++;
# can't match it so return unknown:
return 'C9999998';
}
sub _build_known_referrers {
my $self = shift;
# names that occur only once in clinicians
# (gets incremented in _get_referrer_code):
my %referrers = (
Parapia => { ref_code => 'C1741582' },
McVerry => { ref_code => 'C1356458' },
Hillmen => { ref_code => 'C3084182' },
Moreton => { ref_code => 'C4043672' },
);
return \%referrers;
}
sub _build_private_referrers {
my $self = shift;
my %referrers = (
Williams => { org_code => 'NT[38]', ref_code => 'C3198942' },
Child => { org_code => 'NT[23]', ref_code => 'C0139522' },
Owen => { org_code => 'NT2', ref_code => 'C3271078' },
Batman => { org_code => 'NT8', ref_code => 'C2469160' },
Tijani => { org_code => 'NT8', ref_code => 'C4785635' },
Morgan => { org_code => 'NT2', ref_code => 'C2718723' },
Horgan => { org_code => 'NT3', ref_code => 'C2918341' },
Gouldesbrough
=> { org_code => 'NT8', ref_code => 'C2604231' },
);
return \%referrers;
}
sub _build_known_location_referrers {
my $self = shift;
=begin
HILIS3:
SELECT * FROM Main,Source,Clinician
WHERE OrgCode like 'RR8%' AND
last_name like 'clarke%' AND
Src_ID = Source AND
Clinician = c_id
HILIS4:
select national_code, initials, display_name
from clinicians c
join clinician_organisation co on (co.clinician_id = c.id)
join hospital_departments h on (co.hospital_department_id = h.id)
where `surname` = 'thomas' and `region_prefix` = 'rwy'
# having count(*) = 1
=cut
my %referrers = (
Child => { org_code => 'RR8', ref_code => 'C0139522' },
Smith => { org_code => 'RR8', ref_code => 'C2653558' },
Johnson => { org_code => 'RR8', ref_code => 'C3244348' },
Morgan => { org_code => 'RR8', ref_code => 'C2718723' },
Knight => { org_code => 'RR8', ref_code => 'C3079991' },
Newton => { org_code => 'RAE', ref_code => 'C3555307' },
Calvert => { org_code => 'RAE', ref_code => 'C3313507' },
Elliott => { org_code => 'RAE', ref_code => 'C3468531' },
Patmore => { org_code => 'RWA', ref_code => 'C3309946' }, # Patmore, RD
Williams => { org_code => 'RWD', ref_code => 'C3198942' },
Carter => { org_code => 'RWY', ref_code => 'C2378716' },
Thomas => { org_code => 'RWY', ref_code => 'C1624801' },
McEvoy => { org_code => 'RCD', ref_code => 'C2394967' }, # Bynoe
Lee => { org_code => 'RXF', ref_code => 'C4202019' }, # Lee, RA
Braithwaite
=> { org_code => 'RWY', ref_code => 'C2308535' },
# 2 Macdonalds at Mid-Yorks - Histopathology & Dermatology (Macdonald Hull)
# Macdonald => { org_code => 'RXF', ref_code => 'C1552852' }, # MacDonald Hull
);
return \%referrers;
}
sub _build_known_location_screen_referrers {
my $self = shift;
my %referrers = (
Wilson => { org_code => 'RR8', ref_code => 'C2645429', screen => 'HIV' },
Clarke => { org_code => 'RR8', ref_code => 'C2718156', screen => 'HIV' },
);
return \%referrers;
}
1;