package LIMS::Controller::HMRN::Data; use Moose; with ( 'LIMS::Controller::Roles::Misc', # redirect_after_edit_success() 'LIMS::Controller::Roles::FormData', # validate_form_params() ); BEGIN { extends 'LIMS::Base'; } __PACKAGE__->meta->make_immutable(inline_constructor => 0); use Data::Dumper; use Data::Printer alias => 'p'; #__PACKAGE__->authz->authz_runmodes( ':all' => 'view_clinical_data' ); # ------------------------------------------------------------------------------ # default() should never be called direct - redirect to start page: sub default : StartRunmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->redirect( $self->query->url ); } # ------------------------------------------------------------------------------ sub load : Runmode { # initial point of entry ie /hmrn_data/=/nnn return shift->forward('hmrn'); # just forward } # ------------------------------------------------------------------------------ sub hmrn : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $errs = shift; # $self->stash( errs => $errs ); # for debugging in tmpl my @required_permissions = qw(view_clinical_data edit_clinical_data); return $self->forbidden() unless $self->user_can(\@required_permissions); my $request_id = $self->param('id') || return $self->error('no id passed to '.$self->get_current_runmode); # get request data: my $request_data = $self->model('Request')->get_single_request($request_id); $self->tt_params( request_data => $request_data ); my $patient_id = $request_data->patient_case->patient_id; { # get request history: my $history = $self->model('History')->get_request_history($request_id); # create hash with keys = action & values = associated history object: my %request_history = map { $_->action => $_ } @$history; $self->tt_params( request_history => \%request_history ); } { # get patient demographic data: my $demographics = $self->model('HMRN')->get_patient_demographics($patient_id); if ( $demographics ) { my $demographic_data = $demographics->as_tree; { # add post-code at diagnosis: my $post_code_at_diagnosis = $self->model('HMRN')->get_post_code_at_diagnosis($patient_id); $demographic_data->{post_code_at_diagnosis} = $post_code_at_diagnosis; } $self->tt_params( demographic_data => $demographic_data ); # list of GP's for practice if exists: if ( my $practice_id = $demographics->practice_id ) { my $GPs = $self->model('Outreach') # same requirement in Outreach model ->get_practitioners_for_practice($practice_id); $self->tt_params( practice_gps => $GPs ); # get unknown practitioner id: my $o = LIMS::DB::ReferralType ->new(description => 'practitioner') ->load(with => 'unknown_referrer'); # warn Dumper $o->unknown_referrer; $self->tt_params( unknown_gp_id => $o->unknown_referrer->id); } } } { # get hmrn data: my $vars = $self->query->Vars(); my %args = ( patient_id => $patient_id, vars => $vars || {}, # might be required if validation fails ); my $hmrn_data = $self->model('HMRN')->get_all_hmrn_data(\%args); # is patient also in outreach (can't edit GP practice if so): if ($self->cfg('settings')->{have_outreach}) { my $in_outreach = $self->model('HMRN')->is_in_outreach($patient_id); $hmrn_data->{is_in_outreach} = $in_outreach; } $self->tt_params( hmrn_data => $hmrn_data ); } { # validation profiles for param data: my %validation_profile = (); my $param_constraints = $self->model('HMRN')->get_parameter_constraints; $validation_profile{constraints} = $param_constraints; for my $type( qw/lymphoid myeloid precursor plasmacell/ ) { my $profile = $self->validate('hmrn_'.$type); # warn Dumper $profile; my %required = map { $_ => 1 } @{ $profile->{required} }; $validation_profile{required_fields}{$type} = \%required; } $self->tt_params( validation_profile => \%validation_profile ); } # provide an age calculation callback: $self->tt_params( calculate_age => sub { LIMS::Local::Utils::calculate_age(@_); }); return $self->tt_process($errs); } # ------------------------------------------------------------------------------ # handles all lymphoid, myeloid, precursor & plasma-cell data, expects hidden param 'data_set': sub edit : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $data_type = $self->query->param('data_set') || return $self->error('no data_set type passed to '.$self->get_current_runmode); my $profile = $self->validate('hmrn_'.$data_type); # warn Dumper $profile; my $dfv = $self->check_rm( 'hmrn', $profile ) || return $self->dfv_error_page; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid; # warn Dumper $data; my %args = ( data => $data, data_type => $data_type, patient_id => $patient_id, ); my $rtn = $self->model('HMRN')->update_params(\%args); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub delete_section_data : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $section = $self->param('Id') || return $self->error('no section passed to '.$self->get_current_runmode); my $data = $self->model('Request') ->get_patient_and_request_data($request_id); # need confirmation to delete record: if ( $self->query->param('confirm_delete') ) { my %h = ( patient_id => $data->patient_case->patient_id, section => $section, ); # warn Dumper \%h; my $rtn = $self->model('HMRN')->delete_section_data(\%h); return $self->error($rtn) if $rtn; # set flash success & redirect: $self->flash( info => $self->messages('action')->{delete_success} ); $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id ); } else { # just load tt: my $hmrn_data = do { # get HMRN data for the record to delete my %h = ( patient_id => $data->patient_case->patient_id ); $self->model('HMRN')->get_all_hmrn_data(\%h); }; # p $hmrn_data; # get the section the data belongs to (Id = section name) my $section_name = $self->param('Id'); # get the data for this section to delete my $section_results = $hmrn_data->{params}->{$section_name}; # p $section_results; # get all the parameters and their info (so we can see what is shared or not): my $params_info = $hmrn_data->{maps}->{parameters}; # p $params_info; my %shared_data = (); PARAM: while ( my ($param, $result) = each %$section_results ) { # p $result; # get list of other categories that share this param (ie excluding # current category): my @cat_array = grep { $_ ne $section_name } @{ $params_info->{$param}->{in_categories} }; # warn Dumper \@cat_array; # skip if param not shared with at least one other category: next PARAM unless @cat_array; # hash of category => number of non-shared data items in category: my %in_categories = map { $_ => $hmrn_data->{category_has_data}->{$_}; # eg myeloid => 6 } @cat_array; my %h = ( in_categories => \%in_categories, result => $result, ); $shared_data{$param} = \%h; } # warn Dumper \%shared_data; my %tt_data = ( data => $data, hmrn_data => $hmrn_data, shared_data => \%shared_data, ); return $self->tt_process(\%tt_data); } } # ------------------------------------------------------------------------------ sub comment : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $self->query->Vars(); # only single param passed - 'comment' $data->{patient_id} = $patient_id; my $rtn = $self->model('HMRN')->update_comment($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub view_history : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $patient_id = $self->param('id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $self->model('HMRN')->get_history($patient_id); $self->tt_params( data => $data ); return $self->tt_process(); } # ------------------------------------------------------------------------------ sub edit_demographics : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $dfv = $self->check_rm( 'hmrn', $self->validate('hmrn_demographics') ) || return $self->dfv_error_page; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid; # add patient_id: $data->{patient_id} = $patient_id; # warn Dumper $data; # first update patient_demographics table: my $rtn = $self->model('Patient')->update_patient_demographics($data); return $self->error($rtn) if $rtn; # now update hmrn.patient_post_code table (ie value at diagnosis): if ( $data->{post_code} ) { # only have access if patient NOT in Outreach: $rtn = $self->model('HMRN')->update_post_code_at_diagnosis($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } } # ------------------------------------------------------------------------------ # edit post-code at diagnosis - only necessary if patient in Outreach & post-code # originally entered incorrectly: sub edit_post_code : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || $self->query->param('request_id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || $self->query->param('patient_id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); # submitted via url to request edit page: my $post_code_at_diagnosis = $self->query->param('post_code_at_diagnosis'); # submitted via form to update post-code: my $post_code = $self->query->param('post_code'); if ($post_code) { # assume edit submission - doesn't permit blank submission: # just make sure it's valid: my $profile = $self->validate('hmrn_demographics'); my $dfv = $self->validate_form_params($profile); if ($dfv->has_invalid) { # $dfv->has_missing not req'd - wouldn't get here $self->tt_params(dfv_err => $dfv->msgs); # warn Dumper $dfv->msgs; return $self->fill_form($self->tt_process); } my %data = ( patient_id => $patient_id, post_code => $post_code, ); my $rtn = $self->model('HMRN')->update_post_code_at_diagnosis(\%data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } else { # assume new request for edit: return $self->tt_process({ post_code => $post_code_at_diagnosis }); # return $self->error('no post-code value submitted'); } } # ------------------------------------------------------------------------------ sub edit_event_data : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $dfv = $self->check_rm( 'hmrn', $self->validate('hmrn_chronologies') ) || return $self->dfv_error_page; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid; # add patient_id: $data->{patient_id} = $patient_id; my $rtn = $self->model('HMRN')->update_patient_events($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub edit_antecedent : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $vars = $self->query->Vars; # add patient_id: $vars->{patient_id} = $patient_id; my $rtn = $self->model('HMRN')->update_antecedent_events($vars); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub new_treatment : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $dfv = $self->check_rm( 'hmrn', $self->validate('hmrn_treatment') ) || return $self->dfv_error_page; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid(); # add patient_id: $data->{patient_id} = $patient_id; my $rtn = $self->model('HMRN')->new_treatment_data($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub referral_pathway : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $dfv = $self->check_rm( 'hmrn', $self->validate('hmrn_referral') ) || return $self->dfv_error_page; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid(); # add patient_id: $data->{patient_id} = $patient_id; # warn Dumper $data; my $rtn = $self->model('HMRN')->new_referral_data($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub new_imaging_data : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $dfv = $self->check_rm( 'hmrn', $self->validate('hmrn_imaging') ) || return $self->dfv_error_page; # warn Dumper $dfv; my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); my $data = $dfv->valid(); # add patient_id: $data->{patient_id} = $patient_id; my $rtn = $self->model('HMRN')->new_imaging_data($data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub delete_imaging : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $event_id = $self->param('Id') # || return $self->error('no event id passed to '.$self->get_current_runmode); # need confirmation to delete record: if ( $self->query->param('confirm_delete') ) { my %h = ( event_id => $event_id, scan_type => $self->query->param('item'), ); my $rtn = $self->model('HMRN')->delete_imaging_data(\%h); return $self->error($rtn) if $rtn; # set flash success & redirect: $self->flash( info => $self->messages('action')->{delete_success} ); $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id ); } else { # just load tt: return $self->tt_process(); } } # ------------------------------------------------------------------------------ sub edit_imaging : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $errs = shift; # $self->stash( errs => $errs ); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $event_id = $self->param('Id') # || return $self->error('no event id passed to '.$self->get_current_runmode); { # imaging data for requested scan: my $data = $self->model('HMRN')->get_imaging_data($event_id); # put request_id into $data: $data->{request_id} = $request_id; $self->tt_params(data => $data); } { # imaging_options : my $opts = $self->model('HMRN')->get_imaging_options; $self->tt_params(imaging_opts => $opts); } return $self->tt_process($errs); } # ------------------------------------------------------------------------------ sub do_edit_imaging : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $event_id = $self->param('Id') # event table 'id' || return $self->error('no event id passed to '.$self->get_current_runmode); my $dfv = $self->check_rm( 'edit_imaging', $self->validate('hmrn_imaging') ) || return $self->dfv_error_page; my $data = $dfv->valid(); # warn Dumper $data; # put event table 'id' into $data: $data->{event_id} = $event_id; # warn Dumper $data; my $rtn = $self->model('HMRN')->update_imaging_data($data); $self->flash( info => $self->messages('action')->{edit_success} ) if ! $rtn; return $rtn ? $self->error($rtn) : $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id ); } # ------------------------------------------------------------------------------ sub edit_referral : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $errs = shift; return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $tbl_id = $self->param('Id') # patient_referral table 'id' || return $self->error('no id passed to '.$self->get_current_runmode); my $data = $self->model('HMRN')->get_referral_data($tbl_id); # put request_id into $data: $data->{request_id} = $request_id; $self->tt_params(data => $data); # for jquery validation (date functions don't work with DatePicker): # $self->tt_params( profile_name => 'hmrn_referral' ); return $self->tt_process($errs); } # ------------------------------------------------------------------------------ sub do_edit_referral : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $tbl_id = $self->param('Id') # table 'id' || return $self->error('no id passed to '.$self->get_current_runmode); my $rtn; if ( $self->query->param('delete') ) { return $self->forward('edit_referral') unless $self->query->param('confirm_delete'); $rtn = $self->model('HMRN')->delete_referral_data($tbl_id); # just send id for del $self->flash( info => $self->messages('action')->{delete_success} ) if ! $rtn; } else { my $dfv = $self->check_rm( 'edit_referral', $self->validate('hmrn_referral') ) || return $self->dfv_error_page; my $data = $dfv->valid(); # put treatment table 'id' into $vars: $data->{id} = $tbl_id; # warn Dumper $data; $rtn = $self->model('HMRN')->update_referral_data($data); $self->flash( info => $self->messages('action')->{edit_success} ) if ! $rtn; } return $rtn ? $self->error($rtn) : $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub edit_treatment : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $errs = shift; return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $treatment_id = $self->param('Id') # treatment table 'id' || return $self->error('no id passed to '.$self->get_current_runmode); my $data = $self->model('HMRN')->get_treatment_data($treatment_id); # put request_id into $data: $data->{request_id} = $request_id; $self->tt_params(data => $data); # for jquery validation (date functions don't work with DatePicker): # $self->tt_params( profile_name => 'hmrn_treatment' ); return $self->tt_process($errs); } # ------------------------------------------------------------------------------ sub do_edit_treatment : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $treatment_id = $self->param('Id') # treatment table 'id' || return $self->error('no id passed to '.$self->get_current_runmode); my $rtn; if ( $self->query->param('delete') ) { return $self->forward('edit_treatment') unless $self->query->param('confirm_delete'); $rtn = $self->model('HMRN')->delete_treatment_data($treatment_id); # just send id for del $self->flash( info => $self->messages('action')->{delete_success} ) if ! $rtn; } else { my $dfv = $self->check_rm( 'edit_treatment', $self->validate('hmrn_treatment') ) || return $self->dfv_error_page; my $data = $dfv->valid(); # put treatment table 'id' into $vars: $data->{id} = $treatment_id; # warn Dumper $data; $rtn = $self->model('HMRN')->update_treatment_data($data); $self->flash( info => $self->messages('action')->{edit_success} ) if ! $rtn; } return $rtn ? $self->error($rtn) : $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub edit_mdt_date : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $id = $self->param('Id') || return $self->error('no id passed to '.$self->get_current_runmode); my $vars = $self->query->Vars(); my $rtn; # for jquery validation (does't work with DatePicker): # $self->tt_params( profile_name => 'hmrn_mdt_date' ); # deletion request: if ($vars->{delete}) { # NB: do this 1st as var 'date' also passed return $self->fill_form($self->tt_process) # require confirmation before deleting: unless $self->query->param('confirm_delete'); $rtn = $self->model('HMRN')->delete_mdt_date($id); # just send id for del $self->flash( info => $self->messages('action')->{delete_success} ) if ! $rtn; } # if revised date submitted: elsif ($vars->{date}) { # validate date: my $profile = $self->validate('hmrn_mdt_date'); my $dfv = $self->validate_form_params($profile); if ($dfv->has_invalid) { # $dfv->has_missing not req'd - wouldn't get here $self->tt_params(dfv_err => $dfv->msgs); # warn Dumper $dfv->msgs; return $self->fill_form($self->tt_process); } $vars->{id} = $id; # add row id for update $rtn = $self->model('HMRN')->update_mdt_date($vars); $self->flash( info => $self->messages('action')->{edit_success} ) if ! $rtn; } else { # 1st call to method (just get data): my $data = $self->model('HMRN')->get_mdt_data($id); return $self->tt_process({ data => $data }); } return $rtn ? $self->error($rtn) : $self->redirect( $self->query->url . '/hmrn_data/=/' . $request_id); } # ------------------------------------------------------------------------------ sub edit_practice : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); return $self->forbidden() unless $self->user_can('edit_clinical_data'); my $request_id = $self->param('id') || return $self->error('no request_id passed to '.$self->get_current_runmode); my $patient_id = $self->param('Id') || return $self->error('no patient_id passed to '.$self->get_current_runmode); # if new practice_id submitted: if ( my $practice_id = $self->query->param('practice_id') ) { my %data = ( patient_id => $patient_id, practice_id => $practice_id, ); my $rtn = $self->model('Patient')->update_patient_demographics(\%data); return $rtn ? $self->error($rtn) : $self->redirect_after_edit_success('/hmrn_data/=/' . $request_id); } else { # load existing for editing: # get current practice_id for patient: my $info = $self->model('HMRN')->get_patient_demographics($patient_id); return $self->tt_process({ data => $info }); } } # ------------------------------------------------------------------------------ # ajax function called from treatment type select menu: sub treatment_options : Runmode { my $self = shift; $self->_debug_path($self->get_current_runmode); my $options = []; if ( my $tx_type_id = $self->query->param('tx_type_id') ) { # warn $tx_type_id; $options = $self->model('HMRN')->get_tx_details_for_tx_type($tx_type_id); } return $self->tt_process({ options => $options }); } 1;