LP1888723 Holdings refresh handles deleted call numbers
authorBill Erickson <berickxx@gmail.com>
Mon, 24 Aug 2020 16:16:49 +0000 (12:16 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Sun, 15 Aug 2021 23:55:07 +0000 (19:55 -0400)
Teach the holdings grid in the staff catalog to correctly remove deleted
volumes from its tree when holding are modified in another tab.

To test, in the holding editor, modify a call number to have the same
label as another call number with the same owning org unit and save.  On
the backend, this will result in one of the call numbers getting
deleted.  Confirm the deleted call number no longer appears in the
holdings grid.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Ruth Frasur <rfrasur@library.in.gov>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts

index 8ba0ccb..58809b6 100644 (file)
@@ -508,6 +508,9 @@ export class HoldingsMaintenanceComponent implements OnInit {
             }
 
             this.itemCircsNeeded = [];
+            // Track vol IDs for the current fetch so we can prune
+            // any that were deleted in an out-of-band update.
+            const volsFetched: number[] = [];
 
             this.pcrud.search('acn',
                 {   record: this.recordId,
@@ -525,10 +528,14 @@ export class HoldingsMaintenanceComponent implements OnInit {
                 },
                 {authoritative: true}
             ).subscribe(
-                callNum => this.appendCallNum(callNum),
+                callNum => {
+                    this.appendCallNum(callNum);
+                    volsFetched.push(callNum.id());
+                },
                 err => {},
                 ()  => {
                     this.refreshHoldings = false;
+                    this.pruneVols(volsFetched);
                     this.fetchCircs().then(
                         ok => this.flattenHoldingsTree(observer)
                     );
@@ -537,6 +544,45 @@ export class HoldingsMaintenanceComponent implements OnInit {
         });
     }
 
+    // Remove vols that were deleted out-of-band, via edit, merge, etc.
+    pruneVols(volsFetched: number[]) {
+
+        const toRemove: number[] = []; // avoid modifying mid-loop
+        Object.keys(this.treeNodeCache.callNum).forEach(volId => {
+            const id = Number(volId);
+            if (!volsFetched.includes(id)) {
+                toRemove.push(id);
+            }
+        });
+
+        if (toRemove.length === 0) { return; }
+
+        const pruneNodes = (node: HoldingsTreeNode) => {
+            if (node.nodeType === 'callNum' &&
+                toRemove.includes(node.target.id())) {
+
+                console.debug('pruning deleted vol:', node.target.id());
+
+                // Remove this node from the parents list of children
+                node.parentNode.children =
+                    node.parentNode.children.filter(
+                        c => c.target.id() !== node.target.id());
+
+            } else {
+                node.children.forEach(c => pruneNodes(c));
+            }
+        };
+
+        // remove from cache
+        toRemove.forEach(volId => delete this.treeNodeCache.callNum[volId]);
+
+        // remove from tree
+        pruneNodes(this.holdingsTree.root);
+
+        // refresh tree / grid
+        this.holdingsGrid.reload();
+    }
+
     // Retrieve circulation objects for checked out items.
     fetchCircs(): Promise<any> {
         const copyIds = this.itemCircsNeeded.map(copy => copy.id());
@@ -570,9 +616,6 @@ export class HoldingsMaintenanceComponent implements OnInit {
         if (callNumNode) {
             const pNode = this.treeNodeCache.org[callNum.owning_lib()];
             if (callNumNode.parentNode.target.id() !== pNode.target.id()) {
-                // Call number owning library changed.  Un-link it from the
-                // previous org unit collection before adding to the new one.
-                // XXX TODO: ^--
                 callNumNode.parentNode = pNode;
                 callNumNode.parentNode.children.push(callNumNode);
             }