LP1901930 SIP2Mediator checkout support; with settings
authorBill Erickson <berickxx@gmail.com>
Fri, 30 Oct 2020 19:51:15 +0000 (15:51 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 30 Nov 2020 16:38:25 +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 [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Common.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Item.pm
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.sip-config.sql

index 860f906..820edd5 100644 (file)
@@ -1,16 +1,20 @@
 package OpenILS::Application::SIP2;
 use strict; use warnings;
 use base 'OpenILS::Application';
+use DateTime;
+use DateTime::Format::ISO8601;
 use OpenILS::Application;
 use OpenILS::Event;
 use OpenILS::Utils::Fieldmapper;
 use OpenSRF::Utils::Logger qw(:logger);
 use OpenILS::Utils::CStoreEditor qw/:funcs/;
 use OpenILS::Application::AppUtils;
+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::Patron;
+use OpenILS::Application::SIP2::Checkout;
 
 my $U = 'OpenILS::Application::AppUtils';
 my $SC = 'OpenILS::Application::SIP2::Common';
@@ -61,6 +65,7 @@ sub dispatch_sip2_request {
     }
 
     my $MESSAGE_MAP = {
+        '11' => \&handle_checkout,
         '17' => \&handle_item_info,
         '23' => \&handle_patron_status,
         '63' => \&handle_patron_info,
@@ -376,5 +381,91 @@ sub patron_response_common_data {
     };
 }
 
+sub handle_checkout {
+    my ($session, $message) = @_;
+
+    my $patron_barcode = $SC->get_field_value($message, 'AA');
+    my $item_barcode = $SC->get_field_value($message, 'AB');
+    my $fee_ack = $SC->get_field_value($message, 'BO');
+    my $config = $session->config;
+
+    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
+    );
+
+    if (!$item_details || !$patron_details) { # bad data
+        return {
+            code => '12',
+            fixed_fields => [
+                0,                  # checkout ok
+                $SC->sipbool(0),    # renewal ok
+                $SC->sipbool(0),    # magnetic media
+                $SC->sipbool(0),    # desensitize
+                $SC->sipdate,       # transaction date
+            ],
+            fields => [
+                {AA => $patron_barcode},
+                {AB => $item_barcode},
+            ]
+        };
+    }
+
+    my $circ_details = OpenILS::Application::SIP2::Checkout->checkout(
+        $session, 
+        patron_barcode => $patron_barcode, 
+        item_barcode => $item_barcode,
+        fee_ack => $fee_ack
+    );
+
+    use Data::Dumper;
+    $Data::Dumper::Indent = 0;
+    $logger->info("CHECKOUT RESULTED IN ".Dumper($circ_details));
+
+    my $magnetic = $item_details->{magnetic_media};
+    my $can_renew = 0;
+
+    my $circ = $circ_details->{circ};
+    if ($circ) {
+        $can_renew = !$patron_details->{renew_denied} 
+            && $circ->renewal_remaining > 0;
+    }
+
+    my $response = {
+        code => '12',
+        fixed_fields => [
+            $circ ? 1 : 0,              # checkout ok
+            $SC->sipbool($can_renew),   # renewal ok
+            $SC->sipbool($magnetic),    # magnetic media
+            $SC->sipbool(!$magnetic),   # desensitize
+            $SC->sipdate,               # transaction date
+        ],
+        fields => [
+            {AA => $patron_barcode},
+            {AB => $item_barcode},
+            {AJ => $item_details->{title}},
+            {AO => $config->{institution}},
+            {BT => $item_details->{fee_type}},
+            {CI => 0}, # security inhibit
+            {CK => $item_details->{media_type}}
+        ]
+    };
+
+    if ($circ) {
+        $SC->add_field($response, 'AH', $circ_details->{due_date});
+        $SC->add_field($response, 'BK', $circ->id);
+
+        $SC->maybe_add_field(
+            $response, 'BV', $item_details->{item}->deposit_amount);
+    }
+
+    $SC->maybe_add_field($response, 'AF', $circ_details->{screen_msg});
+
+    return $response;
+}
+
 1;
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Checkout.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/SIP2/Checkout.pm
new file mode 100644 (file)
index 0000000..662f14f
--- /dev/null
@@ -0,0 +1,104 @@
+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 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';
+
+
+# Returns the 'circ' object on success, undef on error.
+sub checkout {
+    my ($class, $session, %params) = @_;
+
+    my $circ_details = {};
+    my $override = 0;
+
+    for (0, 1) { # 2 checkout requests max
+
+        $override = $class->perform_checkout(
+            $session, $circ_details, $override, %params);
+
+        last unless $override;
+    }
+
+    return $circ_details;
+}
+
+# Returns 1 if the checkout should be performed again with override.
+# Returns 0 if there's nothing left to do (final success / error)
+# Updates $circ_details along the way.
+sub perform_checkout {
+    my ($class, $session, $circ_details, $override, %params) = @_;
+    my $config = $session->config;
+
+    my $args = {
+        copy_barcode => $params{item_barcode},
+        patron_barcode => $params{patron_barcode}
+    };
+
+    my $method = $params{is_renew} ?
+        'open-ils.circ.renew' : 'open-ils.circ.checkout.full';
+
+    $method .= '.override' if $override;
+
+    my $resp = $U->simplereq(
+        'open-ils.circ', $method, $session->editor->authtoken, $args);
+
+    $resp = [$resp] unless ref $resp eq 'ARRAY';
+
+    for my $event (@$resp) {
+        next unless $U->is_event($event); # this should never happen.
+        my $textcode = $event->{textcode};
+
+        if ($textcode eq 'SUCCESS' && $event->{payload}) {
+            if (my $circ = $event->{payload}->{circ}) {
+                $circ_details->{circ} = $circ;
+
+                my $due_date= 
+                    DateTime::Format::ISO8601->new
+                        ->parse_datetime(clean_ISO8601($circ->due_date));
+
+                $circ_details->{due_date} =
+                    $config->{due_date_use_sip_date_format} ?
+                    $SC->sipdate($due_date) :
+                    $due_date->strftime('%F %T');
+
+                return 0;
+            }
+        }
+
+        if (!$override) {
+            if ($config->{"checkout.override.$textcode"}) {
+                # Event type is configured for override;
+                return 1;
+
+            } elsif ($params{fee_ack} &&
+                $textcode =~ /ITEM_(?:DEPOSIT|RENTAL)_FEE_REQUIRED/ ) {
+                # Patron acknowledged the fee.  Redo with override.
+                return 1;
+            }
+        }
+
+        if ($textcode eq 'OPEN_CIRCULATION_EXISTS' ) {
+            # TODO: messages
+            $circ_details->{screen_msg} = 'This item is already checked out';
+
+        } else {
+            $circ_details->{screen_msg} = # TODO messages
+                'Patron is not allowed to check out the selected item';
+        }
+    }
+
+    return 0;
+}
+
+
+1;
index e515bf2..196d085 100644 (file)
@@ -11,6 +11,17 @@ sub cache {
     return $_cache;
 }
 
+sub add_field {
+    my ($class, $message, $field, $value) = @_;
+    $value = '' unless defined $value;
+    push (@{$message->{fields}}, {$field => $value});
+}
+
+sub maybe_add_field {
+    my ($class, $message, $field, $value) = @_;
+    push (@{$message->{fields}}, {$field => $value}) if defined $value;
+}
+
 sub sipdate {
     my ($class, $date) = @_;
     $date ||= DateTime->now;
index ba25247..540608a 100644 (file)
@@ -36,7 +36,10 @@ sub get_item_details {
 
     return undef unless $item;
 
-    my $details = {item => $item};
+    my $details = {
+        item => $item,
+        security_marker => '02' # matches SIP/Item.pm
+    };
 
     $details->{circ} = $e->search_action_circulation([{
         target_copy => $item->id,
index 2b164eb..d44889d 100644 (file)
@@ -94,9 +94,24 @@ VALUES (
     (SELECT id FROM config.sip_setting_group WHERE institution = 'example'), 
     'Patron holds data may be returned as either "title" or "barcode"',
     'msg64_hold_items_available', '"title"'
+), (
+    (SELECT id FROM config.sip_setting_group WHERE institution = 'example'), 
+    'Checkout override copy alert message',
+    'checkout.override.COPY_ALERT_MESSAGE', 'true'
+), (
+    (SELECT id FROM config.sip_setting_group WHERE institution = 'example'), 
+    'Checkin override copy alert message',
+    'checkin.override.COPY_ALERT_MESSAGE', 'true'
+), (
+    (SELECT id FROM config.sip_setting_group WHERE institution = 'example'), 
+    'Checkin override bad copy status',
+    'checkin.override.COPY_BAD_STATUS', 'true'
+), (
+    (SELECT id FROM config.sip_setting_group WHERE institution = 'example'), 
+    'Checkin override copy status missing',
+    'checkin.override.COPY_STATUS_MISSING', 'true'
 );
 
-
 /* EXAMPLE SETTINGS