From: Bill Erickson Date: Wed, 2 Sep 2020 16:56:34 +0000 (-0400) Subject: LP1893968 SIP2 checkin-with-cancel / checkin API X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=3312743a75f699d09e5db141a5e21c2eeca9b873;p=working%2FEvergreen.git LP1893968 SIP2 checkin-with-cancel / checkin API Adds new option to open-ils.circ.checkin API called "revert_hold_fulfillment". It behaves much like a No-Op checkin, with the addition that if a hold was fulfilled by the checked out item for the patron which circulated the item, the hold fulfillment is rolled back and the item is put back on the holds shelf. Teaches the SIP Checkin code to pass the 'revert_hold_fulfillment' flag to its checkin call when the SIP 'cancel' value is set, i.e. the SIP 'BI' field contains a 'Y' value. Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm index 66280f5999..a46072947f 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm @@ -255,6 +255,7 @@ sub run_method { $circulator->mk_env(); $circulator->noop(1) if $circulator->claims_never_checked_out; + $circulator->noop(1) if $circulator->revert_hold_fulfillment; return circ_events($circulator) if $circulator->bail_out; @@ -501,6 +502,7 @@ my @AUTOLOAD_FIELDS = qw/ rental_billing capture noop + revert_hold_fulfillment void_overdues parent_circ return_patron @@ -1916,6 +1918,51 @@ sub handle_checkout_holds { } +sub undo_hold_fulfillment { + my $self = shift; + my $e = $self->editor; + + my $hold = $e->search_action_hold_request([ + { usr => $self->patron->id, + cancel_time => undef, + fulfillment_time => {'!=' => undef}, + current_copy => $self->copy->id + }, { + order_by => {ahr => 'fulfillment_time desc'}, + limit => 1 + } + ])->[0]; + + return unless $hold; + + # The hold fulfillment time will match the xact_start time of its + # companion circulation, however in some cases the date stored in PG + # contains milliseconds and in other cases not. To make an accurate + # comparison, truncate the milliseconds. + + my $xact_time = DateTime::Format::ISO8601->new->parse_datetime( + clean_ISO8601($self->circ->xact_start))->strftime('%FT%T%z'); + + my $ff_time = DateTime::Format::ISO8601->new->parse_datetime( + clean_ISO8601($hold->fulfillment_time))->strftime('%FT%T%z'); + + return unless $xact_time eq $ff_time; + + $logger->info("circulator: undoing fulfillment for hold ".$hold->id); + + $hold->clear_fulfillment_time; + $hold->clear_fulfillment_staff; + $hold->clear_fulfillment_lib; + + return $self->bail_on_events($e->event) + unless $e->update_action_hold_request($hold); + + # Put the item back on the holds shelf. + $self->copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF); + $self->update_copy(); +} + + # ------------------------------------------------------------------------------ # If the circ.checkout_fill_related_hold setting is turned on and no hold for # the patron directly targets the checked out item, see if there is another hold @@ -2683,7 +2730,7 @@ sub do_checkin { $self->fix_broken_transit_status; # if applicable $self->check_transit_checkin_interval; - $self->checkin_retarget; + $self->checkin_retarget unless $self->revert_hold_fulfillment; # the renew code and mk_env should have already found our circulation object unless( $self->circ ) { @@ -2701,6 +2748,17 @@ sub do_checkin { my $stat = $U->copy_status($self->copy->status)->id; + if ($self->revert_hold_fulfillment) { + # Rule out any unexpected scenarios before continuing with + # reverting the hold fulfillment. + return $self->bail_on_events(OpenILS::Event->new('NO_CHANGE')) + unless ( + $self->circ + && $stat == OILS_COPY_STATUS_CHECKED_OUT + && !$self->is_renewal + ); + } + # LOST (and to some extent, LONGOVERDUE) may optionally be handled # differently if they are already paid for. We need to check for this # early since overdue generation is potentially affected. @@ -2755,7 +2813,7 @@ sub do_checkin { unless $self->editor->allowed('COPY_CHECKIN'); } - $self->push_events($self->check_copy_alert()); + $self->push_events($self->check_copy_alert()) unless $self->revert_hold_fulfillment; $self->push_events($self->check_checkin_copy_status()); # if the circ is marked as 'claims returned', add the event to the list @@ -2763,7 +2821,7 @@ sub do_checkin { if ($self->circ and $self->circ->stop_fines and $self->circ->stop_fines eq OILS_STOP_FINES_CLAIMSRETURNED); - $self->check_circ_deposit(); + $self->check_circ_deposit() unless $self->revert_hold_fulfillment; # handle the overridable events $self->override_events unless $self->is_renewal; @@ -2879,6 +2937,14 @@ sub do_checkin { return; } + if ($self->revert_hold_fulfillment) { + $self->undo_hold_fulfillment; + return if $self->bail_out; + $self->push_events(OpenILS::Event->new('SUCCESS')); + $self->checkin_flesh_events; + return; + } + # ------------------------------------------------------------------------------ # Circulations and transits are now closed where necessary. Now go on to see if # this copy can fulfill a hold or needs to be routed to a different location diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm index 693d56243d..1911a7e3e1 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP.pm @@ -469,7 +469,8 @@ sub checkin { return $xact; } - $xact->do_checkin( $self, $inst_id, $trans_date, $return_date, $current_loc, $item_props ); + $xact->do_checkin($self, $inst_id, $trans_date, + $return_date, $current_loc, $item_props, $cancel); if ($xact->ok) { $xact->patron($self->find_patron(usr => $xact->{circ_user_id}, slim_user => 1)) if $xact->{circ_user_id}; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/Checkin.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/Checkin.pm index c937892daa..186b9f1614 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/Checkin.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Transaction/Checkin.pm @@ -65,8 +65,8 @@ sub load_override_events { my %org_sn_cache; sub do_checkin { - my $self = shift; - my ($sip_handler, $inst_id, $trans_date, $return_date, $current_loc, $item_props) = @_; # most unused + my ($self, $sip_handler, $inst_id, $trans_date, + $return_date, $current_loc, $item_props, $cancel) = @_; unless($self->{item}) { $self->ok(0); @@ -81,6 +81,7 @@ sub do_checkin { my $args = {barcode => $self->{item}->id}; $args->{hold_as_transit} = 1 if $hold_as_transit; + $args->{revert_hold_fulfillment} = 1 if $cancel; if($return_date) { # SIP date format is YYYYMMDD. Translate to ISO8601