From: Bill Erickson Date: Thu, 8 Jul 2021 14:19:43 +0000 (-0400) Subject: LP1933275 Staff catalog holdings view shows correct counts X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=52a3dd19b4115f800fd862177ec855a471e6a827;p=Evergreen.git 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 --- 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 c3388477d5..43fd1a0c8c 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'; @@ -150,6 +150,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; @@ -405,8 +407,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; } @@ -416,13 +418,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; @@ -526,21 +524,31 @@ export class HoldingsMaintenanceComponent implements OnInit { this.itemCircsNeeded = []; - 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'], - 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'], + acn: ['prefix', 'suffix', 'copies'], + acli: ['inventory_workstation'] + } + }, + {authoritative: true} + ); + }) ).subscribe( callNum => this.appendCallNum(callNum), err => {}, @@ -550,7 +558,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 ab372c872e..e780d085e6 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm @@ -3290,6 +3290,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;