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,
--- /dev/null
+
+<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">×</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>
--- /dev/null
+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() {
+ }
+}
+
+
<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">×</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">×</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>
<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>
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';
} 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
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.
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',
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,
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,
}));
}
+ 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.
return row.overdue;
}
- showMarkDamagedDialog(rows: CircGridEntry[]) {
+ markDamaged(rows: CircGridEntry[]) {
const copyIds = this.getCopyIds(rows, 14 /* ignore damaged */);
if (copyIds.length === 0) { return; }
});
}
- showMarkMissingDialog(rows: CircGridEntry[]) {
+ markMissing(rows: CircGridEntry[]) {
const copyIds = this.getCopyIds(rows, 4 /* ignore missing */);
if (copyIds.length === 0) { return; }
}
);
}
+
+ claimsReturned(rows: CircGridEntry[]) {
+ this.claimsReturnedDialog.barcodes =
+ this.getCopies(rows).map(c => c.barcode());
+
+ this.claimsReturnedDialog.open().subscribe(
+ rowsModified => {
+ if (rowsModified) {
+ this.emitReloadRequest();
+ }
+ }
+ );
+ }
}