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;
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
}
# 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(
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.
# _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 : ())
# 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 : ())
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)
+ / }
]
}
);
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.
}
};
- # 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;
}