Handle shelf-expired holds in NCIP::ILS::Evergreen->checkinitem.
authorJason Stephenson <jstephenson@mvlc.org>
Thu, 14 Jan 2016 16:40:59 +0000 (11:40 -0500)
committerJason Stephenson <jstephenson@mvlc.org>
Fri, 15 Jan 2016 18:17:27 +0000 (13:17 -0500)
We modify the check_circ_details method to look for shelf-expired
holds in addition to circulations and transits.  It is also modified
to better handle being used from the renewitem handler.

We add the clear_expired flag when actually doing the checkin.

Finally, a new helper _date_past is added to check if a date is in the
past, and the _expired helper is modified to use the _date_past
subroutine.

Signed-off-by: Jason Stephenson <jstephenson@mvlc.org>

lib/NCIP/ILS/Evergreen.pm

index b19ceee..2e2bbd5 100644 (file)
@@ -430,8 +430,8 @@ sub checkinitem {
     # Isolate the copy.
     my $copy = $details->{copy};
 
-    # Look for a circulation and examine its information:
-    my $circ = $details->{circ};
+    # Look for a circulation or hold so we can retrieve the user.
+    my $circ = $details->{circ} || $details->{hold};
 
     # Check the circ details to see if the copy is checked out and, if
     # the patron was provided, that it is checked out to the patron in
@@ -457,7 +457,8 @@ sub checkinitem {
         copy_barcode => $copy->barcode(),
         force => 1,
         noop => 1,
-        void_overdues => 1
+        void_overdues => 1,
+        clear_expired => 1
     };
     my $result = $U->simplereq(
         'open-ils.circ',
@@ -590,7 +591,7 @@ sub renewitem {
     # the patron was provided, that it is checked out to the patron in
     # question. We also verify the copy ownership and circulation
     # location.
-    my $problem = $self->check_circ_details($details, $user);
+    my $problem = $self->check_circ_details($details, $user, 1);
     if ($problem) {
         # We need to fill in some information, however.
         if (!$problem->ProblemValue() && !$problem->ProblemElement()) {
@@ -1752,7 +1753,7 @@ sub check_user_for_problems {
 
 =head2 check_circ_details
 
-    $problem = $ils->check_circ_details($details, $user);
+    $problem = $ils->check_circ_details($details, $user, $isrenewal);
 
 Checks if we can checkin or renew a circulation. That is, the
 circulation is still open (i.e. the copy is still checked out), if we
@@ -1761,6 +1762,17 @@ circulation is for the optional $user argument. The $details argument
 is required and comes from the retrieve_copy_details call. $user is
 optional.
 
+The optional C<$isrenewal> argument must be true when checking for
+renewals.  This argument set to true bypasses the hold check
+(described below) and requires a circulation.
+
+If we are not checking for renewals, this function will also check for
+a shelf-expired hold for the copy and patron.  If that is found, it is
+considered success as well.
+
+Also, if we are not checking for renewals, it will also check for an
+open transit return the item to our working organizational unit.
+
 Returns a problem if any of the above conditions fail. Returns undef
 if they pass and we can proceed with the checkin or renewal.
 
@@ -1773,11 +1785,15 @@ fields will be empty and need to be filled in by the caller.
 =cut
 
 sub check_circ_details {
-    my ($self, $details, $user) = @_;
+    my ($self, $details, $user, $isrenewal) = @_;
 
     my $copy = $details->{copy};
     my $circ = $details->{circ};
     my $transit = $details->{transit};
+    my $hold = $details->{hold};
+
+    # User from the hold or circulation.
+    my $circ_user;
 
     # Shortcut for the next check.
     my $ou_id = $self->{session}->{work_ou}->id();
@@ -1786,19 +1802,20 @@ sub check_circ_details {
     # been checked out at the NCIP user's working_ou or it needs to be
     # owned there.  If the circulation was subsequently checked in,
     # then we need an open transit to the NCIP user's working_ou.
-    if (!$circ || ($circ->circ_lib() != $ou_id && $copy->circ_lib() != $ou_id)
-            || ($circ->checkin_time() && (!$transit || $transit->dest() != $ou_id))) {
-        # Item isn't checked out.
-        return NCIP::Problem->new(
-            {
-                ProblemType => 'Item Not Checked Out',
-                ProblemDetail => 'Item with barcode ' . $copy->barcode() . ' is not checked out.',
-                ProblemValue => $copy->barcode()
-            }
-        );
-    } else {
-        # Get data on the patron who has it checked out.
-        my $circ_user = $self->retrieve_user_by_id($circ->usr());
+    if ($circ) {
+        if (($circ->circ_lib() == $ou_id || $copy->circ_lib() == $ou_id)
+            || ($circ->checkin_time() && !$isrenewal && ($transit && $transit->dest() == $ou_id))) {
+            $circ_user = $self->retrieve_user_by_id($circ->usr());
+        }
+    } elsif ($hold && !$isrenewal) {
+        # If we don't have a circulation, we want to have a shelf-expired hold.
+        if ($hold->shelf_time() && _date_past($hold->shelf_expire_time())) {
+            $circ_user = $self->retrieve_user_by_id($hold->usr());
+        }
+    }
+
+    if ($circ_user) {
+        # Check if the $circ_user matches the passed in $user.
         if ($user && $circ_user && $user->id() != $circ_user->id()) {
             # The ProblemElement and ProblemValue field need to be
             # filled in by the caller.
@@ -1809,6 +1826,15 @@ sub check_circ_details {
                 }
             );
         }
+    } else {
+        # We consider the item to be not checked out.
+        return NCIP::Problem->new(
+            {
+                ProblemType => 'Item Not Checked Out',
+                ProblemDetail => 'Item with barcode ' . $copy->barcode() . ' is not checked out.',
+                ProblemValue => $copy->barcode()
+            }
+        );
     }
     # If we get here, we're good to go.
     return undef;
@@ -2976,16 +3002,27 @@ sub _expired {
 
     # Users might not expire.  If so, they have no expire_date.
     if ($user->expire_date()) {
-        my $expires = DateTime::Format::ISO8601->parse_datetime(
-            cleanse_ISO8601($user->expire_date())
-        )->epoch();
-        my $now = DateTime->now()->epoch();
-        $expired = $now > $expires;
+        $expired = _date_past($user->expire_date());
     }
 
     return $expired;
 }
 
+# Check if a date has been passed, i.e. is in the past.
+#
+# This subroutine was added to have the same functionality of _expired
+# without necessitating a change to the _expired subroutine interface
+# and the code that already uses it.
+sub _date_past {
+    my $date = shift;
+
+    my $date_clean = DateTime::Format::ISO8601->parse_datetime(
+        cleanse_ISO8601($date)
+    )->epoch();
+    my $now = DateTime->now()->epoch();
+    return $now > $date_clean;
+}
+
 # Creates a NCIP Problem from an event. Takes a string for the problem
 # type, the event hashref (or a string to use for the detail), and
 # optional arguments for the ProblemElement and ProblemValue fields.