LP#1386347: Clear hold-copy-map efficiently
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Circ / Holds.pm
index 4f56877..1ec6066 100644 (file)
@@ -826,8 +826,6 @@ sub cancel_hold {
     $e->update_action_hold_request($hold)
         or return $e->die_event;
 
-    delete_hold_copy_maps($self, $e, $hold->id);
-
     $e->commit;
 
     # re-fetch the hold to pick up the real cancel_time (not "now") for A/T
@@ -844,20 +842,6 @@ sub cancel_hold {
     return 1;
 }
 
-sub delete_hold_copy_maps {
-    my $class  = shift;
-    my $editor = shift;
-    my $holdid = shift;
-
-    my $maps = $editor->search_action_hold_copy_map({hold=>$holdid});
-    for(@$maps) {
-        $editor->delete_action_hold_copy_map($_)
-            or return $editor->event;
-    }
-    return undef;
-}
-
-
 my $update_hold_desc = 'The login session is the requestor. '       .
    'If the requestor is different from the usr field on the hold, ' .
    'the requestor must have UPDATE_HOLDS permissions. '             .
@@ -1110,7 +1094,7 @@ sub set_hold_shelf_expire_time {
 
     $start_time = ($start_time) ?
         DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($start_time)) :
-        DateTime->now;
+        DateTime->now(time_zone => 'local'); # without time_zone we get UTC ... yuck!
 
     my $seconds = OpenSRF::Utils->interval_to_seconds($shelf_expire);
     my $expire_time = $start_time->add(seconds => $seconds);
@@ -1555,6 +1539,25 @@ __PACKAGE__->register_method(
     }
 );
 
+__PACKAGE__->register_method(
+    method    => "hold_pull_list",
+    stream => 1,
+    # TODO: tag with api_level 2 once fully supported
+    api_name  => "open-ils.circ.hold_pull_list.fleshed.stream",
+    signature => {
+        desc   => q/Returns a stream of fleshed holds  that need to be 
+                    "pulled" by a given location.  The location is 
+                    determined by the login session.  
+                    This API calls always run in authoritative mode./,
+        params => [
+            { desc => 'Limit (optional)',  type => 'number'},
+            { desc => 'Offset (optional)', type => 'number'},
+        ],
+        return => {
+            desc => 'Stream of holds holds, or event on failure',
+        }
+    }
+);
 
 sub hold_pull_list {
     my( $self, $conn, $authtoken, $limit, $offset ) = @_;
@@ -1577,12 +1580,24 @@ sub hold_pull_list {
         return $count;
 
     } elsif( $self->api_name =~ /id_list/ ) {
-        return $U->storagereq(
+        $U->storagereq(
             'open-ils.storage.direct.action.hold_request.pull_list.id_list.current_copy_circ_lib.status_filtered.atomic',
             $org, $limit, $offset );
 
+    } elsif ($self->api_name =~ /fleshed/) {
+
+        my $ids = $U->storagereq(
+            'open-ils.storage.direct.action.hold_request.pull_list.id_list.current_copy_circ_lib.status_filtered.atomic',
+            $org, $limit, $offset );
+
+        my $e = new_editor(xact => 1, requestor => $reqr);
+        $conn->respond(uber_hold_impl($e, $_, {flesh_acpl => 1})) for @$ids;
+        $e->rollback;
+        $conn->respond_complete;
+        return;
+
     } else {
-        return $U->storagereq(
+        $U->storagereq(
             'open-ils.storage.direct.action.hold_request.pull_list.search.current_copy_circ_lib.status_filtered.atomic',
             $org, $limit, $offset );
     }
@@ -2148,7 +2163,7 @@ sub fetch_captured_holds {
     };
     if($self->api_name =~ /expired/) {
         $query->{'where'}->{'+alhr'}->{'-or'} = {
-                shelf_expire_time => { '<' => 'now'},
+                shelf_expire_time => { '<' => 'today'},
                 cancel_time => { '!=' => undef },
         };
     }
@@ -2477,7 +2492,11 @@ sub do_possibility_checks {
 
     } elsif( $hold_type eq OILS_HOLD_TYPE_METARECORD ) {
 
-        my ($recs) = __PACKAGE__->method_lookup('open-ils.circ.holds.metarecord.filterd_records')->run($mrid, $holdable_formats);
+        # pasing undef as the depth to filtered_records causes the depth
+        # of the selection_ou to be used, which is not what we want here.
+        $depth ||= 0;
+
+        my ($recs) = __PACKAGE__->method_lookup('open-ils.circ.holds.metarecord.filtered_records')->run($mrid, $holdable_formats, $selection_ou, $depth);
         my @status = ();
         for my $rec (@$recs) {
             @status = _check_title_hold_is_possible(
@@ -2491,11 +2510,23 @@ sub do_possibility_checks {
 }
 
 sub MR_filter_records {
-    return $U->storagereq('open-ils.storage.metarecord.filtered_records.atomic', $_[2], $_[3]);
+    my $self = shift;
+    my $client = shift;
+    my $m = shift;
+    my $f = shift;
+    my $o = shift;
+    my $d = shift;
+    my $opac_visible = shift;
+    
+    my $org_at_depth = defined($d) ? $U->org_unit_ancestor_at_depth($o, $d) : $o;
+    return $U->storagereq(
+        'open-ils.storage.metarecord.filtered_records.atomic', 
+        $m, $f, $org_at_depth, $opac_visible
+    );
 }
 __PACKAGE__->register_method(
     method   => 'MR_filter_records',
-    api_name => 'open-ils.circ.holds.metarecord.filterd_records',
+    api_name => 'open-ils.circ.holds.metarecord.filtered_records',
 );
 
 
@@ -3368,6 +3399,10 @@ sub uber_hold_impl {
         %$details
     };
 
+    $resp->{copy}->location(
+        $e->retrieve_asset_copy_location($resp->{copy}->location))
+        if $resp->{copy} and $args->{flesh_acpl};
+
     unless($args->{suppress_patron_details}) {
         my $card = $e->retrieve_actor_card($user->card) or return $e->event;
         $resp->{patron_first}   = $user->first_given_name,
@@ -3588,7 +3623,6 @@ sub clear_shelf_process {
             $hold->cancel_time('now');
             $hold->cancel_cause(2); # Hold Shelf expiration
             $e->update_action_hold_request($hold) or return $e->die_event;
-            delete_hold_copy_maps($self, $e, $hold->id) and return $e->die_event;
             push(@canceled_holds, $hold_id);
         }
 
@@ -4065,15 +4099,15 @@ __PACKAGE__->register_method(
     }
 );
 
-# XXX Need to add type I (and, soon, type P) holds to these counts
+# XXX Need to add type I holds to these counts
 sub rec_hold_count {
     my($self, $conn, $target_id, $args) = @_;
     $args ||= {};
 
     my $mmr_join = {
         mmrsm => {
-            field => 'id',
-            fkey => 'source',
+            field => 'source',
+            fkey => 'id',
             filter => {metarecord => $target_id}
         }
     };
@@ -4131,6 +4165,17 @@ sub rec_hold_count {
                     },
                     {
                         '-and' => {
+                            hold_type => 'P',
+                            target => {
+                                in => {
+                                    select => {bmp => ['id']},
+                                    from => {bmp => $bre_join}
+                                }
+                            }
+                        }
+                    },
+                    {
+                        '-and' => {
                             hold_type => 'T',
                             target => $target_id
                         }
@@ -4141,7 +4186,7 @@ sub rec_hold_count {
     };
 
     if($self->api_name =~ /mmr/) {
-        $query->{where}->{'+ahr'}->{'-or'}->[2] = {
+        $query->{where}->{'+ahr'}->{'-or'}->[3] = {
             '-and' => {
                 hold_type => 'T',
                 target => {
@@ -4153,7 +4198,7 @@ sub rec_hold_count {
             }
         };
 
-        $query->{where}->{'+ahr'}->{'-or'}->[3] = {
+        $query->{where}->{'+ahr'}->{'-or'}->[4] = {
             '-and' => {
                 hold_type => 'M',
                 target => $target_id
@@ -4218,6 +4263,7 @@ __PACKAGE__->register_method(
         /,
         params => [
             {desc => 'Metarecord ID', type => 'number'},
+            {desc => 'Context Org ID', type => 'number'},
             {desc => 'Hold ID List', type => 'array'},
         ],
         return => {
@@ -4232,18 +4278,24 @@ __PACKAGE__->register_method(
     }
 );
 
-sub mr_hold_filter_attrs {
-    my ($self, $client, $mr_id, $hold_ids) = @_;
+sub mr_hold_filter_attrs { 
+    my ($self, $client, $mr_id, $org_id, $hold_ids) = @_;
     my $e = new_editor();
 
+    # by default, return MR / hold attributes for all constituent
+    # records with holdable copies.  If there is a hard boundary,
+    # though, limit to records with copies within the boundary,
+    # since anything outside the boundary can never be held.
+    my $org_depth = 0;
+    if ($org_id) {
+        $org_depth = $U->ou_ancestor_setting_value(
+            $org_id, OILS_SETTING_HOLD_HARD_BOUNDARY) || 0;
+    }
 
-    my $mr = $e->retrieve_metabib_metarecord($mr_id) or return $e->event;
-    my $bre_ids = $e->json_query({
-        select => {mmrsm => ['source']},
-        from => 'mmrsm',
-        where => {'+mmrsm' => {metarecord => $mr_id}}
-    });
-    $bre_ids = [map {$_->{source}} @$bre_ids];
+    # get all org-scoped records w/ holdable copies for this metarecord
+    my ($bre_ids) = $self->method_lookup(
+        'open-ils.circ.holds.metarecord.filtered_records')->run(
+            $mr_id, undef, $org_id, $org_depth);
 
     my $item_lang_attr = 'item_lang'; # configurable?
     my $format_attr = $e->retrieve_config_global_flag(
@@ -4293,10 +4345,10 @@ sub mr_hold_filter_attrs {
             }
         };
 
-        # collect the ccvm's for the selected formats / language (
+        # collect the ccvm's for the selected formats / language
         # (i.e. the holdable formats) on the MR.
         # this assumes a two-key structure for format / language,
-        # though assumption is made about the keys themselves.
+        # though no assumption is made about the keys themselves.
         my $hformats = OpenSRF::Utils::JSON->JSON2perl($hold->holdable_formats);
         my $lang_vals = [];
         my $format_vals = [];
@@ -4320,8 +4372,9 @@ sub mr_hold_filter_attrs {
         # find all of the bib records within this metarcord whose 
         # format / language match the holdable formats on the hold
         my ($bre_ids) = $self->method_lookup(
-            'open-ils.circ.holds.metarecord.filterd_records')->run(
-                $hold->target, $hold->holdable_formats);
+            'open-ils.circ.holds.metarecord.filtered_records')->run(
+                $hold->target, $hold->holdable_formats, 
+                $hold->selection_ou, $hold->selection_depth);
 
         # now find all of the 'icon' attributes for the records
         $resp->{hold}{icons} = get_batch_ccvms($e, $icon_attr, $bre_ids);