From: Bill Erickson Date: Mon, 18 Mar 2019 21:46:42 +0000 (-0400) Subject: Angular holdings maintenance wip X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=23d8f0af2acf34fbfdd57ba77af698266ff75156;p=working%2FEvergreen.git Angular holdings maintenance wip Signed-off-by: Bill Erickson --- diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts index 1855000f60..46d25d7d1c 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/catalog/catalog.module.ts @@ -47,7 +47,8 @@ import {HoldingsMaintenanceComponent} from './record/holdings.component'; StaffCommonModule, CatalogCommonModule, CatalogRoutingModule, - HoldsModule + HoldsModule, + HoldingsModule ], providers: [ StaffCatalogService diff --git a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html index 3cfcb273a5..64f36e5520 100644 --- a/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html +++ b/Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html @@ -27,11 +27,13 @@ + +
@@ -49,7 +51,19 @@ #emptyLibsCheckbox (onChange)="toggleShowEmptyLibs($event)"> + + + + + + + + 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 0f9e4ad990..3bb2efa739 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 @@ -12,6 +12,10 @@ import {GridDataSource} from '@eg/share/grid/grid'; import {GridComponent} from '@eg/share/grid/grid.component'; import {GridToolbarCheckboxComponent} from '@eg/share/grid/grid-toolbar-checkbox.component'; import {ServerStoreService} from '@eg/core/server-store.service'; +import {MarkDamagedDialogComponent +} from '@eg/staff/share/holdings/mark-damaged-dialog.component'; +import {MarkMissingDialogComponent +} from '@eg/staff/share/holdings/mark-missing-dialog.component'; // The holdings grid models a single HoldingsTree, composed of HoldingsTreeNodes @@ -64,10 +68,18 @@ export class HoldingsMaintenanceComponent implements OnInit { @ViewChild('holdingsGrid') holdingsGrid: GridComponent; // Manage visibility of various sub-sections - @ViewChild('volsCheckbox') volsCheckbox: GridToolbarCheckboxComponent; - @ViewChild('copiesCheckbox') copiesCheckbox: GridToolbarCheckboxComponent; - @ViewChild('emptyVolsCheckbox') emptyVolsCheckbox: GridToolbarCheckboxComponent; - @ViewChild('emptyLibsCheckbox') emptyLibsCheckbox: GridToolbarCheckboxComponent; + @ViewChild('volsCheckbox') + private volsCheckbox: GridToolbarCheckboxComponent; + @ViewChild('copiesCheckbox') + private copiesCheckbox: GridToolbarCheckboxComponent; + @ViewChild('emptyVolsCheckbox') + private emptyVolsCheckbox: GridToolbarCheckboxComponent; + @ViewChild('emptyLibsCheckbox') + private emptyLibsCheckbox: GridToolbarCheckboxComponent; + @ViewChild('markDamagedDialog') + private markDamagedDialog: MarkDamagedDialogComponent; + @ViewChild('markMissingDialog') + private markMissingDialog: MarkMissingDialogComponent; contextOrg: IdlObject; holdingsTree: HoldingsTree; @@ -155,6 +167,7 @@ export class HoldingsMaintenanceComponent implements OnInit { this.emptyVolsCheckbox.checked(settings['cat.holdings_show_empty']); this.emptyLibsCheckbox.checked(settings['cat.holdings_show_empty_org']); + this.initHoldingsTree(); this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { return this.fetchHoldings(pager); }; @@ -357,6 +370,26 @@ export class HoldingsMaintenanceComponent implements OnInit { this.renderFromPrefs = false; } + // Find an existing tree node by id and type + findNode(targetId: number, nodeType: string): HoldingsTreeNode { + const id = Number(targetId); + + const search = (node: HoldingsTreeNode): HoldingsTreeNode => { + if (!node) return null; + + if (node.nodeType === nodeType && Number(node.target.id()) === id) { + return node; + } + // for loop for early exit + for (let idx = 0; idx < node.children.length; idx++) { + const found = search(node.children[idx]); + if (found) { return found; } + } + } + + return search(this.holdingsTree.root); + } + fetchHoldings(pager: Pager): Observable { if (!this.recId) { return of([]); } @@ -368,7 +401,6 @@ export class HoldingsMaintenanceComponent implements OnInit { return; } - this.initHoldingsTree(); this.itemCircsNeeded = []; this.pcrud.search('acn', @@ -384,7 +416,8 @@ export class HoldingsMaintenanceComponent implements OnInit { acn: ['prefix', 'suffix', 'copies'], acli: ['inventory_workstation'] } - } + }, + {authoritative: true} ).subscribe( vol => this.appendVolume(vol), err => {}, @@ -413,27 +446,114 @@ export class HoldingsMaintenanceComponent implements OnInit { })).toPromise(); } + // Create the tree node for the volume if it doesn't already exist. + // Do the same for its linked copies. appendVolume(volume: IdlObject) { - const volNode = new HoldingsTreeNode(); - volNode.parentNode = this.holdingsTreeOrgCache[volume.owning_lib()]; - volNode.parentNode.children.push(volNode); - volNode.nodeType = 'volume'; + let volNode = this.findNode(volume.id(), 'volume'); + if (volNode) { + const pNode = this.holdingsTreeOrgCache[volume.owning_lib()]; + if (volNode.parentNode.target.id() !== pNode.target.id()) { + // Volume owning library changed. Un-link it from the previous + // org unit collection before adding to the new one. + // XXX TODO: ^-- + volNode.parentNode = pNode; + volNode.parentNode.children.push(volNode); + } + } else { + volNode = new HoldingsTreeNode(); + volNode.nodeType = 'volume'; + volNode.parentNode = this.holdingsTreeOrgCache[volume.owning_lib()]; + volNode.parentNode.children.push(volNode); + } + volNode.target = volume; volume.copies() .sort((a: IdlObject, b: IdlObject) => a.barcode() < b.barcode() ? -1 : 1) - .forEach((copy: IdlObject) => { - const copyNode = new HoldingsTreeNode(); + .forEach((copy: IdlObject) => this.appendCopy(volNode, copy)); + } + + appendCopy(volNode: HoldingsTreeNode, copy: IdlObject) { + let copyNode = this.findNode(copy.id(), 'copy'); + + if (copyNode) { + const oldParent = copyNode.parentNode; + if (oldParent.target.id() !== volNode.target.id()) { + // TODO: copy changed owning volume. Remove it from + // the previous volume before adding to the new volume. copyNode.parentNode = volNode; volNode.children.push(copyNode); - copyNode.nodeType = 'copy'; - copyNode.target = copy; - const stat = Number(copy.status().id()); - if (stat === 1 /* checked out */ || stat === 16 /* long overdue */) { - this.itemCircsNeeded.push(copy); - } - }); + } + } else { + // New node required + copyNode = new HoldingsTreeNode(); + copyNode.nodeType = 'copy'; + volNode.children.push(copyNode); + copyNode.parentNode = volNode; + } + + copyNode.target = copy; + const stat = Number(copy.status().id()); + + if (stat === 1 /* checked out */ || stat === 16 /* long overdue */) { + // Avoid looking up circs on items that are not checked out. + this.itemCircsNeeded.push(copy); + } + } + + selectedCopyIds(rows: HoldingsEntry[], skipStatus?: number): number[] { + let copyRows = rows.filter(r => Boolean(r.copy)).map(r => r.copy); + if (skipStatus) { + copyRows = copyRows.filter( + c => Number(c.status().id()) !== Number(skipStatus)); + } + return copyRows.map(c => Number(c.id())); + } + + async showMarkDamagedDialog(rows: HoldingsEntry[]) { + const copyIds = this.selectedCopyIds(rows, 14 /* ignore damaged */); + + if (copyIds.length === 0) { return; } + + let rowsModified = false; + + const markNext = async(ids: number[]) => { + if (ids.length === 0) { + return Promise.resolve(); + } + + this.markDamagedDialog.copyId = ids.pop(); + return this.markDamagedDialog.open({size: 'lg'}).then( + ok => { + if (ok) { rowsModified = true; } + return markNext(ids); + }, + dismiss => markNext(ids) + ); + }; + + await markNext(copyIds); + if (rowsModified) { + this.refreshHoldings = true; + this.holdingsGrid.reload(); + } + } + + showMarkMissingDialog(rows: any[]) { + const copyIds = this.selectedCopyIds(rows, 4 /* ignore missing */); + if (copyIds.length > 0) { + this.markMissingDialog.copyIds = copyIds; + this.markMissingDialog.open({}).then( + rowsModified => { + if (rowsModified) { + this.refreshHoldings = true; + this.holdingsGrid.reload(); + } + }, + dismissed => {} // avoid console errors + ); + } } } diff --git a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts index af27574528..a95ed8572f 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.ts @@ -335,7 +335,7 @@ export class HoldsGridComponent implements OnInit { } this.markDamagedDialog.copyId = ids.pop(); - this.markDamagedDialog.open({size: 'lg'}).then( + return this.markDamagedDialog.open({size: 'lg'}).then( ok => { if (ok) { rowsModified = true; } return markNext(ids); @@ -397,3 +397,5 @@ export class HoldsGridComponent implements OnInit { } + +