<eg-staff-banner i18n-bannerText bannerText="Item Status">
</eg-staff-banner>
-<eg-barcode-select #barcodeSelect></eg-barcode-select>
<eg-circ-components></eg-circ-components>
+<eg-worklog-strings-components></eg-worklog-strings-components>
+<eg-progress-dialog #progressDialog></eg-progress-dialog>
+<eg-barcode-select #barcodeSelect></eg-barcode-select>
<eg-mark-damaged-dialog #markDamagedDialog></eg-mark-damaged-dialog>
<eg-mark-missing-dialog #markMissingDialog></eg-mark-missing-dialog>
<eg-copy-alerts-dialog #copyAlertsDialog></eg-copy-alerts-dialog>
<eg-make-bookable-dialog #makeBookableDialog></eg-make-bookable-dialog>
<eg-transfer-items #transferItems></eg-transfer-items>
<eg-transfer-holdings #transferHoldings></eg-transfer-holdings>
+<eg-cancel-transit-dialog #cancelTransitDialog></eg-cancel-transit-dialog>
<eg-alert-dialog #transferAlert
i18n-dialogTitle i18n-dialogBody
dialogTitle="No Target Selected"
dialogBody="Please select a suitable transfer target"></eg-alert-dialog>
-
<div class="row">
<div class="col-lg-12 form-inline d-flex">
<div class="input-group">
<div class="flex-1"></div>
+ <!-- ACTIONS MENU -->
<eg-grouped-menu i18n-label label="Actions" *ngIf="item && tab != 'list'">
+ <!-- Un-grouped -->
+ <eg-grouped-menu-entry i18n-label label="Request Items"
+ (entryClicked)="requestItems([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label
+ label="Link as Conjoined to Marked Bib Record"
+ (entryClicked)="openConjoinedDialog([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Delete Items"
+ (entryClicked)="deleteItems([item])">
+ </eg-grouped-menu-entry>
+
+ <!-- Add -->
<eg-grouped-menu-entry i18n-label label="Add Item To Bucket"
- (entryClicked)="addToBucket()"></eg-grouped-menu-entry>
+ i18n-group group="Add" (entryClicked)="addItemToBucket([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Add Record To Bucket"
+ i18n-group group="Add" (entryClicked)="addRecordToBucket([item])">
+ </eg-grouped-menu-entry>
+ <!-- Show -->
<eg-grouped-menu-entry i18n-label label="Show Record Holds"
i18n-group group="Show" [newTab]="true"
routerLink="/staff/catalog/record/{{item.call_number().record().id()}}/holds">
</eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Show In Catalog"
+ i18n-group group="Show" [newTab]="true"
+ routerLink="/staff/catalog/record/{{item.call_number().record().id()}}">
+ </eg-grouped-menu-entry>
+
+ <!-- Booking -->
+ <eg-grouped-menu-entry i18n-label label="Make Items Bookable"
+ i18n-group group="Booking" (entryClicked)="makeItemsBookable([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Book Item Now"
+ i18n-group group="Booking" (entryClicked)="bookItems([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Manage Reservations"
+ i18n-group group="Booking" (entryClicked)="manageReservations([item])">
+ </eg-grouped-menu-entry>
+
+ <eg-grouped-menu-entry i18n-label label="Check In Items"
+ i18n-group group="Circulation" (entryClicked)="checkinItems([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Renew Items"
+ i18n-group group="Circulation" (entryClicked)="renewItems([item])">
+ </eg-grouped-menu-entry>
+ <eg-grouped-menu-entry i18n-label label="Cancel Transit"
+ i18n-group group="Circulation" (entryClicked)="cancelTransits([item])">
+ </eg-grouped-menu-entry>
</eg-grouped-menu>
<div *ngIf="tab != 'list' && item">
+ <div class="row" *ngIf="item.deleted() == 't'">
+ <div class="col-lg-4 offset-lg-4 alert alert-danger" i18n>
+ This item has been marked as Deleted.
+ </div>
+ </div>
+
<div class="mt-2 mb-4">
<eg-bib-summary [recordId]="item.call_number().record().id()">
</eg-bib-summary>
import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
-import {IdlObject} from '@eg/core/idl.service';
+import {from, empty} from 'rxjs';
+import {concatMap, tap} from 'rxjs/operators';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {AuthService} from '@eg/core/auth.service';
import {NetService} from '@eg/core/net.service';
import {PatronPenaltyDialogComponent} from '@eg/staff/share/patron/penalty-dialog.component';
import {BarcodeSelectComponent} from '@eg/staff/share/barcodes/barcode-select.component';
import {CatalogService} from '@eg/share/catalog/catalog.service';
+import {CircService} from '@eg/staff/share/circ/circ.service';
import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
+import {WorkLogService, WorkLogEntry} from '@eg/staff/share/worklog/worklog.service';
+import {CancelTransitDialogComponent
+ } from '@eg/staff/share/circ/cancel-transit-dialog.component';
import {CopyAlertsDialogComponent
} from '@eg/staff/share/holdings/copy-alerts-dialog.component';
import {ReplaceBarcodeDialogComponent
private transferHoldings: TransferHoldingsComponent;
@ViewChild('transferAlert')
private transferAlert: AlertDialogComponent;
+ @ViewChild('progressDialog')
+ private progressDialog: ProgressDialogComponent;
+ @ViewChild('cancelTransitDialog')
+ private cancelTransitDialog: CancelTransitDialogComponent;
constructor(
private router: Router,
private route: ActivatedRoute,
private net: NetService,
+ private idl: IdlService,
private printer: PrintService,
private pcrud: PcrudService,
private auth: AuthService,
+ private circ: CircService,
private evt: EventService,
private cat: CatalogService,
+ private worklog: WorkLogService,
private holdings: HoldingsService
) {}
if (!this.tab) {
if (this.itemId) {
- this.router.navigate([`/staff/cat/item/${this.itemId}/summary`])
- .then(ok => {if (ok) { this.load(); }});
- return;
+ this.tab = 'summary';
} else {
this.tab = 'list';
}
}
- this.load();
+ this.worklog.loadSettings().then(_ => this.load());
}
load() {
});
}
- addToBucket() {
+ openProgressDialog(copies: IdlObject[]): ProgressDialogComponent {
+ this.progressDialog.update({value: 0, max: copies.length});
+ this.progressDialog.open();
+ return this.progressDialog;
+ }
+
+ addItemToBucket(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
this.bucketDialog.bucketClass = 'copy';
- this.bucketDialog.itemIds = [this.item.id()];
+ this.bucketDialog.itemIds = copies.map(c => c.id());
+ this.bucketDialog.open({size: 'lg'});
+ }
+
+ addRecordToBucket(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ const recId = copies[0].call_number().record().id();
+ this.bucketDialog.bucketClass = 'biblio';
+ this.bucketDialog.itemIds = [recId];
this.bucketDialog.open({size: 'lg'});
}
+
+ makeItemsBookable(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ this.makeBookableDialog.copyIds = copies.map(c => c.id());
+ this.makeBookableDialog.open({});
+ }
+
+ bookItems(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ const barcode = copies[0].barcode();
+ this.router.navigate(
+ ['/staff/booking/create_reservation/for_resource', barcode]);
+ }
+
+ manageReservations(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ const barcode = copies[0].barcode();
+ this.router.navigate(
+ ['/staff/booking/manage_reservations/by_resource', barcode]);
+ }
+
+ requestItems(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ const params = {target: copies.map(c => c.id()), holdFor: 'staff'};
+ this.router.navigate(['/staff/catalog/hold/C'], {queryParams: params});
+ }
+
+ openConjoinedDialog(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ this.conjoinedDialog.copyIds = copies.map(c => c.id());
+ this.conjoinedDialog.open({size: 'sm'});
+ }
+
+ deleteItems(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+ const callNumHash: any = {};
+
+ // Collect the copies to be deleted, including their call numbers
+ // since the API expects fleshed call number objects.
+ copies.forEach(copy => {
+ const callNum = copy.call_number();
+ if (!callNumHash[callNum.id()]) {
+ callNumHash[callNum.id()] = this.idl.clone(callNum);
+ callNumHash[callNum.id()].copies([]);
+ }
+ const delCopy = this.idl.clone(copy);
+ delCopy.isdeleted(true);
+ callNumHash[callNum.id()].copies().push(delCopy);
+ });
+
+ if (Object.keys(callNumHash).length === 0) {
+ // No data to process.
+ return;
+ }
+
+ this.deleteHolding.callNums = Object.values(callNumHash);
+ this.deleteHolding.open({size: 'sm'}).subscribe(modified => this.load());
+ }
+
+ checkinItems(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+
+ const dialog = this.openProgressDialog(copies);
+
+ let changesApplied = false;
+
+ this.circ.checkinBatch(copies.map(c => c.id()))
+ .subscribe(
+ result => {
+ if (result) { changesApplied = true; }
+ dialog.increment();
+ },
+ err => {
+ console.error('' + err);
+ dialog.close();
+ },
+ () => {
+ dialog.close();
+ this.load();
+ }
+ );
+ }
+
+ renewItems(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+
+ const dialog = this.openProgressDialog(copies);
+
+ let changesApplied = false;
+
+ this.circ.renewBatch(copies.map(c => c.id()))
+ .subscribe(
+ result => {
+ if (result) { changesApplied = true; }
+ dialog.increment();
+ },
+ err => {
+ console.error('' + err);
+ dialog.close();
+ },
+ () => {
+ dialog.close();
+ this.load();
+ }
+ );
+ }
+
+ cancelTransits(copies: IdlObject[]) {
+ if (copies.length === 0) { return; }
+
+ // Copies in transit are not always accompanied by their transit.
+ const transitIds = [];
+ from(copies).pipe(concatMap(c => {
+ return from(
+ this.circ.findCopyTransitById(c.id())
+ .then(
+ transit => transitIds.push(transit.id()),
+ err => {}
+ )
+ );
+ }))
+
+ .pipe(concatMap(_ => {
+
+ if (transitIds.length > 0) {
+ this.cancelTransitDialog.transitIds = transitIds;
+ return this.cancelTransitDialog.open();
+ } else {
+ return empty();
+ }
+
+ })).subscribe();
+ }
}
+