From dd4931bca6b660227a1e540725ba60351cdbb0b4 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 8 Jul 2021 10:19:43 -0400 Subject: [PATCH] LP1933275 Staff catalog holdings view shows correct counts teaches the Holdings view to determine the number of copies and call numbers attached to each org unit based on the full data set (via new API) instead of copies in hand, since we may only have copies in hand for a subset of child org units. Signed-off-by: Bill Erickson Signed-off-by: Mary Llewellyn Signed-off-by: Jane Sandberg --- .../catalog/record/holdings.component.ts | 58 ++++++++------- .../lib/OpenILS/Application/Search/Biblio.pm | 72 +++++++++++++++++++ 2 files changed, 105 insertions(+), 25 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts index 8ba8583b09..d7678605c0 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts @@ -2,7 +2,7 @@ import {Component, OnInit, Input, ViewChild, ViewEncapsulation } from '@angular/core'; import {Router} from '@angular/router'; import {Observable, Observer, of, empty} from 'rxjs'; -import {map} from 'rxjs/operators'; +import {map, tap, concatMap} from 'rxjs/operators'; import {Pager} from '@eg/share/util/pager'; import {IdlObject, IdlService} from '@eg/core/idl.service'; import {StaffCatalogService} from '../catalog.service'; @@ -158,6 +158,8 @@ export class HoldingsMaintenanceComponent implements OnInit { orgClassCallback: (orgId: number) => string; marked_orgs: number[] = []; + copyCounts: {[orgId: number]: {}} = {}; + private _recId: number; @Input() set recordId(id: number) { this._recId = id; @@ -419,8 +421,8 @@ export class HoldingsMaintenanceComponent implements OnInit { setTreeCounts(node: HoldingsTreeNode) { if (node.nodeType === 'org') { - node.copyCount = 0; - node.callNumCount = 0; + node.copyCount = this.copyCounts[node.target.id() + ''].copies; + node.callNumCount = this.copyCounts[node.target.id() + ''].call_numbers; } else if (node.nodeType === 'callNum') { node.copyCount = 0; } @@ -430,13 +432,9 @@ export class HoldingsMaintenanceComponent implements OnInit { node.children.forEach(child => { this.setTreeCounts(child); if (node.nodeType === 'org') { - node.copyCount += child.copyCount; - if (child.nodeType === 'callNum') { - node.callNumCount++; - } else { + if (child.nodeType !== 'callNum') { hasChildOrgWithData = child.callNumCount > 0; hasChildOrgSansData = child.callNumCount === 0; - node.callNumCount += child.callNumCount; } } else if (node.nodeType === 'callNum') { node.copyCount = node.children.length; @@ -543,22 +541,32 @@ export class HoldingsMaintenanceComponent implements OnInit { // any that were deleted in an out-of-band update. const volsFetched: number[] = []; - this.pcrud.search('acn', - { record: this.recordId, - owning_lib: this.org.fullPath(this.contextOrg, true), - deleted: 'f', - label: {'!=' : '##URI##'} - }, { - flesh: 3, - flesh_fields: { - acp: ['status', 'location', 'circ_lib', 'parts', 'notes', - 'tags', 'age_protect', 'copy_alerts', 'latest_inventory', - 'total_circ_count', 'last_circ'], - acn: ['prefix', 'suffix', 'copies'], - acli: ['inventory_workstation'] - } - }, - {authoritative: true} + return this.net.request( + 'open-ils.search', + 'open-ils.search.biblio.record.copy_counts.global.staff', + this.recordId + ).pipe( + tap(counts => this.copyCounts = counts), + concatMap(_ => { + + return this.pcrud.search('acn', + { record: this.recordId, + owning_lib: this.org.fullPath(this.contextOrg, true), + deleted: 'f', + label: {'!=' : '##URI##'} + }, { + flesh: 3, + flesh_fields: { + acp: ['status', 'location', 'circ_lib', 'parts', 'notes', + 'tags', 'age_protect', 'copy_alerts', 'latest_inventory', + 'total_circ_count', 'last_circ'], + acn: ['prefix', 'suffix', 'copies'], + acli: ['inventory_workstation'] + } + }, + {authoritative: true} + ); + }) ).subscribe( callNum => { this.appendCallNum(callNum); @@ -572,7 +580,7 @@ export class HoldingsMaintenanceComponent implements OnInit { ok => this.flattenHoldingsTree(observer) ); } - ); + ); }); } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm index 26ccaac068..20cec4eb26 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm @@ -3308,6 +3308,78 @@ sub get_one_record_summary { }; } +__PACKAGE__->register_method( + method => 'record_copy_counts_global', + api_name => 'open-ils.search.biblio.record.copy_counts.global.staff', + signature => { + desc => q/Returns a count of copies and call numbers for each org + unit, including items attached to each org unit plus + a sum of counts for all descendants./, + params => [ + {desc => 'Record ID', type => 'number'} + ], + return => { + desc => 'Hash of org unit ID => {copy: $count, call_number: $id}' + } + } +); + +sub record_copy_counts_global { + my ($self, $client, $rec_id) = @_; + + my $copies = new_editor()->json_query({ + select => { + acp => [{column => 'id', alias => 'copy_id'}, 'circ_lib'], + acn => [{column => 'id', alias => 'cn_id'}, 'owning_lib'] + }, + from => {acn => {acp => {type => 'left'}}}, + where => { + '+acp' => { + '-or' => [ + {deleted => 'f'}, + {id => undef} # left join + ] + }, + '+acn' => {deleted => 'f', record => $rec_id} + } + }); + + my $hash = {}; + my %seen_cn; + + for my $copy (@$copies) { + my $org = $copy->{circ_lib} || $copy->{owning_lib}; + $hash->{$org} = {copies => 0, call_numbers => 0} unless $hash->{$org}; + $hash->{$org}->{copies}++ if $copy->{circ_lib}; + + if (!$seen_cn{$copy->{cn_id}}) { + $seen_cn{$copy->{cn_id}} = 1; + $hash->{$org}->{call_numbers}++; + } + } + + my $sum; + $sum = sub { + my $node = shift; + my $h = $hash->{$node->id} || {copies => 0, call_numbers => 0}; + delete $h->{cn_id}; + + for my $child (@{$node->children}) { + my $vals = $sum->($child); + $h->{copies} += $vals->{copies}; + $h->{call_numbers} += $vals->{call_numbers}; + } + + $hash->{$node->id} = $h; + + return $h; + }; + + $sum->($U->get_org_tree); + + return $hash; +} + 1; -- 2.43.2