1 import {Injectable, EventEmitter} from '@angular/core';
2 import {IdlObject} from '@eg/core/idl.service';
3 import {NetService} from '@eg/core/net.service';
4 import {OrgService} from '@eg/core/org.service';
5 import {AuthService} from '@eg/core/auth.service';
6 import {PatronService, PatronSummary, PatronStats, PatronAlerts
7 } from '@eg/staff/share/patron/patron.service';
8 import {PatronSearch} from '@eg/staff/share/patron/search.component';
9 import {StoreService} from '@eg/core/store.service';
10 import {ServerStoreService} from '@eg/core/server-store.service';
11 import {CircService, CircDisplayInfo} from '@eg/staff/share/circ/circ.service';
13 export interface BillGridEntry extends CircDisplayInfo {
14 xact: IdlObject; // mbt
15 billingLocation?: string;
16 paymentPending?: number;
19 export interface CircGridEntry {
29 copyAlertCount: number;
34 const PATRON_FLESH_FIELDS = [
53 export class PatronContextService {
55 summary: PatronSummary;
57 lastPatronSearch: PatronSearch;
58 searchBarcode: string = null;
60 // These should persist tab changes
61 checkouts: CircGridEntry[] = [];
65 settingsCache: {[key: string]: any} = {};
68 private store: StoreService,
69 private serverStore: ServerStoreService,
70 private org: OrgService,
71 private circ: CircService,
72 public patrons: PatronService
78 this.lastPatronSearch = null;
79 this.searchBarcode = null;
83 loadPatron(id: number): Promise<any> {
86 return this.refreshPatron(id).then(_ => this.loaded = true);
89 // Update the patron data without resetting all of the context data.
90 refreshPatron(id?: number): Promise<any> {
94 return Promise.resolve();
100 return this.patrons.getFleshedById(id, PATRON_FLESH_FIELDS)
101 .then(p => this.summary = new PatronSummary(p))
102 .then(_ => this.getPatronStats(id))
103 .then(_ => this.compileAlerts())
104 .then(_ => this.addRecentPatron());
107 addRecentPatron(patronId?: number): Promise<any> {
109 if (!patronId) { patronId = this.summary.id; }
111 return this.serverStore.getItem('ui.staff.max_recent_patrons')
113 if (num) { this.maxRecentPatrons = num; }
115 const patrons: number[] =
116 this.store.getLoginSessionItem('eg.circ.recent_patrons') || [];
118 patrons.splice(0, 0, patronId); // put this user at front
119 patrons.splice(this.maxRecentPatrons, 1); // remove excess
121 // remove any other occurrences of this user, which may have been
122 // added before the most recent user.
123 const idx = patrons.indexOf(patronId, 1);
124 if (idx > 0) { patrons.splice(idx, 1); }
126 this.store.setLoginSessionItem('eg.circ.recent_patrons', patrons);
130 getPatronStats(id: number): Promise<any> {
132 // When quickly navigating patron search results it's possible
133 // for this.patron to be cleared right before this function
134 // is called. Exit early instead of making an unneeded call.
135 if (!this.summary) { return Promise.resolve(); }
137 return this.patrons.getVitalStats(this.summary.patron)
138 .then(stats => this.summary.stats = stats);
141 patronAlertsShown(): boolean {
142 if (!this.summary) { return false; }
143 this.store.addLoginSessionKey('eg.circ.last_alerted_patron');
144 const shown = this.store.getLoginSessionItem('eg.circ.last_alerted_patron');
145 if (shown === this.summary.patron.id()) { return true; }
146 this.store.setLoginSessionItem('eg.circ.last_alerted_patron', this.summary.patron.id());
150 compileAlerts(): Promise<any> {
152 // User navigated to a different patron mid-data load.
153 if (!this.summary) { return Promise.resolve(); }
155 return this.patrons.compileAlerts(this.summary)
157 this.summary.alerts = alerts;
159 if (this.searchBarcode) {
160 const card = this.summary.patron.cards()
161 .filter(c => c.barcode() === this.searchBarcode)[0];
162 this.summary.alerts.retrievedWithInactive =
163 card && card.active() === 'f';
164 this.searchBarcode = null;
169 orgSn(orgId: number): string {
170 const org = this.org.get(orgId);
171 return org ? org.shortname() : '';
174 formatXactForDisplay(xact: IdlObject): BillGridEntry {
176 const entry: BillGridEntry = {
181 if (xact.summary().xact_type() !== 'circulation') {
183 entry.xact.grocery().billing_location(
184 this.org.get(entry.xact.grocery().billing_location()));
186 entry.title = xact.summary().last_billing_type();
187 entry.billingLocation =
188 xact.grocery().billing_location().shortname();
192 entry.xact.circulation().circ_lib(
193 this.org.get(entry.xact.circulation().circ_lib()));
195 const circDisplay: CircDisplayInfo =
196 this.circ.getDisplayInfo(xact.circulation());
198 entry.billingLocation =
199 xact.circulation().circ_lib().shortname();
201 return Object.assign(entry, circDisplay);