Fetch data on units for holdings, if asked to do so
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Tue, 6 Mar 2012 22:51:56 +0000 (17:51 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Wed, 7 Mar 2012 21:57:11 +0000 (16:57 -0500)
So the TPAC can display them (to come)

Signed-off-by: Lebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/AppUtils.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Record.pm

index b3777c2..c47d51c 100644 (file)
@@ -1943,5 +1943,111 @@ sub bib_container_items_via_search {
     return [map { $ordering_hash{$_} } @$id_list];
 }
 
+
+# I hate to put this here exactly, but this code needs to be shared between
+# the TPAC's mod_perl module and open-ils.serial.
+#
+# There is a reason every part of the query *except* those parts dealing
+# with scope are moved here from the code's origin in TPAC.  The serials
+# use case does *not* want the same scoping logic.
+#
+# Also, note that for the serials uses case, we may filter in OPAC visible
+# status and copy/call_number deletedness, but we don't filter on any
+# particular values for serial.item.status or serial.item.date_received.
+# Since we're only using this *after* winnowing down the set of issuances
+# that copies should be related to, I'm not sure we need any such serial.item
+# filters.
+
+sub basic_opac_copy_query {
+    # Pass a defined value for $rec_id OR $iss_id, not both.
+    my ($self, $rec_id, $iss_id, $copy_limit, $copy_offset, $staff) = @_;
+
+    return {
+        select => {
+            acp => ['id', 'barcode', 'circ_lib', 'create_date',
+                    'age_protect', 'holdable'],
+            acpl => [
+                {column => 'name', alias => 'copy_location'},
+                {column => 'holdable', alias => 'location_holdable'}
+            ],
+            ccs => [
+                {column => 'name', alias => 'copy_status'},
+                {column => 'holdable', alias => 'status_holdable'}
+            ],
+            acn => [
+                {column => 'label', alias => 'call_number_label'},
+                {column => 'id', alias => 'call_number'}
+            ],
+            circ => ['due_date'],
+            acnp => [
+                {column => 'label', alias => 'call_number_prefix_label'},
+                {column => 'id', alias => 'call_number_prefix'}
+            ],
+            acns => [
+                {column => 'label', alias => 'call_number_suffix_label'},
+                {column => 'id', alias => 'call_number_suffix'}
+            ],
+            bmp => [
+                {column => 'label', alias => 'part_label'},
+            ],
+            ($iss_id ? (sitem => ["issuance"]) : ())
+        },
+
+        from => {
+            acp => {
+                ($iss_id ? (
+                    sitem => {
+                        fkey => 'id',
+                        field => 'unit',
+                        filter => {issuance => $iss_id}
+                    }
+                ) : ()),
+                acn => {
+                    join => {
+                        acnp => { fkey => 'prefix' },
+                        acns => { fkey => 'suffix' }
+                    },
+                    filter => [
+                        {deleted => 'f'},
+                        ($rec_id ? {record => $rec_id} : ())
+                    ],
+                },
+                circ => { # If the copy is circulating, retrieve the open circ
+                    type => 'left',
+                    filter => {checkin_time => undef}
+                },
+                acpl => {
+                    ($staff ? () : (filter => { opac_visible => 't' }))
+                },
+                ccs => {
+                    ($staff ? () : (filter => { opac_visible => 't' }))
+                },
+                aou => {},
+                acpm => {
+                    type => 'left',
+                    join => {
+                        bmp => { type => 'left' }
+                    }
+                }
+            }
+        },
+
+        where => {
+            '+acp' => {
+                deleted => 'f',
+                ($staff ? () : (opac_visible => 't'))
+            }
+        },
+
+        order_by => [
+            {class => 'aou', field => 'name'},
+            {class => 'acn', field => 'label'}
+        ],
+
+        limit => $copy_limit,
+        offset => $copy_offset
+    };
+}
+
 1;
 
index b172272..6ccf7d1 100644 (file)
@@ -718,8 +718,6 @@ sub _find_ou_in_holdings_tree {
     return;
 }
 
-# XXX deprecate/replace scoped_bib_holdings_summary
-
 sub scoped_holding_summary_tree_for_bib {
     my (
         $self, $client, $bib, $org_unit, $depth, $limit, $offset, $ascending
@@ -917,13 +915,42 @@ sub _get_deepest_holding_level {
 }
 
 # This is a helper for grouped_holdings_for_summary() later.
+sub _opac_visible_unit_data {
+    my ($issuance_id_list, $staff, $e) = @_;
+
+    my $rows = $e->json_query(
+        $U->basic_opac_copy_query(
+            undef, $issuance_id_list,
+            1000, 0,    # XXX no mechanism for users to page at this level yet
+            $staff
+        )
+    ) or return $e->die_event;
+
+    my $results = {};
+
+    # Take the list of rows returned from json_query() and sort results into
+    # several smaller lists stored in a hash keyed by issuance ID.
+    foreach my $row (@$rows) {
+        $results->{$row->{issuance}} = [] unless
+            exists $results->{$row->{issuance}};
+        push @{ $results->{$row->{issuance}} }, $row;
+    }
+
+    return $results;
+}
+
+# This is a helper for grouped_holdings_for_summary() later.
 sub _make_grouped_holding_node {
-    my ($row, $subfield, $deepest_level, $pattern_field, $mfhd_cache) = @_;
+    my (
+        $row, $subfield, $deepest_level, $pattern_field,
+        $unit_data, $mfhd_cache
+    ) = @_;
 
     return {
         $subfield eq $deepest_level ? (
             label => $row->{label},
-            holding => $row->{id}
+            holding => $row->{id},
+            ($unit_data ? (units => ($unit_data->{$row->{id}} || [])) : ())
         ) : (
             value => $row->{value},
             label => _label_holding_level(
@@ -936,7 +963,7 @@ sub _make_grouped_holding_node {
 sub grouped_holdings_for_summary {
     my (
         $self, $client, $summary_type, $summary_id,
-        $expand_path, $limit, $offsets, $auto_expand_first
+        $expand_path, $limit, $offsets, $auto_expand_first, $with_units
     ) = @_;
 
     # Validate input or set defaults.
@@ -1104,11 +1131,22 @@ sub grouped_holdings_for_summary {
     # _label_holding_level() to see what I mean.
     my $mfhd_cache = {};
 
+    # Prepare related unit data if appropriate.
+    my $unit_data;
+
+    if ($with_units and $subfield eq $deepest_level) {
+        $unit_data = _opac_visible_unit_data(
+            [map { $_->{id} } @$top], $with_units > 1, $e
+        );
+        return $unit_data if defined $U->event_code($unit_data);
+    }
+
     # Make the tree we have so far.
     my $tree = [
         map(
             _make_grouped_holding_node(
-                $_, $subfield, $deepest_level, $pattern_field, $mfhd_cache
+                $_, $subfield, $deepest_level, $pattern_field,
+                $unit_data, $mfhd_cache
             ),
             @$top
         ), ($top_more ? undef : ())
@@ -1190,11 +1228,20 @@ sub grouped_holdings_for_summary {
         # Find attachment point for our results.
         my ($point) = grep { ref $_ and $_->{value} eq $value } @$parent;
 
+        # Prepare related unit data if appropriate.
+        if ($with_units and $subfield eq $deepest_level) {
+            $unit_data = _opac_visible_unit_data(
+                [map { $_->{id} } @$level], $with_units > 1, $e
+            );
+            return $unit_data if defined $U->event_code($unit_data);
+        }
+
         # Set parent for the next iteration.
         $parent = $point->{children} = [
             map(
                 _make_grouped_holding_node(
-                    $_, $subfield, $deepest_level, $pattern_field, $mfhd_cache
+                    $_, $subfield, $deepest_level, $pattern_field,
+                    $unit_data, $mfhd_cache
                 ),
                 @$level
             ), ($level_more ? undef : ())
@@ -1210,19 +1257,31 @@ __PACKAGE__->register_method(
     method    => "grouped_holdings_for_summary",
     api_name  => "open-ils.serial.holdings.grouped_by_summary",
     api_level => 1,
-    argc      => 6,
+    argc      => 7,
     signature => {
         desc   => q/Return a tree of holdings associated with a given summary
         grouped by all but the last of either chron or enum units./,
         params => [
             { name => "summary_type", type => "string" },
             { name => "summary_id", type => "number" },
-            { name => "expand_path", type => "array" },
+            { name => "expand_path", type => "array",
+                desc => "In root-to-leaf order, the values of the nodes along the axis you want to expand" },
             { name => "limit (default 10)", type => "number" },
             { name => "offsets", type => "array", desc =>
                 "This must be exactly one element longer than expand_path" },
             { name => "auto_expand_first", type => "boolean", desc =>
-                "Only if expand_path is empty, automatically expand first top-level grouping" }
+                "Only if expand_path is empty, automatically expand first top-level grouping" },
+            { name => "with_units", type => "number", desc => q/
+                If true at all, for each holding, if there are associated units,
+                add some information about them to the result tree. These units
+                will be filtered by OPAC visibility unless you provide a value
+                greater than 1.
+
+                IOW:
+                    0 = no units,
+                    1 = opac visible units,
+                    2 = all units (i.e. staff view)
+                / }
         ]
     }
 );
index 1110a0d..68739d6 100644 (file)
@@ -131,72 +131,9 @@ sub mk_copy_query {
     my $copy_limit = shift;
     my $copy_offset = shift;
 
-    my $query = {
-        select => {
-            acp => ['id', 'barcode', 'circ_lib', 'create_date', 'age_protect', 'holdable'],
-            acpl => [
-                {column => 'name', alias => 'copy_location'},
-                {column => 'holdable', alias => 'location_holdable'}
-            ],
-            ccs => [
-                {column => 'name', alias => 'copy_status'},
-                {column => 'holdable', alias => 'status_holdable'}
-            ],
-            acn => [
-                {column => 'label', alias => 'call_number_label'},
-                {column => 'id', alias => 'call_number'}
-            ],
-            circ => ['due_date'],
-            acnp => [
-                {column => 'label', alias => 'call_number_prefix_label'},
-                {column => 'id', alias => 'call_number_prefix'}
-            ],
-            acns => [
-                {column => 'label', alias => 'call_number_suffix_label'},
-                {column => 'id', alias => 'call_number_suffix'}
-            ],
-            bmp => [
-                {column => 'label', alias => 'part_label'},
-            ]
-        },
-
-        from => {
-            acp => {
-                acn => { 
-                    join => { 
-                        acnp => { fkey => 'prefix' },
-                        acns => { fkey => 'suffix' }
-                    },
-                    filter => [{deleted => 'f'}, {record => $rec_id}],
-                },
-                circ => { # If the copy is circulating, retrieve the open circ
-                    type => 'left',
-                    filter => {checkin_time => undef}
-                },
-                acpl => {},
-                ccs => {},
-                aou => {},
-                acpm => {
-                    type => 'left',
-                    join => {
-                        bmp => { type => 'left' }
-                    }
-                }
-            }
-        },
-
-        where => {
-            '+acp' => {deleted => 'f' }
-        },
-
-        order_by => [
-            {class => 'aou', field => 'name'}, 
-            {class => 'acn', field => 'label'}
-        ],
-
-        limit => $copy_limit,
-        offset => $copy_offset
-    };
+    my $query = $U->basic_opac_copy_query(
+        $rec_id, undef, $copy_limit, $copy_offset, $self->ctx->{is_staff}
+    );
 
     # XXX In the future, $sort_org should be understood to be an abstration
     # that refers to something configurable, not necessariyl physical_loc.
@@ -230,13 +167,6 @@ sub mk_copy_query {
         }
     };
 
-    # Filter hidden items if this is the public catalog
-    unless($self->ctx->{is_staff}) { 
-        $query->{where}->{'+acp'}->{opac_visible} = 't';
-        $query->{from}->{'acp'}->{'acpl'}->{filter} = {opac_visible => 't'};
-        $query->{from}->{'acp'}->{'ccs'}->{filter} = {opac_visible => 't'};
-    }
-
     return $query;
 }