From: Bill Erickson Date: Thu, 12 Mar 2020 16:40:18 +0000 (-0400) Subject: SIP2Mediator experiment: item info WIP X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=70726756edf23003e343b6553cf849b3156dc676;p=working%2FEvergreen.git SIP2Mediator experiment: item info WIP Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm index f614505e94..a92f473a14 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm @@ -12,6 +12,9 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # --------------------------------------------------------------- +# Code borrows heavily and sometimes copies directly from from +# ../SIP* and SIPServer* +# --------------------------------------------------------------- package OpenILS::WWW::SIP2Mediator; use strict; use warnings; use Apache2::Const -compile => @@ -27,6 +30,7 @@ use OpenILS::Utils::CStoreEditor q/:funcs/; use OpenSRF::Utils::Logger q/$logger/; use OpenILS::Application::AppUtils; use OpenILS::Utils::DateTime qw/:datetime/; +use OpenILS::Const qw/:const/; my $U = 'OpenILS::Application::AppUtils'; my $cache; @@ -35,6 +39,8 @@ my $json = JSON::XS->new; $json->ascii(1); $json->allow_nonref(1); +my $SIP_DATE_FORMAT = "%Y%m%d %H%M%S"; + my $config = { # TODO: move to external config / database settings options => { # Allow 99 (sc status) message before successful 93 (login) message @@ -67,7 +73,9 @@ my $config = { # TODO: move to external config / database settings 'Y', # renew, 'N', # renew all, ], - options => {} + options => { + due_date_use_sip_date_format => 0 + } }] }; @@ -90,8 +98,8 @@ sub init { } sub sipdate { - my $now = DateTime->now; - return $now->strftime("%Y%m%d %H%M%S"); + my $date = shift || DateTime->now; + return $date->strftime($SIP_DATE_FORMAT); } sub handler { @@ -101,7 +109,8 @@ sub handler { init(); my $seskey = $cgi->param('session'); - my $message = $json->decode($cgi->param('message')); + my $msg_json = $cgi->param('message'); + my $message = $json->decode($msg_json); my $msg_code = $message->{code}; my $response; @@ -110,6 +119,8 @@ sub handler { $response = handle_login($seskey, $message); } elsif ($msg_code eq '99') { $response = handle_sc_status($seskey, $message); + } elsif ($msg_code eq '17') { + $response = handle_item_info($seskey, $message); } unless ($response) { @@ -127,23 +138,28 @@ sub handler { sub get_field_value { my ($message, $code) = @_; for my $field (@{$message->{fields}}) { - my ($c, $v) = each(%$field); # one key/value pair per field - return $v if $c eq $code; + while (my ($c, $v) = each(%$field)) { # one pair per field + return $v if $c eq $code; + } } return undef; } +sub get_inst_config { + my $institution = shift; + my ($instconf) = grep {$_->{id} eq $institution} @{$config->{institutions}}; + return $instconf; +} + +# Returns account object if found, undef otherwise. sub get_auth_account { my ($seskey) = @_; my $account = $cache->get_cache("sip2_$seskey"); + return $account if $account; - if ($account) { - return $account->{authtoken}; - } else { - $logger->info("SIP2 no cached session for seskey=$seskey"); - return undef; - } + $logger->info("SIP2 has no cached session for seskey=$seskey"); + return undef; } # Logs in to Evergreen and caches the authtoken with the SIP account. @@ -198,7 +214,6 @@ sub handle_login { return $response; } -# NOTE: response should be modified as message handlers are implemented. sub handle_sc_status { my ($seskey, $message) = @_; @@ -210,8 +225,8 @@ sub handle_sc_status { # The SC Status message does not include an institution, but expects # one in return. Use the configuration for the first institution. # Maybe the SIP server itself should track which institutoin its - # instance is configured to use. That may multiple servers could, - # one per institution. + # instance is configured to use? That may multiple servers could + # run, one per institution. my $instconf = $config->{institutions}->[0]; my $instname = $instconf->{id}; @@ -236,4 +251,146 @@ sub handle_sc_status { } } +sub handle_item_info { + my ($seskey, $message) = @_; + + my $institution = get_field_value($message, 'AO'); + my $barcode = get_field_value($message, 'AB'); + my $instconf = get_inst_config($institution); + my $item_details = get_item_details($barcode, $instconf); + + my $response = {code => '18'}; + + if (!$item_details) { + # No matching item found, return a vague, minimal response. + $response->{fixed_fields} = ['01', '01', '01', sipdate()]; + $response->{fields} = [{AB => $barcode, AJ => ''}]; + return $response; + }; + + $response->{fixed_fields} = [ + $item_details->{circ_status}, + '02', # Security Marker, consistent with ../SIP* + $item_details->{fee_type}, + sipdate() + ]; + + $response->{fields} = [ + {AB => $barcode}, + {AJ => $item_details->{title}}, + {CF => $item_details->{hold_queue_length}}, + {AH => $item_details->{due_date}} + ]; + + return $response; +} + +sub get_item_details { + my ($barcode, $instconf) = @_; + my $e = new_editor(); + + my $item = $e->search_asset_copy([{ + barcode => $barcode, + deleted => 'f' + }, { + flesh => 3, + flesh_fields => { + acp => [qw/circ_lib call_number status stat_cat_entry_copy_maps/], + acn => [qw/owning_lib record/], + bre => [qw/flat_display_entries/], + ascecm => [qw/stat_cat stat_cat_entry/], + } + }])->[0]; + + return undef unless $item; + + my $details = {item => $item}; + + $details->{circ} = $e->search_action_circulation([{ + target_copy => $item->id, + checkin_time => undef, + '-or' => [ + {stop_fines => undef}, + {stop_fines => [qw/MAXFINES LONGOVERDUE/]}, + ] + }, { + flesh => 2, + flesh_fields => {circ => ['usr'], au => ['card']} + }])->[0]; + + if ($item->status->id == OILS_COPY_STATUS_IN_TRANSIT) { + $details->{transit} = $e->search_action_transit_copy([{ + target_copy => $item->id, + dest_recv_time => undef, + cancel_time => undef + },{ + flesh => 1, + flesh_fields => {atc => ['dest']} + }])->[0]; + } + + if ($item->status->id == OILS_COPY_STATUS_ON_HOLDS_SHELF || ( + $details->{transit} && + $details->{transit}->copy_status == OILS_COPY_STATUS_ON_HOLDS_SHELF)) { + + $details->{hold} = $e->search_action_hold_request([{ + current_copy => $item->id, + capture_time => {'!=' => undef}, + cancel_time => undef, + fulfillment_time => undef + }, { + limit => 1, + flesh => 1, + flesh_fields => {ahr => ['pickup_lib']} + }])->[0]; + } + + my ($title_entry) = grep {$_->name eq 'title'} + @{$item->call_number->record->flat_display_entries}; + + $details->{title} = $title_entry ? $title_entry->value : ''; + + # Same as ../SIP* + $details->{hold_queue_length} = $details->{hold} ? 1 : 0; + + $details->{circ_status} = circulation_status($item->status->id); + + $details->{fee_type} = + ($item->deposit_amount > 0.0 && $item->deposit eq 'f') ? '06' : '01'; + + if ($details->{circ}) { + + my $due_date = DateTime::Format::ISO8601->new-> + parse_datetime(clean_ISO8601($details->{circ}->due_date)); + + $details->{due_date} = + $instconf->{due_date_use_sip_date_format} ? + sipdate($due_date) : + $due_date->strftime('%F %T'); + } + + return $details; +} + +# Maps item status to SIP circulation status constants. +sub circulation_status { + my $stat = shift; + + return '02' if $stat == OILS_COPY_STATUS_ON_ORDER; + return '03' if $stat == OILS_COPY_STATUS_AVAILABLE; + return '04' if $stat == OILS_COPY_STATUS_CHECKED_OUT; + return '06' if $stat == OILS_COPY_STATUS_IN_PROCESS; + return '08' if $stat == OILS_COPY_STATUS_ON_HOLDS_SHELF; + return '09' if $stat == OILS_COPY_STATUS_RESHELVING; + return '10' if $stat == OILS_COPY_STATUS_IN_TRANSIT; + return '12' if ( + $stat == OILS_COPY_STATUS_LOST || + $stat == OILS_COPY_STATUS_LOST_AND_PAID + ); + return '13' if $stat == OILS_COPY_STATUS_MISSING; + + return '01'; +} + + 1;