package LIMS::Controller::WorkList;
use base 'LIMS::Base';
use Moose;
with (
'LIMS::Controller::Roles::Misc',
'LIMS::Controller::Roles::User',
'LIMS::Controller::Roles::DataMap',
'LIMS::Controller::Roles::FormData',
);
__PACKAGE__->meta->make_immutable(inline_constructor => 0);
use Data::Dumper;
# ------------------------------------------------------------------------------
sub default : StartRunmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
my $active_sections = $self->model('WorkList')->get_active_sections_list;
my $request_status_options = $self->request_status_options_map;
# locally defined worklists:
if ( my $yaml = $self->get_yaml_file('local_worklists') ) { # warn Dumper $yaml;
$self->tt_params( local_worklists => $yaml );
}
# print labels:
if ( my $yaml = $self->get_yaml_file('print_labels') ) {
$self->tt_params( print_labels => $yaml );
}
$self->tt_params(
active_sections => $active_sections,
request_status_options => $request_status_options,
);
return $self->tt_process;
}
# ------------------------------------------------------------------------------
sub select : Runmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
# don't need ValidateRM->check() as vars passed automatically on submit:
my $profile = $self->validate('worklist');
my $data = $self->get_data_from_dfv($profile); # $self->debug($data);
my $lab_section_id = $data->{lab_section_id}
|| return $self->redirect( $self->query->url . '/worklist' );
{ # active investigations for this section:
my $investigations = $self->model('WorkList')
->get_active_investigations_for_section($lab_section_id);
$self->tt_params( active_investigations => $investigations );
}
{ # lab_test status_options for this section:
my $section_status_options
= $self->get_status_options_for_select($lab_section_id);
$self->tt_params( status_options => $section_status_options );
}
# get list of lab sections to require clinical trial filter
if ( my $cfg = $self->get_yaml_file('worklist_cfg') ) { # warn Dumper $cfg;
# check it's generating hashref or die (can't return $self->error here):
die "yml doesn't return hashref" unless ref $cfg eq 'HASH';
if ( my $sections = $cfg->{clinical_trial_filter}{lab_sections} ) { # warn Dumper $sections;
$self->tt_params( exclude_clinical_trial_sections => $sections );
}
}
# return to default() to load lab_sections & re-display:
return $self->forward('default');
}
# ------------------------------------------------------------------------------
# for dashboard lab-test status charts, retrieves section.id for param 'id', and
# status_option.id & lab_test.id for query params & forwards to display():
sub test_status : Runmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
my $vars = $self->query->Vars();
my ($status_option, $section_name, $test_name)
= map $vars->{$_}, qw(status section_name lab_test);
# warn Dumper [$status_option, $section_name, $lab_test];
my $section = $self->model('LabSection')
->get_lab_section_by_name($section_name);
# display() expects lab_section.id passing as param 'id':
$self->param( id => $section->id ); # lab_section.id
{ # lab_test.id as query param:
my %args = ( lab_section_id => $section->id, lab_test => $test_name );
my $lab_test = $self->model('LabTest')->get_section_lab_test(\%args);
$self->query->param( lab_test_id => $lab_test->id );
}
{ # lab_test_status_option.id as query param:
my $options_map = $self->lab_test_status_options_map('description');
my $option_id = $options_map->{$status_option}->{id}; # warn Dumper $option_id;
$self->query->param( status_option_id => $option_id );
}
return $self->forward('display');
}
# ------------------------------------------------------------------------------
sub display : Runmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
my $errs = shift; # $self->stash( errs => $errs ); # warn Dumper $errs;
my $lab_section_id = $self->param('id')
|| return $self->error('no lab_section_id passed to ' . $self->get_current_runmode);
# don't need ValidateRM->check() as vars passed automatically on submit:
my $profile = $self->validate('worklist');
my $data = $self->get_data_from_dfv($profile); # warn Dumper $data;
# do NOT want status_option_id if returning from update_results() with error:
delete $data->{status_option_id} # status_option_id is the one to update *to*
if $self->query->param('results_entry');
# put lab_section_id into $data for model:
$data->{lab_section_id} = $lab_section_id; # $self->debug($data);
{ # get lab_section data:
my $lab_section = $self->model('LabSection')->get_lab_section($lab_section_id);
$self->tt_params( lab_section => $lab_section );
# stash lab_section for request_section_notes_map() & template:
$self->stash( lab_section => $lab_section );
}
my $work = $self->model('WorkList')->get_outstanding_investigations($data);
# check we have something to do - status_option_id restriction might have been applied
unless (@$work) {
my $msg;
if ( my $status_option_id = $data->{status_option_id} ) {
my $status_option
= $self->model('LabTest')->get_status_option($status_option_id);
$msg = sprintf $self->messages('worklist')->{no_tests_for_status},
uc $status_option->description;
}
else { # shouldn't fail if not status_option restricted, but just in case:
$msg = sprintf $self->messages('worklist')->{no_outstanding_tests},
$self->stash->{lab_section}->section_name;
}
$self->flash ( info => $msg );
my $destination = '/worklist/select?lab_section_id=' . $lab_section_id;
return $self->redirect($self->query->url . $destination);
}
{ # convert objects to hashrefs to prevent template lookups:
my @data = map { $_->as_tree(deflate => 0) } @$work; # preserve datetime
$self->tt_params( outstanding_investigations => \@data );
}
# get some data maps for tmpl:
{
my $unique_ids = $self->get_unique_request_ids($work); # arrayref of request_ids
{ # specimens:
my $map = $self->specimen_map($unique_ids);
$self->tt_params( specimen_map => $map );
}
{ # request_options:
my $map = $self->request_options_map($unique_ids);
$self->tt_params( request_options_map => $map );
}
{ # section notes:
my $map = $self->request_section_notes_map($unique_ids);
$self->tt_params( request_section_notes_map => $map );
}
{ # config override for non-default table cols:
if ( my $yaml = $self->get_yaml_file('worklist_columns') ) {
$self->tt_params( worklist_cols => $yaml );
}
}
{ # callback for who requested test where test_type = test:
if ( my $yaml = $self->get_yaml_file('requesting_user_sections') ) {
$self->tt_params( requesting_user_sections => $yaml );
}
my $_self = $self; weaken $_self; # or get circular refs inside the callbacks
my $user = sub { $_self->model('WorkList')->get_requesting_user(@_) };
$self->tt_params( requesting_user => $user );
}
}
my $vars = $self->query->Vars; # warn Dumper $vars;
$vars->{display_format} ||= 'defined'; # or get 'uninitialized' warning in re
{ # if it's a request for data entry, set tmpl flag, get lab users, rtn tt:
my $is_data_entry =
$vars->{results_entry} || $vars->{display_format} =~ /data entry/i;
if ( $is_data_entry ) {
my $user_list = $self->get_lab_staff_users;
my $status_options
= $self->_get_status_options_for_data_entry($lab_section_id);
$self->tt_params(
is_results_entry => 1,
user_list => $user_list,
status_options => $status_options,
);
$self->js_validation_profile('worklist_update_status');
return $self->tt_process('worklist/data_entry.tt', $errs);
}
}
# else return display format:
return $self->tt_process();
}
# ------------------------------------------------------------------------------
sub request_status : Runmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
my $status_query = $self->query->param('status_query')
|| return $self->forward('default');
my $duration = $self->query->param('duration') # only used for status = unreported
|| $self->cfg('settings')->{unreported_duration};
my %args = (
status_query => $status_query,
duration => $duration,
); # warn Dumper \%args;
my $data = $self->model('WorkList')->request_status_query(\%args);
# return if no requests:
if (! @$data ) {
my $msg = $self->messages('worklist')->{no_outstanding_requests};
$self->flash( info => $msg );
return $self->redirect( $self->query->url . '/worklist' );
}
$self->tt_params( requests => $data );
{ # get some data maps for tmpl:
my @request_ids = map { $_->id } @$data;
{ # specimens map:
my $map = $self->specimen_map(\@request_ids);
$self->tt_params( specimen_map => $map );
}
{ # request_options:
my $map = $self->request_options_map(\@request_ids);
$self->tt_params( request_options_map => $map );
}
{ # duration map:
my $map = $self->time_duration_map($data);
$self->tt_params( duration_map => $map );
}
# outstanding lab-tests:
my @want_lab_tests = qw( incomplete unreported unauthorised );
if ( grep $status_query eq $_, @want_lab_tests ) {
my $o = $self->model('LabTest')
->get_request_lab_tests_status(\@request_ids); # warn Dumper $data;
my %tests;
for (@$o) {
next if $_->status->description eq 'complete'; # skip
my %t = (
section => $_->lab_test->lab_section->section_name,
test => $_->lab_test->field_label,
);
push @{ $tests{$_->request_id} }, \%t;
}
$self->tt_params( incomplete_lab_tests => \%tests );
}
}
return $self->render_view('worklist/status_query.tt'); # using firstname_format
}
# ------------------------------------------------------------------------------
sub update_results : Runmode {
my $self = shift; $self->_debug_path($self->get_current_runmode);
# need user_id & status_option_id:
my $dfv = $self->check_rm('display', $self->validate('worklist_update_status') )
|| return $self->dfv_error_page;
my $data = $dfv->valid; # warn Dumper $data;
# get list of request_lab_test.id's
my @request_lab_test_ids = $self->query->param('request_lab_test_id');
if (! @request_lab_test_ids) {
$self->flash( warning => $self->messages('worklist')->{no_lab_test_ids} );
my $option_id = $self->query->param('status_option_id'); # warn $option_id;
my $url = $self->query->url . '/worklist/display/' . $self->param('id')
# have to pass 'results_entry' flag in url:
. "?results_entry=1;status_option_id=$option_id";
return $self->redirect( $url );
}
=begin # too complicated to do this - using checkbox flag in tt now
{ # require confirmation if using delete option:
my $options_map
= $self->model('Result')->lab_test_status_options_map; # warn Dumper $options_map;
my $option_id = $data->{status_option_id};
if ( $options_map->{$option_id}->{description} eq 'delete' ) {
unless ( $self->query->param('confirm_delete') ) {
$self->tt_params( confirm_required => 1 );
return $self->forward('display'); # NEED SOME PARAMS
}
}
} return 1;
=cut
# add request_lab_test_ids to $data:
$data->{request_lab_test_ids} = \@request_lab_test_ids;
my $rtn = $self->model('Result')->update_lab_tests_from_worklist($data);
$self->tt_params(
updates => $rtn->{updates}, # arrayref
failed => $rtn->{failures}, # scalar ie record already deleted
);
{ # get some maps for worklist/updates.tt:
my $users_map = $self->usernames_map;
$self->tt_params( users_map => $users_map );
my $status_options_map = $self->lab_test_status_options_map('id');
$self->tt_params( status_options_map => $status_options_map );
}
if ( my $err = $rtn->{error} ) { # $self->debug($rtn);
return $self->error($err);
}
elsif ($rtn->{success}) { # warn $rtn->{success};
$self->flash( info => $self->messages('worklist')->{update_success} );
return $self->tt_process('worklist/updates.tt');
}
elsif ($rtn->{failures}) { # warn $rtn->{failures}; # ie all failed
$self->flash( warning => $self->messages('worklist')->{update_fails} );
return $self->redirect( $self->query->param('query_params') ); # hidden fld
}
else { # no db error, but also no records updated (probably unlikely unless db->err):
$self->flash( warning => $self->messages('worklist')->{update_failure} );
return $self->redirect( $self->query->param('query_params') ); # hidden fld
}
}
# ------------------------------------------------------------------------------
sub _get_status_options_for_data_entry {
my ($self, $lab_section_id) = @_; $self->_debug_path();
# get all status options (supply 'key'):
my $all_status_options = $self->lab_test_status_options_map('description');
my $section_status_options
= $self->model('LabSection')->get_section_status_options($lab_section_id);
my @options = map {
{
description => $_->status_option->description,
id => $_->status_option_id,
};
} @$section_status_options;
# need to add 'complete' & 'delete' to @options:
push @options, (
{
description => 'complete',
id => $all_status_options->{complete}->{id},
},
{
description => 'delete',
id => $all_status_options->{delete}->{id},
},
); # warn Dumper \@options;
return \@options;
=begin
while ( my ($option, $data) = each %$all_status_options ) {
next unless grep $option eq $_, qw(complete delete);
$section_status_options->{$option} = $data->{id};
}
return $section_status_options;
=cut
}
1;