From: Bill Erickson Date: Tue, 1 Sep 2020 21:56:39 +0000 (-0400) Subject: SIP2Mediator patron status; hold items list X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=c379d96b572a558eb40e42a3317d65036d2840f5;p=working%2FEvergreen.git SIP2Mediator patron status; hold items list Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway.pm index 294ba62042..ea6d69ba78 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway.pm @@ -276,10 +276,12 @@ sub handler { return Apache2::Const::FORBIDDEN unless $session; - if ($msg_code eq '63') { - $response = handle_patron_info($session, $message); - } elsif ($msg_code eq '17') { + if ($msg_code eq '17') { $response = handle_item_info($session, $message); + } elsif ($msg_code eq '23') { + $response = handle_patron_status($session, $message); + } elsif ($msg_code eq '63') { + $response = handle_patron_info($session, $message); } } @@ -294,6 +296,7 @@ sub handler { return Apache2::Const::OK; } + # Returns the value of the first occurrence of the requested SIP code. sub get_field_value { my ($message, $code) = @_; @@ -477,9 +480,76 @@ sub handle_patron_info { summary_list_items => patron_summary_list_items($summary) ); + my $response = patron_response_common_data( + $session, $institution, $barcode, $password, $pdetails); + + $response->{code} = '64'; + + return $response unless $pdetails; + + push( + @{$response->{fixed_fields}}, + count4($pdetails->{holds_count}), + count4($pdetails->{overdue_count}), + count4($pdetails->{out_count}), + count4($pdetails->{fine_count}), + count4($pdetails->{recall_count}), + count4($pdetails->{unavail_holds_count}) + ); + + # TODO: Add + # overdue items AT variable-length optional field (this field should be sent for each overdue item). + # charged items AU variable-length optional field (this field should be sent for each charged item). + # fine items AV variable-length optional field (this field should be sent for each fine item). + # recall items BU variable-length optional field (this field should be sent for each recall item). + # unavailable hold items CD variable-length optional field (this field should be sent for each unavailable hold item). + + my $list_items = patron_summary_list_items($summary) || ''; + + if ($list_items eq 'hold_items') { + for my $hold (@{$pdetails->{hold_items}}) { + push(@{$response->{fields}}, {AS => $hold}); + } + } + + return $response; +} + +sub handle_patron_status { + my ($session, $message) = @_; + my $sip_account = $session->sip_account; + + my $institution = get_field_value($message, 'AO'); + my $barcode = get_field_value($message, 'AA'); + my $password = get_field_value($message, 'AD'); + my $instconf = get_inst_config($institution) || return undef; + + my $pdetails = OpenILS::WWW::SIP2Gateway::Patron->get_patron_details( + session => $session, + instconf => $instconf, + barcode => $barcode, + password => $password + ); + + my $response = patron_response_common_data( + $session, $institution, $barcode, $password, $pdetails); + + $response->{code} = '24'; + + return $response; +} + +# Patron Info and Patron Status responses share mostly the same data. +# This returns the base data which can be augmented as needed. +# Note we don't call Patron->get_patron_details here since different +# messages collect different amounts of data. +sub patron_response_common_data { + my ($session, $institution, $barcode, $password, $pdetails) = @_; + if (!$pdetails) { + # No such user. Return a stub response with all things denied. + return { - code => '64', fixed_fields => [ spacebool(1), # charge denied spacebool(1), # renew denied @@ -497,9 +567,8 @@ sub handle_patron_info { ] }; } - + return { - code => '64', fixed_fields => [ spacebool($pdetails->{charge_denied}), spacebool($pdetails->{renew_denied}), @@ -516,24 +585,18 @@ sub handle_patron_info { spacebool(0), # recall overdue spacebool($pdetails->{too_many_fines}), '000', # language - sipdate(), - count4($pdetails->{holds_count}), - count4($pdetails->{overdue_count}), - count4($pdetails->{out_count}), - count4($pdetails->{fine_count}), - count4($pdetails->{recall_count}), - count4($pdetails->{unavail_holds_count}), + sipdate() ], fields => [ {AO => $institution}, {AA => $barcode}, - {BL => sipbool(1)}, # valid patron - {CQ => sipbool($password)} # password verified if exists + {BL => sipbool(1)}, # valid patron + {BV => $pdetails->{balance_owed}}, # fee amount + {CQ => sipbool($password)} # password verified if exists ] }; } - # Determines which class of data the SIP client wants detailed # information on in the patron info request. sub patron_summary_list_items { diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway/Patron.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway/Patron.pm index 8396154a57..ed9bc9a3a0 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway/Patron.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/SIP2Gateway/Patron.pm @@ -74,7 +74,11 @@ sub get_patron_details { grep {$_->{id} == OILS_PENALTY_PATRON_EXCEEDS_FINES} @$penalties; + my $summary = $e->retrieve_money_open_user_summary($patron->id); + $details->{balance_owed} = ($summary) ? $summary->balance_owed : 0; + set_patron_summary_items($session, $instconf, $details, %params); + set_patron_summary_list_items($session, $instconf, $details, %params); return $details; } @@ -91,28 +95,16 @@ sub set_patron_summary_items { my ($session, $instconf, $details, %params) = @_; my $patron = $details->{patron}; - my $start_item = $params{summary_start_item} || 0; - my $end_item = $params{summary_end_item} || 10; - my $list_items = $params{summary_list_items}; - my $e = new_editor(); - my $holds_where = { - usr => $patron->id, - fulfillment_time => undef, - cancel_time => undef - }; + $details->{recall_count} = 0; # not supported - $holds_where->{current_shelf_lib} = {'=' => {'+ahr' => 'pickup_lib'}} - if $instconf->{msg64_hold_items_available}; + my $hold_ids = get_hold_ids($e, $instconf, $patron); + $details->{holds_count} = scalar(@$hold_ids); - my $hold_ids = $e->json_query({ - select => {ahr => ['id']}, - from => 'ahr', - where => {'+ahr' => $holds_where} - }); + my $unavail_hold_ids = get_hold_ids($e, $instconf, $patron, 1); + $details->{unavail_holds_count} = scalar(@$unavail_hold_ids); - $details->{holds_count} = scalar(@$hold_ids); $details->{overdue_count} = 0; $details->{out_count} = 0; @@ -124,8 +116,6 @@ sub set_patron_summary_items { $details->{out_count} = scalar(@$out_ids) + scalar(@$overdue_ids); } - $details->{recall_count} = undef; # not supported - my $xacts = $U->simplereq( 'open-ils.actor', 'open-ils.actor.user.transactions.history.have_balance', @@ -134,10 +124,129 @@ sub set_patron_summary_items { ); $details->{fine_count} = scalar(@$xacts); +} + +sub get_hold_ids { + my ($e, $instconf, $patron, $unavail, $offset, $limit) = @_; + + my $holds_where = { + usr => $patron->id, + fulfillment_time => undef, + cancel_time => undef + }; + + if ($unavail) { + $holds_where->{'-or'} = [ + {current_shelf_lib => undef}, + {current_shelf_lib => {'!=' => {'+ahr' => 'pickup_lib'}}} + ]; + + } else { + + $holds_where->{current_shelf_lib} = {'=' => {'+ahr' => 'pickup_lib'}} + if $instconf->{msg64_hold_items_available}; + } + + my $query = { + select => {ahr => ['id']}, + from => 'ahr', + where => {'+ahr' => $holds_where} + }; + + $query->{offset} = $offset if $offset; + $query->{limit} = $limit if $limit; - # TODO: unavail holds count; summary details request + my $id_hashes = $e->json_query($query); + + return [map {$_->{id}} @$id_hashes]; +} + +sub set_patron_summary_list_items { + my ($session, $instconf, $details, %params) = @_; + my $e = new_editor(); + + my $list_items = $params{summary_list_items}; + my $offset = $params{summary_start_item} || 0; + my $end_item = $params{summary_end_item} || 10; + my $limit = $end_item - $offset; + + add_hold_items($e, $session, $instconf, $details, $offset, $limit) + if $list_items eq 'hold_items'; } +sub add_hold_items { + my ($e, $session, $instconf, $details, $offset, $limit) = @_; + + my $patron = $details->{patron}; + my $format = $instconf->{msg64_hold_datatype} || ''; + my $hold_ids = get_hold_ids($e, $instconf, $patron, 0, $offset, $limit); + + my @hold_items; + for my $hold_id (@$hold_ids) { + my $hold = $e->retrieve_action_hold_request($hold_id); + + if ($format eq 'barcode') { + my $copy = find_copy_for_hold($e, $hold); + push(@hold_items, $copy->barcode) if $copy; + } else { + my $title = find_title_for_hold($e, $hold); + push(@hold_items, $title) if $title; + } + } + + $details->{hold_items} = \@hold_items; +} + +# Hold -> reporter.hold_request_record -> display field for title. +sub find_title_for_hold { + my ($e, $hold) = @_; + + my $bib_link = $e->retrieve_reporter_hold_request_record($hold->id); + + my $title_field = $e->search_metabib_flat_display_entry({ + source => $bib_link->bib_record, name => 'title'})->[0]; + + return $title_field ? $title_field->value : ''; +} + +# Finds a representative copy for the given hold. If no copy exists at +# all, undef is returned. The only limit placed on what constitutes a +# "representative" copy is that it cannot be deleted. Otherwise, any +# copy that allows us to find the hold later is good enough. +sub find_copy_for_hold { + my ($e, $hold) = @_; + + return $e->retrieve_asset_copy($hold->current_copy) + if $hold->current_copy; + + return $e->retrieve_asset_copy($hold->target) + if $hold->hold_type =~ /C|R|F/; + + return $e->search_asset_copy([ + {call_number => $hold->target, deleted => 'f'}, + {limit => 1}])->[0] if $hold->hold_type eq 'V'; + + my $bre_ids = [$hold->target]; + + if ($hold->hold_type eq 'M') { + # find all of the bibs that link to the target metarecord + my $maps = $e->search_metabib_metarecord_source_map( + {metarecord => $hold->target}); + $bre_ids = [map {$_->record} @$maps]; + } + + my $vol_ids = $e->search_asset_call_number( + {record => $bre_ids, deleted => 'f'}, + {idlist => 1} + ); + + return $e->search_asset_copy([ + {call_number => $vol_ids, deleted => 'f'}, + {limit => 1} + ])->[0]; +} + + sub set_patron_privileges { my ($session, $instconf, $details, $penalties) = @_; my $patron = $details->{patron}; @@ -146,8 +255,7 @@ sub set_patron_privileges { ->parse_datetime(clean_ISO8601($patron->expire_date)); if ($expire < DateTime->now) { - $logger->info( - "SIP2 Patron account is expired; all privileges blocked"); + $logger->info("SIP2 Patron account is expired; all privileges blocked"); $details->{charge_denied} = 1; $details->{recall_denied} = 1; $details->{renew_denied} = 1;