# 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 =>
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;
$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
'Y', # renew,
'N', # renew all,
],
- options => {}
+ options => {
+ due_date_use_sip_date_format => 0
+ }
}]
};
}
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 {
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;
$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) {
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.
return $response;
}
-# NOTE: response should be modified as message handlers are implemented.
sub handle_sc_status {
my ($seskey, $message) = @_;
# 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};
}
}
+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;