speedy json_query version of metarecord hold permit
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Wed, 5 Dec 2007 17:01:38 +0000 (17:01 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Wed, 5 Dec 2007 17:01:38 +0000 (17:01 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@8139 dcc99617-32d9-48b4-a31d-7c20da2025e4

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

index 2801f35..9691f2b 100644 (file)
@@ -1092,6 +1092,119 @@ sub ___check_title_hold_is_possible {
 
 my %prox_cache;
 
+sub _check_metarecord_hold_is_possible {
+       my( $mrid, $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 metarecord
+    my $copies = $e->json_query(
+        { 
+            select => { acp => ['id', 'circ_lib'] },
+            from => {
+                acp => {
+                    acn => {
+                        field => 'id',
+                        fkey => 'call_number',
+                        'join' => {
+                            bre => {
+                                field => 'id',
+                                fkey => 'record',
+                               'join' => {
+                                       mmrsm => {
+                                               filter => { metarecord => $mrid },
+                                               field => 'source',
+                                               fkey => 'id'
+                                       }
+                               }
+                            }
+                        }
+                    },
+                    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("metarecord 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 %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);
+
+         my $vol = $e->retrieve_asset_call_number(
+           [ $copy->call_number, { flesh => 1, flesh_fields => { acn => ['record'] } } ] );
+
+         return 1 if verify_copy_for_hold( 
+            $patron, $requestor, $vol->record, $copy, $pickup_lib, $request_lib );
+   
+      }
+   }
+
+   return 0;
+}
+
 sub _check_title_hold_is_possible {
        my( $titleid, $rangelib, $depth, $request_lib, $patron, $requestor, $pickup_lib ) = @_;