TPAC Org unit hiding
authorBill Erickson <berick@esilibrary.com>
Fri, 21 Sep 2012 17:58:46 +0000 (13:58 -0400)
committerMike Rylander <mrylander@gmail.com>
Thu, 14 Feb 2013 19:12:53 +0000 (14:12 -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>
Signed-off-by: Mike Rylander <mrylander@gmail.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
docs/RELEASE_NOTES_NEXT/tpac-ou-hiding.txt [new file with mode: 0644]

index 820e7c6..40cf63e 100644 (file)
@@ -3922,6 +3922,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'}
     }
@@ -3942,8 +3947,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 => {
@@ -4037,6 +4042,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 ad222e5..0838a29 100644 (file)
@@ -288,6 +288,7 @@ sub load_common {
     $self->load_copy_location_groups;
     $self->staff_saved_searches_set_expansion_state if $ctx->{is_staff};
     $self->load_search_filter_groups($ctx->{search_ou});
+    $self->load_org_util_funcs;
 
     return Apache2::Const::OK;
 }
index a4af2c6..026d792 100644 (file)
@@ -378,13 +378,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 340f9f1..ec8b6be 100644 (file)
@@ -595,4 +595,83 @@ sub check_for_temp_list_warning {
     return $warn;
 }
 
+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 9e2a054..c871c89 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 159af59..62b1898 100644 (file)
@@ -19,6 +19,11 @@ BLOCK build_org_selector;
     IF !value;
         value = loc_value;
     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 %]'>
@@ -63,8 +68,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 b705574..a38bd54 100644 (file)
@@ -123,8 +123,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,
diff --git a/docs/RELEASE_NOTES_NEXT/tpac-ou-hiding.txt b/docs/RELEASE_NOTES_NEXT/tpac-ou-hiding.txt
new file mode 100644 (file)
index 0000000..adebd77
--- /dev/null
@@ -0,0 +1,20 @@
+TPAC Org Unit Hiding
+====================
+
+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).
+
+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.
+
+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 page