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