much better: sorting desc except at actual holding level, other improvements
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Fri, 2 Mar 2012 19:02:04 +0000 (14:02 -0500)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Wed, 7 Mar 2012 21:57:10 +0000 (16:57 -0500)
all that i'm sure is left to do at the middle layer level is to support
translating "06" to "Jun." and the like

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

index ece120b..552611a 100644 (file)
@@ -837,11 +837,13 @@ __PACKAGE__->register_method(
     method    => "scoped_holding_summary_tree_for_bib",
     api_name  => "open-ils.serial.holding_summary_tree.by_bib",
     api_level => 1,
-    argc      => 1,
+    argc      => 6,
     signature => {
         desc   => q/Return a set of holding summaries organized into a tree
         of nodes that look like:
             {org_unit:<id>, holding_summaries:[], children:[]}
+
+        All arguments except the first (bibid) are optional.
         /,
         params => [
             {   name => "bibid",
@@ -859,26 +861,39 @@ __PACKAGE__->register_method(
 
 # This is a helper for grouped_holdings_for_summary() later.
 sub _label_holding_level {
-    my ($pattern_code, $subfield, $value) = @_;
+    my ($pattern_field, $subfield, $value) = @_;
 
     return $value;  # XXX TODO
 }
 
 # This is a helper for grouped_holdings_for_summary() later.
 sub _get_deepest_holding_level {
-    my ($display_grouping, $pattern_code) = @_;
-
-    my $field = new MARC::Field(
-        "999", @{ OpenSRF::Utils::JSON->JSON2perl($pattern_code) }
-    );
-
-    my @subfields = @{ $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping} };
+    my ($display_grouping, $pattern_field) = @_;
 
-    my @present = grep { $field->subfield($_) } @subfields;
+    my @present = grep { $pattern_field->subfield($_) } @{
+        $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping}
+    };
 
     return pop @present;
 }
 
+# This is a helper for grouped_holdings_for_summary() later.
+sub _make_grouped_holding_node {
+    my ($row, $subfield, $deepest_level, $pattern_field) = @_;
+
+    return {
+        $subfield eq $deepest_level ? (
+            label => $row->{label},
+            holding => $row->{id}
+        ) : (
+            value => $row->{value},
+            label => _label_holding_level(
+                $pattern_field, $subfield, $row->{value}
+            )
+        )
+    };
+}
+
 sub grouped_holdings_for_summary {
     my (
         $self, $client, $summary_type, $summary_id,
@@ -896,16 +911,18 @@ sub grouped_holdings_for_summary {
         if (ref $_ ne 'ARRAY') {
             return new OpenILS::Event(
                 "BAD_PARAMS", note =>
-                    "expand_path, limits and offsets arguments must be arrays"
+                    "'expand_path', 'limits' and 'offsets' arguments must " .
+                    "be arrays"
             );
         }
     }
 
-    if (not (scalar(@$limits) == scalar(@$expand_path) + 1) and
-        (scalar(@$offsets) == scalar(@$expand_path) + 1)) {
+    if (scalar(@$limits) != scalar(@$expand_path) + 1 or
+        scalar(@$offsets) != scalar(@$expand_path) + 1) {
         return new OpenILS::Event(
             "BAD_PARAMS", note =>
-                "limits and offsets must be one element longer than expand_path"
+                "'limits' and 'offsets' arrays each must be one element " .
+                "longer than 'expand_path'"
         );
     }
 
@@ -916,19 +933,74 @@ sub grouped_holdings_for_summary {
 
     my $e = new_editor;
 
-    # First, get display grouping for requested summary (either chron or enum).
+    # First, get display grouping for requested summary (either chron or enum)
+    # and the pattern code. Even though we have to JOIN through sitem to get
+    # pattern_code from scap, we don't actually care about specific items yet.
     my $row = $e->json_query({
-        select => {sdist => ["display_grouping"]},
-        from => {$summary_hint => {sdist => {}}},
-        where => {"+$summary_hint" => {id => $summary_id}}
+        select => {sdist => ["display_grouping"], scap => ["pattern_code"]},
+        from => {
+            $summary_hint => {
+                sdist => {
+                    join => {
+                        sstr => {
+                            join => {
+                                sitem => {
+                                    join => {
+                                        siss => {
+                                            join => {scap => {}}
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        where => {
+            "+$summary_hint" => {id => $summary_id},
+            "+sitem" => {date_received => {"!=" => undef}}
+        },
+        limit => 1
     }) or return $e->die_event;
 
-    return new OpenILS::Event("BAD_PARAMS", note => "summary_id not found")
-        unless @$row;
+    # Summaries without attached holdings constitute bad data, not benign
+    # empty result sets.
+    return new OpenILS::Event(
+        "BAD_PARAMS",
+        note => "Summary #$summary_id not found, or no holdings attached"
+    ) unless @$row;
 
-    # And now we know which subfields we care about from
+    # Unless data has been disarranged, all holdings grouped together under
+    # the same summary should have the same pattern code, so we can take any
+    # result from the set we just got.
+    my $pattern_field;
+    eval {
+        $pattern_field = new MARC::Field(
+            "999", # irrelevant for our purposes
+            @{ OpenSRF::Utils::JSON->JSON2perl($row->[0]->{pattern_code}) }
+        );
+    };
+    if ($@) {
+        return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $@);
+    }
+
+    # And now we know which subfields we will care about from
     # serial.materialized_holding_code.
     my $display_grouping = $row->[0]->{display_grouping};
+
+    # This will tell us when to stop grouping and start showing actual
+    # holdings.
+    my $deepest_level =
+        _get_deepest_holding_level($display_grouping, $pattern_field);
+    if (not defined $deepest_level) {
+        # corrupt pattern code
+        my $msg = "couldn't determine deepest holding level for " .
+            "$summary_type summary #$summary_id";
+        $logger->warn($msg);
+        return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $msg);
+    }
+
     my @subfields = @{ $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping} };
 
     # We look for holdings grouped at the top level once no matter what,
@@ -944,8 +1016,10 @@ sub grouped_holdings_for_summary {
     # Now get the top level of holdings.
     my $top = $e->json_query({
         select => {
-            "smhc_$subfield" => ["value"],
-            scap => ["pattern_code"]
+            "smhc_$subfield" => ["value"], (
+                $subfield eq $deepest_level ?
+                    (siss => [qw/id label date_published/]) : ()
+            )
         },
         from => {
             $summary_hint => {
@@ -956,9 +1030,7 @@ sub grouped_holdings_for_summary {
                                 sitem => {
                                     join => {
                                         siss => {
-                                            join => {
-                                                scap => {}, %subfield_joins
-                                            }
+                                            join => {%subfield_joins}
                                         }
                                     }
                                 }
@@ -976,50 +1048,24 @@ sub grouped_holdings_for_summary {
         distinct => 1,  # sic, this goes here in json_query
         limit => int(shift(@$limits)),
         offset => int(shift(@$offsets)),
-        order_by => [
-            {class => "smhc_$subfield", field => "value",
-                direction => "descending"}
-        ]
+        order_by => {
+            "smhc_$subfield" => {
+                "value" => {
+                    direction => ($subfield eq $deepest_level ? "asc" : "desc")
+                }
+            }
+        }
     }) or return $e->die_event;
 
-    # Unless data has been disarranged, all holdings grouped together under
-    # the same summary should have the same pattern code, so we can take any
-    # result from the set we just got.
-
-    my $pattern_code = $top->[0]->{pattern_code};
-
     # Make the tree we have so far.
-    my $tree = [
-        map {
-            +{
-                value => $_->{value},
-                label =>
-                    _label_holding_level($pattern_code, $subfield, $_->{value})
-            };
-        } @$top
-    ];
+    my $tree = [ map(
+        _make_grouped_holding_node($_,$subfield,$deepest_level,$pattern_field),
+        @$top
+    ) ];
 
     # Ok, that got us the top level, with nothing expanded. Now we loop through
-    # the deeper levels of @$expand_path, issuing similar queries to get us
-    # lower groupings and even actual specific holdings.
-
-    # This will tell us when to stop grouping and start showing actual
-    # holdings.
-    my $deepest_level =
-        _get_deepest_holding_level($display_grouping, $pattern_code);
-    if (not defined $deepest_level) {
-        # corrupt pattern code
-        my $msg = "couldn't determine deepest holding level for " .
-            "$summary_type summary #$summary_id";
-        $logger->warn($msg);
-        return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $msg);
-    }
-
-    $logger->debug(
-        "deepest holding level for $summary_type summary " .
-        "#$summary_id is $deepest_level"
-    );
-
+    # the elements of @$expand_path, issuing similar queries to get us deeper
+    # groupings and even actual specific holdings.
     my $parent = $tree;
 
     foreach my $value (@$expand_path) {
@@ -1067,10 +1113,13 @@ sub grouped_holdings_for_summary {
             distinct => 1,  # sic, this goes here in json_query
             limit => int(shift(@$limits)),
             offset => int(shift(@$offsets)),
-            order_by => [
-                {class => "smhc_$subfield", field => "value",
-                    direction => "descending"}
-            ]
+            order_by => {
+                "smhc_$subfield" => {
+                    "value" => {
+                        direction => ($subfield eq $deepest_level?"asc":"desc")
+                    }
+                }
+            }
         }) or return $e->die_event;
 
         return $tree unless @$level;
@@ -1078,17 +1127,14 @@ sub grouped_holdings_for_summary {
         # Find attachment point for our results.
         my ($point) = grep { $_->{value} eq $value } @$parent;
 
-        # Set parent for the next iteration
+        # Set parent for the next iteration.
         $parent = $point->{children} = [
-            map {
-                +{
-                    # XXX if on deepest level, show actual holdings
-                    value => $_->{value},
-                    label => _label_holding_level(
-                        $pattern_code, $subfield, $_->{value}
-                    )
-                };
-            } @$level
+            map(
+                _make_grouped_holding_node(
+                    $_, $subfield, $deepest_level, $pattern_field
+                ),
+                @$level
+            )
         ];
 
         last if $subfield eq $deepest_level;
@@ -1101,7 +1147,7 @@ __PACKAGE__->register_method(
     method    => "grouped_holdings_for_summary",
     api_name  => "open-ils.serial.holdings.grouped_by_summary",
     api_level => 1,
-    argc      => 1,
+    argc      => 5,
     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./,