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
75 loadPatron(id: number): Promise<any> {
78 return this.refreshPatron(id).then(_ => this.loaded = true);
81 // Update the patron data without resetting all of the context data.
82 refreshPatron(id?: number): Promise<any> {
86 return Promise.reject('no can do');
92 return this.patrons.getFleshedById(id, PATRON_FLESH_FIELDS)
93 .then(p => this.summary = new PatronSummary(p))
94 .then(_ => this.getPatronStats(id))
95 .then(_ => this.compileAlerts())
96 .then(_ => this.addRecentPatron());
99 addRecentPatron(patronId?: number): Promise<any> {
101 if (!patronId) { patronId = this.summary.id; }
103 return this.serverStore.getItem('ui.staff.max_recent_patrons')
105 if (num) { this.maxRecentPatrons = num; }
107 const patrons: number[] =
108 this.store.getLoginSessionItem('eg.circ.recent_patrons') || [];
110 patrons.splice(0, 0, patronId); // put this user at front
111 patrons.splice(this.maxRecentPatrons, 1); // remove excess
113 // remove any other occurrences of this user, which may have been
114 // added before the most recent user.
115 const idx = patrons.indexOf(patronId, 1);
116 if (idx > 0) { patrons.splice(idx, 1); }
118 this.store.setLoginSessionItem('eg.circ.recent_patrons', patrons);
122 getPatronStats(id: number): Promise<any> {
124 // When quickly navigating patron search results it's possible
125 // for this.patron to be cleared right before this function
126 // is called. Exit early instead of making an unneeded call.
127 if (!this.summary) { return Promise.resolve(); }
129 return this.patrons.getVitalStats(this.summary.patron)
130 .then(stats => this.summary.stats = stats);
133 patronAlertsShown(): boolean {
134 if (!this.summary) { return false; }
135 const shown = this.store.getSessionItem('eg.circ.last_alerted_patron');
136 if (shown === this.summary.patron.id()) { return true; }
137 this.store.setSessionItem('eg.circ.last_alerted_patron', this.summary.patron.id());
141 compileAlerts(): Promise<any> {
143 // User navigated to a different patron mid-data load.
144 if (!this.summary) { return Promise.resolve(); }
146 return this.patrons.compileAlerts(this.summary)
148 this.summary.alerts = alerts;
150 if (this.searchBarcode) {
151 const card = this.summary.patron.cards()
152 .filter(c => c.barcode() === this.searchBarcode)[0];
153 this.summary.alerts.retrievedWithInactive =
154 card && card.active() === 'f';
155 this.searchBarcode = null;
160 orgSn(orgId: number): string {
161 const org = this.org.get(orgId);
162 return org ? org.shortname() : '';
165 formatXactForDisplay(xact: IdlObject): BillGridEntry {
167 const entry: BillGridEntry = {
172 if (xact.summary().xact_type() !== 'circulation') {
174 entry.xact.grocery().billing_location(
175 this.org.get(entry.xact.grocery().billing_location()));
177 entry.title = xact.summary().last_billing_type();
178 entry.billingLocation =
179 xact.grocery().billing_location().shortname();
183 entry.xact.circulation().circ_lib(
184 this.org.get(entry.xact.circulation().circ_lib()));
186 const circDisplay: CircDisplayInfo =
187 this.circ.getDisplayInfo(xact.circulation());
189 entry.billingLocation =
190 xact.circulation().circ_lib().shortname();
192 return Object.assign(entry, circDisplay);