SIP2Mediator experiment: item info WIP
authorBill Erickson <berickxx@gmail.com>
Thu, 12 Mar 2020 16:40:18 +0000 (12:40 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 28 Oct 2020 18:57:39 +0000 (14:57 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Mediator.pm

index f614505..a92f473 100644 (file)
@@ -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;