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