1 angular.module('egHoldingsMod', ['egCoreMod','egGridMod'])
3 .factory('holdingsSvc',
5 function(egCore , $q) {
7 var service = function() {
9 this.copies = []; // record search results
10 this.index = 0; // search grid index
15 service.prototype.flesh = {
18 acp : ['status','location','circ_lib','parts','age_protect','copy_alerts', 'latest_inventory'],
19 acn : ['prefix','suffix','copies','label_class','record'],
20 bre : ['simple_record'],
21 alci : ['inventory_workstation']
25 service.prototype.fetchAgain = function() {
32 empty_org: this.empty_org
36 // resolved with the last received copy
37 service.prototype.fetch = function(opts) {
40 if (svc.ongoing && svc.p) {
42 console.log('Canceling fetch for org '+ svc.org.id());
43 if (svc.p.reject) svc.p.reject();
47 var empty_org = opts.empty_org;
51 var empty = opts.empty;
53 if (!rid) return $q.when();
54 if (!org) return $q.when();
59 svc.empty_org = opts.empty_org;
63 svc.empty = opts.empty;
68 var org_list = egCore.org.descendants(org.id(), true);
69 console.log('Holdings fetch with: rid='+rid+' org='+org_list+' copy='+copy+' vol='+vol+' empty='+empty);
72 org_list.map(function(o){svc.org_use_map[''+o]=0;})
74 var p = egCore.pcrud.search(
76 {record : rid, owning_lib : org_list, deleted : 'f', label : {'!=' : '##URI##'}},
79 function() { // finished
82 // create virtual field for displaying active parts
83 angular.forEach(svc.copies, function (cp) {
84 cp.monograph_parts = '';
85 if (cp.parts && cp.parts.length > 0) {
86 cp.monograph_parts = cp.parts.map(function(obj) { return obj.label; }).join(', ');
87 cp.monograph_parts_sortkeys = cp.parts.map(function(obj) { return obj.label_sortkey; }).join();
91 svc.copies = svc.copies.sort(
93 function compare_array (x, y, i) {
94 if (x[i] && y[i]) { // both have values
95 if (x[i] == y[i]) { // need to look deeper
96 return compare_array(x, y, ++i);
99 if (x[i] < y[i]) { // x is first
101 } else if (x[i] > y[i]) { // y is first
105 } else { // no orgs to compare ...
112 var owner_order = compare_array(a.owner_list, b.owner_list, 0);
114 // now compare on CN label
115 if (a.call_number.label < b.call_number.label) return -1;
116 if (a.call_number.label > b.call_number.label) return 1;
118 // also parts sortkeys combined string
119 if (a.monograph_parts_sortkeys < b.monograph_parts_sortkeys) return -1;
120 if (a.monograph_parts_sortkeys > b.monograph_parts_sortkeys) return 1;
123 if (a.copy_number < b.copy_number) return -1;
124 if (a.copy_number > b.copy_number) return 1;
127 if (a.barcode < b.barcode) return -1;
128 if (a.barcode > b.barcode) return 1;
134 // create virtual fields for copy alert count and most recent circ
135 angular.forEach(svc.copies, function (cp) {
136 if (cp.copy_alerts) {
137 cp.copy_alert_count = cp.copy_alerts.filter(function(aca) { return aca.ack_time == null ;}).length;
139 else cp.copy_alert_count = 0;
141 var copy_circ = egCore.pcrud.search('combcirc', { target_copy : cp.id },
143 order_by : {combcirc : 'xact_start desc'},
146 ).then(function(copy_circ) {
148 cp._circ = egCore.idl.toHash(copy_circ, true);
149 cp._circ_lib = copy_circ.circ_lib();
150 cp._duration = copy_circ.duration();
156 // create a label using just the unique part of the owner list
159 angular.forEach(svc.copies, function (cp) {
160 if (!prev_owner_list) {
161 cp.owner_label = cp.owner_list.join(' ... ');
163 var current_owner_list = cp.owner_list.slice();
164 while (current_owner_list[1] && prev_owner_list[1] && current_owner_list[0] == prev_owner_list[0]) {
165 current_owner_list.shift();
166 prev_owner_list.shift();
168 cp.owner_label = current_owner_list.join(' ... ');
172 prev_owner_list = cp.owner_list.slice();
175 var new_list = svc.copies;
176 if (!copy || !vol) { // collapse copy rows, supply a count instead
181 var current_blob = { copy_count : 0 };
182 angular.forEach(new_list, function (cp) {
184 prev_key = cp.owner_list.join('') + cp.call_number.label;
185 if (cp.barcode) current_blob.copy_count = 1;
186 current_blob.index = index++;
187 current_blob.id_list = cp.id_list;
188 if (cp.raw) current_blob.raw = cp.raw;
189 current_blob.call_number = cp.call_number;
190 current_blob.owner_list = cp.owner_list;
191 current_blob.owner_label = cp.owner_label;
192 current_blob.owner_id = cp.owner_id;
194 var current_key = cp.owner_list.join('') + cp.call_number.label;
195 if (prev_key == current_key) { // collapse into current_blob
196 current_blob.copy_count++;
197 current_blob.id_list = current_blob.id_list.concat(cp.id_list);
198 current_blob.raw = current_blob.raw.concat(cp.raw);
200 current_blob.barcode = current_blob.copy_count;
201 cp_list.push(current_blob);
202 prev_key = current_key;
203 current_blob = { copy_count : 0 };
204 if (cp.barcode) current_blob.copy_count = 1;
205 current_blob.index = index++;
206 current_blob.id_list = cp.id_list;
207 if (cp.raw) current_blob.raw = cp.raw;
208 current_blob.owner_label = cp.owner_label;
209 current_blob.owner_id = cp.owner_id;
210 current_blob.call_number = cp.call_number;
211 current_blob.owner_list = cp.owner_list;
216 current_blob.barcode = current_blob.copy_count;
217 cp_list.push(current_blob);
220 if (!vol) { // do the same for vol rows
225 current_blob = { copy_count : 0 };
226 angular.forEach(cp_list, function (cp) {
228 prev_key = cp.owner_list.join('');
229 current_blob.index = index++;
230 current_blob.id_list = cp.id_list;
231 if (cp.raw) current_blob.raw = cp.raw;
232 current_blob.cn_count = 1;
233 current_blob.copy_count = cp.copy_count;
234 current_blob.owner_list = cp.owner_list;
235 current_blob.owner_label = cp.owner_label;
236 current_blob.owner_id = cp.owner_id;
238 var current_key = cp.owner_list.join('');
239 if (prev_key == current_key) { // collapse into current_blob
240 current_blob.cn_count++;
241 current_blob.copy_count += cp.copy_count;
242 current_blob.id_list = current_blob.id_list.concat(cp.id_list);
244 if (current_blob.raw) current_blob.raw = current_blob.raw.concat(cp.raw);
245 else current_blob.raw = cp.raw;
248 current_blob.barcode = current_blob.copy_count;
249 current_blob.call_number = { label : current_blob.cn_count };
250 cn_list.push(current_blob);
251 prev_key = current_key;
252 current_blob = { copy_count : 0 };
253 current_blob.index = index++;
254 current_blob.id_list = cp.id_list;
255 if (cp.raw) current_blob.raw = cp.raw;
256 current_blob.owner_label = cp.owner_label;
257 current_blob.owner_id = cp.owner_id;
258 current_blob.cn_count = 1;
259 current_blob.copy_count = cp.copy_count;
260 current_blob.owner_list = cp.owner_list;
265 current_blob.barcode = current_blob.copy_count;
266 current_blob.call_number = { label : current_blob.cn_count };
267 cn_list.push(current_blob);
275 var empty_org_list = [];
276 angular.forEach(svc.org_use_map,function(v,k){
277 if (v == 0) empty_org_list.push(k);
280 angular.forEach(empty_org_list, function (oid) {
281 var owner = egCore.org.get(oid);
282 if (owner.ou_type().can_have_vols() != 't') return;
285 while (owner.parent_ou()) { // we're going to skip the top of the tree...
286 owner_list.unshift(owner.shortname());
287 owner = egCore.org.get(owner.parent_ou());
290 var owner_label = owner_list.join(' ... ');
295 call_number: { label : '' },
298 owner_list : owner_list,
299 owner_label: owner_label,
307 svc.copies = new_list;
313 // notify reads the stream of copies, one at a time.
315 if (p.cancel) return;
317 var copies = cn.copies().filter(function(cp){ return cp.deleted() == 'f' });
320 angular.forEach(copies, function (cp) {
324 var owner_id = cn.owning_lib();
325 var owner = egCore.org.get(owner_id);
326 svc.org_use_map[''+owner_id] += 1;
328 var owner_name_list = [];
329 while (owner.parent_ou()) { // we're going to skip the top of the tree...
330 owner_name_list.unshift(owner.shortname());
331 owner = egCore.org.get(owner.parent_ou());
336 angular.forEach(copies, function (cp) {
337 var flat_cp = egCore.idl.toHash(cp);
338 flat_cp.owner_id = owner_id;
339 flat_cp.owner_list = owner_name_list;
340 flat_cp.id_list = [flat_cp.id];
345 svc.copies = svc.copies.concat(flat);
350 owner_list : owner_name_list,
351 call_number: egCore.idl.toHash(cn),
365 .directive("egVolumeList", function () {
373 templateUrl: './cat/share/t_volume_list',
375 ['$scope','holdingsSvc','egCore','egGridDataProvider','$uibModal',
376 function($scope , holdingsSvc , egCore , egGridDataProvider, $uibModal) {
377 var holdingsSvcInst = new holdingsSvc();
379 $scope.holdingsGridControls = {};
380 $scope.holdingsGridDataProvider = egGridDataProvider.instance({
381 get : function(offset, count) {
382 return this.arrayNotifier(holdingsSvcInst.copies, offset, count);
386 function gatherHoldingsIds () {
389 $scope.holdingsGridControls.allItems(),
390 function (item) { cp_id_list = cp_id_list.concat(item.id_list) }
395 var spawn_volume_editor = function (copies_too) {
398 'open-ils.actor.anon_cache.set_value',
399 null, 'edit-these-copies', {
400 record_id: $scope.recordId,
401 copies: gatherHoldingsIds(),
403 hide_copies : ((copies_too) ? false : true)
405 ).then(function(key) {
408 templateUrl: './cat/share/t_embedded_volcopy',
411 windowClass: 'eg-wide-modal',
413 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
415 egCore.env.basePath + 'cat/volcopy/' + key + '/embedded';
416 $scope.ok = function(args) { $uibModalInstance.close(args) }
417 $scope.cancel = function () { $uibModalInstance.dismiss() }
419 }).result.then(function() {
425 $scope.edit_volumes = function() {
426 spawn_volume_editor(false);
428 $scope.edit_copies = function() {
429 spawn_volume_editor(true);
432 function load_holdings() {
433 holdingsSvcInst.fetch({
434 rid : $scope.recordId,
435 org : egCore.org.root(),
440 $scope.holdingsGridDataProvider.refresh();
443 $scope.$watch('recordId',
444 function(newVal, oldVal) {
445 if (newVal && newVal !== oldVal) {
454 .filter('string_pick', function() { return function(i){ return arguments[i] || ''; }; })