package LIMS::Controller::Roles::PatientDemographics;
use Moose::Role;
use Data::Dumper;
use Sys::SigAction qw( timeout_call ); # for PDS service
use lib '/home/raj/perl-lib'; # PDS classes
# PDS::* classes generated using SOAP::WSDL function:
# wsdl2perl.pl -b lib -p PDS:: file:RenalWebService.wsdl.xml
use PDS::Interfaces::PatientInterface::PatientInterfaceSoap; # SOAP::WSDL classes
sub get_pds_data {
my $self = shift;
my $args = shift; # warn Dumper $args->{patient}->as_tree(deflate => 0);
my $patient = $args->{data}->as_tree(deflate => 0); # warn Dumper $patient;
my $messages = $args->{msgs};
my $config = $args->{config}; # warn $config->{pds_proxy};
my $pds = PDS::Interfaces::PatientInterface::PatientInterfaceSoap->new();
$pds->set_proxy($config->{pds_proxy})if $ENV{DEVEL_SERVER}; # dev server can't find 'regint'
# $pds->outputxml(1);
=begin # alternate method - doesn't work
use SOAP::WSDL::Client;
my $urn = 'urn:Leeds-Renal.service/'
. 'LTH.Renal.BusinessService.RenalWebService.GetPatientDetails';
my %method = (
soap_action => $urn,
operation => 'GetPatientDetails',
style => 'document',
use => 'literal',
);
my @parts = %h; warn Dumper \@parts;
my $soap = SOAP::WSDL::Client->new({ proxy => $config->{pds_proxy} });
my $result2 = $soap->call( \%method, [] ); warn Dumper $result2;
=cut
my $result;
{ # get PDS result inside a Sys::SigAction::timeout_call - normal alarm/eval/die doesn't work with $pds
my $args = $self->_process_patient_details($patient); # warn Dumper $args;
my $sub = sub {
$result = $pds->GetPatientDetails($args);
};
# Sys::SigAction::timeout_call( $duration, sub ):
if ( timeout_call( 10, $sub ) ) { return $messages->{pds_timeout} }
} # warn Dumper $result; # PDS::Elements::GetPatientDetailsResponse object
=begin # normal alarm/eval/die doesn't work
eval { # in case we're in off-line testing mode
local $SIG{ALRM} = sub { die $messages->{pds_timeout} . "\n" }; # NB \n required
# create data structure from $patient to hand to PDS:
my $args = $self->_process_patient_details($patient); # warn Dumper $args;
alarm 10;
# while (1) {} # this triggers timeout, PDS offline doesn't - why ?? does $pds use alarm ??
$result = $pds->GetPatientDetails($args); # warn Dumper $result;
alarm 0; # warn Dumper $result; # PDS::Elements::GetPatientDetailsResponse object
};
return $@ if $@;
# return $result if not $result; # see docs for reasons for stupid syntax
=cut
# parse PDS return:
my $data = $self->_process_pds_response($result); # warn Dumper $data;
return $data || $messages->{pds_no_xml}; # sub returns 0 if no xml passed
}
# create a data structure to hand to the PDS:
sub _process_patient_details {
my ($self, $patient) = @_;
# reformat dob as yyyymmdd if supplied (mandatory field so should be):
if ( $patient->{dob} ) {
my $str = $patient->{dob}->ymd(''); # string, no spaces
$patient->{dob} = $str;
} # warn Dumper $patient;
else { # mandatory field
$patient->{dob} = '19000101';
}
# replace gender with numerical index:
if ( my $gender = $patient->{gender} ) {
my %o = (
U => 0, # PDS = not recorded
M => 1,
F => 2,
);
$patient->{gender} = $o{$gender} || $o{U}; # default unknown
}
my %h = (
Surname => $patient->{last_name},
Forename => $patient->{first_name},
Gender => $patient->{gender},
DOB => $patient->{dob},
# Postcode => $some_value, # string
);
# add NHS number if exists:
$h{NHSNumber} = $patient->{nhs_number} if $patient->{nhs_number};
# add user ID for audit:
$h{VitalDataUserID} = 'HMDS-' . $self->user_profile->{id};
# warn Dumper \%h;
return \%h;
}
sub _process_pds_response {
my ($self, $pds) = @_;
return 0 unless $pds; # PDS::Elements::GetPatientDetailsResponse object
=begin # using as_hash_ref() on $pds object directly now
my @args = (
ForceArray => 0, # force nested elements to be represented as arrays
KeyAttr => '', # don't need it, but required by :strict
SuppressEmpty => undef, # default empty is {}, displayed as HASHREF by tt
);
my $ref = XMLin($pds, @args); warn Dumper $ref; return 1;
my $patient = $ref->{GetPatientDetailsResult}; # warn Dumper $patient; # hashref
=cut
# can call serialize() on $pds to get xml, or as_hash_ref():
my $ref = $pds->as_hash_ref; # warn Dumper $ref;
my $patient = $ref->{GetPatientDetailsResult}; # warn Dumper $patient; # hashref
my $pds_return_codes = $self->get_yaml_file('pds_return_codes'); # warn Dumper $pds_return_codes;
{ # return 'error code' unless SMSP-0000 (success):
my $code = $patient->{ErrorCode};
my $result = $pds_return_codes->{$code};
return $result unless lc $result eq 'success';
}
# reformat DoB (yyyymmdd) as yyyy-mm-dd:
if ( $patient->{DoB} ) {
$patient->{DoB} =~ s/(\d{4})(\d{2})(\d{2})/$1-$2-$3/;
} # warn Dumper $patient;
# decode PDS Gender:
if ( my $gender = $patient->{Gender} ) {
my %o = (
1 => 'M',
2 => 'F',
);
$patient->{Gender} = $o{$gender} || 'U'; # default unknown
}
my %data = (
prefix => $patient->{Prefix},
first_name => $patient->{GivenName1},
last_name => $patient->{FamilyName},
nhs_number => $patient->{NHSNumber},
gender => $patient->{Gender},
dob => $patient->{DoB},
# error_code => $patient->{ErrorCode}, # handled above
post_code => $patient->{HomePostCode},
);
# only include middle name if > 1 char:
$data{middle_name} = $patient->{GivenName2}
if $patient->{GivenName2} && length $patient->{GivenName2} > 1;
# create $data{home_address} attr from HomeAddr1 .. HomeAddr5 components:
if ( grep $patient->{'HomeAddr'.$_}, 1 .. 5 ) {
my $str = join ', ',
map $patient->{'HomeAddr'.$_},
grep $patient->{'HomeAddr'.$_},
(1 .. 5); # empty field is {}, or undef if using SuppressEmpty
$data{home_address} = $str;
}
return \%data;
}
1;