37b8b07b4866a1c0f1d4d708c593ed0ae8843b83
[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', 'last_copy_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'},
76             svc.flesh
77         ).then(
78             function() { // finished
79                 if (p.cancel) return;
80
81                 svc.copies = svc.copies.sort(
82                     function (a, b) {
83                         function compare_array (x, y, i) {
84                             if (x[i] && y[i]) { // both have values
85                                 if (x[i] == y[i]) { // need to look deeper
86                                     return compare_array(x, y, ++i);
87                                 }
88
89                                 if (x[i] < y[i]) { // x is first
90                                     return -1;
91                                 } else if (x[i] > y[i]) { // y is first
92                                     return 1;
93                                 }
94
95                             } else { // no orgs to compare ...
96                                 if (x[i]) return -1;
97                                 if (y[i]) return 1;
98                             }
99                             return 0;
100                         }
101
102                         var owner_order = compare_array(a.owner_list, b.owner_list, 0);
103                         if (!owner_order) {
104                             // now compare on CN label
105                             if (a.call_number.label < b.call_number.label) return -1;
106                             if (a.call_number.label > b.call_number.label) return 1;
107
108                             // try copy number
109                             if (a.copy_number < b.copy_number) return -1;
110                             if (a.copy_number > b.copy_number) return 1;
111
112                             // finally, barcode
113                             if (a.barcode < b.barcode) return -1;
114                             if (a.barcode > b.barcode) return 1;
115                         }
116                         return owner_order;
117                     }
118                 );
119
120                 // create virtual field for displaying active parts
121                 angular.forEach(svc.copies, function (cp) {
122                     cp.monograph_parts = '';
123                     if (cp.parts && cp.parts.length > 0) {
124                         cp.monograph_parts = cp.parts.map(function(obj) { return obj.label; }).join();
125                     }
126                 });
127
128                 // create virtual field for copy alert count
129                 angular.forEach(svc.copies, function (cp) {
130                     if (cp.copy_alerts) cp.copy_alert_count = cp.copy_alerts.length;
131                     else cp.copy_alert_count = 0;
132                 });
133
134                 // create a label using just the unique part of the owner list
135                 var index = 0;
136                 var prev_owner_list;
137                 angular.forEach(svc.copies, function (cp) {
138                     if (!prev_owner_list) {
139                         cp.owner_label = cp.owner_list.join(' ... ');
140                     } else {
141                         var current_owner_list = cp.owner_list.slice();
142                         while (current_owner_list[1] && prev_owner_list[1] && current_owner_list[0] == prev_owner_list[0]) {
143                             current_owner_list.shift();
144                             prev_owner_list.shift();
145                         }
146                         cp.owner_label = current_owner_list.join(' ... ');
147                     }
148
149                     cp.index = index++;
150                     prev_owner_list = cp.owner_list.slice();
151                 });
152
153                 var new_list = svc.copies;
154                 if (!copy || !vol) { // collapse copy rows, supply a count instead
155
156                     index = 0;
157                     var cp_list = [];
158                     var prev_key;
159                     var current_blob = { copy_count : 0 };
160                     angular.forEach(new_list, function (cp) {
161                         if (!prev_key) {
162                             prev_key = cp.owner_list.join('') + cp.call_number.label;
163                             if (cp.barcode) current_blob.copy_count = 1;
164                             current_blob.index = index++;
165                             current_blob.id_list = cp.id_list;
166                             if (cp.raw) current_blob.raw = cp.raw;
167                             current_blob.call_number = cp.call_number;
168                             current_blob.owner_list = cp.owner_list;
169                             current_blob.owner_label = cp.owner_label;
170                             current_blob.owner_id = cp.owner_id;
171                         } else {
172                             var current_key = cp.owner_list.join('') + cp.call_number.label;
173                             if (prev_key == current_key) { // collapse into current_blob
174                                 current_blob.copy_count++;
175                                 current_blob.id_list = current_blob.id_list.concat(cp.id_list);
176                                 current_blob.raw = current_blob.raw.concat(cp.raw);
177                             } else {
178                                 current_blob.barcode = current_blob.copy_count;
179                                 cp_list.push(current_blob);
180                                 prev_key = current_key;
181                                 current_blob = { copy_count : 0 };
182                                 if (cp.barcode) current_blob.copy_count = 1;
183                                 current_blob.index = index++;
184                                 current_blob.id_list = cp.id_list;
185                                 if (cp.raw) current_blob.raw = cp.raw;
186                                 current_blob.owner_label = cp.owner_label;
187                                 current_blob.owner_id = cp.owner_id;
188                                 current_blob.call_number = cp.call_number;
189                                 current_blob.owner_list = cp.owner_list;
190                             }
191                         }
192                     });
193
194                     current_blob.barcode = current_blob.copy_count;
195                     cp_list.push(current_blob);
196                     new_list = cp_list;
197
198                     if (!vol) { // do the same for vol rows
199
200                         index = 0;
201                         var cn_list = [];
202                         prev_key = '';
203                         current_blob = { copy_count : 0 };
204                         angular.forEach(cp_list, function (cp) {
205                             if (!prev_key) {
206                                 prev_key = cp.owner_list.join('');
207                                 current_blob.index = index++;
208                                 current_blob.id_list = cp.id_list;
209                                 if (cp.raw) current_blob.raw = cp.raw;
210                                 current_blob.cn_count = 1;
211                                 current_blob.copy_count = cp.copy_count;
212                                 current_blob.owner_list = cp.owner_list;
213                                 current_blob.owner_label = cp.owner_label;
214                                 current_blob.owner_id = cp.owner_id;
215                             } else {
216                                 var current_key = cp.owner_list.join('');
217                                 if (prev_key == current_key) { // collapse into current_blob
218                                     current_blob.cn_count++;
219                                     current_blob.copy_count += cp.copy_count;
220                                     current_blob.id_list = current_blob.id_list.concat(cp.id_list);
221                                     if (cp.raw) {
222                                         if (current_blob.raw) current_blob.raw = current_blob.raw.concat(cp.raw);
223                                         else current_blob.raw = cp.raw;
224                                     }
225                                 } else {
226                                     current_blob.barcode = current_blob.copy_count;
227                                     current_blob.call_number = { label : current_blob.cn_count };
228                                     cn_list.push(current_blob);
229                                     prev_key = current_key;
230                                     current_blob = { copy_count : 0 };
231                                     current_blob.index = index++;
232                                     current_blob.id_list = cp.id_list;
233                                     if (cp.raw) current_blob.raw = cp.raw;
234                                     current_blob.owner_label = cp.owner_label;
235                                     current_blob.owner_id = cp.owner_id;
236                                     current_blob.cn_count = 1;
237                                     current_blob.copy_count = cp.copy_count;
238                                     current_blob.owner_list = cp.owner_list;
239                                 }
240                             }
241                         });
242     
243                         current_blob.barcode = current_blob.copy_count;
244                         current_blob.call_number = { label : current_blob.cn_count };
245                         cn_list.push(current_blob);
246                         new_list = cn_list;
247     
248                     }
249                 }
250
251                 if (empty_org) {
252
253                     var empty_org_list = [];
254                     angular.forEach(svc.org_use_map,function(v,k){
255                         if (v == 0) empty_org_list.push(k);
256                     });
257
258                     angular.forEach(empty_org_list, function (oid) {
259                         var owner = egCore.org.get(oid);
260                         if (owner.ou_type().can_have_vols() != 't') return;
261
262                         var owner_list = [];
263                         while (owner.parent_ou()) { // we're going to skip the top of the tree...
264                             owner_list.unshift(owner.shortname());
265                             owner = egCore.org.get(owner.parent_ou());
266                         }
267
268                         var owner_label = owner_list.join(' ... ');
269
270                         new_list.push({
271                             index      : index++,
272                             id_list    : [],
273                             call_number: { label : '' },
274                             barcode    : '',
275                             owner_id   : oid,
276                             owner_list : owner_list,
277                             owner_label: owner_label,
278                             copy_count : 0,
279                             cn_count   : 0,
280                             copy_alert_count : 0
281                         });
282                     });
283                 }
284
285                 svc.copies = new_list;
286                 svc.ongoing = false;
287             },
288
289             null, // error
290
291             // notify reads the stream of copies, one at a time.
292             function(cn) {
293                 if (p.cancel) return;
294
295                 var copies = cn.copies().filter(function(cp){ return cp.deleted() == 'f' });
296                 cn.copies([]);
297
298                 angular.forEach(copies, function (cp) {
299                     cp.call_number(cn);
300                 });
301
302                 var owner_id = cn.owning_lib();
303                 var owner = egCore.org.get(owner_id);
304                 svc.org_use_map[''+owner_id] += 1;
305
306                 var owner_name_list = [];
307                 while (owner.parent_ou()) { // we're going to skip the top of the tree...
308                     owner_name_list.unshift(owner.shortname());
309                     owner = egCore.org.get(owner.parent_ou());
310                 }
311
312                 if (copies[0]) {
313                     var flat = [];
314                     angular.forEach(copies, function (cp) {
315                         var flat_cp = egCore.idl.toHash(cp);
316                         flat_cp.owner_id = owner_id;
317                         flat_cp.owner_list = owner_name_list;
318                         flat_cp.id_list = [flat_cp.id];
319                         flat_cp.raw = [cp];
320                         flat.push(flat_cp);
321                     });
322
323                     svc.copies = svc.copies.concat(flat);
324                 } else if (empty) {
325                     svc.copies.push({
326                         id_list    : [],
327                         owner_id   : owner_id,
328                         owner_list : owner_name_list,
329                         call_number: egCore.idl.toHash(cn),
330                         raw_call_number: cn
331                     });
332                 }
333
334                 return cn;
335             }
336         );
337
338         return svc.p = p;
339     };
340
341     return service;
342 }])
343 .directive("egVolumeList", function () {
344     return {
345         restrict:   'AE',
346         scope: {
347             recordId : '=',
348             editVolumes : '@',
349             editCopies  : '@'
350         },
351         templateUrl: './cat/share/t_volume_list',
352         controller:
353                    ['$scope','holdingsSvc','egCore','egGridDataProvider','$uibModal',
354             function($scope , holdingsSvc , egCore , egGridDataProvider,  $uibModal) {
355                 var holdingsSvcInst = new holdingsSvc();
356
357                 $scope.holdingsGridControls = {};
358                 $scope.holdingsGridDataProvider = egGridDataProvider.instance({
359                     get : function(offset, count) {
360                         return this.arrayNotifier(holdingsSvcInst.copies, offset, count);
361                     }
362                 });
363
364                 function gatherHoldingsIds () {
365                     var cp_id_list = [];
366                     angular.forEach(
367                         $scope.holdingsGridControls.allItems(),
368                         function (item) { cp_id_list = cp_id_list.concat(item.id_list) }
369                     );
370                     return cp_id_list;
371                 }
372
373                 var spawn_volume_editor = function (copies_too) {
374                     egCore.net.request(
375                         'open-ils.actor',
376                         'open-ils.actor.anon_cache.set_value',
377                         null, 'edit-these-copies', {
378                             record_id: $scope.recordId,
379                             copies: gatherHoldingsIds(),
380                             hide_vols : false,
381                             hide_copies : ((copies_too) ? false : true)
382                         }
383                     ).then(function(key) {
384                         if (key) {
385                             $uibModal.open({
386                                 templateUrl: './cat/share/t_embedded_volcopy',
387                                 backdrop: 'static',
388                                 size: 'lg',
389                                 windowClass: 'eg-wide-modal',
390                                 controller:
391                                     ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
392                                     $scope.volcopy_url = 
393                                         egCore.env.basePath + 'cat/volcopy/' + key + '/embedded';
394                                     $scope.ok = function(args) { $uibModalInstance.close(args) }
395                                     $scope.cancel = function () { $uibModalInstance.dismiss() }
396                                 }]
397                             }).result.then(function() {
398                                 load_holdings();
399                             });
400                         }
401                     });
402                 }
403                 $scope.edit_volumes = function() {
404                     spawn_volume_editor(false);
405                 }
406                 $scope.edit_copies = function() {
407                     spawn_volume_editor(true);
408                 }
409
410                 function load_holdings() {
411                     holdingsSvcInst.fetch({
412                         rid   : $scope.recordId,
413                         org   : egCore.org.root(),
414                         copy  : false,
415                         vol   : true,
416                         empty : true
417                     }).then(function() {
418                         $scope.holdingsGridDataProvider.refresh();
419                     });
420                 };
421                 $scope.$watch('recordId',
422                     function(newVal, oldVal) {
423                         if (newVal && newVal !== oldVal) {
424                             load_holdings();
425                         }
426                     }
427                 );
428                 load_holdings();
429             }]
430     }
431 })
432 ;