"+ssub" => {record_entry => int($bib)},
"+sitem" => {date_received => {"!=" => undef}}
},
- limit => int($limit),
+ limit => int($limit) + 1, # see comment below on "limit trick"
offset => int($offset),
order_by => [
{
# Now we build a tree out of our result set.
my $result = {};
+ # Use our "limit trick" from above to cheaply determine whether there's
+ # another page of results, for the UI's benefit. Put $more into the
+ # result hash at the very end.
+ my $more = 0;
+ if (scalar(@$rows) > int($limit)) {
+ $more = 1;
+ pop @$rows;
+ }
+
foreach my $row (@$rows) {
my $org_node_needs_placed = 0;
my $org_node =
}
}
+ $result->{more} = $more;
return $result;
}
api_level => 1,
argc => 6,
signature => {
- desc => q/Return a set of holding summaries organized into a tree
+ desc => 'Return a set of holding summaries organized into a tree
of nodes that look like:
{org_unit:<id>, holding_summaries:[], children:[]}
+ The root node has an extra key: "more". Its value is 1 if there
+ are more pages (in the limit/offset sense) of results that the caller
+ could potentially fetch.
+
All arguments except the first (bibid) are optional.
- /,
+ ',
params => [
{ name => "bibid",
desc => "ID of the bre to which holdings belong",
type => "number"
},
{ name => "org_unit", type => "number" },
- { name => "depth", type => "number" },
- { name => "limit", type => "number" },
- { name => "offset", type => "number" },
- { name => "ascending", type => "boolean" },
+ { name => "depth (default 0)", type => "number" },
+ { name => "limit (default 10)", type => "number" },
+ { name => "offset (default 0)", type => "number" },
+ { name => "ascending (default false)", type => "boolean" },
]
}
);
sub grouped_holdings_for_summary {
my (
$self, $client, $summary_type, $summary_id,
- $expand_path, $limits, $offsets
+ $expand_path, $limit, $offsets, $auto_expand_first
) = @_;
# Validate input or set defaults.
($summary_type .= "") =~ s/[^\w]//g;
$summary_id = int($summary_id);
$expand_path ||= [];
- $limits ||= [10];
+ $limit ||= 10;
+ $limit = 10 if $limit < 1;
$offsets ||= [0];
- foreach ($expand_path, $limits, $offsets) {
+ foreach ($expand_path, $offsets) {
if (ref $_ ne 'ARRAY') {
return new OpenILS::Event(
"BAD_PARAMS", note =>
- "'expand_path', 'limits' and 'offsets' arguments must " .
- "be arrays"
+ "'expand_path' and 'offsets' arguments must be arrays"
);
}
}
- if (scalar(@$limits) != scalar(@$expand_path) + 1 or
- scalar(@$offsets) != scalar(@$expand_path) + 1) {
+ if (scalar(@$offsets) != scalar(@$expand_path) + 1) {
return new OpenILS::Event(
"BAD_PARAMS", note =>
- "'limits' and 'offsets' arrays each must be one element " .
- "longer than 'expand_path'"
+ "'offsets' array must be one element longer than 'expand_path'"
);
}
%subfield_where_clauses
},
distinct => 1, # sic, this goes here in json_query
- limit => int(shift(@$limits)),
+ limit => int($limit) + 1,
offset => int(shift(@$offsets)),
order_by => {
"smhc_$subfield" => {
}
}) or return $e->die_event;
+ my $top_more = 0;
+ if (scalar(@$top) > int($limit)) {
+ $top_more = 1;
+ pop @$top;
+ }
+
# This will help us avoid certain repetitive calculations. Examine
# _label_holding_level() to see what I mean.
my $mfhd_cache = {};
# Make the tree we have so far.
- my $tree = [ map(
- _make_grouped_holding_node(
- $_, $subfield, $deepest_level, $pattern_field, $mfhd_cache
- ),
- @$top
- ) ];
+ my $tree = [
+ map(
+ _make_grouped_holding_node(
+ $_, $subfield, $deepest_level, $pattern_field, $mfhd_cache
+ ),
+ @$top
+ ), ($top_more ? undef : ())
+ ];
# Ok, that got us the top level, with nothing expanded. Now we loop through
# the elements of @$expand_path, issuing similar queries to get us deeper
# groupings and even actual specific holdings.
my $parent = $tree;
+ # Will we try magic auto-expansion of the first top-level grouping?
+ if ($auto_expand_first and (not @$expand_path) and @$tree) {
+ $expand_path = [$tree->[0]->{value}];
+ unshift @$offsets, 0;
+ }
+
foreach my $value (@$expand_path) {
my $prev_subfield = $subfield;
$subfield = shift @subfields;
%subfield_where_clauses
},
distinct => 1, # sic, this goes here in json_query
- limit => int(shift(@$limits)),
+ limit => int($limit) + 1,
offset => int(shift(@$offsets)),
order_by => {
"smhc_$subfield" => {
return $tree unless @$level;
+ my $level_more = 0;
+ if (scalar(@$level) > int($limit)) {
+ $level_more = 1;
+ pop @$level;
+ }
+
# Find attachment point for our results.
- my ($point) = grep { $_->{value} eq $value } @$parent;
+ my ($point) = grep { ref $_ and $_->{value} eq $value } @$parent;
# Set parent for the next iteration.
$parent = $point->{children} = [
$_, $subfield, $deepest_level, $pattern_field, $mfhd_cache
),
@$level
- )
+ ), ($level_more ? undef : ())
];
last if $subfield eq $deepest_level;
method => "grouped_holdings_for_summary",
api_name => "open-ils.serial.holdings.grouped_by_summary",
api_level => 1,
- argc => 5,
+ argc => 6,
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./,
{ name => "summary_type", type => "string" },
{ name => "summary_id", type => "number" },
{ name => "expand_path", type => "array" },
- { name => "limits", type => "array", desc =>
- "This must be exactly one element longer than expand_path" },
+ { name => "limit (default 10)", type => "number" },
{ name => "offsets", type => "array", desc =>
- "This must be exactly one element longer than expand_path" }
+ "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" }
]
}
);
$ctx->{get_org_setting}->
($org, "opac.fully_compressed_serial_holdings")
) {
- $ctx->{holding_summaries} =
- $self->get_holding_summaries($rec_id, $org, $depth);
-
- $ctx->{have_holdings_to_show} =
- scalar(@{$ctx->{holding_summaries}->{basic}}) ||
- scalar(@{$ctx->{holding_summaries}->{index}}) ||
- scalar(@{$ctx->{holding_summaries}->{supplement}});
+ # We're loading this data here? Are we therefore assuming that we
+ # *are* going to display something in the "issues" expandy?
+ $self->load_serial_holding_summaries($rec_id, $org, $depth);
} else {
$ctx->{mfhd_summaries} =
$self->get_mfhd_summaries($rec_id, $org, $depth);
$ctx->{marchtml} = $self->mk_marc_html($rec_id);
},
issues => sub {
- $ctx->{expanded_holdings} =
- $self->get_expanded_holdings($rec_id, $org, $depth)
- if $ctx->{have_holdings_to_show};
+ return;
+ # XXX this needed?
},
cnbrowse => sub {
$self->prepare_browse_call_numbers();
'open-ils.search.biblio.record.html', $rec_id, 1);
}
-sub get_holding_summaries {
+sub load_serial_holding_summaries {
my ($self, $rec_id, $org, $depth) = @_;
+ my $limit = $self->cgi->param("slimit") || 10;
+ my $offset = $self->cgi->param("soffset") || 0;
+
my $serial = create OpenSRF::AppSession("open-ils.serial");
- my $result = $serial->request(
- "open-ils.serial.bib.summary_statements",
- $rec_id, {"org_id" => $org, "depth" => $depth}
+
+ # First, get the tree of /summaries/ of holdings.
+ my $tree = $serial->request(
+ "open-ils.serial.holding_summary_tree.by_bib",
+ $rec_id, $org, $depth, $limit, $offset
)->gather(1);
+ return if $self->apache_log_if_event(
+ $tree, "getting holding summary tree for record $rec_id"
+ );
+
+ # Next, if requested, get a list of individual holdings under a
+ # particular summary.
+ my $holdings;
+ my $summary_id = int($self->cgi->param("sid") || 0);
+ my $summary_type = $self->cgi->param("stype");
+
+ if ($summary_id and $summary_type) {
+ my $expand_path = [ $self->cgi->param("sepath") ],
+ my $expand_limit = $self->cgi->param("selimit");
+ my $expand_offsets = [ $self->cgi->param("seoffset") ];
+ my $auto_expand_first = 0;
+
+ if (not @$expand_offsets) {
+ $expand_offsets = undef;
+ $auto_expand_first = 1;
+ }
+
+ $holdings = $serial->request(
+ "open-ils.serial.holdings.grouped_by_summary",
+ $summary_type, $summary_id,
+ $expand_path, $expand_limit, $expand_offsets,
+ $auto_expand_first
+ )->gather(1);
+
+ if ($holdings and ref $holdings eq "ARRAY") {
+ $self->place_holdings_with_summary(
+ $tree, $holdings, $summary_id, $summary_type
+ );
+# or $self->apache->log->warn(
+# "could not place holdings within summary tree"
+# );
+ } else {
+ $self->apache_log_if_event(
+ $holdings, "getting holdings grouped by summary $summary_id"
+ );
+ }
+ }
+
$serial->kill_me;
- return $result;
+
+ # The presence of any keys in the tree hash other than 'more' means that we
+ # must have /something/ we could show.
+ $self->ctx->{have_holdings_to_show} = grep { $_ ne 'more' } (keys %$tree);
+
+ $self->ctx->{holding_summary_tree} = $tree;
}
-sub get_mfhd_summaries {
- my ($self, $rec_id, $org, $depth) = @_;
+# This helper to load_serial_holding_summaries() recursively searches in
+# $tree for a holding summary matching $sid and $stype, and places $holdings
+# within the node for that summary. IOW, this is about showing expanded
+# holdings under their "parent" summary.
+sub place_holdings_with_summary {
+ my ($self, $tree, $holdings, $sid, $stype) = @_;
+
+ foreach my $sum (@{$tree->{holding_summaries}}) {
+ if ($sum->{id} == $sid and $sum->{summary_type} eq $stype) {
+ $sum->{holdings} = $holdings;
+ return 1;
+ }
+ }
- my $serial = create OpenSRF::AppSession("open-ils.search");
- my $result = $serial->request(
- "open-ils.search.serial.record.bib.retrieve",
- $rec_id, $org, $depth
- )->gather(1);
+ foreach my $child (@{$tree->{children}}) {
+ return if $self->place_holdings_with_summary(
+ $child, $holdings, $sid, $stype
+ );
+ }
- $serial->kill_me;
- return $result;
+ return;
}
-sub get_expanded_holdings {
+sub get_mfhd_summaries {
my ($self, $rec_id, $org, $depth) = @_;
- my $holding_limit = int($self->cgi->param("holding_limit") || 10);
- my $holding_offset = int($self->cgi->param("holding_offset") || 0);
- my $type = $self->cgi->param("expand_holding_type");
-
- my $serial = create OpenSRF::AppSession("open-ils.serial");
+ my $serial = create OpenSRF::AppSession("open-ils.search");
my $result = $serial->request(
- "open-ils.serial.received_siss.retrieve.by_bib.atomic",
- $rec_id, {
- "ou" => $org, "depth" => $depth,
- "limit" => $holding_limit, "offset" => $holding_offset,
- "type" => $type
- }
+ "open-ils.search.serial.record.bib.retrieve",
+ $rec_id, $org, $depth
)->gather(1);
$serial->kill_me;
}
}
+sub apache_log_if_event {
+ my ($self, $event, $prefix_text, $success_ok, $level) = @_;
+
+ $prefix_text ||= "Evergreen returned event";
+ $success_ok ||= 0;
+ $level ||= "warn";
+
+ chomp $prefix_text;
+ $prefix_text .= ": ";
+
+ my $code = $U->event_code($event);
+ if (defined $code and ($code or not $success_ok)) {
+ $self->apache->log->$level(
+ $prefix_text .
+ ($event->{textcode} || "") . " ($code)" .
+ ($event->{note} ? (": " . $event->{note}) : "")
+ );
+ return 1;
+ }
+
+ return;
+}
+
1;
-<div class='rdetail_extras_div'>
-[%
-base_expando = ctx.full_path _ "?expand=issues";
-FOREACH type IN ctx.holding_summaries.keys;
- NEXT UNLESS ctx.holding_summaries.$type.size;
- expanded = CGI.param('expand_holding_type') == type; %]
- <div class="rdetail-issue-type">
- <a href="[% base_expando; expanded ? '' : '&expand_holding_type=' _ type; %]#issues">[[% expanded ? '-' : '+' %]]</a>
- [% ctx.holding_summaries.$type.join(", ") %]
- [% IF expanded %]
- <table>
- [% FOR blob IN ctx.expanded_holdings %]
- <tr>
- <td class="rdetail-issue-issue">[% blob.issuance.label | html %]</td>
- [% IF blob.has_units %]
- <td class="rdetail-issue-place-hold">
- <a href="[% mkurl(ctx.opac_root _ '/place_hold',
- {hold_target => blob.issuance.id, hold_type => 'I', hold_source_page => mkurl()}) %]">[% l("Place Hold") %]</a>
- </td>
- [% END %]
- </tr>
- [% END %]
- </table>
- [% END %]
- </div>
-[% END %]
+<div class='rdetail_extras_div'>[%
+VIEW grouped_holding_tree;
+ BLOCK list;
+ '<ul class="rdetail-holding-group">';
+ has_more = 0;
+ FOREACH node IN item;
+ IF NOT node.label;
+ has_more = 1;
+ LAST;
+ END;
+ "<li>"; node.label; "</li>";
+ IF node.children;
+ view.print(node.children);
+ END;
+ END;
+ '</ul>';
+ END;
+END;
+
+VIEW holding_summary_tree;
+ BLOCK hash;
+ '<ul>';
+ '<span class="rdetail-issue-org-unit">';
+ ctx.get_aou(item.org_unit).name;
+ '</span>';
+ FOREACH summary IN item.holding_summaries;
+ '<li><a href="' _ mkurl('', {sid => summary.id, stype => summary.summary_type}, ['selimit', 'sepath', 'seoffset']) _ '">';
+ summary.generated_coverage.join(", ");
+ '</a></li>';
+ IF summary.holdings;
+ grouped_holding_tree.print(summary.holdings);
+ END;
+ END;
+ FOREACH child IN item.children;
+ view.print(child);
+ END;
+ '</ul>';
+ END;
+END %]
+<div class="holding-summary-tree">
+[% holding_summary_tree.print(ctx.holding_summary_tree) %]
+</div>
+<div class="holding-summary-tree-pager">
+ [% slimit = CGI.param('slimit') || 10;
+ soffset = CGI.param('soffset') || 0;
+ soffset_prev = soffset - slimit;
+ IF soffset_prev < 0; soffset_prev = 0; END;
+ soffset_next = soffset + slimit;
+ %]
+ [% IF soffset > 0 %]
+ <a href="[% mkurl('', {soffset => soffset_prev}, ['sid','stype']) %]>[% l('Previous') %]</a>
+ [% END %]
+ [% IF ctx.holding_summary_tree.more %]
+ <a href="[% mkurl('', {soffset => soffset_next}, ['sid','stype']) %]">[% l('Next') %]</a>
+ [% END %]
+</div>
[% IF ctx.mfhd_summaries.size; %]
<div class="rdetail-mfhd-holdings">
<table><tbody>