for title hold possibility check, we now sort copies into buckets based
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 5 Feb 2007 19:14:23 +0000 (19:14 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 5 Feb 2007 19:14:23 +0000 (19:14 +0000)
on the copy circ lib.  then we check "closest" copies first since they
are the more likely to be allowed, and therefore allow the
possibility check to succeed.

git-svn-id: svn://svn.open-ils.org/ILS/branches/rel_1_0@6879 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm

index ef708c0..9d37096 100644 (file)
@@ -1046,7 +1046,7 @@ sub check_title_hold {
 
 
 
-sub _check_title_hold_is_possible {
+sub ___check_title_hold_is_possible {
        my( $titleid, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
 
        my $limit       = 10;
@@ -1081,6 +1081,120 @@ sub _check_title_hold_is_possible {
        return 0;
 }
 
+my %prox_cache;
+
+sub _check_title_hold_is_possible {
+       my( $titleid, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
+   
+   my $e = new_editor();
+
+    # this monster will grab the id and circ_lib of all of the "holdable" copies for the given record
+    my $copies = $e->json_query(
+        { 
+            select => { acp => ['id', 'circ_lib'] },
+            from => {
+                acp => {
+                    acn => {
+                        field => 'id',
+                        fkey => 'call_number',
+                        'join' => {
+                            bre => {
+                                field => 'id',
+                                filter => { id => $titleid },
+                                fkey => 'record'
+                            }
+                        }
+                    },
+                    acpl => { field => 'id', filter => { holdable => 't'}, fkey => 'location' },
+                    ccs => { field => 'id', filter => { holdable => 't'}, fkey => 'status' }
+                }
+            }, 
+            where => {
+                '+acp' => { circulate => 't', deleted => 'f', holdable => 't' }
+            }
+        }
+    );
+
+   return $e->event unless defined $copies;
+   $logger->info("title possible found ".scalar(@$copies)." potential copies");
+   return 0 unless @$copies;
+
+   # -----------------------------------------------------------------------
+   # sort the copies into buckets based on their circ_lib proximity to 
+   # the patron's home_ou.  
+   # -----------------------------------------------------------------------
+
+   my $home_org = $patron->home_ou;
+   my $req_org = $request_lib->id;
+
+   my $home_prox = 
+      ($prox_cache{$home_org}) ? 
+         $prox_cache{$home_org} :
+         $prox_cache{$home_org} = $e->search_actor_org_unit_proximity({from_org => $home_org});
+
+   my %buckets;
+   my %hash = map { ($_->to_org => $_->prox) } @$home_prox;
+   push( @{$buckets{ $hash{$_->{circ_lib}} } }, $_->{id} ) for @$copies;
+
+   my @keys = sort { $a <=> $b } keys %buckets;
+
+
+   if( $home_org ne $req_org ) {
+      # -----------------------------------------------------------------------
+      # shove the copies close to the request_lib into the primary buckets 
+      # directly before the farthest away copies.  That way, they are not 
+      # given priority, but they are checked before the farthest copies.
+      # -----------------------------------------------------------------------
+      my $req_prox = 
+         ($prox_cache{$req_org}) ? 
+            $prox_cache{$req_org} :
+            $prox_cache{$req_org} = $e->search_actor_org_unit_proximity({from_org => $req_org});
+
+      my %buckets2;
+      my %hash2 = map { ($_->to_org => $_->prox) } @$req_prox;
+      push( @{$buckets2{ $hash2{$_->{circ_lib}} } }, $_->{id} ) for @$copies;
+
+      my $highest_key = $keys[@keys - 1];  # the farthest prox in the exising buckets
+      my $new_key = $highest_key - 0.5; # right before the farthest prox
+      my @keys2 = sort { $a <=> $b } keys %buckets2;
+      for my $key (@keys2) {
+         last if $key >= $highest_key;
+         push( @{$buckets{$new_key}}, $_ ) for @{$buckets2{$key}};
+      }
+   }
+
+   @keys = sort { $a <=> $b } keys %buckets;
+
+   my $title;
+   my %seen;
+   for my $key (@keys) {
+      my @cps = @{$buckets{$key}};
+
+      $logger->info("looking at " . scalar(@{$buckets{$key}}). " copies in proximity bucket $key");
+
+      for my $copyid (@cps) {
+
+         next if $seen{$copyid};
+         $seen{$copyid} = 1; # there could be dupes given the merged buckets
+         my $copy = $e->retrieve_asset_copy($copyid) or return $e->event;
+         $logger->debug("looking at bucket_key=$key, copy $copyid : circ_lib = " . $copy->circ_lib);
+
+         unless($title) { # grab the title if we don't already have it
+            my $vol = $e->retrieve_asset_call_number(
+               [ $copy->call_number, { flesh => 1, flesh_fields => { acn => ['record'] } } ] );
+            $title = $vol->record;
+         }
+   
+         return 1 if verify_copy_for_hold( 
+            $patron, $requestor, $title, $copy, $pickup_lib, $request_lib );
+   
+      }
+   }
+
+   return 0;
+}
+
+
 sub _check_volume_hold_is_possible {
        my( $vol, $title, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;
        my $copies = new_editor->search_asset_copy({call_number => $vol->id});