LP1901930 Hold cancel support
authorBill Erickson <berickxx@gmail.com>
Wed, 4 Nov 2020 20:36:01 +0000 (15:36 -0500)
committerBill Erickson <berickxx@gmail.com>
Mon, 30 Nov 2020 16:38:26 +0000 (08:38 -0800)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Checkout.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Hold.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Item.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Patron.pm

index 38cc2f8..240ea7c 100644 (file)
@@ -13,6 +13,7 @@ use OpenILS::Utils::DateTime qw/:datetime/;
 use OpenILS::Application::SIP2::Common;
 use OpenILS::Application::SIP2::Session;
 use OpenILS::Application::SIP2::Item;
+use OpenILS::Application::SIP2::Hold;
 use OpenILS::Application::SIP2::Patron;
 use OpenILS::Application::SIP2::Checkout;
 use OpenILS::Application::SIP2::Checkin;
@@ -69,6 +70,7 @@ sub dispatch_sip2_request {
     my $MESSAGE_MAP = {
         '09' => \&handle_checkin,
         '11' => \&handle_checkout,
+        '15' => \&handle_hold,
         '17' => \&handle_item_info,
         '23' => \&handle_patron_status,
         '29' => \&handle_renew,
@@ -391,20 +393,12 @@ sub patron_response_common_data {
 
 sub handle_checkout {
     my ($session, $message) = @_;
-
-    my ($msg, $details) = checkout_renew_common($session, $message);
-
-    # No modifications required
-    return $msg;
+    return checkout_renew_common($session, $message);
 }
 
 sub handle_renew {
     my ($session, $message) = @_;
-
-    my ($msg, $details) = checkout_renew_common($session, $message, 1);
-
-    # No modifications required
-    return $msg;
+    return checkout_renew_common($session, $message, 1);
 }
 
 sub checkout_renew_common {
@@ -415,17 +409,8 @@ sub checkout_renew_common {
     my $item_barcode = $SC->get_field_value($message, 'AB');
     my $fee_ack = $SC->get_field_value($message, 'BO');
 
-    my $item_details = OpenILS::Application::SIP2::Item->get_item_details(
-        $session, barcode => $item_barcode
-    );
-
-    my $patron_details = OpenILS::Application::SIP2::Patron->get_patron_details(
-        $session, barcode => $patron_barcode
-    );
-
     my $code = $is_renewal ? '30' : '12';
-
-    return ({
+    my $stub = {
         code => $code,
         fixed_fields => [
             0,                  # checkout ok
@@ -438,7 +423,17 @@ sub checkout_renew_common {
             {AA => $patron_barcode},
             {AB => $item_barcode}
         ]
-    }) unless ($item_details && $patron_details);
+    };
+
+    my $item_details = OpenILS::Application::SIP2::Item->get_item_details(
+        $session, barcode => $item_barcode);
+
+    return $stub unless $item_details;
+
+    my $patron_details = OpenILS::Application::SIP2::Patron->get_patron_details(
+        $session, barcode => $patron_barcode);
+    
+    return $stub unless $patron_details;
 
     my $circ_details = OpenILS::Application::SIP2::Checkout->checkout(
         $session, 
@@ -460,7 +455,7 @@ sub checkout_renew_common {
             && $circ->renewal_remaining > 0;
     }
 
-    return ({
+    return {
         code => $code,
         fixed_fields => [
             $circ ? 1 : 0,              # checkout ok
@@ -482,7 +477,7 @@ sub checkout_renew_common {
             $circ       ? {BK => $circ->id}     : (),
             $deposit    ? {BV => $deposit}      : (),
         ]
-    }, $circ_details);
+    };
 }
 
 sub handle_renew_all {
@@ -492,11 +487,7 @@ sub handle_renew_all {
     my $patron_barcode = $SC->get_field_value($message, 'AA');
     my $fee_ack = $SC->get_field_value($message, 'BO');
 
-    my $patron_details = OpenILS::Application::SIP2::Patron->get_patron_details(
-        $session, barcode => $patron_barcode
-    );
-
-    return {
+    my $stub = {
         code => '66',
         fixed_fields => [
             0,              # ok
@@ -508,7 +499,12 @@ sub handle_renew_all {
             {AA => $patron_barcode},
             {AO => $config->{institution}},
         ]
-    } unless $patron_details;
+    };
+
+    my $patron_details = OpenILS::Application::SIP2::Patron->get_patron_details(
+        $session, barcode => $patron_barcode);
+
+    return $stub unless $patron_details;
 
     my $circ_details = OpenILS::Application::SIP2::Checkout->renew_all(
         $session, $patron_details, fee_ack => $fee_ack
@@ -547,11 +543,7 @@ sub handle_checkin {
     my $current_loc = $SC->get_field_value($message, 'AP');
     my $return_date = $fixed_fields[2];
 
-    my $item_details = OpenILS::Application::SIP2::Item->get_item_details(
-        $session, barcode => $item_barcode
-    );
-
-    return {
+    my $stub = {
         code => '10',
         fixed_fields => [
             0,                  # checkin ok
@@ -565,7 +557,12 @@ sub handle_checkin {
             {AO => $config->{institution}},
             {CV => '00'} # unkown alert type
         ]
-    } unless $item_details;
+    };
+
+    my $item_details = OpenILS::Application::SIP2::Item->get_item_details(
+        $session, barcode => $item_barcode);
+
+    return $stub unless $item_details;
 
     my $checkin_details = OpenILS::Application::SIP2::Checkin->checkin(
         $session, 
@@ -610,6 +607,73 @@ sub handle_checkin {
     };
 }
 
+sub handle_hold {
+    my ($session, $message) = @_;
+    my $config = $session->config;
+
+    my @fixed_fields = @{$message->{fixed_fields} || []};
+    my $hold_mode = $fixed_fields[0];
+
+    my $patron_barcode = $SC->get_field_value($message, 'AA');
+    my $item_barcode = $SC->get_field_value($message, 'AB');
+
+    my $stub = {
+        code => '16',
+        fixed_fields => [
+            0, # ok
+            0, # available
+            $SC->sipdate
+        ],
+        fields => [
+            {AA => $patron_barcode},
+            {AB => $item_barcode},
+            {AO => $config->{institution}}
+        ]
+    };
+
+    # Hold Cancel is the only supported action.
+    return $stub unless $hold_mode eq '-';
+
+    my $patron_details = 
+        OpenILS::Application::SIP2::Patron->get_patron_details(
+        $session, barcode => $patron_barcode);
+
+    return $stub unless $patron_details;
+
+    my $item_details = OpenILS::Application::SIP2::Item->get_item_details(
+        $session, barcode => $item_barcode);
+
+    return $stub unless $item_details;
+
+    my $hold = OpenILS::Application::SIP2::Hold->hold_from_copy(
+        $session, $patron_details, $item_details);
+
+    return $stub unless $hold;
+
+    my $details = OpenILS::Application::SIP2::Hold->cancel($session, $hold);
+
+    return $stub unless $details->{ok};
+    
+    # report info on the targeted copy if one is set.
+    my $copy = $hold->current_copy || $item_details->{item};
+    my $title_id = $item_details->{item}->call_number->record->id;
+
+    return {
+        code => '16',
+        fixed_fields => [
+            1, # ok
+            0, # available
+            $SC->sipdate
+        ],
+        fields => [
+            {AA => $patron_barcode},
+            {AB => $copy->barcode},
+            {AJ => $title_id},
+            {AO => $config->{institution}}
+        ]
+    };
+}
+
 sub handle_payment {
     my ($session, $message) = @_;
     my $config = $session->config;
index 2c6f33a..a739d0d 100644 (file)
@@ -2,14 +2,10 @@ package OpenILS::Application::SIP2::Checkout;
 use strict; use warnings;
 use DateTime;
 use DateTime::Format::ISO8601;
-use OpenSRF::System;
-use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenILS::Utils::DateTime qw/:datetime/;
 use OpenSRF::Utils::Logger q/$logger/;
 use OpenILS::Application::AppUtils;
-use OpenILS::Utils::DateTime qw/:datetime/;
-use OpenILS::Const qw/:const/;
 use OpenILS::Application::SIP2::Common;
-use OpenILS::Application::SIP2::Session;
 my $U = 'OpenILS::Application::AppUtils';
 my $SC = 'OpenILS::Application::SIP2::Common';
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Hold.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Hold.pm
new file mode 100644 (file)
index 0000000..3cb3edd
--- /dev/null
@@ -0,0 +1,78 @@
+package OpenILS::Application::SIP2::Hold;
+use strict; use warnings;
+use OpenSRF::Utils::Logger q/$logger/;
+use OpenILS::Application::AppUtils;
+use OpenILS::Application::SIP2::Common;
+my $U = 'OpenILS::Application::AppUtils';
+my $SC = 'OpenILS::Application::SIP2::Common';
+
+
+sub cancel {
+    my ($class, $session, $hold) = @_;
+
+    my $details = {ok => 0};
+    
+    my $resp = $U->simplereq(
+        'open-ils.circ',
+        'open-ils.circ.hold.cancel', 
+        $session->editor->authtoken, $hold->id, 7 # cancel via SIP
+    );
+
+    return $details unless $resp && !$U->event_code($resp);
+
+    $details->{ok} = 1;
+
+    return $details;
+}
+
+# Given a "representative" copy, finds a matching hold
+sub hold_from_copy {
+    my ($class, $session, $patron_details, $item_details) = @_;
+    my $e = $session->editor;
+    my $hold;
+
+    my $copy = $item_details->{item};
+
+    my $run_hold_query = sub {
+        my %filter = @_;
+        return $e->search_action_hold_request([
+            {   usr => $patron_details->{patron}->id,
+                cancel_time => undef,
+                fulfillment_time => undef,
+                %filter
+            }, {
+                flesh => 2,
+                flesh_fields => {
+                    ahr => ['current_copy'],
+                    acp => ['call_number']
+                },
+                order_by => {ahr => 'request_time DESC'},
+                limit => 1
+            }
+        ])->[0];
+    };
+
+    # first see if there is a match on current_copy
+    return $hold if $hold = 
+        $run_hold_query->(current_copy => $copy->id);
+
+    # next, assume bib-level holds are the most common
+    return $hold if $hold = $run_hold_query->(
+        target => $copy->call_number->record->id, hold_type => 'T');
+
+    # next try metarecord holds
+    my $map = $e->search_metabib_metarecord_source_map(
+        {source => $copy->call_number->record->id})->[0];
+
+    return $hold if $hold = $run_hold_query->(
+        target => $map->metarecord, hold_type => 'M');
+
+    # volume holds
+    return $hold if $hold = $run_hold_query->(
+        target => $copy->call_number->id, hold_type => 'V');
+
+    # copy holds
+    return $run_hold_query->(
+        target => $copy->id, hold_type => ['C', 'F', 'R']);
+}
+
index 5ab25ff..f697382 100644 (file)
@@ -9,7 +9,6 @@ use OpenILS::Application::AppUtils;
 use OpenILS::Utils::DateTime qw/:datetime/;
 use OpenILS::Const qw/:const/;
 use OpenILS::Application::SIP2::Common;
-use OpenILS::Application::SIP2::Session;
 my $U = 'OpenILS::Application::AppUtils';
 my $SC = 'OpenILS::Application::SIP2::Common';
 
index b9d3ea3..40a6a2f 100644 (file)
@@ -9,7 +9,6 @@ use OpenILS::Const qw/:const/;
 use OpenILS::Application::AppUtils;
 use OpenILS::Utils::DateTime qw/:datetime/;
 use OpenILS::Application::SIP2::Common;
-use OpenILS::Application::SIP2::Session;
 my $U = 'OpenILS::Application::AppUtils';
 my $SC = 'OpenILS::Application::SIP2::Common';
 
@@ -38,6 +37,8 @@ sub get_patron_details {
         }
     }])->[0];
 
+    return undef unless $card;
+
     my $patron = $details->{patron} = $card->usr;
     $patron->card($card);