package Role::Patient;
use Moose::Role;
use Data::Dumper;
# get patient id :
sub get_patient_id {
my $self = shift;
my $vals = shift;
my $dbh = $self->db->{dbix4};
my $log_file = $self->log_file;
my @h4 = qw(last_name first_name middle_name dob);
my @h3 = qw(lname fname mname dob);
# if $vals has an nhs_number:
if ( my $nhs_number = $vals->{nhsno} ) {
# if nhs_number in list of resolved duplicates:
if ( my $new_data = $self->resolved_nhsno_duplicates_map->{$nhs_number} ) {
no warnings 'uninitialized'; # for all print statements:
# return patient_id if already been here:
if (my $patient_id = $self->nhs_number_map->{$nhs_number}) {
my $sql = q!select last_name, first_name, middle_name, dob, gender,
nhs_number from patients where id = ?!;
my $p = $dbh->query($sql, $patient_id)->hash;
if ( (join '', map uc($_), @{$new_data}{@h3}) ne (join '', map uc($_), @{$p}{@h4}) ) {
print $log_file 'have existing resolved nhsno mismatch for ' . $nhs_number . "\n";
print $log_file join ',', map $p->{$_}, @h4; print $log_file "\n";
print $log_file join ',', map $new_data->{$_}, @h3; print $log_file "\n";
}
return $patient_id;
}
elsif ( (join '', map uc($_), @{$new_data}{@h3}) ne (join '', map uc($_), @{$vals}{@h3}) ) {
print $log_file 'have new resolved nhsno mismatch for ' . $nhs_number . "\n";
print $log_file join ',', map $vals->{$_}, @h3; print $log_file "\n";
print $log_file join ',', map $new_data->{$_}, @h3; print $log_file "\n";
}
# set new params:
$vals->{nhsno} = $nhs_number; # not stored as key in map_hashes
while ( my ($param, $val) = each %$new_data ) {
$vals->{$param} = $val;
} # warn Dumper $vals;
}
# first try to update any records with last_name, dob & unit_no match, but
# WITHOUT nhsno (affects <100 of 45K recs):
if ( $vals->{patno} && $vals->{dob} ) {
my $sql = q!select p.id from patients p join patient_case pc on p.id =
pc.patient_id where unit_number = ? and last_name = ? and dob = ?
and nhs_number is null!;
my $patient_id
= $dbh->query( $sql, map $vals->{$_}, qw(patno lname dob) )->list;
# update record (must be only 1) with nhs_number:
if ($patient_id) {
# check nhsno not already used - in which case need to flag for merge:
if ($self->nhs_number_map->{$nhs_number}) {
print $log_file "merge required on $vals->{lname} $vals->{fname}\n";
}
else {
$dbh->update('patients', {nhs_number => $nhs_number}, {id => $patient_id});
print $log_file "updating $patient_id with $nhs_number for $vals->{dbid}\n";
# cache & return it:
$self->nhs_number_map->{$nhs_number} = $patient_id;
}
return $patient_id;
}
}
# update middle name if exists:
if ( my $mname = $vals->{mname} ) { # already checked mname > 1 char
my $sql = q!select p.id from patients p where nhs_number = ? and last_name = ?
and first_name = ? and middle_name is null!;
my $patient_id
= $dbh->query( $sql, map $vals->{$_}, qw(nhsno lname fname) )->list;
if ($patient_id) {
print $log_file "updating $patient_id with $mname for $vals->{dbid}\n";
$dbh->update('patients', {middle_name => $mname}, {id => $patient_id});
}
}
# if not already seen this nhs_no, create new:
if (! $self->nhs_number_map->{$nhs_number}) {
my $patient_id = $self->_create_new_record($vals);
# now cache it:
$self->nhs_number_map->{$nhs_number} = $patient_id;
}
# return patient_id:
return $self->nhs_number_map->{$nhs_number};
}
# else need to find best match or create new record:
else {
my $patient_id = $self->find_or_create_new_patient($vals);
return $patient_id;
}
}
# don't have an nhs_no, so find best match or create new patient & return LAST_INSERT_ID:
sub find_or_create_new_patient {
my $self = shift;
my $vals = shift;
my $dbh = $self->db->{dbix4};
my $log_file = $self->log_file;
my $patient_id = 0;
# ok, no nhs_number, see if we can find exact match on ALL pid params:
if ($vals->{dob} && $vals->{patno}) { # already know we have fname & lname
{ # 1st see if we have a last_name, first_name & unit_no match with null dob:
my $sql = q!select p.id from patients p join patient_case pc on p.id = pc.patient_id
where unit_number = ? and last_name = ? and first_name = ? and dob is null!;
$patient_id = $dbh->query( $sql, map $vals->{$_}, qw(patno lname fname) )->list;
if ($patient_id) { # update dob:
print $log_file "got $patient_id from matching details with null dob for $vals->{dbid}\n";
$dbh->update('patients', { dob => $vals->{dob} }, {id => $patient_id});
return $patient_id;
}
}
my $middle_name =
$vals->{mname} ?
sprintf q!= %s!, $self->_quote_term($vals->{mname})
: 'IS NULL';
my $sql = sprintf q!
SELECT p.id
FROM patients p
join patient_case pc on p.id = pc.patient_id
WHERE
last_name = ? and
first_name = ? and
middle_name %s and
dob = ? and
unit_number = ? and
nhs_number is null!, $middle_name; # warn $pid_sql;
$patient_id
= $dbh->query( $sql, map $vals->{$_}, qw(lname fname dob patno) )->list;
if ($patient_id) {
# print $log_file "got $patient_id from full matching details for $vals->{dbid}\n";
return $patient_id;
}
# next, try to get patient_id from existing combination of last_name,
# dob & unit_no only (ie skip first_name):
{
my $sql = q!
select p.id from patients p join patient_case pc on p.id = pc.patient_id
where unit_number = ? and last_name = ? and dob = ?!;
$patient_id
= $dbh->query( $sql, map $vals->{$_}, qw(patno lname dob) )->list;
if ($patient_id) {
print $log_file "got $patient_id from partial matching details for $vals->{dbid}\n";
return $patient_id;
}
}
}
# some known exceptions before we give up trying to find a match:
if ($vals->{lname} eq 'CYCLACEL') { # cyclacels
$patient_id = $dbh->query( q!select p.id from patients p where last_name =
'cyclacel' and first_name = ? and dob = ?!, $vals->{fname}, $vals->{dob})
->list;
return $patient_id if $patient_id;
}
elsif (grep $vals->{fname} eq $_, qw/LGI PIN/) { # HIV's
$patient_id = $dbh->query( q!select p.id from patients p where last_name = ?
and first_name = ?!, $vals->{lname}, $vals->{fname})->list;
return $patient_id if $patient_id;
}
# exhausted all attempts to match patient, so create new record & retrieve id:
$patient_id = $self->_create_new_record($vals);
# print $log_file "creating new record for $vals->{dbid}\n";
return $patient_id;
}
sub find_or_create_new_patient_case {
my $self = shift;
my $data = shift;
my $dbh = $self->db->{dbix4};
my $case_id;
{
# update any unknown hospital if patient_id & unit_number match:
my $sql = q!SELECT pc.`id` FROM `patient_case` pc join referral_sources rs on
pc.referral_source_id = rs.id WHERE pc.`patient_id` = ? AND
pc.`unit_number` = ? AND rs.`organisation_code` = 'X99999'!; # unknown source
$case_id = $dbh->query( $sql, $data->{patient_id}, $data->{unit_number} )->list;
if ($case_id) {
$dbh->update( 'patient_case', { referral_source_id => $data->{referral_source_id} },
{id => $case_id} );
# print $log_file "updating $case_id with ".$data->{referral_source_id}."\n";
}
return $case_id if $case_id;
}
{
# update any unknown unit_numbers if patient_id & location_id match:
my $sql = q!SELECT `id` FROM `patient_case` WHERE `patient_id` = ? AND
`referral_source_id` = ? AND `unit_number` = 'UNKNOWN'!; # unknown source
$case_id = $dbh->query($sql, $data->{patient_id}, $data->{referral_source_id})->list;
if ($case_id) {
$dbh->update( 'patient_case', { unit_number => $data->{unit_number} },
{id => $case_id} );
# print $log_file "updating $case_id with ".$data->{unit_number}."\n";
}
return $case_id if $case_id;
}
# failed to find matching case_id so create one:
$dbh->insert('patient_case', $data);
$case_id = $dbh->last_insert_id(undef, undef, 'patient_case', 'id');
return $case_id;
}
sub get_case_id {
my $self = shift;
my $data = shift;
my $sql = q!SELECT `id` FROM `patient_case` WHERE `patient_id` = ? AND
`referral_source_id` = ? AND `unit_number` = ?!;
my $case_id = $self->db->{dbix4}->query(
$sql, @{$data}{ qw(patient_id referral_source_id unit_number) }
)->list;
return $case_id;
}
sub _create_new_record {
my $self = shift;
my $vals = shift;
my $dbh = $self->db->{dbix4};
# data for creating new patient (required):
my %data = (
last_name => lc $vals->{lname},
first_name => lc $vals->{fname},
created_at => $vals->{pid_time},
updated_at => $vals->{pid_time}, # or defaults to now()
);
# add data if exists:
$data{middle_name} = lc $vals->{mname} if $vals->{mname};
$data{dob} = $vals->{dob} if $vals->{dob};
$data{gender} = $vals->{sex} if $vals->{sex};
$data{nhs_number} = $vals->{nhsno} if $vals->{nhsno};
$dbh->insert('patients', \%data); # warn Dumper \%data;
my $patient_id = $dbh->last_insert_id(undef, undef, 'patients', 'id');
return $patient_id;
}
sub _quote_term {
my $self = shift;
my $term = shift;
return $self->db->{dbh3}->quote($term);
}
1;