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
@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;
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);
};
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<any> {
if (!this.recId) { return of([]); }
return;
}
- this.initHoldingsTree();
this.itemCircsNeeded = [];
this.pcrud.search('acn',
acn: ['prefix', 'suffix', 'copies'],
acli: ['inventory_workstation']
}
- }
+ },
+ {authoritative: true}
).subscribe(
vol => this.appendVolume(vol),
err => {},
})).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
+ );
+ }
}
}