import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs';
+import {Observable, empty} from 'rxjs';
import {map, mergeMap} from 'rxjs/operators';
import {IdlObject} from '@eg/core/idl.service';
import {NetService} from '@eg/core/net.service';
record?: IdlObject;
}
+export interface CheckinParams {
+ noop?: boolean;
+ copy_id?: number;
+ copy_barcode?: string;
+}
+
+export interface CheckinResult {
+ index: number;
+ evt: EgEvent;
+ params: CheckinParams;
+ success: boolean;
+ copy?: IdlObject;
+ circ?: IdlObject;
+ record?: IdlObject;
+}
+
@Injectable()
export class CircService {
static resultIndex = 0;
return Promise.resolve(result);
}
+
+ checkin(params: CheckinParams, override?: boolean): Promise<CheckinResult> {
+
+ console.debug('checking in with', params);
+
+ let method = 'open-ils.circ.checkin';
+ if (override) { method += '.override'; }
+
+ return this.net.request(
+ 'open-ils.circ', method,
+ this.auth.token(), params).toPromise()
+ .then(result => this.processCheckinResult(params, result));
+ }
+
+ processCheckinResult(
+ params: CheckinParams, response: any): Promise<CheckinResult> {
+
+ console.debug('checkout resturned', response);
+
+ if (Array.isArray(response)) { response = response[0]; }
+
+ const evt = this.evt.parse(response);
+ const payload = evt.payload;
+
+ if (!payload) {
+ this.audio.play('error.unknown.no_payload');
+ return Promise.reject();
+ }
+
+ switch (evt.textcode) {
+ case 'ITEM_NOT_CATALOGED':
+ // alert, etc.
+ }
+
+ const result: CheckinResult = {
+ index: CircService.resultIndex++,
+ evt: evt,
+ params: params,
+ success: evt.textcode === 'SUCCESS', // or route, no change, etc.
+ circ: payload.circ,
+ copy: payload.copy,
+ record: payload.record
+ };
+
+ return Promise.resolve(result);
+ }
+
+ // The provided params (minus the copy_id) will be used
+ // for all items.
+ checkinBatch(copyIds: number[], params?: CheckinParams): Observable<CheckinResult> {
+ if (copyIds.length === 0) { return empty(); }
+
+ if (!params) { params = {}; }
+ const ids = [].concat(copyIds); // clone
+
+ let observer;
+ const observable = new Observable<CheckinResult>(o => observer = o);
+
+ const checkinOne = (ids: number[]): Promise<CheckinResult> => {
+ if (ids.length === 0) {
+ observer.complete();
+ return Promise.resolve(null);
+ }
+
+ const cparams = Object.assign(params, {}); // clone
+ cparams.copy_id = ids.pop();
+
+ return this.checkin(cparams).then(result => {
+ observer.next(result);
+ return checkinOne(ids);
+ });
+ }
+
+ checkinOne(ids);
+
+ return observable;
+ }
}
<eg-due-date-dialog #dueDateDialog></eg-due-date-dialog>
<eg-mark-damaged-dialog #markDamagedDialog [handleCheckin]="true">
</eg-mark-damaged-dialog>
+<eg-mark-missing-dialog #markMissingDialog></eg-mark-missing-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">
group="Mark" i18n-group i18n-label label="Mark Item Damaged"
(onClick)="showMarkDamagedDialog($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>
+
+ <eg-grid-toolbar-action i18n-label label="Checkin" (onClick)="checkin($event)">
+ </eg-grid-toolbar-action>
+
<eg-grid-column [index]="true" path="index" [hidden]="true"
label="Row Index" i18n-label></eg-grid-column>
import {OrgService} from '@eg/core/org.service';
import {NetService} from '@eg/core/net.service';
import {PcrudService} from '@eg/core/pcrud.service';
-import {CheckoutParams, CheckoutResult, CircService} from './circ.service';
+import {CheckoutParams, CheckoutResult, CheckinParams, CheckinResult,
+ CircService} from './circ.service';
import {PromptDialogComponent} from '@eg/share/dialog/prompt.component';
+import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
import {GridDataSource, GridColumn, GridCellTextGenerator,
GridRowFlairEntry} from '@eg/share/grid/grid';
import {GridComponent} from '@eg/share/grid/grid.component';
import {DueDateDialogComponent} from './due-date-dialog.component';
import {MarkDamagedDialogComponent
} from '@eg/staff/share/holdings/mark-damaged-dialog.component';
+import {MarkMissingDialogComponent
+ } from '@eg/staff/share/holdings/mark-missing-dialog.component';
export interface CircGridEntry {
index: string; // class + id -- row index
@ViewChild('dueDateDialog') private dueDateDialog: DueDateDialogComponent;
@ViewChild('markDamagedDialog')
private markDamagedDialog: MarkDamagedDialogComponent;
+ @ViewChild('markMissingDialog')
+ private markMissingDialog: MarkMissingDialogComponent;
+ @ViewChild('itemsOutConfirm')
+ private itemsOutConfirm: ConfirmDialogComponent;
constructor(
private org: OrgService,
});
}
+ showMarkMissingDialog(rows: CircGridEntry[]) {
+ const copyIds = this.getCopyIds(rows, 4 /* ignore missing */);
+
+ if (copyIds.length === 0) { return; }
+
+ // This assumes all of our items our checked out, since this is
+ // a circ grid. If we add support later for showing completed
+ // circulations, there may be cases where we can skip the items
+ // out confirmation alert and subsequent checkin
+ this.itemsOutConfirm.open().subscribe(confirmed => {
+ if (!confirmed) { return; }
+
+ this.checkin(rows, {noop: true}, true).then(_ => {
+
+ this.markMissingDialog.copyIds = copyIds;
+ this.markMissingDialog.open({}).subscribe(
+ rowsModified => {
+ if (rowsModified) {
+ this.emitReloadRequest();
+ }
+ }
+ );
+ });
+ });
+ }
+
+ // TODO: progress dialog
+ // Same params will be used for each copy
+ checkin(rows: CircGridEntry[], params?: CheckinParams, noReload?: boolean): Promise<any> {
+ return this.circ.checkinBatch(this.getCopyIds(rows), params).toPromise()
+ .then(_ => { if (!noReload) { this.emitReloadRequest(); } });
+ }
+
emitReloadRequest() {
this.entries = null;
this.reloadRequested.emit();