]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/share/catalog/bib-record.service.ts
LP1615805 No inputs after submit in patron search (AngularJS)
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / share / catalog / bib-record.service.ts
1 import {Injectable} from '@angular/core';
2 import {Observable, from} from 'rxjs';
3 import {map} from 'rxjs/operators';
4 import {OrgService} from '@eg/core/org.service';
5 import {IdlObject} from '@eg/core/idl.service';
6 import {NetService} from '@eg/core/net.service';
7 import {PermService} from '@eg/core/perm.service';
8
9 export const NAMESPACE_MAPS = {
10     'mods':     'http://www.loc.gov/mods/v3',
11     'biblio':   'http://open-ils.org/spec/biblio/v1',
12     'holdings': 'http://open-ils.org/spec/holdings/v1',
13     'indexing': 'http://open-ils.org/spec/indexing/v1'
14 };
15
16 export const HOLDINGS_XPATH =
17     '/holdings:holdings/holdings:counts/holdings:count';
18
19 interface EResourceUrl {
20     href: string;
21     note: string;
22     label: string;
23 }
24
25 export interface HoldingsSummary {
26     org_unit: number;
27     depth: number;
28     unshadow: number;
29     count: number;
30     available: number;
31     transcendant: number;
32 }
33
34 export class BibRecordSummary {
35     id: number; // == record.id() for convenience
36     metabibId: number; // If present, this is a metabib summary
37     metabibRecords: number[]; // all constituent bib records
38     staffViewMetabibId: number; // to supplement a record summary
39     staffViewMetabibRecords: number[]; // to supplement a record summary
40     staffViewMetabibAttributes: any; // to supplement a record summary
41     orgId: number;
42     orgDepth: number;
43     record: IdlObject;
44     display: any;
45     attributes: any;
46     holdingsSummary: HoldingsSummary[];
47     prefOuHoldingsSummary: HoldingsSummary[];
48     holdCount: number;
49     recordNoteCount: number;
50     bibCallNumber: string;
51     firstCallNumber: string;
52     net: NetService;
53     displayHighlights: {[name: string]: string | string[]} = {};
54     eResourceUrls: EResourceUrl[] = [];
55     copies: any[];
56     isHoldable: boolean;
57
58     constructor(record: IdlObject, orgId: number, orgDepth?: number) {
59         this.id = Number(record.id());
60         this.record = record;
61         this.orgId = orgId;
62         this.orgDepth = orgDepth;
63         this.display = {};
64         this.attributes = {};
65         this.bibCallNumber = null;
66         this.metabibRecords = [];
67     }
68
69     // Get -> Set -> Return bib-level call number
70     getBibCallNumber(): Promise<string> {
71
72         if (this.bibCallNumber !== null) {
73             return Promise.resolve(this.bibCallNumber);
74         }
75
76         return this.net.request(
77             'open-ils.cat',
78             'open-ils.cat.biblio.record.marc_cn.retrieve',
79             this.id, null, this.orgId
80         ).toPromise().then(cnArray => {
81             if (cnArray && cnArray.length > 0) {
82                 const key1 = Object.keys(cnArray[0])[0];
83                 this.bibCallNumber = cnArray[0][key1];
84             } else {
85                 this.bibCallNumber = '';
86             }
87             return this.bibCallNumber;
88         });
89     }
90 }
91
92 @Injectable()
93 export class BibRecordService {
94
95     // Cache of bib editor / creator objects
96     // Assumption is this list will be limited in size.
97     userCache: {[id: number]: IdlObject};
98     allowUnfillableHolds: boolean;
99
100     constructor(
101         private net: NetService,
102         private org: OrgService,
103         private perm: PermService
104     ) {
105         this.userCache = {};
106         this.perm.hasWorkPermHere(['PLACE_UNFILLABLE_HOLD'])
107             .then(perms => {
108                 this.allowUnfillableHolds = perms.PLACE_UNFILLABLE_HOLD;
109             });
110     }
111
112     getBibSummary(id: number,
113         orgId?: number, isStaff?: boolean): Observable<BibRecordSummary> {
114         return this.getBibSummaries([id], orgId, isStaff);
115     }
116
117     getBibSummaries(bibIds: number[], orgId?: number,
118         isStaff?: boolean, options?: any): Observable<BibRecordSummary> {
119
120         if (bibIds.length === 0) { return from([]); }
121         if (!orgId) { orgId = this.org.root().id(); }
122
123         let method = 'open-ils.search.biblio.record.catalog_summary';
124         if (isStaff) { method += '.staff'; }
125
126         return this.net.request('open-ils.search', method, orgId, bibIds, options)
127             .pipe(map(bibSummary => {
128                 const summary = new BibRecordSummary(bibSummary.record, orgId);
129                 summary.net = this.net; // inject
130                 summary.staffViewMetabibId = Number(bibSummary.staff_view_metabib_id);
131                 summary.staffViewMetabibRecords = bibSummary.staff_view_metabib_records;
132                 summary.staffViewMetabibAttributes = bibSummary.staff_view_metabib_attributes;
133                 summary.display = bibSummary.display;
134                 summary.attributes = bibSummary.attributes;
135                 summary.holdCount = Number(bibSummary.hold_count);
136                 summary.recordNoteCount = Number(bibSummary.record_note_count);
137                 summary.holdingsSummary = bibSummary.copy_counts;
138                 summary.copies = bibSummary.copies;
139                 summary.firstCallNumber = bibSummary.first_call_number;
140                 summary.prefOuHoldingsSummary = bibSummary.pref_ou_copy_counts;
141
142                 summary.isHoldable = bibSummary.record.deleted() === 'f'
143                 && bibSummary.has_holdable_copy
144                 || this.allowUnfillableHolds;
145
146                 // De-duplicate urls, frequently caused by multiple subfield 9's
147                 // Note that .forEach() and .every() pass their callback functions the
148                 // parameters (element, index, array) such that element = array[index]
149                 // and they need to be distinctly named when sharing scope.
150                 bibSummary.urls.forEach(function (elb, indb, aryb) {
151                     if(summary.eResourceUrls.every((els, inds, arys) =>
152                         elb.href !== els.href || elb.note !== els.note || elb.label !== els.label)) {
153                         summary.eResourceUrls.push(elb);
154                     }
155                 });
156
157                 return summary;
158             }));
159     }
160
161     getMetabibSummaries(metabibIds: number[],
162         orgId?: number, isStaff?: boolean, options?: any): Observable<BibRecordSummary> {
163
164         if (metabibIds.length === 0) { return from([]); }
165         if (!orgId) { orgId = this.org.root().id(); }
166
167         let method = 'open-ils.search.biblio.metabib.catalog_summary';
168         if (isStaff) { method += '.staff'; }
169
170         return this.net.request('open-ils.search', method, orgId, metabibIds, options)
171             .pipe(map(metabibSummary => {
172                 const summary = new BibRecordSummary(metabibSummary.record, orgId);
173                 summary.net = this.net; // inject
174                 summary.metabibId = Number(metabibSummary.metabib_id);
175                 summary.metabibRecords = metabibSummary.metabib_records;
176                 summary.display = metabibSummary.display;
177                 summary.attributes = metabibSummary.attributes;
178                 summary.holdCount = metabibSummary.hold_count;
179                 summary.holdingsSummary = metabibSummary.copy_counts;
180                 summary.copies = metabibSummary.copies;
181                 summary.firstCallNumber = metabibSummary.first_call_number;
182                 summary.prefOuHoldingsSummary = metabibSummary.pref_ou_copy_counts;
183
184                 summary.isHoldable = metabibSummary.record.deleted() === 'f'
185                 && metabibSummary.has_holdable_copy
186                 || this.allowUnfillableHolds;
187
188                 return summary;
189             }));
190     }
191 }
192
193