package LIMS::Model::Request; use Moose; extends 'LIMS::Model::Base'; with ( 'LIMS::Model::Roles::QueryFormatter', 'LIMS::Model::Roles::RequestUpdate', 'LIMS::Model::Roles::ScreenUpdate', # do_new_lab_test, auto_screen 'LIMS::Model::Roles::HistoryAction', ); use namespace::clean -except => 'meta'; has frozen_data => ( is => 'rw', isa => 'HashRef'); has form_data => ( is => 'rw', isa => 'HashRef', default => sub { {} } ); has archive => ( is => 'ro', isa => 'ArrayRef[HashRef]', default => sub { [] }, lazy => 1, traits => ['Array'], handles => { add_to_archive => 'push', archived_data => 'elements', }, ); has $_ => ( is => 'ro', isa => 'HashRef', lazy_build => 1 ) for qw( referral_type_map specimen_lab_test_map request_status_options_map ); __PACKAGE__->meta->make_immutable; use Data::Dumper; use LIMS::Local::Utils; #------------------------------------------------------------------------------- sub new_request { my $self = shift; my $data = shift; # DEBUG $data; return; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; # extract request, options & consent data from $data: my $request_data = $self->_get_request_data($data); my $trial_data = $self->_get_clinical_trial_data($data); # get specimens table iterator: my $specimen = LIMS::DB::Specimen::Manager ->get_specimens_iterator(sort_by => 'sample_code'); # get specimen -> lab_test map (for any auto-generated lab tests): my $specimen_lab_test_map = $self->specimen_lab_test_map; # get consent_options iterator: my $consent_options = LIMS::DB::ConsentOption::Manager ->get_consent_options_iterator(); # get additional_options table iterator: my $request_options = LIMS::DB::AdditionalOption::Manager ->get_additional_options_iterator(); # split specimens on comma and/or space(s): my @specimens = split /\,\s?|\s+/, $data->{specimen}; # DEBUG \@specimens; my $user_id = $self->user_profile->{id}; # create new request in transaction: my $new_request = sub { # save request_data to request table 1st so we can get request.id: my $request = LIMS::DB::Request->new(%$request_data); $request->save; # cycle specimens iterator, adding specimen_id to request_specimen table: while ( my $o = $specimen->next ) { next unless grep { lc $o->sample_code eq lc $_ } @specimens; # DEBUG $o->id; LIMS::DB::RequestSpecimen->new( request_id => $request->id, specimen_id => $o->id, )->save; # any auto-generated specimen-associated lab-tests ? if ( my $lab_test_ref = $specimen_lab_test_map->{$o->id} ) { map { # generate lab-test request(s): $self->do_new_lab_test({ _request_id => $request->id, # method required underscored var lab_test_id => $_, }); } @$lab_test_ref; } } # clinical trial: if ( my $trial_id = $trial_data->{trial_id} ) { LIMS::DB::RequestTrial->new( trial_id => $trial_id, request_id => $request->id, )->save; # trial_number - should not be submitted without trial_id: if ( my $trial_number = $trial_data->{trial_number} ) { # update existing or create new patient trial data: LIMS::DB::PatientTrial->new( patient_id => $trial_data->{patient_id}, trial_number => $trial_number, trial_id => $trial_id, )->insert_or_update; } } # consent data: while ( my $o = $consent_options->next ) { my $option_name = $o->consent_name; next unless $data->{$option_name}; LIMS::DB::RequestConsent->new( status => $data->{$option_name}, request_id => $request->id, consent_id => $o->id, )->save; } # error codes: if ( my $error_code_id = $data->{error_code_id} ) { my %data = ( request_id => $request->id, user_id => $user_id, ); # get error_code_ids as an arrayref (if not already): my $codes = ref $error_code_id eq 'ARRAY' ? $error_code_id : [ $error_code_id ]; for (@$codes) { $data{error_code_id} = $_; LIMS::DB::RequestErrorCode->new(%data)->save; } } # cycle request_options iterator, adding additional_option_id to request_options table: while ( my $o = $request_options->next ) { my $option_name = $o->option_name; next unless $data->{$option_name}; LIMS::DB::RequestOption->new( request_id => $request->id, option_id => $o->id, )->save; } # external_reference: if ( my $ref = $data->{external_reference} ) { LIMS::DB::RequestExternalRef->new( request_id => $request->id, external_reference => $ref, )->save; } # request_history: $self->add_to_actions('registered'); # auto-screen (if configured): if ($data->{auto_screen_config}) { $data->{_request_id} = $request->id; $self->form_data($data); # save form_data for Role method $self->do_auto_screen() # Roles::ScreenUpdate } $self->do_request_history(); # commit actions to request_history table }; # do_transaction() returns true if succeeds; sets $db->error on failure: my $ok = $db->do_transaction($new_request); return $ok ? 0 : 'new_request() error - ' . $db->error; } #------------------------------------------------------------------------------- sub get_requests_count { my $self = shift; my ($request_number, $year) = @_; my %args = ( query => [ request_number => $request_number, year => $year || DateTime->now->year, ], ); my $total = LIMS::DB::Request::Manager->get_requests_count(%args); return $total; } #------------------------------------------------------------------------------- sub get_previous_diagnosis_count { my ($self, $request_id) = @_; my %args = ( query => [ request_id => $request_id ], ); my $count = LIMS::DB::RequestDiagnosisHistory::Manager ->get_request_diagnosis_histories_count(%args); return $count; } #------------------------------------------------------------------------------- # gets request.id if $n == 1: sub get_request_id { my ($self, $search_constraints) = @_; my $formatted_args = $self->get_args_for_request_id($search_constraints); my $request = LIMS::DB::Request::Manager->get_requests(%$formatted_args); return $request->[0]->id; } #------------------------------------------------------------------------------- # called by Search::do_search() to find number of requests matching search criteria: sub search_requests_count { my ($self, $search_constraints) = @_; # warn Dumper $search_constraints; my $formatted_args = $self->get_args_for_requests_count($search_constraints); # warn Dumper $formatted_args; #$self->set_rose_debug(1); my $total = LIMS::DB::Request::Manager->get_requests_count(%$formatted_args); #$self->set_rose_debug(0); return $total; } #------------------------------------------------------------------------------- # called by Search::do_search() to retrieve records matching search criteria for n > 1: sub find_requests { my $self = shift; my $args = shift; # hashref with keys = 'search_constraints' & 'args_for_search' warn Dumper $args; # get query, with_objects, require_objects, etc from $args: my $formatted_args = $self->get_args_for_find_requests($args); #$self->set_rose_debug(1); my $requests = LIMS::DB::Request::Manager->get_requests(%$formatted_args); #$self->set_rose_debug(0); return $requests; } #------------------------------------------------------------------------------- # accepts request.id & returns all required request data: sub get_single_request { my ($self, $request_id) = @_; # warn $request_id; # check it exists 1st (in case user input of request_id into url): $self->_verify_request_exists($request_id) || return 0; # require data from these tables: my @tables = qw( patients referrers diagnoses status_options clinical_trials referral_sources request_external_ref hospital_departments request_general_notes request_initial_screen request_gross_description ); my $relationships = $self->get_relationships(\@tables); #$self->set_rose_debug(1); my $request = LIMS::DB::Request->new(id => $request_id)->load(with => $relationships); #$self->set_rose_debug(0); return $request; } #------------------------------------------------------------------------------- # finds previous requests on current request nhs_number or patient id: sub get_previous_requests { my $self = shift; my $args = shift; # hashref of args for query (eg nhs_number => 123, etc) # require data from these tables: my @tables = qw( patients diagnoses ); my $relationships = $self->get_relationships(\@tables); my %params = ( query => [ %$args ], require_objects => $relationships, sort_by => 'year DESC, request_number DESC', nested_joins => 0, ); my $records = LIMS::DB::Request::Manager->get_requests_iterator(%params); return $records; } #------------------------------------------------------------------------------- sub get_request_options { my ($self, $request_id) = @_; # warn $request_id; my %args = ( query => [ request_id => $request_id ], require_objects => 'option', ); my $request_options = LIMS::DB::RequestOption::Manager->get_request_options(%args); return $request_options; } #------------------------------------------------------------------------------- sub get_request_report_diagnosis { my ($self, $request_id) = @_; # warn $request_id; my %args = ( query => [ request_id => $request_id ], require_objects => 'request_report.diagnosis', ); my $request_diagnosis = ref $request_id eq 'ARRAY' # can handle either single or list ? LIMS::DB::Request::Manager->get_requests(%args) : LIMS::DB::Request->new(request_id => $request_id) ->load(with => 'request_report.diagnosis'); return $request_diagnosis; } #------------------------------------------------------------------------------- sub get_request_consent { my ($self, $request_id) = @_; # warn $request_id; my %args = ( query => [ request_id => $request_id ], require_objects => 'consent', ); my $request_consent = LIMS::DB::RequestConsent::Manager->get_request_consents(%args); return $request_consent; } #------------------------------------------------------------------------------- sub get_referrer_department { my ($self, $request_id) = @_; # warn $request_id; my @rels = qw( referrer_department.referrer referrer_department.hospital_department ); my $request = LIMS::DB::Request->new(id => $request_id)->load(with => \@rels); return $request->as_tree; } #------------------------------------------------------------------------------- sub get_request_errors { my ($self, $request_id) = @_; # warn $request_id; my %args = ( query => [ request_id => $request_id ], require_objects => [ 'error_code', 'user' ], ); my $request_errors = LIMS::DB::RequestErrorCode::Manager->get_request_error_codes(%args); return $request_errors; } #------------------------------------------------------------------------------- sub get_request_error_code { my ($self, $id) = @_; # warn $id; my $err = LIMS::DB::RequestErrorCode->new(id => $id) ->load(with => [ 'error_code', 'user' ]); return $err; } #------------------------------------------------------------------------------- sub delete_request_error_code { my ($self, $id) = @_; # warn $id; my $delete = sub { my $o = LIMS::DB::RequestErrorCode->new(id => $id) ->load( with => 'error_code' ); my $request_id = $o->request_id; $o->delete; $self->add_to_actions('deleted error code ' . uc $o->error_code->code); $self->do_history_log({ _request_id => $request_id }); }; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $result = $db->do_transaction( $delete ); # don't need return value unless error: return $result ? 0 : 'error in delete_request_error_code() - ' . $db->error; } #------------------------------------------------------------------------------- sub request_error_code { my $self = shift; my $data = shift; # warn Dumper $data; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my %args = ( _request_id => $data->{request_id} ); # do_request_error_code() format my $error = sub { if ($data->{LIC}) { $self->add_to_actions('completed LIC'); } if ( my $error_code_id = $data->{error_code_id} ) { $args{error_code_id} = $error_code_id; $self->do_request_error_code(\%args); } # log history: $self->do_history_log(\%args); }; my $result = $db->do_transaction( $error ); # don't need return value unless error: return $result ? 0 : 'error in new_request_error() - ' . $db->error; } #------------------------------------------------------------------------------- sub edit_request_error_code { my $self = shift; my $data = shift; # warn Dumper $data; my $error_code_id = $data->{error_code_id}; # get error_code object: my $error_code = LIMS::DB::ErrorCode->new(id => $error_code_id)->load; # edit request_error_code entry: my $edit = sub { my $o = LIMS::DB::RequestErrorCode->new(id => $data->{id}) ->load( with => 'error_code' ); # add to actions for history log: my $msg = sprintf 'updated error code %s to %s', uc $o->error_code->code, uc $error_code->code; # old -> new $self->add_to_actions($msg); $o->error_code_id($error_code_id); # change it $o->save(changes_only => 1); # save it $self->do_history_log({ _request_id => $o->request_id }); # log it }; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $result = $db->do_transaction( $edit ); # don't need return value unless error: return $result ? 0 : 'error in edit_request_error_code() - ' . $db->error; } #------------------------------------------------------------------------------- # basic version of get_single_request() - just gets request & patient data: sub get_patient_and_request_data { my ($self, $param) = @_; # warn $param; my @args = ref $param eq 'ARRAY' ? @$param # eg request_number => nn, year => yyyy : (id => $param); # assume request.id passed if $param is scalar my $data = LIMS::DB::Request->new(@args)->load(with => 'patient_case.patient'); return $data; } #------------------------------------------------------------------------------- # gets basic request summary data (req, patient, referral) for multiple request_ids: sub requests_summary_data { my ($self, $request_ids) = @_; # arrayref my @tables = qw( patients referral_sources ); my $relationships = $self->get_relationships(\@tables); my @args = ( query => [ id => $request_ids ], require_objects => $relationships, ); my $data = LIMS::DB::Request::Manager->get_requests(@args); return $data; } #------------------------------------------------------------------------------- sub get_section_notes { my ($self, $request_id) = @_; my %args = ( query => [ request_id => $request_id ], ); my $section_notes = LIMS::DB::RequestLabSectionNote::Manager ->get_request_lab_section_notes(%args); return $section_notes; } #------------------------------------------------------------------------------- sub get_laboratory_number { my ($self, $request_id) = @_; my $request = LIMS::DB::Request->new(id => $request_id)->load; my $lab_number = join '/', $request->request_number, sprintf '%02d', $request->year - 2000; return $lab_number; } #------------------------------------------------------------------------------- sub get_request { my ($self, $request_id) = @_; my $request = LIMS::DB::Request->new(id => $request_id)->load; return $request; } #------------------------------------------------------------------------------- sub get_request_dispatch_logs { my ($self, $request_id) = @_; my $logs = LIMS::DB::RequestDispatchLog::Manager->get_request_dispatch_logs( query => [ request_id => $request_id ] ); return $logs; } #------------------------------------------------------------------------------- # how many requests 'have' this patient_case.id ? sub get_patient_case_requests_count { my $self = shift; my $case_id = shift; my $requests_count = LIMS::DB::Request::Manager->get_requests_count( query => [ patient_case_id => $case_id ], ); return $requests_count; } #------------------------------------------------------------------------------- sub get_new_and_relapsed_cases { my $self = shift; my $args = shift; # warn Dumper $args; my $org_code = $args->{org_code}; # need org_code = 'xxxxx' OR org_code like 'xxx%': my $org_code_expr = length($org_code) < 5 ? { like => $org_code . '%' } # '%%' ok for wild-card : $org_code; # ie look for specific location my $days_ago = $self->time_now ->subtract( days => $args->{duration} ) ->truncate( to => 'day' ); my @tables = qw( patients diagnoses referral_sources request_history ); my $relationships = $self->get_relationships(\@tables); # set status level required for displaying reports: my $report_status = $self->does_authorisation() ? 'authorised' : 'reported'; my @params = ( query => [ 'request_report.status' => { ne => 'default' }, 'request_history.time' => { ge => $days_ago }, 'request_history.action' => $report_status, # reported or authorised 'referral_sources.organisation_code' => $org_code_expr, ], require_objects => $relationships, # sort_by => 'request_history.time', # doesn't work as t1.id gets priority ); my $cases = LIMS::DB::Request::Manager->get_requests(@params); return $cases; } #------------------------------------------------------------------------------- sub update_request_dispatch_log { my $self = shift; my $data = shift; my $request_id = $data->{request_id}; my $recipient = $data->{recipient}; my $action = 'dispatched report to ' . $recipient; my $server_name = $self->lims_cfg->{settings}->{server_username}; # get username of server: my $user_id = LIMS::DB::User->new(username => $server_name)->load->id; my $update = sub { LIMS::DB::RequestDispatchLog->new( request_id => $request_id, recipient => $recipient, )->save; LIMS::DB::RequestHistory->new( request_id => $request_id, user_id => $user_id, action => $action, )->save; }; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $ok = $db->do_transaction($update); # don't need return value unless error: return $ok ? 0 : 'update_request_dispatch_log() error - ' . $db->error; } #------------------------------------------------------------------------------- sub update_request { my ($self, $form_data) = @_; # use Data::Dumper; # warn Dumper $form_data; # get original data from session (and store it in $self->frozen_data): my $original_data = $self->_get_original_data; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $update_request = sub { # referrer_code (only submitted if field edited): if ( $form_data->{referrer_code} ) { my $original_referrer_code = $self->frozen_data->{referrer_code}; if ( $form_data->{referrer_code} ne $original_referrer_code ) { $self->do_referrer_update($form_data); } # warn "$form_data->{referrer_code} ne $original_referrer_code"; } # specimen_code (always submitted): { my $original_specimen_code = $self->frozen_data->{specimen_code}; if ( $form_data->{specimen_code} ne $original_specimen_code ) { $self->do_specimen_code_update($form_data); } # warn "$form_data->{specimen_code} ne $original_specimen_code"; } # clinical trial: { no warnings 'uninitialized'; # either original or form params can be undef my $original_trial_id = $self->frozen_data->{trial_id}; if ( $form_data->{trial_id} != $original_trial_id ) { $self->do_clinical_trial_update($form_data); } } # external reference: { no warnings 'uninitialized'; # either original or form param can be undef my $original_external_ref = $self->frozen_data->{external_reference}; if ( $form_data->{external_reference} ne $original_external_ref ) { $self->do_external_ref_update($form_data); } } # trial number: { no warnings 'uninitialized'; # either original or form params can be undef my $original_trial_number = $self->frozen_data->{trial_number}; if ( $form_data->{trial_number} ne $original_trial_number ) { $self->do_trial_number_update($form_data); } } # request_options: { no warnings 'uninitialized'; # any of form params or original data can be undef # get list of all additional options: my $request_options = LIMS::DB::AdditionalOption::Manager->get_additional_options; my $frozen = $self->frozen_data; # warn Dumper $frozen; # hash for new request options: my %new_request_options = (); foreach (@$request_options) { my $option = $_->option_name; # warn Dumper $option; my $original = $frozen->{$option} || ''; $new_request_options{$_->id}{new} = $form_data->{$option}; # 1 or undef $new_request_options{$_->id}{old} = $original; # old value $new_request_options{$_->id}{name} = $option; } if (%new_request_options) { # warn Dumper \%new_request_options; $self->do_request_options_update($form_data, \%new_request_options); } } # request_consent: { no warnings 'uninitialized'; # any of form params or original data can be undef # get list of all additional options: my $request_consent = LIMS::DB::ConsentOption::Manager->get_consent_options; my $frozen = $self->frozen_data; # hash for new request consent: my %new_request_consent = (); foreach (@$request_consent) { my $consent_name = $_->consent_name; $new_request_consent{$_->id}{new} = $form_data->{$consent_name}; # yes, no or undef $new_request_consent{$_->id}{old} = $frozen->{$consent_name}; # old value $new_request_consent{$_->id}{name} = $consent_name; } if (%new_request_consent) { $self->do_request_consent_update($form_data, \%new_request_consent); } } # update error code & history log: $self->do_request_error_code($form_data); $self->do_history_log($form_data); }; #$self->set_rose_debug(1); my $result = $db->do_transaction( $update_request ); #$self->set_rose_debug(0); # return value needs to match format in update_patient_case(): return { error => $db->error ? 'update_request() error - ' . $db->error : undef, success => $result, # true on success, false on failure ( & will set $db->error) } } #------------------------------------------------------------------------------- sub unlock_request { my ($self, $request_id) = @_; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $unlock = sub { my $o = LIMS::DB::Request->new(id => $request_id)->load; =begin # would need to manually reset status to locked, reverted to timestamp: # update request_status: my $status_otions_map = $self->request_status_options_map; my $status_option_id = $status_otions_map->{authorised}->{is_active} eq 'yes' ? $status_otions_map->{authorised}->{id} : $status_otions_map->{reported}->{id}; $o->status_option_id($status_option_id); =cut $o->updated_at($self->time_now); $o->save(changes_only => 1); LIMS::DB::RequestHistory->new( request_id => $request_id, user_id => $self->user_profile->{id}, action => 'unlocked record', )->save; }; #$self->set_rose_debug(1); my $ok = $db->do_transaction($unlock); #$self->set_rose_debug(0); # don't need return value unless error: return $ok ? 0 : 'unlock_request() error - ' . $db->error; } #------------------------------------------------------------------------------- sub delete_request { my $self = shift; my $data = shift; # $self->debug($data); # return; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $request_id = $data->{request_id}; my $request = LIMS::DB::Request->new(id => $request_id) ->load(with => ['patient_case.patient', 'request_report.diagnosis']); my %current_action = ( user_id => $self->user_profile->{id}, time => $self->time_now(), action => sprintf 'deleted record (%s)', $data->{reason}, ); my $delete = sub { # retrieve all history data for archiving before cascade delete: $self->_archive_request_history($request); # warn Dumper $self->archive; # add current action (delete): $self->add_to_archive(\%current_action); # sort archive into datetime order: my @chronological = sort { DateTime->compare($a->{time}, $b->{time}) } $self->archived_data; # warn Dumper \@chronological; # save to deleted_requests table: for my $entry (@chronological) { # warn Dumper $data; LIMS::DB::DeletedRequest->new( request_id => $request_id, request_number => $request->request_number, year => $request->year, action => $entry->{action}, user_id => $entry->{user_id}, time => $entry->{time}, )->save; } LIMS::DB::Request->new(id => $request_id)->delete; # (cascade => 'delete'); using ON DELETE CASCADE in sql }; #$self->set_rose_debug(1); my $ok = $db->do_transaction($delete); #$self->set_rose_debug(0); # don't need return value unless error: return $ok ? 0 : 'delete_request() error - ' . $db->error; } #------------------------------------------------------------------------------- sub get_print_run_request_ids { my ($self, $args) = @_; # start & end datetimes + optional limit & offset my $start = $args->{start}; # DT my $end = $args->{end}; # DT # limt & offset optional: my $offset = $args->{offset}; my $limit = $args->{limit}; my $query = $self->_get_print_run_query($start, $end); my %args = ( query => $query, # arrayref select => [ 'id' ], # only need id's require_objects => [ qw(request_report status_option) ], ); if ($limit) { $args{offset} = $offset; # eg 0, 100, 200 $args{limit} = $limit; } # warn Dumper \%args; return []; my $requests = LIMS::DB::Request::Manager->get_requests(%args); my @request_ids = map { $_->id } @$requests; return \@request_ids; } #------------------------------------------------------------------------------- sub get_print_run_size { my ($self, $start, $end) = @_; # start & end datetimes my $query = $self->_get_print_run_query($start, $end); my %args = ( query => $query, # arrayref require_objects => [ qw(request_report status_option) ], ); my $count = LIMS::DB::Request::Manager->get_requests_count(%args); return $count; } #------------------------------------------------------------------------------- sub _get_print_run_query { my ($self, $start, $end) = @_; # set status level required for printing reports: my $status = $self->does_authorisation() ? 'authorised' : 'reported'; my @query = ( description => [ $status, 'complete' ], # status options # or => [ # and => [ # includes unlocked records - affects updated_at timestamp # 'requests.updated_at' => { ge => $start }, # 'requests.updated_at' => { le => $end }, # ], # and => [ 'request_report.updated_at' => { ge => $start }, 'request_report.updated_at' => { le => $end }, # ], # ], ); return \@query; } #------------------------------------------------------------------------------- sub _archive_request_history { my ($self, $request) = @_; # common to all queries: my %args = ( query => [ request_id => $request->id ] ); { # request error_code: local $args{require_objects} = 'error_code'; # warn Dumper \%args; my $o = LIMS::DB::RequestErrorCode::Manager->get_request_error_codes(%args); for (@$o) { # warn Dumper $_->as_tree; my $data = $self->_format_data_for_archive($_); # format action: $data->{action} = 'recorded error code ' . $_->error_code->code; $self->add_to_archive($data); } } { # request_history: my $o = LIMS::DB::RequestHistory::Manager->get_request_histories(%args); for (@$o) { my $data = $self->_format_data_for_archive($_); # format action: my $action = $_->action; # warn Dumper $data; if ($action eq 'reported') { # get diagnosis: $action .= sprintf ' (diagnosis = %s)', $request->request_report->diagnosis->name; } elsif ($action eq 'registered') { my $patient = $request->patient_case->patient; $action .= sprintf ' (%s, %s, %s)', $patient->last_name, $patient->first_name, $patient->dob ? $patient->dob->ymd : 'NULL'; } $data->{action} = $action; $self->add_to_archive($data); } } { # request_diagnosis_history: local $args{require_objects} = 'diagnosis'; my $o = LIMS::DB::RequestDiagnosisHistory::Manager ->get_request_diagnosis_histories(%args); for (@$o) { my $data = $self->_format_data_for_archive($_); # format action: $data->{action} = sprintf 'amended diagnosis = %s; reason = %s', $_->diagnosis->name, $_->reason; $self->add_to_archive($data); } } { # request_phonelog: my $o = LIMS::DB::RequestPhoneLog::Manager->get_request_phone_log(%args); for (@$o) { my $data = $self->_format_data_for_archive($_); # format action: $data->{action} = join '; ', $_->status, $_->contact, $_->details; $self->add_to_archive($data); } } } #------------------------------------------------------------------------------- # returns common data items user_id & time: sub _format_data_for_archive { my $self = shift; my $data = shift; my %data = ( user_id => $data->user_id, time => $data->time, ); return \%data; } #------------------------------------------------------------------------------- sub update_patient_case { =begin # how it works: scope determines whether to apply change to single record (default) or to all records. 1) Get a new patient_case.id - 'use_patient_case_id' param if submitted, otherwise find existing combination of submitted patient_id, referral_source_id & unit_number in patient_case table, or create a new patient_case. 2) If scope = all (or if only 1 record attached to patient_case), change all instances of requests.patient_case_id to new value & delete old patient_case entry 3) If scope = single record, just change patient_case_id for single request.id 4) If referral_source is changed, requests.referrer_department_id may be incorrect, so unless parent_organisation is same as old, requests.referrer_department_id is updated to a new one if found, or to the entry corresponding to unknown referrer (clinician or gp, if not already), pending referrer change. =cut my ($self, $form_data) = @_; # warn 'form_data:'; warn Dumper $form_data; # return; # get original data from session (and store it in $self->frozen_data): my $original_data = $self->_get_original_data; # warn 'orginal_data:'; warn Dumper $original_data; my $db = $self->lims_db; # ie LIMS::DB->new_or_cached; my $i = 0; # successful updates counter my $update_patient_case = sub { # get new patient_case_id: my $new_patient_case_id = $self->_get_new_patient_case_id($form_data) || die 'no patient_case_id returned by _get_new_patient_case_id()'; # protect against old patient_case_id == new patient_case_id, where 'old' # patient_case gets deleted if scope set to 'all': return 0 unless $new_patient_case_id != $original_data->{patient_case_id}; if ($form_data->{scope} eq 'all') { # warn 'all'; { # update requests table: my %args = ( set => { patient_case_id => $new_patient_case_id }, where => [ patient_case_id => $original_data->{patient_case_id} ], ); $i += LIMS::DB::Request::Manager->update_requests(%args); } { # delete old patient_case: my $patient_case_id = $original_data->{patient_case_id}; LIMS::DB::PatientCase->new(id => $patient_case_id)->delete(); } } else { # just update single record: my $o = LIMS::DB::Request->new(id => $form_data->{_request_id})->load; $o->patient_case_id($new_patient_case_id); # warn 'one'; $i += 1 if $o->save(changes_only => 1); # $i gets memory address on success ?? } # might need to update referrer department if new referral source submitted: if ( my $new_referral_source_id = $form_data->{referral_source_id} ) { if ( $new_referral_source_id != $original_data->{referral_source_id} ) { $self->do_referrer_department_update($form_data); } } $self->do_patient_case_history($form_data); }; #$self->set_rose_debug(1); # this method differs from the usual do_transaction(), which returns 0 on # error and 1 on success, even if coderef exits early; not interested in # return value now, only number of successful updates, which gets returned to # controller, along with $db->error (if any): $db->do_transaction($update_patient_case); # warn $i; # warn Dumper $db->error; # or can do: $db->do_transaction( sub { $result = $update_patient_case->() } ); #$self->set_rose_debug(0); # return hashref of db error (if any), and numerical value of success (updates count): return { error => $db->error ? 'update_patient_case() error - ' . $db->error : undef, success => $i, } } #------------------------------------------------------------------------------- sub get_first_request_date { my $self = shift; my $first_request = LIMS::DB::Request->new(id => 1)->load(speculative => 1); $first_request->created_at if $first_request; } #------------------------------------------------------------------------------- sub _get_new_patient_case_id { my ($self, $form_data) = @_; # patient_case_id might be submitted by 'use this' radio button: my $patient_case_id = $form_data->{use_patient_case_id} || ''; # if $form_data patient_case_id used, original values are submitted in form # fields so need to get new values into $form_data to replace original ones: if ($patient_case_id) { my $patient_case = LIMS::DB::PatientCase->new(id => $patient_case_id) ->load(with => 'referral_source'); map { $form_data->{$_} = $patient_case->$_; } qw(unit_number referral_source_id); $form_data->{_location_name} = $patient_case->referral_source->display_name; } # if we don't already have a patient_case_id, go and get one: else { # find matching patient_case, or create new: my $patient_case = $self->get_patient_case($form_data); $patient_case_id = $patient_case->id; } return $patient_case_id; } #------------------------------------------------------------------------------- sub _get_original_data { my $self = shift; # put original data into frozen_data(): my $original_data = $self->session_data('_request_edit_data'); $self->frozen_data($original_data); # warn Dumper $original_data->{_data}; =begin # don't do this - causes fatal error if back button used & then data resubmitted # clear session data (not required as it's overwritten anyway, but tidier): # $self->clear_data('_request_edit_data'); =cut return $original_data; } #------------------------------------------------------------------------------- sub _verify_request_exists { my ($self, $request_id) = @_; # warn $request_id; my @q = (id => $request_id); return LIMS::DB::Request::Manager->get_requests_count( query => \@q ); } #------------------------------------------------------------------------------- sub _get_request_data { my $self = shift; my $data = shift; # get referrer_department.id for supplied referral source & referrer code: my $referrer_department = $self->_get_referrer_department($data); $data->{referrer_department_id} = $referrer_department->id; my %request_data = map { $_ => $data->{$_}; } qw( request_number patient_case_id referrer_department_id ); # current year: # $request_data{year} = DateTime->now->year; # done by DB::Request meta data =begin # not using this method anymore { # check for previously deleted request_number/year combination, if so use request.id: my %args = ( request_number => $data->{request_number}, year => DateTime->now->year, ); #$self->set_rose_debug(1); my $deleted_request = LIMS::DB::DeletedRequest->new(%args)->load(speculative => 1); #$self->set_rose_debug(0); if ($deleted_request) { $request_data{id} = $deleted_request->request_id; } } =cut return \%request_data; } #------------------------------------------------------------------------------- sub _get_referrer_department { my $self = shift; my $data = shift; # warn Dumper $data; my $referrer = LIMS::DB::Referrer->new(national_code => $data->{referrer_code})->load; my $referral_source = LIMS::DB::ReferralSource->new(id => $data->{referral_source_id}) ->load(with => 'referral_type'); # get referral_type for possible use later; # get referrer_department for supplied referral source & referrer code: my %args = ( referrer_id => $referrer->id, parent_organisation_id => $referral_source->parent_organisation_id, ); my $referrer_department = LIMS::DB::ReferrerDepartment->new(%args)->load(speculative => 1); # if no $referrer_department, get referrer_department.id for unknown referrer of correct type: if (! $referrer_department ) { # warn 'here'; # get map between referral_type.id & referrer_department.id for unknown locations: my $referral_type_map = $self->referral_type_map; # warn Dumper $referral_type_map; # get id of default referrer_department for this location type (hospital or practice): my $referrer_department_id = $referral_type_map->{$referral_source->referral_type_id}; $referrer_department = LIMS::DB::ReferrerDepartment ->new(id => $referrer_department_id)->load; # warn Dumper $referrer_department->as_tree; } return $referrer_department; } #------------------------------------------------------------------------------- sub _build_request_status_options_map { my $self = shift; my $status_options = LIMS::DB::StatusOption::Manager->get_status_options; my %map = map { $_->description => $_->as_tree; } @$status_options; # warn Dumper \%map; return \%map; } #------------------------------------------------------------------------------- # creates map between referral_type.id and referrer_department.id for unknown locations: sub _build_referral_type_map { my $self = shift; my %args = ( # using 2 custom relationships in ReferralType & ParentOrg classes: require_objects => 'unknown_parent_org.unknown_referrer_department', ); # get referral_types: my $referral_types = LIMS::DB::ReferralType::Manager->get_referral_types(%args); =begin # effective sql for ReferralType::Manager->get_referral_types(): SELECT t1.id as 'referral_type_id', t3.id as 'referrer_department_id' FROM referral_types t1 JOIN parent_organisations t2 ON (t1.default_unknown = t2.parent_code) JOIN referrer_department t3 ON (t2.id = t3.parent_organisation_id) =cut # create map: my %referral_type_map = map { $_->id => $_->unknown_parent_org->unknown_referrer_department->id; } @$referral_types; # warn Dumper \%referral_type_map; return \%referral_type_map; } #------------------------------------------------------------------------------- # warning: method of same name exists in C::Roles::DataMap # returns hash of arrayrefs sub _build_specimen_lab_test_map { my $self = shift; my $o = $self->get_objects('SpecimenLabTest'); my %map; for (@$o) { my $specimen_id = $_->specimen_id; # warn $specimen_id; my $lab_test_id = $_->lab_test_id; # warn $lab_test_id; push @{ $map{$specimen_id} }, $lab_test_id; } # warn Dumper \%map; return \%map; } #------------------------------------------------------------------------------- # *** method of similar name in Role::RequestUpdate *** sub _get_clinical_trial_data { my $self = shift; my $data = shift; # no need for db access if no trial_id: return unless $data->{trial_id}; my $patient_case = LIMS::DB::PatientCase->new( id => $data->{patient_case_id} )->load; my %trial_data = ( trial_id => $data->{trial_id}, trial_number => $data->{trial_number}, patient_id => $patient_case->patient_id, ); return \%trial_data; } 1; __END__ multi_many_ok is used to suppress: WARNING: Fetching sub-objects via more than one "one to many" relationship in a single query may produce many redundant rows, and the query may be slow. If you're sure you want to do this, you can silence this warning by using the "multi_many_ok" parameter