LP1840773 Renewals
authorBill Erickson <berickxx@gmail.com>
Thu, 14 Jul 2022 20:49:13 +0000 (16:49 -0400)
committerBill Erickson <berickxx@gmail.com>
Thu, 14 Jul 2022 20:49:13 +0000 (16:49 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/scko/banner.component.ts
Open-ILS/src/eg2/src/app/staff/scko/items.component.html
Open-ILS/src/eg2/src/app/staff/scko/items.component.ts
Open-ILS/src/eg2/src/app/staff/scko/scko.component.css
Open-ILS/src/eg2/src/app/staff/scko/scko.service.ts

index 5805d32..4041c88 100644 (file)
@@ -126,6 +126,7 @@ 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 = '';
index 63e36db..49d1ccd 100644 (file)
@@ -1,14 +1,20 @@
 <div class="d-flex">
   <div class="flex-1"></div>
   <div>
-    <button type="button" class="scko-button" (click)="printList()" i18n>Print List</button>
+    <button type="button" class="scko-button mr-2" 
+      (click)="renewSelected()" i18n>Renew Selected</button>
+    <button type="button" class="scko-button" 
+      (click)="printList()" i18n>Print List</button>
   </div>
 </div>
 <div id='oils-selfck-circ-table-div'>
   <table id='oils-selfck-circ-table' class='oils-selfck-item-table'>
     <thead>
       <tr>
-        <td class="rounded-left" id='oils-self-circ-pic-cell'></td>
+        <td class="rounded-left">
+          <input type="checkbox" checked (click)="toggleSelect()"/>
+        </td>
+        <td><!-- jacket --></td>
         <td i18n>Barcode</td>
         <td i18n>Title</td>
         <td i18n>Author</td>
@@ -20,6 +26,8 @@
     <tbody id='oils-selfck-circ-out-tbody' class='oils-selfck-item-table'>
            <tr *ngFor="let circ of circs">
         <td>
+          <input type="checkbox" [(ngModel)]="selected[circ.id()]"/>
+        <td>
           <ng-container *ngIf="circ.target_copy().id() != -1">
             <img src="/opac/extras/ac/jacket/small/r/{{circ.target_copy().call_number().record().id()}}"/>
           </ng-container>
index 2926a27..94ac3aa 100644 (file)
@@ -1,6 +1,7 @@
 import {Component, OnInit, ViewEncapsulation} from '@angular/core';
 import {Router, ActivatedRoute, NavigationEnd} from '@angular/router';
-import {tap} from 'rxjs/operators';
+import {of, from} from 'rxjs';
+import {switchMap, tap} from 'rxjs/operators';
 import {AuthService} from '@eg/core/auth.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {NetService} from '@eg/core/net.service';
@@ -16,6 +17,7 @@ import {PrintService} from '@eg/share/print/print.service';
 export class SckoItemsComponent implements OnInit {
 
     circs: IdlObject[] = [];
+    selected: {[id: number]: boolean} = {};
 
     constructor(
         private router: Router,
@@ -45,6 +47,7 @@ export class SckoItemsComponent implements OnInit {
             const ids = data.out.concat(data.overdue).concat(data.long_overdue);
             return this.scko.getFleshedCircs(ids).pipe(tap(circ => {
                 this.circs.push(circ);
+                this.selected[circ.id()] = true;
             })).toPromise();
         });
     }
@@ -69,6 +72,38 @@ export class SckoItemsComponent implements OnInit {
             printContext: 'default'
         });
     }
+
+    toggleSelect() {
+        const selectMe =
+            Object.values(this.selected).filter(v => v).length < this.circs.length;
+        Object.keys(this.selected).forEach(key => this.selected[key] = selectMe);
+    }
+
+    renewSelected() {
+
+        const renewList = this.circs.filter(c => this.selected[c.id()]);
+        if (renewList.length === 0) { return; }
+
+        from(renewList).pipe(switchMap(circ => {
+            return of(
+                this.scko.renew(circ.target_copy().barcode())
+                .then(res => {
+                    if (!res.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);
+                        } else {
+                            circs.push(c);
+                        }
+                    });
+                    this.circs = circs;
+                })
+            );
+        })).toPromise(); // run it
+    }
 }
 
 
index 0150ee3..04aeeef 100644 (file)
@@ -124,3 +124,8 @@ A {
 .scko-status-row {
     font-size: 20px;
 }
+
+input[type="checkbox"] {
+  padding: 10px;
+  transform: scale(1.5);
+}
index ebe06e6..36f7ace 100644 (file)
@@ -1,6 +1,6 @@
 import {Injectable, EventEmitter} from '@angular/core';
 import {Router, ActivatedRoute, NavigationEnd} from '@angular/router';
-import {Observable} from 'rxjs';
+import {empty, Observable} from 'rxjs';
 import {OrgService} from '@eg/core/org.service';
 import {NetService} from '@eg/core/net.service';
 import {AuthService} from '@eg/core/auth.service';
@@ -28,6 +28,8 @@ interface CheckoutContext {
     shouldPopup: boolean;
     previousCirc?: IdlObject;
     renewalFailure?: boolean;
+    newCirc?: IdlObject;
+    external?: boolean; // not from main checkout input.
 }
 
 interface SessionCheckout {
@@ -159,6 +161,8 @@ export class SckoService {
     }
 
     getFleshedCircs(circIds: number[]): Observable<IdlObject> {
+        if (circIds.length === 0) { return empty(); }
+
         return this.pcrud.search('circ', {id: circIds}, {
             flesh: CIRC_FLESH_DEPTH,
             flesh_fields: CIRC_FLESH_FIELDS,
@@ -272,14 +276,14 @@ export class SckoService {
 
     accountTotalCheckouts(): number {
         // stats.checkouts.total_out includes claims returned
+        // Exclude locally renewed items from the total checkouts
 
-        return this.sessionTotalCheckouts() +
+        return this.sessionCheckouts.filter(co => !co.ctx.external).length +
             this.patronSummary.stats.checkouts.out +
             this.patronSummary.stats.checkouts.overdue +
             this.patronSummary.stats.checkouts.long_overdue;
     }
 
-
     checkout(barcode: string, override?: boolean): Promise<any> {
         this.resetPatronTimeout();
 
@@ -321,7 +325,8 @@ export class SckoService {
         .finally(() => this.router.navigate(['/staff/scko']));
     }
 
-    renew(barcode: string, override?: boolean): Promise<any> {
+    renew(barcode: string,
+        override?: boolean, external?: boolean): Promise<CheckoutContext> {
 
         let method = 'open-ils.circ.renew';
         if (override) { method += '.override'; }
@@ -335,14 +340,16 @@ export class SckoService {
         .then(result => {
             console.debug('Renew returned', result);
 
-            return this.handleCheckoutResult(result, barcode, 'renew');
+            return this.handleCheckoutResult(result, barcode, 'renew', external);
 
         }).then(ctx => {
             console.debug('handleCheckoutResult returned', ctx);
 
             if (ctx.override) {
-                return this.renew(barcode, true);
+                return this.renew(barcode, true, external);
             }
+
+            return ctx;
         });
     }
 
@@ -372,8 +379,8 @@ export class SckoService {
         });
     }
 
-    handleCheckoutResult(
-        result: any, barcode: string, action: string): Promise<CheckoutContext> {
+    handleCheckoutResult(result: any, barcode: string,
+        action: string, external?: boolean): Promise<CheckoutContext> {
 
         if (Array.isArray(result)) {
             result = result[0];
@@ -397,7 +404,8 @@ export class SckoService {
             shouldPopup: false,
             redo: false,
             override: false,
-            renew: false
+            renew: false,
+            external: external
         };
 
         if (evt.textcode === 'SUCCESS') {
@@ -406,6 +414,7 @@ export class SckoService {
 
             return this.getFleshedCirc(payload.circ.id()).then(
                 circ => {
+                    ctx.newCirc = circ;
                     this.sessionCheckouts.push({circ: circ, ctx: ctx});
                     return ctx;
                 }