]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
LP1798628: Copy alert counts in Holdings
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / cat / services / holdings.js
1 angular.module('egHoldingsMod', ['egCoreMod','egGridMod'])
2
3 .factory('holdingsSvc', 
4        ['egCore','$q',
5 function(egCore , $q) {
6
7     var service = function() {
8         this.ongoing = false;
9         this.copies = []; // record search results
10         this.index = 0; // search grid index
11         this.org = null;
12         this.rid = null;
13     };
14
15     service.prototype.flesh = {   
16         flesh : 3,
17         flesh_fields : {
18             acp : ['status','location','circ_lib','parts','age_protect','copy_alerts', 'latest_inventory'],
19             acn : ['prefix','suffix','copies'],
20             alci : ['inventory_workstation']
21         }
22     }
23
24     service.prototype.fetchAgain = function() {
25         return this.fetch({
26             rid: this.rid,
27             org: this.org,
28             copy: this.copy,
29             vol: this.vol,
30             empty: this.empty,
31             empty_org: this.empty_org
32         })
33     };
34
35     // resolved with the last received copy
36     service.prototype.fetch = function(opts) {
37         var svc = this;
38
39         if (svc.ongoing && svc.p) {
40             svc.p.cancel = true;
41             console.log('Canceling fetch for org '+ svc.org.id());
42             if (svc.p.reject) svc.p.reject();
43         }
44
45         var rid = opts.rid;
46         var empty_org = opts.empty_org;
47         var org = opts.org;
48         var copy = opts.copy;
49         var vol = opts.vol;
50         var empty = opts.empty;
51
52         if (!rid) return $q.when();
53         if (!org) return $q.when();
54
55         svc.ongoing = true;
56
57         svc.rid = rid;
58         svc.empty_org = opts.empty_org;
59         svc.org = org;
60         svc.copy = opts.copy;
61         svc.vol = opts.vol;
62         svc.empty = opts.empty;
63
64         svc.copies = [];
65         svc.index = 0;
66
67         var org_list = egCore.org.descendants(org.id(), true);
68         console.log('Holdings fetch with: rid='+rid+' org='+org_list+' copy='+copy+' vol='+vol+' empty='+empty);
69
70         svc.org_use_map = {};
71         org_list.map(function(o){svc.org_use_map[''+o]=0;})
72
73         var p = egCore.pcrud.search(
74             'acn',
75             {record : rid, owning_lib : org_list, deleted : 'f', label : {'!=' : '##URI##'}},
76             svc.flesh
77         ).then(
78             function() { // finished
79                 if (p.cancel) return;
80
81                 // create virtual field for displaying active parts
82                 angular.forEach(svc.copies, function (cp) {
83                     cp.monograph_parts = '';
84                     if (cp.parts && cp.parts.length > 0) {
85                         cp.monograph_parts = cp.parts.map(function(obj) { return obj.label; }).join(', ');
86                         cp.monograph_parts_sortkeys = cp.parts.map(function(obj) { return obj.label_sortkey; }).join();
87                     }
88                 });
89
90                 svc.copies = svc.copies.sort(
91                     function (a, b) {
92                         function compare_array (x, y, i) {
93                             if (x[i] && y[i]) { // both have values
94                                 if (x[i] == y[i]) { // need to look deeper
95                                     return compare_array(x, y, ++i);
96                                 }
97
98                                 if (x[i] < y[i]) { // x is first
99                                     return -1;
100                                 } else if (x[i] > y[i]) { // y is first
101                                     return 1;
102                                 }
103
104                             } else { // no orgs to compare ...
105                                 if (x[i]) return -1;
106                                 if (y[i]) return 1;
107                             }
108                             return 0;
109                         }
110
111                         var owner_order = compare_array(a.owner_list, b.owner_list, 0);
112                         if (!owner_order) {
113                             // now compare on CN label
114                             if (a.call_number.label < b.call_number.label) return -1;
115                             if (a.call_number.label > b.call_number.label) return 1;
116
117                             // also parts sortkeys combined string
118                             if (a.monograph_parts_sortkeys < b.monograph_parts_sortkeys) return -1;
119                             if (a.monograph_parts_sortkeys > b.monograph_parts_sortkeys) return 1;
120
121                             // try copy number
122                             if (a.copy_number < b.copy_number) return -1;
123                             if (a.copy_number > b.copy_number) return 1;
124
125                             // finally, barcode
126                             if (a.barcode < b.barcode) return -1;
127                             if (a.barcode > b.barcode) return 1;
128                         }
129                         return owner_order;
130                     }
131                 );
132
133                 // create virtual field for copy alert count
134                 angular.forEach(svc.copies, function (cp) {
135                     if (cp.copy_alerts) {
136                         cp.copy_alert_count = cp.copy_alerts.filter(function(aca) { return aca.ack_time == null ;}).length;
137                     }
138                     else cp.copy_alert_count = 0;
139                 });
140
141                 // create a label using just the unique part of the owner list
142                 var index = 0;
143                 var prev_owner_list;
144                 angular.forEach(svc.copies, function (cp) {
145                     if (!prev_owner_list) {
146                         cp.owner_label = cp.owner_list.join(' ... ');
147                     } else {
148                         var current_owner_list = cp.owner_list.slice();
149                         while (current_owner_list[1] && prev_owner_list[1] && current_owner_list[0] == prev_owner_list[0]) {
150                             current_owner_list.shift();
151                             prev_owner_list.shift();
152                         }
153                         cp.owner_label = current_owner_list.join(' ... ');
154                     }
155
156                     cp.index = index++;
157                     prev_owner_list = cp.owner_list.slice();
158                 });
159
160                 var new_list = svc.copies;
161                 if (!copy || !vol) { // collapse copy rows, supply a count instead
162
163                     index = 0;
164                     var cp_list = [];
165                     var prev_key;
166                     var current_blob = { copy_count : 0 };
167                     angular.forEach(new_list, function (cp) {
168                         if (!prev_key) {
169                             prev_key = cp.owner_list.join('') + cp.call_number.label;
170                             if (cp.barcode) current_blob.copy_count = 1;
171                             current_blob.index = index++;
172                             current_blob.id_list = cp.id_list;
173                             if (cp.raw) current_blob.raw = cp.raw;
174                             current_blob.call_number = cp.call_number;
175                             current_blob.owner_list = cp.owner_list;
176                             current_blob.owner_label = cp.owner_label;
177                             current_blob.owner_id = cp.owner_id;
178                         } else {
179                             var current_key = cp.owner_list.join('') + cp.call_number.label;
180                             if (prev_key == current_key) { // collapse into current_blob
181                                 current_blob.copy_count++;
182                                 current_blob.id_list = current_blob.id_list.concat(cp.id_list);
183                                 current_blob.raw = current_blob.raw.concat(cp.raw);
184                             } else {
185                                 current_blob.barcode = current_blob.copy_count;
186                                 cp_list.push(current_blob);
187                                 prev_key = current_key;
188                                 current_blob = { copy_count : 0 };
189                                 if (cp.barcode) current_blob.copy_count = 1;
190                                 current_blob.index = index++;
191                                 current_blob.id_list = cp.id_list;
192                                 if (cp.raw) current_blob.raw = cp.raw;
193                                 current_blob.owner_label = cp.owner_label;
194                                 current_blob.owner_id = cp.owner_id;
195                                 current_blob.call_number = cp.call_number;
196                                 current_blob.owner_list = cp.owner_list;
197                             }
198                         }
199                     });
200
201                     current_blob.barcode = current_blob.copy_count;
202                     cp_list.push(current_blob);
203                     new_list = cp_list;
204
205                     if (!vol) { // do the same for vol rows
206
207                         index = 0;
208                         var cn_list = [];
209                         prev_key = '';
210                         current_blob = { copy_count : 0 };
211                         angular.forEach(cp_list, function (cp) {
212                             if (!prev_key) {
213                                 prev_key = cp.owner_list.join('');
214                                 current_blob.index = index++;
215                                 current_blob.id_list = cp.id_list;
216                                 if (cp.raw) current_blob.raw = cp.raw;
217                                 current_blob.cn_count = 1;
218                                 current_blob.copy_count = cp.copy_count;
219                                 current_blob.owner_list = cp.owner_list;
220                                 current_blob.owner_label = cp.owner_label;
221                                 current_blob.owner_id = cp.owner_id;
222                             } else {
223                                 var current_key = cp.owner_list.join('');
224                                 if (prev_key == current_key) { // collapse into current_blob
225                                     current_blob.cn_count++;
226                                     current_blob.copy_count += cp.copy_count;
227                                     current_blob.id_list = current_blob.id_list.concat(cp.id_list);
228                                     if (cp.raw) {
229                                         if (current_blob.raw) current_blob.raw = current_blob.raw.concat(cp.raw);
230                                         else current_blob.raw = cp.raw;
231                                     }
232                                 } else {
233                                     current_blob.barcode = current_blob.copy_count;
234                                     current_blob.call_number = { label : current_blob.cn_count };
235                                     cn_list.push(current_blob);
236                                     prev_key = current_key;
237                                     current_blob = { copy_count : 0 };
238                                     current_blob.index = index++;
239                                     current_blob.id_list = cp.id_list;
240                                     if (cp.raw) current_blob.raw = cp.raw;
241                                     current_blob.owner_label = cp.owner_label;
242                                     current_blob.owner_id = cp.owner_id;
243                                     current_blob.cn_count = 1;
244                                     current_blob.copy_count = cp.copy_count;
245                                     current_blob.owner_list = cp.owner_list;
246                                 }
247                             }
248                         });
249     
250                         current_blob.barcode = current_blob.copy_count;
251                         current_blob.call_number = { label : current_blob.cn_count };
252                         cn_list.push(current_blob);
253                         new_list = cn_list;
254     
255                     }
256                 }
257
258                 if (empty_org) {
259
260                     var empty_org_list = [];
261                     angular.forEach(svc.org_use_map,function(v,k){
262                         if (v == 0) empty_org_list.push(k);
263                     });
264
265                     angular.forEach(empty_org_list, function (oid) {
266                         var owner = egCore.org.get(oid);
267                         if (owner.ou_type().can_have_vols() != 't') return;
268
269                         var owner_list = [];
270                         while (owner.parent_ou()) { // we're going to skip the top of the tree...
271                             owner_list.unshift(owner.shortname());
272                             owner = egCore.org.get(owner.parent_ou());
273                         }
274
275                         var owner_label = owner_list.join(' ... ');
276
277                         new_list.push({
278                             index      : index++,
279                             id_list    : [],
280                             call_number: { label : '' },
281                             barcode    : '',
282                             owner_id   : oid,
283                             owner_list : owner_list,
284                             owner_label: owner_label,
285                             copy_count : 0,
286                             cn_count   : 0,
287                             copy_alert_count : 0
288                         });
289                     });
290                 }
291
292                 svc.copies = new_list;
293                 svc.ongoing = false;
294             },
295
296             null, // error
297
298             // notify reads the stream of copies, one at a time.
299             function(cn) {
300                 if (p.cancel) return;
301
302                 var copies = cn.copies().filter(function(cp){ return cp.deleted() == 'f' });
303                 cn.copies([]);
304
305                 angular.forEach(copies, function (cp) {
306                     cp.call_number(cn);
307                 });
308
309                 var owner_id = cn.owning_lib();
310                 var owner = egCore.org.get(owner_id);
311                 svc.org_use_map[''+owner_id] += 1;
312
313                 var owner_name_list = [];
314                 while (owner.parent_ou()) { // we're going to skip the top of the tree...
315                     owner_name_list.unshift(owner.shortname());
316                     owner = egCore.org.get(owner.parent_ou());
317                 }
318
319                 if (copies[0]) {
320                     var flat = [];
321                     angular.forEach(copies, function (cp) {
322                         var flat_cp = egCore.idl.toHash(cp);
323                         flat_cp.owner_id = owner_id;
324                         flat_cp.owner_list = owner_name_list;
325                         flat_cp.id_list = [flat_cp.id];
326                         flat_cp.raw = [cp];
327                         flat.push(flat_cp);
328                     });
329
330                     svc.copies = svc.copies.concat(flat);
331                 } else if (empty) {
332                     svc.copies.push({
333                         id_list    : [],
334                         owner_id   : owner_id,
335                         owner_list : owner_name_list,
336                         call_number: egCore.idl.toHash(cn),
337                         raw_call_number: cn
338                     });
339                 }
340
341                 return cn;
342             }
343         );
344
345         return svc.p = p;
346     };
347
348     return service;
349 }])
350 .directive("egVolumeList", function () {
351     return {
352         restrict:   'AE',
353         scope: {
354             recordId : '=',
355             editVolumes : '@',
356             editCopies  : '@'
357         },
358         templateUrl: './cat/share/t_volume_list',
359         controller:
360                    ['$scope','holdingsSvc','egCore','egGridDataProvider','$uibModal',
361             function($scope , holdingsSvc , egCore , egGridDataProvider,  $uibModal) {
362                 var holdingsSvcInst = new holdingsSvc();
363
364                 $scope.holdingsGridControls = {};
365                 $scope.holdingsGridDataProvider = egGridDataProvider.instance({
366                     get : function(offset, count) {
367                         return this.arrayNotifier(holdingsSvcInst.copies, offset, count);
368                     }
369                 });
370
371                 function gatherHoldingsIds () {
372                     var cp_id_list = [];
373                     angular.forEach(
374                         $scope.holdingsGridControls.allItems(),
375                         function (item) { cp_id_list = cp_id_list.concat(item.id_list) }
376                     );
377                     return cp_id_list;
378                 }
379
380                 var spawn_volume_editor = function (copies_too) {
381                     egCore.net.request(
382                         'open-ils.actor',
383                         'open-ils.actor.anon_cache.set_value',
384                         null, 'edit-these-copies', {
385                             record_id: $scope.recordId,
386                             copies: gatherHoldingsIds(),
387                             hide_vols : false,
388                             hide_copies : ((copies_too) ? false : true)
389                         }
390                     ).then(function(key) {
391                         if (key) {
392                             $uibModal.open({
393                                 templateUrl: './cat/share/t_embedded_volcopy',
394                                 backdrop: 'static',
395                                 size: 'lg',
396                                 windowClass: 'eg-wide-modal',
397                                 controller:
398                                     ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
399                                     $scope.volcopy_url = 
400                                         egCore.env.basePath + 'cat/volcopy/' + key + '/embedded';
401                                     $scope.ok = function(args) { $uibModalInstance.close(args) }
402                                     $scope.cancel = function () { $uibModalInstance.dismiss() }
403                                 }]
404                             }).result.then(function() {
405                                 load_holdings();
406                             });
407                         }
408                     });
409                 }
410                 $scope.edit_volumes = function() {
411                     spawn_volume_editor(false);
412                 }
413                 $scope.edit_copies = function() {
414                     spawn_volume_editor(true);
415                 }
416
417                 function load_holdings() {
418                     holdingsSvcInst.fetch({
419                         rid   : $scope.recordId,
420                         org   : egCore.org.root(),
421                         copy  : false,
422                         vol   : true,
423                         empty : true
424                     }).then(function() {
425                         $scope.holdingsGridDataProvider.refresh();
426                     });
427                 };
428                 $scope.$watch('recordId',
429                     function(newVal, oldVal) {
430                         if (newVal && newVal !== oldVal) {
431                             load_holdings();
432                         }
433                     }
434                 );
435                 load_holdings();
436             }]
437     }
438 })
439 ;