$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;
rental_billing
capture
noop
+ revert_hold_fulfillment
void_overdues
parent_circ
return_patron
}
+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
$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 ) {
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.
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
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;
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