LP1840773 SCKO Renewals continued; login failed message
authorBill Erickson <berickxx@gmail.com>
Fri, 15 Jul 2022 14:57:20 +0000 (10:57 -0400)
committerBill Erickson <berickxx@gmail.com>
Fri, 15 Jul 2022 14:57:20 +0000 (10:57 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/string/string.service.ts
Open-ILS/src/eg2/src/app/staff/scko/banner.component.ts
Open-ILS/src/eg2/src/app/staff/scko/items.component.ts
Open-ILS/src/eg2/src/app/staff/scko/scko.component.html
Open-ILS/src/eg2/src/app/staff/scko/scko.service.ts

index 88d0c8a..e51874c 100644 (file)
@@ -56,6 +56,9 @@ export class StringService {
 
     processPending() {
         const pstring = this.pending[0];
+
+        console.debug('STRING', pstring.key, pstring.ctx);
+
         this.strings[pstring.key].resolver(pstring.ctx).then(
             txt => {
                 pstring.resolve(txt);
index 4041c88..9327379 100644 (file)
@@ -4,7 +4,7 @@ import {Router, ActivatedRoute, NavigationEnd} from '@angular/router';
 import {AuthService, AuthWsState} from '@eg/core/auth.service';
 import {NetService} from '@eg/core/net.service';
 import {StoreService} from '@eg/core/store.service';
-import {SckoService} from './scko.service';
+import {SckoService, ActionContext} from './scko.service';
 import {OrgService} from '@eg/core/org.service';
 import {EventService, EgEvent} from '@eg/core/event.service';
 import {HatchService} from '@eg/core/hatch.service';
@@ -21,7 +21,6 @@ export class SckoBannerComponent implements OnInit, AfterViewInit {
 
     patronUsername: string;
     patronPassword: string;
-    patronLoginFailed = false;
 
     staffUsername: string;
     staffPassword: string;
@@ -127,15 +126,26 @@ export class SckoBannerComponent implements OnInit, AfterViewInit {
 
     submitPatronLogin() {
         this.patronUsername = (this.patronUsername || '').trim();
-        this.patronLoginFailed = false;
-        this.scko.loadPatron(this.patronUsername, this.patronPassword).finally(() => {
-            this.patronUsername = '';
-            this.patronPassword = '';
+        this.scko.loadPatron(this.patronUsername, this.patronPassword)
+        .finally(() => {
+
             if (this.scko.patronSummary === null) {
-                this.patronLoginFailed = true;
+
+                const ctx: ActionContext = {
+                    username: this.patronUsername,
+                    shouldPopup: true,
+                    alertSound: 'error.scko.login_failed',
+                    displayText: 'scko.error.login_failed'
+                };
+
+                this.scko.notifyPatron(ctx);
+
             } else {
                 this.focusNode('item-barcode');
             }
+
+            this.patronUsername = '';
+            this.patronPassword = '';
         });
     }
 
index 94ac3aa..83bd419 100644 (file)
@@ -6,7 +6,7 @@ import {AuthService} from '@eg/core/auth.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {NetService} from '@eg/core/net.service';
 import {IdlObject} from '@eg/core/idl.service';
-import {SckoService} from './scko.service';
+import {SckoService, ActionContext} from './scko.service';
 import {ServerStoreService} from '@eg/core/server-store.service';
 import {PrintService} from '@eg/share/print/print.service';
 
@@ -84,17 +84,21 @@ export class SckoItemsComponent implements OnInit {
         const renewList = this.circs.filter(c => this.selected[c.id()]);
         if (renewList.length === 0) { return; }
 
+        const contexts: ActionContext[] = [];
+
         from(renewList).pipe(switchMap(circ => {
             return of(
                 this.scko.renew(circ.target_copy().barcode())
-                .then(res => {
-                    if (!res.newCirc) { return; }
+                .then(ctx => {
+                    contexts.push(ctx);
+
+                    if (!ctx.newCirc) { return; }
 
                     // Replace the renewed circ with the new circ.
                     const circs = [];
                     this.circs.forEach(c => {
                         if (c.id() === circ.id()) {
-                            circs.push(res.newCirc);
+                            circs.push(ctx.newCirc);
                         } else {
                             circs.push(c);
                         }
@@ -102,7 +106,20 @@ export class SckoItemsComponent implements OnInit {
                     this.circs = circs;
                 })
             );
-        })).toPromise(); // run it
+        })).toPromise().then(_ => {
+
+            // Create one ActionContext to represent the batch for
+            // notification purposes.  Avoid popups and audio on batch
+            // renewals.
+
+            const notifyCtx: ActionContext = {
+                displayText: 'scko.batch_renew.result',
+                renewSuccessCount: contexts.filter(c => c.newCirc).length,
+                renewFailCount: contexts.filter(c => !c.newCirc).length
+            };
+
+            this.scko.notifyPatron(notifyCtx);
+        });
     }
 }
 
index 1ae367d..f7fd5d8 100644 (file)
 <eg-string i18n-text key="scko.checkout.already_out" 
   text="Item is checked out to another patron"></eg-string>
 
-<ng-template #maxRenew>No more renewals allowed for item {{barcode}}</ng-template>
+<ng-template i18n let-ctx="ctx" #loginFailed>
+  Login for "{{ctx ? ctx.username : ''}}" failed.
+</ng-template>
+<eg-string i18n-text key="scko.error.login_failed" [template]="loginFailed"></eg-string>
+
+<ng-template i18n let-ctx="ctx" #maxRenew>
+  No more renewals allowed for item {{ctx ? ctx.barcode : ''}}
+</ng-template>
 <eg-string i18n-text key="scko.error.max_renewals" [template]="maxRenew"></eg-string>
 
 <eg-string key="scko.error.patron_fines"
   text="This account has too many fines to checkout."></eg-string>
 
-<ng-template #itemNotCataloged>
-  Item {{barcode}} was not found in the system.  Try re-scanning the item.
+<ng-template i18n let-ctx="ctx" #itemNotCataloged>
+  Item {{ctx ? ctx.barcode : ctx}} was not found in the system.  Try re-scanning the item.
 </ng-template>
 <eg-string key="scko.error.item_not_cataloged" [template]="itemNotCataloged"> </eg-string>
 
 
-<ng-template #copyCircNotAllowed>
-  Item {{barcode}} is not allowed to circulate</ng-template>
+<ng-template i18n let-ctx="ctx" #copyCircNotAllowed>
+  Item {{ctx ? ctx.barcode : ''}} is not allowed to circulate</ng-template>
 <eg-string key="scko.error.copy_circ_not_allowed" [template]="copyCircNotAllowed">
 </eg-string>
 
+<ng-template let-ctx="ctx" #batchRenewResultTmpl>
+  <span class="mr-1" *ngIf="ctx && ctx.renewSuccessCount > 0" i18n>
+    {{ctx.renewSuccessCount}} item(s) successfully renewed.
+  </span>
+  <span class="mr-1" *ngIf="ctx && ctx.renewFailCount > 0" i18n>
+    {{ctx.renewFailCount}} item(s) failed to renew.
+  </span>
+</ng-template>
+<eg-string key="scko.batch_renew.result" [template]="batchRenewResultTmpl">
+</eg-string>
+
 <eg-string i18n-text key="scko.error.actor_usr_barred" 
   text="The patron is barred"></eg-string>
 <eg-string i18n-text key="scko.error.asset_copy_circulate" 
index 36f7ace..c4db1bf 100644 (file)
@@ -15,26 +15,29 @@ import {AudioService} from '@eg/share/util/audio.service';
 import {StringService} from '@eg/share/string/string.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 
-interface CheckoutContext {
-    barcode: string; // item
-    result: any;
-    firstEvent: EgEvent;
-    payload: any;
-    override: boolean;
-    redo: boolean;
-    renew: boolean;
-    displayText: string; // string key
-    alertSound: string;
-    shouldPopup: boolean;
+export interface ActionContext {
+    barcode?: string; // item
+    username?: string; // patron username or barcode
+    result?: any;
+    firstEvent?: EgEvent;
+    payload?: any;
+    override?: boolean;
+    redo?: boolean;
+    renew?: boolean;
+    displayText?: string; // string key
+    alertSound?: string;
+    shouldPopup?: boolean;
     previousCirc?: IdlObject;
     renewalFailure?: boolean;
     newCirc?: IdlObject;
     external?: boolean; // not from main checkout input.
+    renewSuccessCount?: number;
+    renewFailCount?: number;
 }
 
 interface SessionCheckout {
     circ: IdlObject;
-    ctx: CheckoutContext;
+    ctx: ActionContext;
 }
 
 const CIRC_FLESH_DEPTH = 4;
@@ -326,7 +329,7 @@ export class SckoService {
     }
 
     renew(barcode: string,
-        override?: boolean, external?: boolean): Promise<CheckoutContext> {
+        override?: boolean, external?: boolean): Promise<ActionContext> {
 
         let method = 'open-ils.circ.renew';
         if (override) { method += '.override'; }
@@ -353,7 +356,7 @@ export class SckoService {
         });
     }
 
-    notifyPatron(ctx: CheckoutContext) {
+    notifyPatron(ctx: ActionContext) {
         console.debug('notifyPatron(): ', ctx);
 
         this.statusDisplayText = '';
@@ -368,9 +371,10 @@ export class SckoService {
 
         if (!ctx.displayText) { return; }
 
-        this.strings.interpolate(ctx.displayText, {barcode: ctx.barcode})
+        this.strings.interpolate(ctx.displayText, {ctx: ctx})
         .then(str => {
             this.statusDisplayText = str;
+            console.debug('Displaying text to user:', str);
 
             if (this.alertPopup && ctx.shouldPopup && str) {
                 this.alertDialog.dialogBody = str;
@@ -380,7 +384,7 @@ export class SckoService {
     }
 
     handleCheckoutResult(result: any, barcode: string,
-        action: string, external?: boolean): Promise<CheckoutContext> {
+        action: string, external?: boolean): Promise<ActionContext> {
 
         if (Array.isArray(result)) {
             result = result[0];
@@ -394,7 +398,7 @@ export class SckoService {
             return;
         }
 
-        const ctx: CheckoutContext = {
+        const ctx: ActionContext = {
             result: result,
             firstEvent: evt,
             payload: payload,
@@ -428,7 +432,7 @@ export class SckoService {
         return this.handleEvents(ctx);
     }
 
-    handleOpenCirc(ctx: CheckoutContext): Promise<any> {
+    handleOpenCirc(ctx: ActionContext): Promise<any> {
 
         if (ctx.payload.old_circ) {
             const age = this.orgSettings['circ.checkout_auto_renew_age'];
@@ -472,7 +476,7 @@ export class SckoService {
         return Promise.resolve(ctx);
     }
 
-    handleEvents(ctx: CheckoutContext): Promise<CheckoutContext> {
+    handleEvents(ctx: ActionContext): Promise<ActionContext> {
         let override = true;
         let abortTransit = false;
         let lastErrorText = '';