1 import {Component, Input, ViewChild} from '@angular/core';
2 import {Observable} from 'rxjs';
3 import {NetService} from '@eg/core/net.service';
4 import {EventService} from '@eg/core/event.service';
5 import {ToastService} from '@eg/share/toast/toast.service';
6 import {PcrudService} from '@eg/core/pcrud.service';
7 import {AuthService} from '@eg/core/auth.service';
8 import {DialogComponent} from '@eg/share/dialog/dialog.component';
9 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
10 import {StringComponent} from '@eg/share/string/string.component';
11 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
12 import {WorkLogService, WorkLogEntry} from '@eg/staff/share/worklog/worklog.service';
15 * Dialog for canceling hold requests.
19 selector: 'eg-hold-cancel-dialog',
20 templateUrl: 'cancel-dialog.component.html'
23 export class HoldCancelDialogComponent
24 extends DialogComponent {
26 @Input() holdIds: number[];
27 @ViewChild('successMsg', { static: true }) private successMsg: StringComponent;
28 @ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent;
30 changesApplied: boolean;
34 cancelReasons: ComboboxEntry[];
38 private modal: NgbModal, // required for passing to parent
39 private toast: ToastService,
40 private net: NetService,
41 private evt: EventService,
42 private pcrud: PcrudService,
43 private auth: AuthService,
44 private worklog: WorkLogService) {
45 super(modal); // required for subclassing
46 this.cancelReasons = [];
49 // Avoid fetching cancel reasons in ngOnInit becaues that causes
50 // them to load regardless of whether the dialog is ever used.
51 open(args: NgbModalOptions): Observable<boolean> {
52 this.numSucceeded = 0;
55 if (this.cancelReasons.length === 0) {
56 this.pcrud.retrieveAll('ahrcc', {}, {atomic: true}).toPromise()
58 this.cancelReasons = reasons
59 // only display reasons for manually canceling holds
60 .filter(r => 't' === r.manual())
61 .map(r => ({id: r.id(), label: r.label()}));
65 return super.open(args);
68 async cancelNext(ids: number[]): Promise<any> {
69 if (ids.length === 0) {
70 return Promise.resolve();
73 const holdId = ids.pop();
75 return this.net.request(
76 'open-ils.circ', 'open-ils.circ.hold.cancel',
77 this.auth.token(), holdId,
78 this.cancelReason, this.cancelNote
81 if (Number(result) === 1) {
83 this.toast.success(await this.successMsg.current());
84 await this.recordHoldCancelWorkLog(holdId);
87 console.error(this.evt.parse(result));
88 this.toast.warning(await this.errorMsg.current());
90 return this.cancelNext(ids);
95 async recordHoldCancelWorkLog(holdId: number) {
97 // Load work log settings first
98 await this.worklog.loadSettings();
100 // Request hold details
101 const details = await this.net.request(
102 'open-ils.circ', 'open-ils.circ.hold.details.retrieve',
103 this.auth.token(), holdId, {
104 'suppress_notices': true,
105 'suppress_transits': true,
106 'suppress_mvr': true,
110 //console.log('details', details);
111 const entry: WorkLogEntry = {
112 'action': 'canceled_hold',
114 'patron_id': details.hold.usr().id(),
115 'user': details.patron_last,
116 'item': details.copy ? details.copy.barcode() : null,
117 'item_id': details.copy ? details.copy.id() : null
120 this.worklog.record(entry);
123 console.error('Error in work log process:', error);
127 async cancelBatch(): Promise<any> {
128 this.numSucceeded = 0;
130 const ids = [].concat(this.holdIds);
131 await this.cancelNext(ids);
132 this.close(this.numSucceeded > 0);