LP#1053397: Add optional org filter to "has holdable copies", and use that in open...
[working/Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Storage / Publisher / action.pm
index 240e2ab..fe1448d 100644 (file)
@@ -515,8 +515,15 @@ sub nearest_hold {
         $cp_circ_lib = $cp->circ_lib;
     }
 
+    my $cp_owning_lib;
+    if (ref $cp->call_number->owning_lib) {
+        $cp_owning_lib = $cp->call_number->owning_lib->id;
+    } else {
+        $cp_owning_lib = $cp->call_number->owning_lib;
+    }
+
     my ($holdsort, $addl_cte, $addl_join) =
-        build_hold_sort_clause(get_hold_sort_order($here), $cp, $here);
+        build_hold_sort_clause(get_hold_sort_order($cp_owning_lib), $cp, $here);
 
     local $OpenILS::Application::Storage::WRITE = 1;
 
@@ -541,7 +548,7 @@ sub nearest_hold {
                 ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
             $addl_join
           WHERE hm.target_copy = ?
-            AND (AGE(NOW(),h.request_time) >= CAST(? AS INTERVAL) OR p.prox = 0)
+            AND (AGE(NOW(),h.request_time) >= CAST(? AS INTERVAL) OR hm.proximity = 0 OR p.prox = 0)
             AND h.capture_time IS NULL
             AND h.cancel_time IS NULL
             AND (h.expire_time IS NULL OR h.expire_time > NOW())
@@ -737,15 +744,20 @@ sub hold_pull_list {
           FROM  $h_table h
             JOIN $a_table a ON (h.current_copy = a.id)
             LEFT JOIN $ord_table ord ON (a.location = ord.location AND a.circ_lib = ord.org)
-            LEFT JOIN actor.usr_standing_penalty ausp 
-                ON ( h.usr = ausp.usr AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() ) )
-            LEFT JOIN config.standing_penalty csp
-                ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
           WHERE a.circ_lib = ?
             AND h.capture_time IS NULL
             AND h.cancel_time IS NULL
             AND (h.expire_time IS NULL OR h.expire_time > NOW())
-            AND csp.id IS NULL
+            AND NOT EXISTS (
+                SELECT  1
+                  FROM  actor.usr_standing_penalty ausp
+                        JOIN config.standing_penalty csp ON (
+                            csp.id = ausp.standing_penalty
+                            AND csp.block_list LIKE '%CAPTURE%'
+                        )
+                  WHERE h.usr = ausp.usr
+                        AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() )
+            )
             $status_filter
           ORDER BY CASE WHEN ord.position IS NOT NULL THEN ord.position ELSE 999 END, h.request_time
           LIMIT $limit
@@ -754,18 +766,23 @@ sub hold_pull_list {
 
     if ($count) {
         $select = <<"        SQL";
-            SELECT    count(*)
+            SELECT    count(DISTINCT h.id)
               FROM    $h_table h
                   JOIN $a_table a ON (h.current_copy = a.id)
-                  LEFT JOIN actor.usr_standing_penalty ausp 
-                    ON ( h.usr = ausp.usr AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() ) )
-                  LEFT JOIN config.standing_penalty csp
-                    ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
               WHERE    a.circ_lib = ?
                   AND h.capture_time IS NULL
                   AND h.cancel_time IS NULL
                   AND (h.expire_time IS NULL OR h.expire_time > NOW())
-                  AND csp.id IS NULL
+                  AND NOT EXISTS (
+                    SELECT  1
+                      FROM  actor.usr_standing_penalty ausp
+                            JOIN config.standing_penalty csp ON (
+                                csp.id = ausp.standing_penalty
+                                AND csp.block_list LIKE '%CAPTURE%'
+                            )
+                      WHERE h.usr = ausp.usr
+                            AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() )
+                )
                 $status_filter
         SQL
     }
@@ -1186,7 +1203,7 @@ sub generate_fines {
                     my $dow_close = "dow_${dow}_close";
 
                     if (my $h = $hoo{$c->$circ_lib_method}) {
-                        return if ( $h->$dow_open eq '00:00:00' and $h->$dow_close eq '00:00:00');
+                        next if ( $h->$dow_open eq '00:00:00' and $h->$dow_close eq '00:00:00');
                     }
     
                     my @cl = actor::org_unit::closed_date->search_where(
@@ -1194,7 +1211,7 @@ sub generate_fines {
                               close_end => { '>=' => $timestamptz },
                               org_unit  => $c->$circ_lib_method }
                     );
-                    return if (@cl);
+                    next if (@cl);
                 }
 
                 # The billing amount for this billing normally ought to be the recurring fine amount.
@@ -1266,6 +1283,48 @@ __PACKAGE__->register_method(
 );
 
 
+sub MR_records_matching_format {
+    my $self = shift;
+    my $client = shift;
+    my $MR = shift;
+    my $filter = shift;
+    my $org = shift;
+
+    # find filters for MR holds
+    my $mr_filter;
+    if (defined($filter)) {
+        ($mr_filter) = @{action::hold_request->db_Main->selectcol_arrayref(
+            'SELECT metabib.compile_composite_attr(?)',
+            {},
+            $filter
+        )};
+    }
+
+    my $records = [metabib::metarecord->retrieve($MR)->source_records];
+
+    my $q = 'SELECT source FROM metabib.record_attr_vector_list WHERE source = ? AND vlist @@ ? AND asset.record_has_holdable_copy(?,?)';
+    my @args = ( $mr_filter, $org );
+    if (!$mr_filter) {
+        $q = 'SELECT true WHERE asset.record_has_holdable_copy(?,?)';
+        @args = ( $org );
+    }
+
+    for my $r ( map { isTrue($_->deleted) ?  () : ($_->id) } @$records ) {
+        # the map{} below is tricky. it puts the record ID in front of each param. see $q above
+        $client->respond($r)
+            if @{action::hold_request->db_Main->selectcol_arrayref( $q, {}, map { ( $r => $_ ) } @args )};
+    }
+
+    return; # discard final l-val
+}
+__PACKAGE__->register_method(
+    api_name        => 'open-ils.storage.metarecord.filtered_records',
+    api_level       => 1,
+    stream          => 1,
+    argc            => 2,
+    method          => 'MR_records_matching_format',
+);
+
 
 sub new_hold_copy_targeter {
     my $self = shift;
@@ -1415,41 +1474,23 @@ sub new_hold_copy_targeter {
 
             my $all_copies = [];
 
-            # find filters for MR holds
-            my ($types, $formats, $lang);
-            if (defined($hold->holdable_formats)) {
-                ($types, $formats, $lang) = split '-', $hold->holdable_formats;
-            }
-
             # find all the potential copies
             if ($hold->hold_type eq 'M') {
-                my $records = [
-                    map {
-                        isTrue($_->deleted) ?  () : ($_->id)
-                    } metabib::metarecord->retrieve($hold->target)->source_records
-                ];
-                if(@$records > 0) {
-                    for my $r ( map
-                            {$_->record}
-                            metabib::record_descriptor
-                                ->search(
-                                    record => $records,
-                                    ( $types   ? (item_type => [split '', $types])   : () ),
-                                    ( $formats ? (item_form => [split '', $formats]) : () ),
-                                    ( $lang    ? (item_lang => $lang)                : () ),
-                                )
-                    ) {
-                        my ($rtree) = $self
-                            ->method_lookup( 'open-ils.storage.biblio.record_entry.ranged_tree')
-                            ->run( $r->id, $hold->selection_ou, $hold->selection_depth );
-
-                        for my $cn ( @{ $rtree->call_numbers } ) {
-                            push @$all_copies,
-                                asset::copy->search_where(
-                                    { id => [map {$_->id} @{ $cn->copies }],
-                                      deleted => 'f' }
-                                ) if ($cn && @{ $cn->copies });
-                        }
+                for my $r_id (
+                    $self->method_lookup(
+                        'open-ils.storage.metarecord.filtered_records'
+                    )->run( $hold->target, $hold->holdable_formats )
+                ) {
+                    my ($rtree) = $self
+                        ->method_lookup( 'open-ils.storage.biblio.record_entry.ranged_tree')
+                        ->run( $r_id, $hold->selection_ou, $hold->selection_depth );
+
+                    for my $cn ( @{ $rtree->call_numbers } ) {
+                        push @$all_copies,
+                            asset::copy->search_where(
+                                { id => [map {$_->id} @{ $cn->copies }],
+                                  deleted => 'f' }
+                            ) if ($cn && @{ $cn->copies });
                     }
                 }
             } elsif ($hold->hold_type eq 'T') {
@@ -1542,7 +1583,8 @@ sub new_hold_copy_targeter {
             my $prox_list = create_prox_list( $self, $pu_lib, $all_copies, $hold );
             $log->debug( "\tMapping ".scalar(@$all_copies)." potential copies for hold ".$hold->id);
             for my $prox ( keys %$prox_list ) {
-                action::hold_copy_map->create( { proximity => $prox, hold => $hold->id, target_copy => $_->id } ) for (@{$$prox_list{$prox}});
+                action::hold_copy_map->create( { proximity => $prox, hold => $hold->id, target_copy => $_ } )
+                    for keys( %{{ map { $_->id => 1 } @{$$prox_list{$prox}} }} );
             }
 
             #$client->status( new OpenSRF::DomainObject::oilsContinueStatus );
@@ -2305,32 +2347,5 @@ sub title_hold_capture {
     $self->volume_hold_capture($hold,$cn_list) if (ref $cn_list and @$cn_list);
 }
 
-sub metarecord_hold_capture {
-    my $self = shift;
-    my $hold = shift;
-
-    my $titles;
-    try {
-        $titles = [ metabib::metarecord_source_map->search( metarecord => $hold->target) ];
-    
-    } catch Error with {
-        my $e = shift;
-        die "Could not retrieve initial title list:\n\n$e\n";
-    };
-
-    try {
-        my @recs = map {$_->record} metabib::record_descriptor->search( record => $titles, item_type => [split '', $hold->holdable_formats] ); 
-
-        $titles = [ biblio::record_entry->search( id => \@recs ) ];
-    
-    } catch Error with {
-        my $e = shift;
-        die "Could not retrieve format-pruned title list:\n\n$e\n";
-    };
-
-
-    $cache{titles}{$_->id} = $_ for (@$titles);
-    $self->title_hold_capture($hold,$titles) if (ref $titles and @$titles);
-}
 
 1;