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