]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.ts
LP1888723 Angular Holdings Maintenance / Item Attributes Editor
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / cat / volcopy / volcopy.ts
1 import {IdlObject} from '@eg/core/idl.service';
2 import {OrgService} from '@eg/core/org.service';
3
4 /* Models the holdings tree and manages related data shared
5  * volcopy across components. */
6
7 export class HoldingsTreeNode {
8     children: HoldingsTreeNode[];
9     nodeType: 'org' | 'vol' | 'copy';
10     target: any;
11     parentNode: HoldingsTreeNode;
12     constructor() {
13         this.children = [];
14     }
15 }
16
17 class HoldingsTree {
18     root: HoldingsTreeNode;
19     constructor() {
20         this.root = new HoldingsTreeNode();
21     }
22 }
23
24 export class VolCopyContext {
25
26     holdings: HoldingsTree = new HoldingsTree();
27     org: OrgService; // injected
28
29     sessionType: 'copy' | 'vol' | 'record' | 'mixed';
30
31     // Edit content comes from a cached session
32     session: string;
33
34     // Note in multi-record mode this value will be unset.
35     recordId: number;
36
37     // Load specific call number by ID.
38     volId: number;
39
40     // Load specific copy by ID.
41     copyId: number;
42
43     fastAdd: boolean;
44
45     volsToDelete: IdlObject[] = [];
46     copiesToDelete: IdlObject[] = [];
47
48     reset() {
49         this.holdings = new HoldingsTree();
50         this.volsToDelete = [];
51         this.copiesToDelete = [];
52     }
53
54     orgNodes(): HoldingsTreeNode[] {
55         return this.holdings.root.children;
56     }
57
58     volNodes(): HoldingsTreeNode[] {
59         let vols = [];
60         this.orgNodes().forEach(orgNode =>
61             vols = vols.concat(orgNode.children));
62         return vols;
63     }
64
65     copyList(): IdlObject[] {
66         let copies = [];
67         this.volNodes().forEach(volNode => {
68             copies = copies.concat(volNode.children.map(c => c.target));
69         });
70         return copies;
71     }
72
73     // Returns IDs for all bib records represented in our holdings tree.
74     getRecordIds(): number[] {
75         const idHash: {[id: number]: boolean} = {};
76
77         this.volNodes().forEach(volNode =>
78             idHash[volNode.target.record()] = true);
79
80         return Object.keys(idHash).map(id => Number(id));
81     }
82
83     // When working on exactly one record, set our recordId value.
84     setRecordId() {
85         if (!this.recordId) {
86             const ids = this.getRecordIds();
87             if (ids.length === 1) {
88                 this.recordId = ids[0];
89             }
90         }
91     }
92
93     // Adds an org unit node; unsorted.
94     findOrCreateOrgNode(orgId: number): HoldingsTreeNode {
95
96         const existing: HoldingsTreeNode =
97             this.orgNodes().filter(n => n.target.id() === orgId)[0];
98
99         if (existing) { return existing; }
100
101         const node: HoldingsTreeNode = new HoldingsTreeNode();
102         node.nodeType = 'org';
103         node.target = this.org.get(orgId);
104         node.parentNode = this.holdings.root;
105
106         this.orgNodes().push(node);
107
108         return node;
109     }
110
111     findOrCreateVolNode(vol: IdlObject): HoldingsTreeNode {
112         const orgId = vol.owning_lib();
113         const orgNode = this.findOrCreateOrgNode(orgId);
114
115         const existing = orgNode.children.filter(
116             n => n.target.id() === vol.id())[0];
117
118         if (existing) { return existing; }
119
120         const node: HoldingsTreeNode = new HoldingsTreeNode();
121         node.nodeType = 'vol';
122         node.target = vol;
123         node.parentNode = orgNode;
124
125         orgNode.children.push(node);
126
127         return node;
128     }
129
130
131     findOrCreateCopyNode(copy: IdlObject): HoldingsTreeNode {
132         const volNode = this.findOrCreateVolNode(copy.call_number());
133
134         const existing = volNode.children.filter(
135             c => c.target.id() === copy.id())[0];
136
137         if (existing) { return existing; }
138
139         const node: HoldingsTreeNode = new HoldingsTreeNode();
140         node.nodeType = 'copy';
141         node.target = copy;
142         node.parentNode = volNode;
143
144         volNode.children.push(node);
145
146         return node;
147     }
148
149     removeVolNode(volId: number) {
150         this.orgNodes().forEach(orgNode => {
151             for (let idx = 0; idx < orgNode.children.length; idx++) {
152                 if (orgNode.children[idx].target.id() === volId) {
153                     orgNode.children.splice(idx, 1);
154                     break;
155                 }
156             }
157         });
158     }
159
160     removeCopyNode(copyId: number) {
161         this.volNodes().forEach(volNode => {
162             for (let idx = 0; idx < volNode.children.length; idx++) {
163                 if (volNode.children[idx].target.id() === copyId) {
164                     volNode.children.splice(idx, 1);
165                     break;
166                 }
167             }
168         });
169     }
170
171     sortHoldings() {
172
173         this.orgNodes().forEach(orgNode => {
174             orgNode.children.forEach(volNode => {
175
176                 // Sort copys by barcode code
177                 volNode.children = volNode.children.sort((c1, c2) =>
178                     c1.target.barcode() < c2.target.barcode() ? -1 : 1);
179
180             });
181
182             // Sort call numbers by label
183             orgNode.children = orgNode.children.sort((c1, c2) =>
184                 c1.target.label() < c2.target.label() ? -1 : 1);
185         });
186
187         // sort org units by shortname
188         this.holdings.root.children = this.orgNodes().sort((o1, o2) =>
189             o1.target.shortname() < o2.target.shortname() ? -1 : 1);
190     }
191
192     changesPending(): boolean {
193         const modified = (o: IdlObject): boolean => {
194             return o.isnew() || o.ischanged() || o.isdeleted();
195         };
196
197         if (this.volNodes().filter(n => modified(n.target)).length > 0) {
198             return true;
199         }
200
201         if (this.copyList().filter(c => modified(c)).length > 0) {
202             return true;
203         }
204
205         return false;
206     }
207 }