my $soft_boundary = $U->ou_ancestor_setting_value($selection_ou, OILS_SETTING_HOLD_SOFT_BOUNDARY);
my $hard_boundary = $U->ou_ancestor_setting_value($selection_ou, OILS_SETTING_HOLD_HARD_BOUNDARY);
+ my @status = ();
+ my $return_depth = $hard_boundary; # default depth to return on success
if(defined $soft_boundary and $depth < $soft_boundary) {
# work up the tree and as soon as we find a potential copy, use that depth
# also, make sure we don't go past the hard boundary if it exists
my $depth = $soft_boundary;
while($depth >= $min_depth) {
$logger->info("performing hold possibility check with soft boundary $depth");
- my @status = do_possibility_checks($e, $patron, $request_lib, $depth, %params);
- return {success => 1, depth => $depth, local_avail => $status[1]} if $status[0];
+ @status = do_possibility_checks($e, $patron, $request_lib, $depth, %params);
+ if ($status[0]) {
+ $return_depth = $depth;
+ last;
+ }
$depth--;
}
} elsif(defined $hard_boundary and $depth < $hard_boundary) {
# there is no soft boundary, enforce the hard boundary if it exists
$logger->info("performing hold possibility check with hard boundary $hard_boundary");
- my @status = do_possibility_checks($e, $patron, $request_lib, $hard_boundary, %params);
- if($status[0]) {
- return {success => 1, depth => $hard_boundary, local_avail => $status[1]}
- }
+ @status = do_possibility_checks($e, $patron, $request_lib, $hard_boundary, %params);
} else {
# no boundaries defined, fall back to user specifed boundary or no boundary
$logger->info("performing hold possibility check with no boundary");
- my @status = do_possibility_checks($e, $patron, $request_lib, $params{depth}, %params);
- if($status[0]) {
- return {success => 1, depth => $hard_boundary, local_avail => $status[1]};
- }
+ @status = do_possibility_checks($e, $patron, $request_lib, $params{depth}, %params);
+ }
+
+ if ($status[0]) {
+ return {
+ "success" => 1,
+ "depth" => $return_depth,
+ "local_avail" => $status[1]
+ };
+ } elsif ($status[2]) {
+ my $n = scalar @{$status[2]};
+ return {"success" => 0, "last_event" => $status[2]->[$n - 1]};
+ } else {
+ return {"success" => 0};
}
- return {success => 0};
}
sub do_possibility_checks {
my $maps = $e->search_metabib_metarecord_source_map({metarecord=>$mrid});
my @recs = map { $_->source } @$maps;
+ my @status = ();
for my $rec (@recs) {
- my @status = _check_title_hold_is_possible(
- $rec, $depth, $request_lib, $patron, $e->requestor, $pickup_lib, $selection_ou);
- return @status if $status[1];
+ @status = _check_title_hold_is_possible(
+ $rec, $depth, $request_lib, $patron, $e->requestor, $pickup_lib, $selection_ou
+ );
+ last if $status[1];
}
- return (0);
+ return @status;
}
# else { Unrecognized hold_type ! } # FIXME: return error? or 0?
}
);
$logger->info("title possible found ".scalar(@$copies)." potential copies");
- return (0) unless @$copies;
+ return (
+ 0, 0, [
+ new OpenILS::Event(
+ "HIGH_LEVEL_HOLD_HAS_NO_COPIES",
+ "payload" => {"fail_part" => "no_ultimate_items"}
+ )
+ ]
+ ) unless @$copies;
# -----------------------------------------------------------------------
# sort the copies into buckets based on their circ_lib proximity to
my $title;
my %seen;
- for my $key (@keys) {
+ my @status;
+ OUTER: for my $key (@keys) {
my @cps = @{$buckets{$key}};
$logger->info("looking at " . scalar(@{$buckets{$key}}). " copies in proximity bucket $key");
$title = $vol->record;
}
- my @status = verify_copy_for_hold(
- $patron, $requestor, $title, $copy, $pickup_lib, $request_lib );
+ @status = verify_copy_for_hold(
+ $patron, $requestor, $title, $copy, $pickup_lib, $request_lib);
- return @status if $status[0];
+ last OUTER if $status[0];
}
}
- return (0);
+ return @status;
}
my %org_filter = create_ranged_org_filter(new_editor(), $selection_ou, $depth);
my $copies = new_editor->search_asset_copy({call_number => $vol->id, %org_filter});
$logger->info("checking possibility of volume hold for volume ".$vol->id);
+
+ return (
+ 0, 0, [
+ new OpenILS::Event(
+ "HIGH_LEVEL_HOLD_HAS_NO_COPIES",
+ "payload" => {"fail_part" => "no_ultimate_items"}
+ )
+ ]
+ ) unless @$copies;
+
+ my @status;
for my $copy ( @$copies ) {
- my @status = verify_copy_for_hold(
+ @status = verify_copy_for_hold(
$patron, $requestor, $title, $copy, $pickup_lib, $request_lib );
- return @status if $status[0];
+ last if $status[0];
}
- return (0);
+ return @status;
}
title_descriptor => $title->fixed_fields, # this is fleshed into the title object
pickup_lib => $pickup_lib,
request_lib => $request_lib,
- new_hold => 1
+ new_hold => 1,
+ show_event_list => 1
}
);
return (
- $permitted,
+ (not scalar @$permitted), # true if permitted is an empty arrayref
(
($copy->circ_lib == $pickup_lib) and
($copy->status == OILS_COPY_STATUS_AVAILABLE)
- )
+ ),
+ $permitted
);
}
<!ENTITY selfck.day5 "Saturday">
<!ENTITY selfck.day6 "Sunday">
+<!ENTITY circ.fail_part.actor.usr.barred "The patron is barred">
+<!ENTITY circ.fail_part.asset.copy.circulate "The item does not circulate">
+<!ENTITY circ.fail_part.asset.copy_location.circulate "Items from this shelving location do not circulate">
+<!ENTITY circ.fail_part.asset.copy.status "The item cannot circulate at this time">
+<!ENTITY circ.fail_part.circ.holds.target_skip_me "The item's circulation library does not fulfill holds">
+<!ENTITY circ.fail_part.config.circ_matrix_circ_mod_test "The patron has too many items of this type checked out">
+<!ENTITY circ.fail_part.config.circ_matrix_test.available_copy_hold_ratio "The available item-to-hold ratio is too low">
+<!ENTITY circ.fail_part.config.circ_matrix_test.circulate "Circulation rules reject this item as non-circulatable">
+<!ENTITY circ.fail_part.config.circ_matrix_test.total_copy_hold_ratio "The total item-to-hold ratio is too low">
+<!ENTITY circ.fail_part.config.hold_matrix_test.holdable "Hold rules reject this item as unholdable">
+<!ENTITY circ.fail_part.config.hold_matrix_test.max_holds "The patron has reached the maximum number of holds">
+<!ENTITY circ.fail_part.config.rule_age_hold_protect.prox "The item is too new to transit this far">
+<!ENTITY circ.fail_part.no_item "The system could not find this item">
+<!ENTITY circ.fail_part.no_ultimate_items "The system could not find any items to match this hold request">
+<!ENTITY circ.fail_part.no_matchpoint "System rules do not define how to handle this item">
+<!ENTITY circ.fail_part.no_user "The system could not find this patron">
+<!ENTITY circ.fail_part.transit_range "The item cannot transit this far">