package LIMS::Model::Roles::ScreenUpdate;
use Moose::Role;
has status_option_new => (
is => 'ro',
isa => 'LIMS::DB::LabTestStatusOption',
lazy_build => 1,
);
=begin - for _have_required_sample_type_for_lab_test() - replaced with LIMS::DB queries
has $_ => ( is => 'ro', isa => 'HashRef', lazy_build => 1 )
for qw(
specimen_sample_type_map
section_sample_type_map
lab_test_section_map
);
=cut
has skipped_lab_tests => (
is => 'ro',
isa => 'ArrayRef[Int]',
default => sub { [] },
lazy => 1,
traits => ['Array'],
handles => {
add_to_skipped_lab_tests => 'push',
},
);
has added_lab_tests => (
is => 'ro',
isa => 'ArrayRef[Int]',
default => sub { [] },
lazy => 1,
traits => ['Array'],
handles => {
add_to_added_lab_tests => 'push',
},
);
use Data::Dumper;
#-------------------------------------------------------------------------------
# creates new lab_tests according to ScreenLabTest data for this screen_id
# doesn't overwrite existing tests
sub do_lab_tests {
my $self = shift;
my $data = shift;
my %args = (
query => [ screen_id => $data->{screen_id} ],
);
my $lab_tests
= LIMS::DB::ScreenLabTest::Manager->get_screen_lab_tests(%args);
foreach my $t (@$lab_tests) { # warn Dumper $t;
$data->{lab_test_id} = $t->lab_test_id;
$self->do_new_lab_test($data);
}
}
#-------------------------------------------------------------------------------
sub do_new_lab_test { # shared by M::Request::new_request()
my $self = shift;
my $data = shift; # requires lab_test_id && user_id
# if sample type checking is active, check we have valid specimen for lab test:
if ( $self->lims_cfg->{settings}->{lab_section_sample_type} ) {
return 0 unless $self->_have_required_sample_type_for_lab_test($data);
}
my $status_option = $self->status_option_new;
LIMS::DB::RequestLabTestStatus->new(
status_option_id => $status_option->id,
lab_test_id => $data->{lab_test_id},
request_id => $data->{_request_id},
user_id => $self->user_profile->{id},
)->load_or_insert; # in case test already requested manually
$self->add_to_added_lab_tests($data->{lab_test_id});
}
#-------------------------------------------------------------------------------
sub do_lab_test_details {
my $self = shift;
my $data = shift;
# if sample type checking is active, check we have valid specimen for lab test:
if ( $self->lims_cfg->{settings}->{lab_section_sample_type} ) {
return 0 unless $self->_have_required_sample_type_for_lab_test($data);
}
my %args = (
query => [ screen_id => $data->{screen_id} ],
);
my $lab_test_details
= LIMS::DB::ScreenLabTestDetail::Manager->get_screen_lab_test_details(%args);
foreach my $detail (@$lab_test_details) { # should only be 0 or 1:
LIMS::DB::RequestLabSectionNote->new(
details => $detail->test_details,
request_id => $data->{_request_id},
lab_section_id => $detail->lab_section_id,
)->load_or_insert; # in case test_detail already exists
}
}
#-------------------------------------------------------------------------------
sub do_auto_screen {
my $self = shift;
# get hashref or required data (keys = lab_tests, presentation & trial_name):
my $auto_screen_data = $self->_get_auto_screen_data();
return 0 unless %$auto_screen_data; # warn Dumper $auto_screen_data;
my $data = $self->form_data; # warn Dumper $data;
my $request_id = $data->{_request_id};
my $user_id = $self->user_profile->{id};
# first save presentation info:
if ( my $presentation = $auto_screen_data->{presentation} ) {
my $screen_id
= LIMS::DB::Screen->new( description => $presentation)->load->id;
my %data = (
request_id => $request_id,
screen_id => $screen_id,
);
LIMS::DB::RequestInitialScreen->new(%data)->save;
}
# if trial name required:
if ( my $trial_name = $auto_screen_data->{trial_name} ) {
my $trial_id
= LIMS::DB::ClinicalTrial->new( trial_name => $trial_name)->load->id;
my %data = (
request_id => $request_id,
trial_id => $trial_id,
);
LIMS::DB::RequestTrial->new(%data)->load_or_insert; # in case already set in form
}
# if lab tests generated:
if ( my $lab_tests = $auto_screen_data->{lab_tests} ) {
while ( my($lab_test_id, $test_name) = each %$lab_tests ) {
my %data = (
_request_id => $request_id,
lab_test_id => $lab_test_id,
);
$self->do_new_lab_test(\%data);
}
}
$self->add_to_actions('screened');
}
#-------------------------------------------------------------------------------
sub additional_options {
my ($self, $action) = @_; # warn Dumper $action;
my $data = $self->form_data; # warn Dumper $data;
my $cfg = $data->{additional_options_config}->{$action} || return 0;
# get 'screened_as' description:
my $presentation = LIMS::DB::Screen->new(id => $data->{screen_id})->load;
my $screened_as = $presentation->description; # warn $screened_as;
# cycle through options to see if screened_as term triggers option flag:
while ( my($option, $d) = each %$cfg ) { # warn Dumper [$option, $d];
# check option (eg DoI) exists and is active:
my $o = LIMS::DB::AdditionalOption->new(option_name => $option)
->load(speculative => 1); # warn Dumper $o->as_tree;
return 0 unless $o && $o->is_active eq 'yes';
# set option flag if screened_as term matches one of list:
if ( grep lc($screened_as) eq lc($_), @$d ) {
my %data = (
request_id => $data->{_request_id},
option_id => $o->id,
); # warn Dumper \%data;
LIMS::DB::RequestOption->new(%data)->load_or_insert;
}
}
}
#-------------------------------------------------------------------------------
sub _get_auto_screen_data {
my $self = shift;
my $form_data = $self->form_data; # warn Dumper $form_data;
my $cfg = $form_data->{auto_screen_config}; # warn Dumper $cfg;
my $request_id = $form_data->{_request_id};
# get full request data (request, patient_case & patient tables) as a flat
# data stucture, in case we need to find any mandatory field (eg nhs_number):
my $request_data = do {
my $r = LIMS::DB::Request->new(id => $request_id)
->load(with => 'patient_case.patient')->as_tree;
LIMS::Local::Utils::traverse_hash($r); # uses Data::Traverse to flatten $r
}; # warn Dumper $request_data;
my %data = ();
RULE: while ( my ($rule, $d) = each %$cfg ) {
# check any mandatory request/patient fields (eg nhs_number):
if ( my $required_fields = $d->{required_fields} ) {
for my $field(@$required_fields) { # warn $field;
# try to find required value in submitted form data, or else in
# request/patient_case/patient data fields:
next RULE unless $form_data->{$field} || $request_data->{$field};
}
}
my $match_criteria = $d->{match_criteria}; # HoH
# $match_criteria has 1 or more hashref entries:
while ( my ($field, $value) = each %$match_criteria ) {
# a match on specimen takes priority - may also generate trial name:
if ( $field eq 'specimen_type' ) {
# check specimen type(s) match:
my $required_specimen_types = $value; # always arrayref
for my $specimen(@$required_specimen_types) { # warn $specimen;
# may need to split specimens and test as array (eg BMA vs BMAT)
next RULE unless $form_data->{specimen} =~ /$specimen/i;
}
}
elsif ( $field eq 'trial_name' ) {
# get trial id from form, or skip rule:
my $trial_id = $form_data->{trial_id} || next RULE;
my $trial # get trials.trial_name for trial id:
= LIMS::DB::ClinicalTrial->new(id => $trial_id)->load;
# skip rule unless submitted trial is in config:
next RULE unless $value eq $trial->trial_name;
}
else {
next RULE; # no matches
}
}
# add config presentation & trial_name fields to %data (unless already set
# from previous cycle through RULES loop, so ensure rules not inconsistent):
map { $data{$_} ||= $d->{$_} } grep $d->{$_}, qw( presentation trial_name );
# add lab tests:
if ( my $lab_tests = $d->{lab_tests} ) {
$data{lab_tests}{$_} = $lab_tests->{$_} for keys %$lab_tests;
}
} # warn Dumper \%data;
return \%data;
}
#-------------------------------------------------------------------------------
sub _have_required_sample_type_for_lab_test {
my ($self, $data) = @_;
# what lab section does new lab-test belong to?
my $lab_test_id = $data->{lab_test_id} || return 0; # warn Dumper $lab_test_id;
=begin - section replaced by LIMS::DB queries now - uncomment _build_* subs if required
my $lab_section_id = $self->lab_test_section_map->{$lab_test_id};
# what specimen type(s) does the lab section support (arrayref):
my $section_sample_type_map = $self->section_sample_type_map; # hashref of [sample_type ids]
my $required_specimen_type = $section_sample_type_map->{$lab_section_id};
# what specimen type id(s) do we have for this request:
my %sample_type_ids = ();
{ # get map of unique sample-type ids for this request:
my $specimen_id = $self->_get_specimen_id($data->{_request_id}); # arrayref
my $specimen_sample_type_map = $self->specimen_sample_type_map;
foreach my $id (@$specimen_id) {
my $ary = $specimen_sample_type_map->{$id}; # arrayref
$sample_type_ids{$_}++ for @$ary;
} # warn Dumper \%sample_type_ids;
}
# set true if one of available sample types matches a required type:
my $ok = ( grep $sample_type_ids{$_}, @$required_specimen_type );
=cut
=begin # required sql to do above in one go:
my $sql = q!
select count(*)
from request_specimen t4
join specimen_sample_type t5 on (t5.specimen_id = t4.specimen_id)
where
t4.request_id = ? and
t5.sample_type_id in (
select distinct(t3.sample_type_id)
from lab_tests t1
join lab_sections t2 on (t1.lab_section_id = t2.id)
join lab_section_sample_type t3 on (t3.lab_section_id = t2.id)
where t1.id = ?
)!;
=cut # Rose can't do sub-selects, so split query into 2 parts:
# part 1 - get distinct sample_type_id's:
my $lab_section_sample_type = do {
my %args = (
require_objects => [ qw( lab_section.lab_tests ) ],
select => [ 'sample_type_id' ],
query => [ 'lab_tests.id' => $lab_test_id ],
distinct => 1,
);
LIMS::DB::LabSectionSampleType::Manager
->get_lab_section_sample_types(%args);
}; # warn Dumper $lab_section_sample_type;
my @sample_type_ids = map { $_->sample_type_id } @$lab_section_sample_type;
# part 2 - count how many request_specimen rows contain required sample_type_id's:
my $count = do {
my %args = (
query => [
request_id => $data->{_request_id},
sample_type_id => \@sample_type_ids,
],
require_objects => [ 'specimen.specimen_sample_type' ],
);
LIMS::DB::RequestSpecimen::Manager->get_request_specimens_count(%args);
}; # warn Dumper $count;
# if we don't have at least 1 required sample type, add lab_test.id to failed list:
if (! $count) { $self->add_to_skipped_lab_tests($lab_test_id) }
return $count; # returns true if $count > 0
}
#-------------------------------------------------------------------------------
sub _get_specimen_id {
my ($self, $request_id) = @_;
my %args = (
query => [ request_id => $request_id ],
select => 'specimen_id',
);
my $o = LIMS::DB::RequestSpecimen::Manager->get_request_specimens(%args);
return [ map $_->specimen_id, @$o ];
}
#-------------------------------------------------------------------------------
sub _build_status_option_new {
my $self = shift;
my $status_option
= LIMS::DB::LabTestStatusOption->new(description => 'new')->load;
return $status_option;
}
=begin - not required, using LIMS::DB quires in _have_required_sample_type_for_lab_test
#-------------------------------------------------------------------------------
sub _build_section_sample_type_map { # return HoA of lab_section.id => [ sample_type.id ]
my $self = shift;
my $o = $self->get_objects_iterator('LabSectionSampleType');
my $map = {};
while ( my $t = $o->next ) {
my $lab_section_id = $t->lab_section_id;
my $sample_type_id = $t->sample_type_id;
push @{ $map->{$lab_section_id} }, $sample_type_id;
}
return $map;
}
#-------------------------------------------------------------------------------
sub _build_specimen_sample_type_map { # return HoA of specimen.id => [ sample_type.id ]
my $self = shift;
my $o = $self->get_objects_iterator('SpecimenSampleType');
my $map = {};
while ( my $t = $o->next ) {
my $specimen_id = $t->specimen_id;
my $sample_type_id = $t->sample_type_id;
push @{ $map->{$specimen_id} }, $sample_type_id;
}
return $map;
}
#-------------------------------------------------------------------------------
sub _build_lab_test_section_map {
my $self = shift;
my $o = $self->get_objects_iterator('LabTest');
my $map = {};
while ( my $t = $o->next ) {
$map->{$t->id} = $t->lab_section_id;
}
return $map;
}
=cut
1;