capturing copies! yay!
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 8 Jul 2005 18:16:53 +0000 (18:16 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 8 Jul 2005 18:16:53 +0000 (18:16 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@1102 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/support-scripts/hold-copy-capture.pl

index 14a733b..7f4d859 100755 (executable)
@@ -1,14 +1,39 @@
 #!/usr/bin/perl -w
-use strict;use warnings;
+use strict;
 use OpenSRF::EX qw/:try/;
 use OpenSRF::System;
+use OpenSRF::Application;
+use OpenSRF::Utils::SettingsClient;
 use OpenILS::Utils::Fieldmapper;
+use OpenSRF::Utils;
 
 die "USAGE:\n\t$0 config_file\n" unless @ARGV;
 
+
+# hard coded for now, option later
+
+my $time = time;
+my $check_expire = OpenSRF::Utils::interval_to_seconds( '10m' );
+
+my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time - $check_expire);
+$year += 1900;
+$mon += 1;
+my $expire_threshold = sprintf(
+       '%s-%0.2d-%0.2d %s:%0.2d:%0.s2-00',
+       $year, $mon, $mday, $hour, $min, $sec
+);
+
 OpenSRF::System->bootstrap_client( config_file => $ARGV[0] );
 my $session = OpenSRF::AppSession->create('open-ils.storage');
-my $circ = OpenSRF::AppSession->create('open-ils.circ');
+
+my $module = OpenSRF::Utils::SettingsClient
+       ->new
+       ->config_value('apps','open-ils.circ','implementation');
+
+eval "use $module; $module->initialize;";
+die "Can't load the open-ils.circ module [$module] : $@\n" if ($@);
+
+my $user_filter = OpenSRF::Application->method_lookup('open-ils.circ.permit_hold');
 
 my $statuses = $session->request(
        'open-ils.storage.direct.config.copy_status.search.holdable.atomic',
@@ -20,6 +45,8 @@ my $locations = $session->request(
 
 my $holds;
 
+my %cache = (titles => {}, cns => {});
+
 try {
        if ($ARGV[1]) {
                $holds = $session->request(
@@ -27,23 +54,74 @@ try {
                                id => $ARGV[1] )->gather(1);
        } else {
                $holds = $session->request(
+                               'open-ils.storage.direct.action.hold_request.search_where.atomic',
+                               { capture_time => undef,
+                                 prev_check_time => { '<=' => $expire_threshold },
+                               },
+                               { order_by => 'request_time,prev_check_time' } )->gather(1);
+               push @$holds, @{
+                       $session->request(
                                'open-ils.storage.direct.action.hold_request.search.atomic',
-                               capture_time => undef )->gather(1);
+                               { capture_time => undef,
+                                 prev_check_time => undef },
+                               { order_by => 'request_time,prev_check_time' } )->gather(1)
+               };
        }
 } catch Error with {
        my $e = shift;
        die "Could not retrieve uncaptured hold requests:\n\n$e\n";
 };
 
+$_->clear_current_copy for (@$holds);
 
 for my $hold (@$holds) {
-       metarecord_hold_capture($hold) if ($hold->hold_type eq 'M');
-       title_hold_capture($hold) if ($hold->hold_type eq 'T');
-       volume_hold_capture($hold) if ($hold->hold_type eq 'V');
-       copy_hold_capture($hold) if ($hold->hold_type eq 'C');
+       my $copies;
+
+       my @captured_copies = [ map {$_->current_copy} @$holds ];
+
+       if (0) { # hold isn't check-expired
+               # get the copies from the hold-map
+               # and filter on "avialable"
+       } else {
+               $copies = metarecord_hold_capture($hold) if ($hold->hold_type eq 'M');
+               $copies = title_hold_capture($hold) if ($hold->hold_type eq 'T');
+               $copies = volume_hold_capture($hold) if ($hold->hold_type eq 'V');
+               $copies = copy_hold_capture($hold) if ($hold->hold_type eq 'C');
+       }
+
+       next unless (ref $copies);
+
+       my @good_copies;
+       for my $c (@$copies) {
+               next if ( grep {$c->id == $_} @captured_copies);
+               push @good_copies, $c;
+       }
+
+       my $prox_list;
+       $$prox_list[0] = [grep {$_->circ_lib == $hold->pickup_lib } @$copies];
+       $copies = [grep {$_->circ_lib != $hold->pickup_lib } @$copies];
+
+       my $best = choose_nearest_copy($hold, $prox_list);
+
+       if (!$best) {
+               $prox_list = create_prox_list( $hold->pickup_lib, $copies );
+               $best = choose_nearest_copy($hold, $prox_list);
+       }
+
+       if ($best) {
+               print "Updating hold ".$hold->id." with current_copy ".$best->id."\n";
+               $hold->current_copy( $best->id );
+       }
+
+       $hold->prev_check_time( 'now');
+       $session->request(
+               'open-ils.storage.direct.action.hold_request.update',
+               $hold )->gather(1) ||
+                       warn "Could not save hold ".$hold->id."\n";
        print '-'x80 . "\n";
 }
 
+
 sub copy_hold_capture {
        my $hold = shift;
        my $cps = shift;
@@ -62,35 +140,80 @@ sub copy_hold_capture {
 
        my @copies = grep { $_->holdable == 1  and $_->ref == 0 } @$cps;
 
-       $circ->connect;
        print "Applying user defined filters for hold ".$hold->id."...\n";
        for (my $i = 0; $i < @copies; $i++) {
+               
+               my $cn = $cache{cns}{$copies[0]->call_number};
+               my $rec = $cache{titles}{$cn->record};
                $copies[$i] = undef if ($copies[$i] && !grep{ $copies[$i]->status eq $_->id}@$statuses);
                $copies[$i] = undef if ($copies[$i] && !grep{ $copies[$i]->location eq $_->id}@$locations);
                $copies[$i] = undef if (
                        $copies[$i] &&
-                       !$circ->request(
-                               'open-ils.circ.permit_hold',
-                               $hold, $copies[$i] )->gather(1)
+                       !$user_filter->run( $hold, $copies[$i], { title => $rec, call_number => $cn } )
                );
        }
-       $circ->disconnect;
 
        @copies = grep { defined $_ } @copies;
 
-       my @prox_list;
        my $count = @copies;
-       print "Found $count eligible copies for hold ".$hold->id.":\n";
-       for my $cp (@copies) {
+
+       return unless ($count);
+       
+       print "Saving $count eligible copies for hold ".$hold->id.":\n";
+
+       my $old_maps = $session->request(
+               'open-ils.storage.direct.action.hold_copy_map.search.hold.atomic',
+               $hold->id )->gather(1);
+
+       $session->request( 'open-ils.storage.direct.action.hold_copy_map.batch.delete', @$old_maps )
+               ->gather(1) if (defined($old_maps) and @$old_maps);
+       
+       my @maps;
+       for my $c (@copies) {
+               my $m = new Fieldmapper::action::hold_copy_map;
+               $m->hold( $hold->id );
+               $m->target_copy( $c->id );
+               $m->isnew( 1 );
+               push @maps, $m;
+       }
+
+       $session->request(
+               'open-ils.storage.direct.action.hold_copy_map.batch.create',
+               @maps )->gather(1) ||
+                       warn "Could not save copies for hold ".$hold->id."\n";
+
+       return \@copies;
+}
+
+
+sub choose_nearest_copy {
+       my $hold = shift;
+       my $prox_list = shift;
+
+       for my $p ( 0 .. int( scalar(@$prox_list) - 1) ) {
+               next unless (ref $$prox_list[$p]);
+               my @capturable = grep { $_->status == 0 } @{ $$prox_list[$p] };
+               next unless (@capturable);
+               return $capturable[rand(scalar(@capturable))];
+       }
+}
+
+sub create_prox_list {
+       my $lib = shift;
+       my $copies = shift;
+
+       my @prox_list;
+       print "Creating proximity list :\n";
+       for my $cp (@$copies) {
                my $prox = $session->request(
                        'open-ils.storage.asset.copy.proximity',
-                       $cp->id, $hold->pickup_lib )->gather(1);
+                       $cp->id, $lib )->gather(1);
                print "\t".$cp->id." -> ".$cp->barcode." :: Proximity -> $prox\n";
                $prox_list[$prox] = [] unless defined($prox_list[$prox]);
                push @{$prox_list[$prox]}, $cp;
        }
        print "\n";
-
+       return \@prox_list;
 }
 
 sub volume_hold_capture {
@@ -103,6 +226,8 @@ sub volume_hold_capture {
                                'open-ils.storage.direct.asset.call_number.search.id.atomic',
                                $hold->target )->gather(1);
        
+                       $cache{cns}{$_->id} = $_ for (@$vols);
+
                } catch Error with {
                        my $e = shift;
                        die "Could not retrieve initial volume list:\n\n$e\n";
@@ -144,6 +269,8 @@ sub title_hold_capture {
                                'open-ils.storage.direct.biblio.record_entry.search.id.atomic',
                                $hold->target )->gather(1);
        
+                       $cache{titles}{$_->id} = $_ for (@$titles);
+       
                } catch Error with {
                        my $e = shift;
                        die "Could not retrieve initial title list:\n\n$e\n";
@@ -171,6 +298,8 @@ sub title_hold_capture {
                print "\n";
        }
 
+       $cache{cns}{$_->id} = $_ for (@$cn_list);
+
        volume_hold_capture($hold,$cn_list) if (ref $cn_list and @$cn_list);
 }
 
@@ -217,6 +346,8 @@ sub metarecord_hold_capture {
                print "\n";
        }
 
+       $cache{titles}{$_->id} = $_ for (@$titles);
+
        title_hold_capture($hold,$titles) if (ref $titles and @$titles);
 }