From: Bill Erickson Date: Mon, 1 Mar 2021 19:57:29 +0000 (-0500) Subject: LP1904036 events and overrides X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=15180cf6eca1e79dfcb391a52354373788125268;p=working%2FEvergreen.git LP1904036 events and overrides Signed-off-by: Bill Erickson Signed-off-by: Jane Sandberg Signed-off-by: Galen Charlton --- diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/resolver.service.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/resolver.service.ts index 8ddef06f40..e9ea79d511 100644 --- a/Open-ILS/src/eg2/src/app/staff/circ/patron/resolver.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/circ/patron/resolver.service.ts @@ -19,17 +19,23 @@ export class PatronResolver implements Resolve> { resolve( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { - return this.fetchSettings(); } fetchSettings(): Promise { + // Some of these are used by the shared circ service. + // Go ahead and precache them since we're making the call anyway. return this.store.getItemBatch([ 'eg.circ.patron.summary.collapse', 'circ.do_not_tally_claims_returned', - 'circ.tally_lost' - + 'circ.tally_lost', + 'ui.staff.require_initials.patron_standing_penalty', + 'ui.admin.work_log.max_entries', + 'ui.admin.patron_log.max_entries', + 'circ.staff_client.do_not_auto_attempt_print', + 'circ.clear_hold_on_checkout', + 'ui.circ.suppress_checkin_popups' ]).then(settings => { this.context.noTallyClaimsReturned = settings['circ.do_not_tally_claims_returned']; diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/circ.service.ts b/Open-ILS/src/eg2/src/app/staff/share/circ/circ.service.ts index e7ef216717..3b84242d30 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/circ.service.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/circ.service.ts @@ -111,8 +111,10 @@ export interface CheckoutParams { dummy_author?: string; dummy_isbn?: string; circ_modifier?: string; - _override?: boolean; // internal tracking - _renewal?: boolean; // internal tracking + + // internal tracking + _override?: boolean; + _renewal?: boolean; } export interface CheckoutResult { @@ -133,7 +135,9 @@ export interface CheckinParams { copy_id?: number; copy_barcode?: string; claims_never_checked_out?: boolean; - _override?: boolean; // internal tracking + + // internal tracking + _override?: boolean; } export interface CheckinResult { @@ -154,6 +158,8 @@ export class CircService { components: CircComponentsComponent; nonCatTypes: IdlObject[] = null; autoOverrideCheckoutEvents: {[textcode: string]: boolean} = {}; + suppressCheckinPopups = false; + ignoreCheckinPrecats = false; constructor( private audio: AudioService, @@ -183,7 +189,7 @@ export class CircService { apiParams( params: CheckoutParams | CheckinParams): CheckoutParams | CheckinParams { - const apiParams = Object.assign(params, {}); // clone + const apiParams = Object.assign({}, params); // clone const remove = Object.keys(apiParams).filter(k => k.match(/^_/)); remove.forEach(p => delete apiParams[p]); @@ -247,8 +253,11 @@ export class CircService { nonCatCirc: payload.noncat_circ }; + const overridable = result.params._renewal ? + CAN_OVERRIDE_RENEW_EVENTS : CAN_OVERRIDE_CHECKOUT_EVENTS; + if (allEvents.filter( - e => CAN_OVERRIDE_RENEW_EVENTS.includes(e.textcode)).length > 0) { + e => overridable.includes(e.textcode)).length > 0) { return this.handleOverridableCheckoutEvents(result, allEvents); } @@ -256,6 +265,7 @@ export class CircService { case 'SUCCESS': result.success = true; this.audio.play('success.checkout'); + break; case 'ITEM_NOT_CATALOGED': return this.handlePrecat(result); @@ -285,28 +295,31 @@ export class CircService { return this.showOverrideDialog(result, events); } - showOverrideDialog( - result: CheckoutResult, events: EgEvent[]): Promise { + showOverrideDialog(result: CheckoutResult, + events: EgEvent[], checkin?: boolean): Promise { + const params = result.params; + const mode = checkin ? 'checkin' : (params._renewal ? 'renew' : 'checkout'); this.components.circEventsDialog.events = events; - // TODO: support checkins too - this.components.circEventsDialog.mode = params._renewal ? 'renew' : 'checkout'; + this.components.circEventsDialog.mode = mode; return this.components.circEventsDialog.open().toPromise() .then(confirmed => { if (!confirmed) { return null; } - // Indicate these events have been seen and overridden. - events.forEach(evt => { - if (CHECKOUT_OVERRIDE_AFTER_FIRST.includes(evt.textcode)) { - this.autoOverrideCheckoutEvents[evt.textcode] = true; - } - }); + if (!checkin) { + // Indicate these events have been seen and overridden. + events.forEach(evt => { + if (CHECKOUT_OVERRIDE_AFTER_FIRST.includes(evt.textcode)) { + this.autoOverrideCheckoutEvents[evt.textcode] = true; + } + }); + } params._override = true; - return params._renewal ? this.renew(params) : this.checkout(params); + return this[mode](params); // checkout/renew/checkin }); } @@ -345,9 +358,10 @@ export class CircService { console.debug('checkout resturned', response); - const firstResp = Array.isArray(response) ? response[0] : response; + const allEvents = Array.isArray(response) ? + response.map(r => this.evt.parse(r)) : [this.evt.parse(response)]; - const firstEvent = this.evt.parse(firstResp); + const firstEvent = allEvents[0]; const payload = firstEvent.payload; if (!payload) { @@ -355,12 +369,6 @@ export class CircService { return Promise.reject(); } - switch (firstEvent.textcode) { - case 'ITEM_NOT_CATALOGED': - this.audio.play('error.checkout.no_cataloged'); - // alert, etc. - } - const success = firstEvent.textcode.match(/SUCCESS|NO_CHANGE|ROUTE_ITEM/) !== null; @@ -375,17 +383,73 @@ export class CircService { record: payload.record }; + // Informational alerts that can be ignored if configured. + if (this.suppressCheckinPopups && + allEvents.filter(e => + !CAN_SUPPRESS_CHECKIN_ALERTS.includes(e.textcode)).length == 0) { + + // Should not be necessary, but good to be safe. + if (params._override) { return Promise.resolve(null); } + + params._override = true; + return this.checkin(params); + } + + + // Alerts that require a manual override. + if (allEvents.filter( + e => CAN_OVERRIDE_CHECKIN_ALERTS.includes(e.textcode)).length > 0) { + + // Should not be necessary, but good to be safe. + if (params._override) { return Promise.resolve(null); } + + return this.showOverrideDialog(result, allEvents, true); + } + + switch (firstEvent.textcode) { + case 'SUCCESS': + case 'NO_CHANGE': + this.audio.play('success.checkin'); + // TODO do copy status stuff + break; + + case 'ITEM_NOT_CATALOGED': + this.audio.play('error.checkout.no_cataloged'); + + if (!this.suppressCheckinPopups && !this.ignoreCheckinPrecats) { + // Tell the user its a precat and return the result. + return this.components.routeToCatalogingDialog.open() + .toPromise().then(_ => result); + } + + // alert, etc. + } + return Promise.resolve(result); } + handleOverridableCheckinEvents( + result: CheckinResult, events: EgEvent[]): Promise { + const params = result.params; + const firstEvent = events[0]; + + if (params._override) { + // Should never get here. Just being safe. + return Promise.reject(null); + } + + } + + // The provided params (minus the copy_id) will be used // for all items. - checkoutBatch(copyIds: number[], params: CheckoutParams): Observable { + checkoutBatch(copyIds: number[], + params: CheckoutParams): Observable { + if (copyIds.length === 0) { return empty(); } - const source = from(copyIds); - return source.pipe(concatMap(id => { - const cparams = Object.assign(params, {}); // clone + return from(copyIds).pipe(concatMap(id => { + const cparams = Object.assign({}, params); // clone cparams.copy_id = id; return from(this.checkout(cparams)); })); @@ -393,15 +457,14 @@ export class CircService { // The provided params (minus the copy_id) will be used // for all items. - renewBatch(copyIds: number[], params?: CheckoutParams): Observable { - if (copyIds.length === 0) { return empty(); } + renewBatch(copyIds: number[], + params?: CheckoutParams): Observable { + if (copyIds.length === 0) { return empty(); } if (!params) { params = {}; } - const source = from(copyIds); - - return source.pipe(concatMap(id => { - const cparams = Object.assign(params, {}); // clone + return from(copyIds).pipe(concatMap(id => { + const cparams = Object.assign({}, params); // clone cparams.copy_id = id; return from(this.renew(cparams)); })); @@ -409,15 +472,14 @@ export class CircService { // The provided params (minus the copy_id) will be used // for all items. - checkinBatch(copyIds: number[], params?: CheckinParams): Observable { - if (copyIds.length === 0) { return empty(); } + checkinBatch(copyIds: number[], + params?: CheckinParams): Observable { + if (copyIds.length === 0) { return empty(); } if (!params) { params = {}; } - const source = from(copyIds); - - return source.pipe(concatMap(id => { - const cparams = Object.assign(params, {}); // clone + return from(copyIds).pipe(concatMap(id => { + const cparams = Object.assign({}, params); // clone cparams.copy_id = id; return from(this.checkin(cparams)); })); diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.html b/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.html index 7817e9bcd7..d29bc19ed7 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.html @@ -1,4 +1,8 @@ + + diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.ts b/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.ts index 1d8cc153a8..7b506ff929 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/components.component.ts @@ -2,6 +2,8 @@ import {Component, OnInit, Output, Input, ViewChild, EventEmitter} from '@angula import {CircService} from './circ.service'; import {PrecatCheckoutDialogComponent} from './precat-dialog.component'; import {CircEventsComponent} from './events-dialog.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {AlertDialogComponent} from '@eg/share/dialog/alert.component'; /* Container component for sub-components used by circulation actions. * @@ -18,6 +20,7 @@ export class CircComponentsComponent { @ViewChild('precatDialog') precatDialog: PrecatCheckoutDialogComponent; @ViewChild('circEventsDialog') circEventsDialog: CircEventsComponent; + @ViewChild('routeToCatalogingDialog') routeToCatalogingDialog: AlertDialogComponent; constructor(private circ: CircService) { this.circ.components = this; diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.html index e670b6e2f6..0b83e0ccf4 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.html +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.html @@ -18,7 +18,15 @@
{{evt.textcode}}
-
{{evt.desc}}
+
+
{{evt.desc}}
+ + + +
{{evt.payload}}
+
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.ts index 006b06b2d2..bd1f21eba5 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/events-dialog.component.ts @@ -30,5 +30,9 @@ export class CircEventsComponent extends DialogComponent implements OnInit { .then(str => this.modeLabel = str); }); } + + isArray(target: any): boolean { + return Array.isArray(target); + } } diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.ts b/Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.ts index 6b402bbcf3..cd22019899 100644 --- a/Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.ts @@ -30,6 +30,7 @@ import {MarkDamagedDialogComponent import {MarkMissingDialogComponent } from '@eg/staff/share/holdings/mark-missing-dialog.component'; import {ClaimsReturnedDialogComponent} from './claims-returned-dialog.component'; +import {ToastService} from '@eg/share/toast/toast.service'; export interface CircGridEntry { index: string; // class + id -- row index @@ -122,6 +123,7 @@ export class CircGridComponent implements OnInit { private audio: AudioService, private store: StoreService, private printer: PrintService, + private toast: ToastService, private serverStore: ServerStoreService ) {} @@ -149,6 +151,17 @@ export class CircGridComponent implements OnInit { return 'less-intense-alert'; } }; + + this.serverStore.getItemBatch(['ui.circ.suppress_checkin_popups']) + .then(sets => { + this.circ.suppressCheckinPopups = + sets['ui.circ.suppress_checkin_popups']; + }); + } + + reportError(err: any) { + console.error('Circ error occurred: ' + err); + this.toast.danger(err); // EgEvent has a toString() } // Ask the caller to update our data set. @@ -437,7 +450,7 @@ export class CircGridComponent implements OnInit { // Value can be null when dialogs are canceled if (result) { refreshNeeded = true; } }, - err => console.error(err), + err => this.reportError(err), () => { dialog.close(); if (refreshNeeded) { @@ -463,7 +476,7 @@ export class CircGridComponent implements OnInit { if (resp.success) { refreshNeeded = true; } dialog.increment(); }, - err => console.error(err), + err => this.reportError(err), () => { dialog.close(); if (refreshNeeded) { @@ -481,13 +494,17 @@ export class CircGridComponent implements OnInit { const dialog = this.openProgressDialog(rows); + let changesApplied = false; return this.circ.checkinBatch(this.getCopyIds(rows), params) .pipe(tap( - result => dialog.increment(), - err => null, + result => { + if (result) { changesApplied = true; } + dialog.increment(); + }, + err => this.reportError(err), () => { dialog.close(); - if (!noReload) { this.emitReloadRequest(); } + if (changesApplied && !noReload) { this.emitReloadRequest(); } } )); } @@ -504,7 +521,7 @@ export class CircGridComponent implements OnInit { ); })).subscribe( result => dialog.increment(), - err => console.error(err), + err => this.reportError(err), () => { dialog.close(); this.emitReloadRequest(); @@ -542,7 +559,7 @@ export class CircGridComponent implements OnInit { this.getCopyIds(rows), {claims_never_checked_out: true} ).subscribe( result => dialog.increment(), - err => console.error(err), + err => this.reportError(err), () => { dialog.close(); this.emitReloadRequest(); diff --git a/Open-ILS/src/eg2/src/styles.css b/Open-ILS/src/eg2/src/styles.css index bccc56bcbd..f75803fdf2 100644 --- a/Open-ILS/src/eg2/src/styles.css +++ b/Open-ILS/src/eg2/src/styles.css @@ -330,5 +330,5 @@ input.small { */ .less-intense-alert { background-color: #f9dede; - color: black; + color: #212121; }