package LIMS::Controller::Result; use base 'LIMS::Base'; use Moose; with ( 'LIMS::Controller::Roles::DataMap', 'LIMS::Controller::Roles::DataFile', 'LIMS::Controller::Roles::DataImport', 'LIMS::Controller::Roles::FormData', 'LIMS::Controller::Roles::RecordHandler', 'LIMS::Controller::Roles::ResultHandler', ); __PACKAGE__->meta->make_immutable(inline_constructor => 0); # can't use __PACKAGE__->authz->authz_runmodes() - crashes on non-logged-in user #------------------------------------------------------------------------------- sub default : StartRunmode { my $self = shift; # shouldn't be called here - redirect to / $self->redirect( $self->query->url ); } #------------------------------------------------------------------------------- sub load : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('modify_results'); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); my $request_data = $self->get_single_request_data($request_id); # return to home page if record locked (direct url arrival) & not authorized: if ( $request_data->{is_locked} && ! $self->user_can('modify_results') ) { return $self->redirect( $self->query->url . '/search/=/' . $request_id ); } # send $data to process_results_data() for template # - adds 'all_results' & 'results_summary_opts' to $request_data: $self->process_raw_lab_test_data($request_data); { # datafiles - load sub to save db lookup if not required: my $load_data_files = sub { my $data_files = $self->get_result_data_file($request_id); return @$data_files ? 1 : 0; }; $self->tt_params( have_data_files => $load_data_files ); } # get some data maps: my %data_map; { # lab test data type map: my $lab_test_data_type_map = $self->lab_test_data_type_map; $data_map{lab_test_data_type} = $lab_test_data_type_map; } { # lab test result options map: my $lab_test_result_options = $self->lab_test_result_options_map; $data_map{data_options} = $lab_test_result_options; } #{ # lab section notes map (moved to get_single_request_data): # my $lab_section_notes = $self->section_notes_map($request_id); # $data_map{lab_section_notes} = $lab_section_notes; #} $self->tt_params( data_map => \%data_map ); # $self->_debug_path('timer'); return $self->render_view('result/default.tt', $request_data); } #------------------------------------------------------------------------------- sub update : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('modify_results'); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); # required = 2 hidden fields so should never fail, so send to error mode: my $dfv = $self->check_rm('load', $self->validate('update_results') ) || return $self->error('required hidden field(s) not supplied to rm ' . $self->get_current_runmode); my $data = $dfv->valid(); # $self->debug($data); # put request_id into $data: $data->{_request_id} = $request_id; # $self->debug($data); # get (optional) config file for auto_reportable requests: if ( my $cfg = $self->get_yaml_file('auto_reportable') ) { $data->{auto_reportable_config} = $cfg; } my $rtn = $self->model('Result')->update_lab_test_results($data); if ($rtn) { return $self->error($rtn); } else { $self->flash( info => $self->messages('action')->{edit_success}); return $self->redirect( $self->query->url . '/search/=/' . $request_id ); } } #------------------------------------------------------------------------------- sub preview_datafile : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); # get data file from requests' images dir - in arrayref format: my $data_file = $self->get_result_data_file($request_id); # check there's only 1 data file: if (! @$data_file || @$data_file > 1) { my $msg = @$data_file ? 'xs_data_files' : 'no_data_file'; $self->flash( error => $self->messages('results')->{$msg} ); $self->redirect( $self->query->url . '/image/=/' . $request_id ); } # extract data from datafile into arrayref: my $data = $self->get_datafile_contents($data_file->[0]); # deref @data_file unless (@$data) { $self->flash( error => $self->messages('results')->{empty_data} ); $self->redirect( $self->query->url . '/image/=/' . $request_id ); } $self->tt_params( request_id => $request_id, data => $data, file => @$data_file, # deref single arrayref ); return $self->tt_process; } #------------------------------------------------------------------------------- sub import_datafile : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); my $filename = $self->query->param('datafile') || return $self->error('no filename passed to ' . $self->get_current_runmode); # extract contents of datafile to object accessor: $self->parse_data_file($filename); # check internal datafile refs (filename & patient ids) match $self->_check_datafile_integrity() || return $self->redirect( $self->query->url . '/image/=/' . $request_id ); # get flow data (as str) from datafile, or redirect (flash set in sub): my $flow_data_result = $self->_get_flow_data_result() || return $self->redirect( $self->query->url . '/image/=/' . $request_id ); # create hash to hold data for db update: my %results_data = ( request_id => $request_id ); # if lab_test sign_off required, need to get additional params: if ( my $lab_test_data = $self->get_lab_test_data() ) { # warn $lab_test; # get 'acquired_by' user: my $acquired_by = $self->get_analysis_user(); # no need to check, it's next $lab_test_data->{acquired_by} = $acquired_by; # get 'user_id' value: my $user_id = $self->get_analysis_user_id($acquired_by) || $self->_set_flash_msg('no_userid'); # set flash msg on failure # get 'date_acquired' value: my $date_acquired = $self->get_date_acquired() || $self->_set_flash_msg('empty_acquired'); # set flash msg on failure # check both params, or redirect (flash msg already set on either failure): unless ($date_acquired && $user_id) { return $self->redirect( $self->query->url . '/image/=/' . $request_id ); } $lab_test_data->{date_acquired} = $date_acquired; $lab_test_data->{acquisition_userid} = $user_id; $results_data{lab_test_data} = $lab_test_data; } { # request_report data: my $report_data = $self->get_report_params(); # $self->debug($data); $results_data{report_data} = $report_data; } { # request_result_summaries data: my $lab_section = $self->get_lab_section; my %result_summary_data = ( lab_section => $lab_section, results_summary => $flow_data_result, ); # $self->debug(\%result_summaries_data); $results_data{result_summary_data} = \%result_summary_data; } my $rtn = $self->model('Result')->import_results(\%results_data); if ($rtn) { return $self->error($rtn); } else { $self->flash( info => $self->messages('action')->{edit_success}); return $self->redirect( $self->query->url . '/report/=/' . $request_id ); } } #------------------------------------------------------------------------------- sub notes : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); # don't need to validate, either have content or not: my $profile = $self->validate('general_notes'); my $data = $self->get_data_from_dfv($profile); # $self->debug($data); $data->{_request_id} = $request_id; my $rtn = $self->model('Result')->general_notes($data); if ($rtn) { return $self->error($rtn); } else { $self->flash( info => $self->messages('action')->{edit_success}); return $self->redirect( $self->query->url . '/result/=/' . $request_id ); } } #------------------------------------------------------------------------------- sub data_entry : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('modify_results'); my $request_id = $self->param('id') || return $self->error('no id passed to ' . $self->get_current_runmode); my $lab_test_data = $self->_get_test_results_data_map; my %data = ( lab_test_data => $lab_test_data, request_id => $request_id, ); my $rtn = $self->model('Result')->update_request_lab_test_results(\%data); if ($rtn) { return $self->error($rtn); } else { $self->flash( info => $self->messages('results')->{update_success} ); return $self->redirect( $self->query->url . '/result/=/'.$request_id); } } #------------------------------------------------------------------------------- # check internal datafile refs (filename & patient ids) match # sets $self->param_mismatch() arrayref on error: sub _check_datafile_integrity { my $self = shift; # check_datafile_integrity() returns names of any errors: if ( my $error_names = $self->check_datafile_integrity() ) { my @errs = map $self->messages('results')->{$_}, @$error_names; $self->flash( error => join '; ', @errs ); return 0; } return 1; } #------------------------------------------------------------------------------- # data passed from form fields as lab_test_id_(\d) sub _get_test_results_data_map { my $self = shift; my $params = $self->query->Vars; # can't use $dfv->valid for dynamic params my %map; while ( my($param, $value) = each %$params ) { # warn $param; # look for param lab_test_id_(\d): my ($lab_test_id) = $param =~ /lab_test_id_(\d+)/; # don't do '|| next' here next unless $lab_test_id; # warn $lab_test_id; warn $value; $map{$lab_test_id} = $value; } $self->debug(\%map); return \%map; } #------------------------------------------------------------------------------- sub _get_flow_data_result { my $self = shift; if ( my $flow_data_result = $self->get_flow_data_result() ) { return $flow_data_result; } else { $self->flash( error => $self->messages('results')->{empty_result} ); return 0; } } #------------------------------------------------------------------------------- sub _set_flash_msg { my $self = shift; my $msg = shift; $self->flash( error => $self->messages('results')->{$msg} ); return 0; # IMPORTANT - return value is captured by caller } 1;