TPAC Org unit hiding
authorBill Erickson <berick@esilibrary.com>
Fri, 21 Sep 2012 17:58:46 +0000 (13:58 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 14 Nov 2012 15:05:07 +0000 (10:05 -0500)
Adds support for the opac.org_unit_hiding.depth org unit setting to
TPAC, which makes out-of-scope org units disappear (except when
explicitly requested).

Ui changes:

All search org unit selectors
Holds pickup lib selector
Copy summary in search results page
Copy list in search results page
Copy summary in record detail page (which controls the copy grid).
Hold summary in record detail

Org unit hiding is based on the physical_loc (Physical Location) param /
cookie, which is the closest analog to 'ol' (original location), from
which it was based in the JSPAC.

Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
Open-ILS/src/templates/opac/parts/misc_util.tt2
Open-ILS/src/templates/opac/parts/org_selector.tt2
Open-ILS/src/templates/opac/parts/record/copy_counts.tt2
Open-ILS/src/templates/opac/parts/record/summary.tt2
Open-ILS/src/templates/opac/parts/result/copy_counts.tt2

index 3b46e8c..dc02942 100644 (file)
@@ -3832,6 +3832,11 @@ __PACKAGE__->register_method(
             selected bib record or its associated copies and call_numbers/,
         params => [
             { desc => 'Bib ID', type => 'number' },
+            { desc => q/Optional arguments.  Supported arguments include:
+                "pickup_lib_descendant" -> limit holds to those whose pickup
+                library is equal to or is a child of the provided org unit/,
+                type => 'object'
+            }
         ],
         return => {desc => 'Hold count', type => 'number'}
     }
@@ -3852,8 +3857,8 @@ __PACKAGE__->register_method(
 
 # XXX Need to add type I (and, soon, type P) holds to these counts
 sub rec_hold_count {
-    my($self, $conn, $target_id) = @_;
-
+    my($self, $conn, $target_id, $args) = @_;
+    $args ||= {};
 
     my $mmr_join = {
         mmrsm => {
@@ -3947,6 +3952,21 @@ sub rec_hold_count {
     }
 
 
+    if (my $pld = $args->{pickup_lib_descendant}) {
+        $query->{where}->{'+ahr'}->{pickup_lib} = {
+            in => {
+                select  => {aou => [{ 
+                    column => 'id', 
+                    transform => 'actor.org_unit_descendants', 
+                    result_field => 'id' 
+                }]},
+                from    => 'aou',
+                where   => {id => $pld}
+            }
+        };
+    }
+
+
     return new_editor()->json_query($query)->[0]->{count};
 }
 
index 15ffb57..5882d91 100644 (file)
@@ -280,6 +280,7 @@ sub load_common {
     $self->load_eg_cache_hash;
     $self->load_copy_location_groups;
     $self->staff_saved_searches_set_expansion_state if $ctx->{is_staff};
+    $self->load_org_util_funcs;
 
     return Apache2::Const::OK;
 }
index cdf7e15..f5634ba 100644 (file)
@@ -356,13 +356,23 @@ sub prepare_browse_call_numbers {
 
 sub get_hold_copy_summary {
     my ($self, $rec_id, $org) = @_;
+    my $ctx = $self->ctx;
     
     my $search = OpenSRF::AppSession->create('open-ils.search');
     my $req1 = $search->request(
         'open-ils.search.biblio.record.copy_count', $org, $rec_id); 
 
+    # if org unit hiding applies, limit the hold count to holds
+    # whose pickup library is within our depth-scoped tree
+    my $count_args = {};
+    while ($org and $ctx->{org_within_hiding_scope}->($org)) {
+        $count_args->{pickup_lib_descendant} = $org;
+        $org = $ctx->{get_aou}->($org)->parent_ou;
+    }
+
     $self->ctx->{record_hold_count} = $U->simplereq(
-        'open-ils.circ', 'open-ils.circ.bre.holds.count', $rec_id);
+        'open-ils.circ', 'open-ils.circ.bre.holds.count', 
+        $rec_id, $count_args);
 
     $self->ctx->{copy_summary} = $req1->recv->content;
 
index c2b24bb..ddd1224 100644 (file)
@@ -523,4 +523,79 @@ sub apache_log_if_event {
     return;
 }
 
+sub load_org_util_funcs {
+    my $self = shift;
+    my $ctx = $self->ctx;
+
+    # evaluates to true if test_ou is within the same depth-
+    # scoped tree as ctx_ou. both ou's are org unit objects.
+    $ctx->{org_within_scope} = sub {
+        my ($ctx_ou, $test_ou, $depth) = @_;
+
+        return 1 if $ctx_ou->id == $test_ou->id;
+
+        if ($depth) {
+
+            # find the top-most ctx-org ancestor at the provided depth
+            while ($depth < $ctx_ou->ou_type->depth 
+                    and $ctx_ou->id != $test_ou->id) {
+                $ctx_ou = $ctx->{get_aou}->($ctx_ou->parent_ou);
+            }
+
+            # the preceeding loop may have landed on our org
+            return 1 if $ctx_ou->id == $test_ou->id;
+
+        } else {
+
+            return 1 if defined $depth; # $depth == 0;
+        }
+
+        for my $child (@{$ctx_ou->children}) {
+            return 1 if $ctx->{org_within_scope}->($child, $test_ou);
+        }
+
+        return 0;
+    };
+
+    # Returns true if the provided org unit is within the same 
+    # org unit hiding depth-scoped tree as the physical location.
+    # Org unit hiding is based on the immutable physical_loc
+    # and is not meant to change as search/pref/etc libs change
+    $ctx->{org_within_hiding_scope} = sub {
+        my $org_id = shift;
+        my $ploc = $ctx->{physical_loc} or return 1;
+
+        my $depth = $ctx->{get_org_setting}->(
+            $ploc, 'opac.org_unit_hiding.depth');
+
+        return 1 unless $depth; # 0 or undef
+
+        return $ctx->{org_within_scope}->( 
+            $ctx->{get_aou}->($ploc), 
+            $ctx->{get_aou}->($org_id), $depth);
+    };
+
+    # Evaluates to true if the context org (defaults to get_library) 
+    # is not within the hiding scope.  Also evaluates to true if the 
+    # user's pref_ou is set and it's out of hiding scope.
+    # Always evaluates to true when ctx.is_staff
+    $ctx->{org_hiding_disabled} = sub {
+        my $ctx_org = shift || $ctx->{search_ou};
+
+        return 1 if $ctx->{is_staff};
+
+        # beware locg values formatted as org:loc
+        $ctx_org =~ s/:.*//g;
+
+        return 1 if !$ctx->{org_within_hiding_scope}->($ctx_org);
+
+        return 1 if $ctx->{pref_ou} and $ctx->{pref_ou} != $ctx_org 
+            and !$ctx->{org_within_hiding_scope}->($ctx->{pref_ou});
+
+        return 0;
+    };
+
+}
+
 1;
index cfe4c4a..99a81e1 100644 (file)
             );
         END;
 
+        ou_hiding_disabled = ctx.org_hiding_disabled();
+
         FOR volume IN xml.findnodes('//*[local-name()="volumes"]/*[local-name()="volume"]');
 
             # Check volume visibility - could push this into XPath
                     status = copy.findnodes('./*[local-name()="status"]');
                     NEXT IF status.getAttribute('opac_visible') == 'false';
 
+                    UNLESS ou_hiding_disabled;
+                        # extract the circ_lib id from the circ_lib node
+                        circ_lib = copy.findnodes('./*[local-name()="circ_lib"]');
+                        circ_lib_id = circ_lib.getAttribute('id').replace('.*/', '');
+                        NEXT UNLESS ctx.org_within_hiding_scope(circ_lib_id);
+                    END;
+
                     holding = {
                         label => vol.label,
                         part_label => part_label,
index 31ba30d..84e6a8d 100644 (file)
@@ -20,6 +20,11 @@ BLOCK build_org_selector;
             value = CGI.param('locg') || ctx.search_ou;
         END;
     END;
+
+    # if the selected org unit is out of hiding scope, 
+    # disable the ou-hide scoping altogether.
+    hiding_disabled = ctx.org_hiding_disabled(value);
+
     %]
 
     <select [% IF id %] id='[% id %]' [% END %] name='[% name %]'>
@@ -64,8 +69,11 @@ BLOCK build_org_selector;
 
             END;
 
-            # This org unit is not publicly visible (though its children may be).
+            # org is not publicly visible (though its children may be).
             NEXT UNLESS ctx.is_staff OR visible;
+            
+            # org is not within hiding scope (though its children may be).
+            NEXT UNLESS hiding_disabled OR ctx.org_within_hiding_scope(ou_id);
 
             node_value = ou_id;
             IF loc_grp;
index cd59442..9a6c695 100644 (file)
@@ -4,11 +4,13 @@
     [%- depths = ctx.copy_summary.size;
         depth = 0;
         displayed_ous = {};
+        ou_hiding_disabled = org_hiding_disabled();
         WHILE depth < depths;
             ou_avail = ctx.copy_summary.$depth.available;
             ou_id = ctx.copy_summary.$depth.org_unit;
             cp_org_unit = ctx.get_aou(ou_id);
-            IF cp_org_unit.opac_visible == 'f' AND !ctx.is_staff;
+            skip_me = !ou_hiding_disabled AND !ctx.org_within_hiding_scope(ou_id);
+            IF (cp_org_unit.opac_visible == 'f' AND !ctx.is_staff) OR skip_me;
                 depth = depth + 1;
                 NEXT;
             END;
index 3b348d6..d606a92 100644 (file)
@@ -101,8 +101,20 @@ IF num_uris > 0;
     <span id="rdetail_hold_counts">
         <h2>[% l('Current holds') %]</h2>
         <p>
-            [%- l("[quant,_1,current hold,current holds] with [quant,_2,total copy,total copies].", 
-                ctx.record_hold_count, ctx.copy_summary.0.count) %]
+            [% 
+                # If org hiding is enabled/relevant, only show 
+                # counts for copies within the hiding scope.
+                count_entry = 0;
+                FOR count_chunk IN ctx.copy_summary;
+                    IF ctx.org_within_hiding_scope(count_chunk.org_unit);
+                        # always true when hiding is disabled
+                        LAST;
+                    END;
+                    count_entry = count_entry + 1;
+                END;
+                l("[quant,_1,current hold,current holds] with [quant,_2,total copy,total copies].", 
+                    ctx.record_hold_count, ctx.copy_summary.$count_entry.count) 
+            %]
         </p>
     </span>
 [%- INCLUDE "opac/parts/record/copy_table.tt2" copies=ctx.copies %]
index 1bbc357..dc8aab7 100644 (file)
@@ -1,10 +1,13 @@
 [%- depths = attrs.copy_counts.size;
     depth = 0;
     displayed_ous = {};
+    hiding_disabled = ctx.org_hiding_disabled();
     WHILE depth < depths;
-        ou_name = ctx.get_aou(attrs.copy_counts.$depth.org_unit).name;
+        org_unit = ctx.get_aou(attrs.copy_counts.$depth.org_unit);
+        ou_name = org_unit.name;
         displayed_ous.$ou_name = 1;
-        IF attrs.copy_counts.$depth.count > 0;
+        IF attrs.copy_counts.$depth.count > 0 AND (
+            hiding_disabled OR ctx.org_within_hiding_scope(org_unit.id));
 %]
 <div class="result_count">
 [% IF ctx.get_aou(attrs.copy_counts.$depth.org_unit).opac_visible == 't' %]
     END;
 
     depth = attrs.plib_copy_counts.size - 1;
-    ou_name = ctx.get_aou(attrs.plib_copy_counts.$depth.org_unit).name;
+    org_unit = ctx.get_aou(attrs.plib_copy_counts.$depth.org_unit);
+    ou_name = org_unit.name;
     UNLESS displayed_ous.exists(ou_name);
     
 %]
-[%- IF attrs.plib_copy_counts.$depth.count > 0; %]
+[%- IF attrs.plib_copy_counts.$depth.count > 0 AND (
+        hiding_disabled OR ctx.org_within_hiding_scope(org_unit.id)) %]
 <div class="result_count preferred">[%
      l('[_1] of [quant,_2,copy,copies] available at [_3].',
         attrs.plib_copy_counts.$depth.available,