LP1904036 Claims returned; circ notices
authorBill Erickson <berickxx@gmail.com>
Fri, 26 Feb 2021 16:53:11 +0000 (11:53 -0500)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:24 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/share/circ/circ.module.ts
Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/share/circ/due-date-dialog.component.html
Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.html
Open-ILS/src/eg2/src/app/staff/share/circ/grid.component.ts

index 714cf65..e9b1050 100644 (file)
@@ -5,12 +5,14 @@ import {CircService} from './circ.service';
 import {CircGridComponent} from './grid.component';
 import {DueDateDialogComponent} from './due-date-dialog.component';
 import {PrecatCheckoutDialogComponent} from './precat-dialog.component';
+import {ClaimsReturnedDialogComponent} from './claims-returned-dialog.component';
 
 @NgModule({
     declarations: [
         CircGridComponent,
         DueDateDialogComponent,
-        PrecatCheckoutDialogComponent
+        PrecatCheckoutDialogComponent,
+        ClaimsReturnedDialogComponent
     ],
     imports: [
         StaffCommonModule,
diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.html
new file mode 100644 (file)
index 0000000..4f43fd1
--- /dev/null
@@ -0,0 +1,41 @@
+
+<eg-string #successMsg text="Successfully Marked Claims Returned" i18n-text></eg-string>
+<eg-string #errorMsg text="Failed To Mark Claims Returned" i18n-text></eg-string>
+
+<ng-template #dialogContent>
+  <div class="modal-header bg-info">
+    <h4 class="modal-title">
+      <span i18n>Mark Claims Returned</span>
+    </h4>
+    <button type="button" class="close"
+      i18n-aria-label aria-label="Close" (click)="close()">
+      <span aria-hidden="true">&times;</span>
+    </button>
+  </div>
+  <div class="modal-body">
+    <h5 i18n>Marking Claims Returned for {{barcodes.length}} Item(s)</h5>
+    <div class="row mt-3">
+      <div class="col-lg-6" i18n>Enter Claims Returned Date</div>
+      <div class="col-lg-6">
+        <eg-datetime-select [required]="true" [initialIso]="returnDate" 
+          (onChangeAsIso)="returnDate = $event">
+        </eg-datetime-select>
+      </div>
+    </div>
+    <div *ngIf="patronExceeds" class="row">
+      <div class="col-lg-9 alert alert-danger" i18n>
+        Patron exceeds claims returned count.  Force this action?
+      </div>
+      <div class="col-lg-3">
+        <button class="btn btn-warn" (click)="confirmExceeds()" i18n>Confirm</button>
+      </div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-success" 
+      [disabled]="!returnDate || patronExceeds"
+      (click)="modifyBatch()" i18n>Submit</button>
+    <button type="button" class="btn btn-warning"
+      (click)="close()" i18n>Cancel</button>
+  </div>
+</ng-template>
diff --git a/Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/share/circ/claims-returned-dialog.component.ts
new file mode 100644 (file)
index 0000000..be32a10
--- /dev/null
@@ -0,0 +1,30 @@
+import {Component, OnInit, Output, Input, ViewChild, EventEmitter} from '@angular/core';
+import {Observable, empty, of, from} from 'rxjs';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+
+@Component({
+  templateUrl: 'claims-returned-dialog.component.html',
+  selector: 'eg-claims-returned-dialog'
+})
+export class ClaimsReturnedDialogComponent
+    extends DialogComponent implements OnInit {
+
+    barcodes: string[];
+    returnDate: string;
+    patronExceeds: boolean;
+
+    ngOnInit() {
+        this.onOpen$.subscribe(_ => {
+            this.returnDate = new Date().toISOString()
+            this.patronExceeds = false;
+        });
+    }
+
+    modifyBatch() {
+    }
+
+    confirmExceeds() {
+    }
+}
+
+
index f47258f..b991ef7 100644 (file)
@@ -2,49 +2,49 @@
 <eg-string #errorMsg text="Failed To Modify Due Date" i18n-text></eg-string>
 
 <ng-template #dialogContent>
-    <div class="modal-header bg-info">
-      <h4 class="modal-title">
-        <span i18n>Modify Due Date</span>
-      </h4>
-      <button type="button" class="close"
-        i18n-aria-label aria-label="Close" (click)="close()">
-        <span aria-hidden="true">&times;</span>
-      </button>
-    </div>
-    <div class="modal-body">
-      <h5 i18n>Modifying Due Date For {{circs.length}} Circulation(s)</h5>
+  <div class="modal-header bg-info">
+    <h4 class="modal-title">
+      <span i18n>Modify Due Date</span>
+    </h4>
+    <button type="button" class="close"
+      i18n-aria-label aria-label="Close" (click)="close()">
+      <span aria-hidden="true">&times;</span>
+    </button>
+  </div>
+  <div class="modal-body">
+    <h5 i18n>Modifying Due Date For {{circs.length}} Circulation(s)</h5>
 
-      <div class="row mt-3">
-        <div class="col-lg-3" i18n>New Date</div>
-        <div class="col-lg-9">
-          <eg-datetime-select [required]="true" (onChangeAsIso)="dueDateChange($event)">
-          </eg-datetime-select>
-        </div>
+    <div class="row mt-3">
+      <div class="col-lg-3" i18n>New Date</div>
+      <div class="col-lg-9">
+        <eg-datetime-select [required]="true" (onChangeAsIso)="dueDateChange($event)">
+        </eg-datetime-select>
       </div>
+    </div>
 
-      <div class="row mt-3" *ngIf="!dueDateIso">
-        <div class="col-lg-12 alert-danger" i18n>
-          Selected due date is not valid.
-        </div>
+    <div class="row mt-3" *ngIf="!dueDateIso">
+      <div class="col-lg-12 alert-danger" i18n>
+        Selected due date is not valid.
       </div>
+    </div>
 
-      <div class="row mt-3" *ngIf="numSucceeded > 0">
-        <div class="col-lg-12" i18n>
-          {{numSucceeded}} Due Date(s) Successfully Modified
-        </div>
+    <div class="row mt-3" *ngIf="numSucceeded > 0">
+      <div class="col-lg-12" i18n>
+        {{numSucceeded}} Due Date(s) Successfully Modified
       </div>
-      <div class="row mt-3" *ngIf="numFailed > 0">
-        <div class="col-lg-12">
-          <div class="alert alert-warning">
-            {{numFailed}} Due Date(s) Failed to Modify
-          </div>
+    </div>
+    <div class="row mt-3" *ngIf="numFailed > 0">
+      <div class="col-lg-12">
+        <div class="alert alert-warning">
+          {{numFailed}} Due Date(s) Failed to Modify
         </div>
       </div>
     </div>
-    <div class="modal-footer">
-      <button type="button" class="btn btn-warning"
-        (click)="close()" i18n>Cancel</button>
-      <button type="button" class="btn btn-success" [disabled]="!dueDateIso"
-        (click)="modifyBatch()" i18n>Modify</button>
-    </div>
-  </ng-template>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-success" [disabled]="!dueDateIso"
+      (click)="modifyBatch()" i18n>Modify</button>
+    <button type="button" class="btn btn-warning"
+      (click)="close()" i18n>Cancel</button>
+  </div>
+</ng-template>
index 18b0ec6..4cd4d90 100644 (file)
@@ -6,12 +6,14 @@
 <eg-mark-damaged-dialog #markDamagedDialog [handleCheckin]="true">
 </eg-mark-damaged-dialog>
 <eg-mark-missing-dialog #markMissingDialog></eg-mark-missing-dialog>
+<eg-claims-returned-dialog #claimsReturnedDialog></eg-claims-returned-dialog>
 <eg-confirm-dialog #itemsOutConfirm
   i18n-dialogTitle i18n-dialogBody
   dialogTitle="Items Checked Out"
   dialogBody="The selected items are checked out.  Check them in before continuing?">
 </eg-confirm-dialog>
 
+
 <ng-template #titleTemplate let-r="row">
   <ng-container *ngIf="r.record">
     <a routerLink="/staff/catalog/record/{{r.record.id()}}">{{r.title}}</a>
 
   <eg-grid-toolbar-action
     group="Mark" i18n-group i18n-label label="Mark Item Damaged"
-    (onClick)="showMarkDamagedDialog($event)"></eg-grid-toolbar-action>
+    (onClick)="markDamaged($event)"></eg-grid-toolbar-action>
 
   <eg-grid-toolbar-action
     group="Mark" i18n-group i18n-label label="Mark Item Missing"
-    (onClick)="showMarkMissingDialog($event)"></eg-grid-toolbar-action>
+    (onClick)="markMissing($event)"></eg-grid-toolbar-action>
+
+  <eg-grid-toolbar-action
+    group="Mark" i18n-group i18n-label label="Mark Claims Returned"
+    (onClick)="claimsReturned($event)"></eg-grid-toolbar-action>
 
   <eg-grid-toolbar-action
-    group="Mark" i18n-group i18n-label label="Mark Item Lost"
+    group="Mark" i18n-group i18n-label label="Mark Lost (By Patron)"
     (onClick)="markLost($event)"></eg-grid-toolbar-action>
 
   <!-- .subscribe() nudges the observable to run -->
   <eg-grid-column path="title" label="Title" i18n-label 
     [cellTemplate]="titleTemplate"></eg-grid-column>
 
+  <eg-grid-column path="circ.stop_fines" label="Fines Stopped"
+    i18n-label></eg-grid-column>
+
+  <eg-grid-column path="circ.renewal_remaining" label="Renewals Remaining"
+    i18n-label></eg-grid-column>
+
+  <eg-grid-column path="circ.circ_lib.shortname" label="Checkout / Renewal Library"
+    i18n-label></eg-grid-column>
+
+  <eg-grid-column path="circ.checkin_workstation.name" label="Checkin Workstation"
+    i18n-label></eg-grid-column>
+
+  <eg-grid-column path="circ.workstation.name" label="Checkout Workstation"
+    i18n-label></eg-grid-column>
+
   <eg-grid-column path="author" label="Author" i18n-label></eg-grid-column>
 
+  <eg-grid-column path="noticeCount" label="Total Notices" i18n-label></eg-grid-column>
+
+  <eg-grid-column path="lastNotice" label="Last Notice" i18n-label></eg-grid-column>
+
   <eg-grid-column path="nonCatCount" label="Non-Cataloged Count"
-    i18n-label></eg-grid-column>
+    [hidden]="true" i18n-label></eg-grid-column>
 
 </eg-grid>
 
index 0282e39..519c29a 100644 (file)
@@ -1,7 +1,7 @@
 import {Component, OnInit, Output, Input, ViewChild, EventEmitter} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
 import {Observable, empty, of, from} from 'rxjs';
-import {map, tap, switchMap, concatMap} from 'rxjs/operators';
+import {map, concat, ignoreElements, last, tap, mergeMap, switchMap, concatMap} from 'rxjs/operators';
 import {IdlObject} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
 import {NetService} from '@eg/core/net.service';
@@ -29,6 +29,7 @@ import {MarkDamagedDialogComponent
     } from '@eg/staff/share/holdings/mark-damaged-dialog.component';
 import {MarkMissingDialogComponent
     } from '@eg/staff/share/holdings/mark-missing-dialog.component';
+import {ClaimsReturnedDialogComponent} from './claims-returned-dialog.component';
 
 export interface CircGridEntry {
     index: string; // class + id -- row index
@@ -42,6 +43,8 @@ export interface CircGridEntry {
     dueDate?: string;
     copyAlertCount?: number;
     nonCatCount?: number;
+    noticeCount?: number;
+    lastNotice?: string; // iso date
 
     // useful for reporting precaculated values and avoiding
     // repetitive date creation on grid render.
@@ -50,7 +53,7 @@ export interface CircGridEntry {
 
 const CIRC_FLESH_DEPTH = 4;
 const CIRC_FLESH_FIELDS = {
-  circ: ['target_copy', 'workstation', 'checkin_workstation'],
+  circ: ['target_copy', 'workstation', 'checkin_workstation', 'circ_lib'],
   acp:  [
     'call_number',
     'holds_count',
@@ -100,8 +103,12 @@ export class CircGridComponent implements OnInit {
         private markMissingDialog: MarkMissingDialogComponent;
     @ViewChild('itemsOutConfirm')
         private itemsOutConfirm: ConfirmDialogComponent;
+    @ViewChild('claimsReturnedConfirm')
+        private claimsReturnedConfirm: ConfirmDialogComponent;
     @ViewChild('progressDialog')
         private progressDialog: ProgressDialogComponent;
+    @ViewChild('claimsReturnedDialog')
+        private claimsReturnedDialog: ClaimsReturnedDialogComponent;
 
     constructor(
         private org: OrgService,
@@ -163,6 +170,14 @@ export class CircGridComponent implements OnInit {
 
         this.entries = [];
 
+        // fetchCircs and fetchNotices both return observable of grid entries.
+        // ignore the entries from fetchCircs so they are not duplicated.
+        return this.fetchCircs(circIds)
+            .pipe(ignoreElements(), concat(this.fetchNotices(circIds)));
+    }
+
+    fetchCircs(circIds: number[]): Observable<CircGridEntry> {
+
         return this.pcrud.search('circ', {id: circIds}, {
             flesh: CIRC_FLESH_DEPTH,
             flesh_fields: CIRC_FLESH_FIELDS,
@@ -181,6 +196,21 @@ export class CircGridComponent implements OnInit {
         }));
     }
 
+    fetchNotices(circIds: number[]): Observable<CircGridEntry> {
+        return this.net.request(
+            'open-ils.actor',
+            'open-ils.actor.user.itemsout.notices',
+            this.auth.token(), circIds
+        ).pipe(tap(notice => {
+
+            const entry = this.entries.filter(
+                e => e.circ.id() === Number(notice.circ_id))[0];
+
+            entry.noticeCount = notice.numNotices;
+            entry.lastNotice = notice.lastDt;
+            return entry;
+        }));
+    }
 
     // Also useful for manually appending circ-like things (e.g. noncat
     // circs) that can be massaged into CircGridEntry structs.
@@ -317,7 +347,7 @@ export class CircGridComponent implements OnInit {
         return row.overdue;
     }
 
-    showMarkDamagedDialog(rows: CircGridEntry[]) {
+    markDamaged(rows: CircGridEntry[]) {
         const copyIds = this.getCopyIds(rows, 14 /* ignore damaged */);
 
         if (copyIds.length === 0) { return; }
@@ -345,7 +375,7 @@ export class CircGridComponent implements OnInit {
         });
     }
 
-    showMarkMissingDialog(rows: CircGridEntry[]) {
+    markMissing(rows: CircGridEntry[]) {
         const copyIds = this.getCopyIds(rows, 4 /* ignore missing */);
 
         if (copyIds.length === 0) { return; }
@@ -413,5 +443,18 @@ export class CircGridComponent implements OnInit {
             }
         );
     }
+
+    claimsReturned(rows: CircGridEntry[]) {
+        this.claimsReturnedDialog.barcodes =
+            this.getCopies(rows).map(c => c.barcode());
+
+        this.claimsReturnedDialog.open().subscribe(
+            rowsModified => {
+                if (rowsModified) {
+                    this.emitReloadRequest();
+                }
+            }
+        );
+    }
 }