]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js
webstaff: Supply a "defaults" interface for disabling element and setting call number...
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / cat / volcopy / app.js
1 /**
2  * Vol/Copy Editor
3  */
4
5 angular.module('egVolCopy',
6     ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod'])
7
8 .filter('boolText', function(){
9     return function (v) {
10         return v == 't';
11     }
12 })
13
14 .config(function($routeProvider, $locationProvider, $compileProvider) {
15     $locationProvider.html5Mode(true);
16     $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
17
18     var resolver = {
19         delay : ['egStartup', function(egStartup) { return egStartup.go(); }]
20     };
21
22     $routeProvider.when('/cat/volcopy/:dataKey', {
23         templateUrl: './cat/volcopy/t_view',
24         controller: 'EditCtrl',
25         resolve : resolver
26     });
27
28 })
29
30 .factory('itemSvc', 
31        ['egCore','$q',
32 function(egCore , $q) {
33
34     var service = {
35         tree : {}, // holds lib->cn->copy hash stack
36         copies : [] // raw copy list
37     };
38
39     // returns a promise resolved with the list of circ mods
40     service.get_classifications = function() {
41         if (egCore.env.acnc)
42             return $q.when(egCore.env.acnc.list);
43
44         return egCore.pcrud.retrieveAll('acnc', null, {atomic : true})
45         .then(function(list) {
46             egCore.env.absorbList(list, 'acnc');
47             return list;
48         });
49     };
50
51     service.get_prefixes = function(org) {
52         return egCore.pcrud.search('acnp',
53             {owning_lib : egCore.org.fullPath(org, true)},
54             null, {atomic : true}
55         );
56
57     };
58
59     service.get_locations = function(orgs) {
60         return egCore.pcrud.search('acpl',
61             {owning_lib : orgs},
62             null, {atomic : true}
63         );
64     };
65
66     service.get_suffixes = function(org) {
67         return egCore.pcrud.search('acns',
68             {owning_lib : egCore.org.fullPath(org, true)},
69             null, {atomic : true}
70         );
71
72     };
73
74     service.get_statuses = function() {
75         if (egCore.env.ccs)
76             return $q.when(egCore.env.ccs.list);
77
78         return egCore.pcrud.retrieveAll('ccs', {}, {atomic : true}).then(
79             function(list) {
80                 egCore.env.absorbList(list, 'ccs');
81                 return list;
82             }
83         );
84
85     };
86
87     service.get_circ_mods = function() {
88         if (egCore.env.ccm)
89             return $q.when(egCore.env.ccm.list);
90
91         return egCore.pcrud.retrieveAll('ccm', {}, {atomic : true}).then(
92             function(list) {
93                 egCore.env.absorbList(list, 'ccm');
94                 return list;
95             }
96         );
97
98     };
99
100     service.get_circ_types = function() {
101         if (egCore.env.citm)
102             return $q.when(egCore.env.citm.list);
103
104         return egCore.pcrud.retrieveAll('citm', {}, {atomic : true}).then(
105             function(list) {
106                 egCore.env.absorbList(list, 'citm');
107                 return list;
108             }
109         );
110
111     };
112
113     service.get_age_protects = function() {
114         if (egCore.env.crahp)
115             return $q.when(egCore.env.crahp.list);
116
117         return egCore.pcrud.retrieveAll('crahp', {}, {atomic : true}).then(
118             function(list) {
119                 egCore.env.absorbList(list, 'crahp');
120                 return list;
121             }
122         );
123
124     };
125
126     service.bmp_parts = {};
127     service.get_parts = function(rec) {
128         if (service.bmp_parts[rec])
129             return $q.when(service.bmp_parts[rec]);
130
131         return egCore.pcrud.search('bmp',
132             {record : rec},
133             null, {atomic : true}
134         ).then(function(list) {
135             service.bmp_parts[rec] = list;
136             return list;
137         });
138
139     };
140
141     service.flesh = {   
142         flesh : 3, 
143         flesh_fields : {
144             acp : ['call_number','parts'],
145             acn : ['label_class','prefix','suffix']
146         }
147     }
148
149     service.addCopy = function (cp) {
150
151         if (!cp.parts()) cp.parts([]); // just in case...
152
153         var lib = cp.call_number().owning_lib();
154         var cn = cp.call_number().id();
155
156         if (!service.tree[lib]) service.tree[lib] = {};
157         if (!service.tree[lib][cn]) service.tree[lib][cn] = [];
158
159         service.tree[lib][cn].push(cp);
160         service.copies.push(cp);
161     }
162
163     service.fetchIds = function(idList) {
164         service.tree = {}; // clear the tree on fetch
165         service.copies = []; // clear the copy list on fetch
166         return egCore.pcrud.search('acp', { 'id' : idList }, service.flesh).then(null,null,
167             function(copy) {
168                 service.addCopy(copy);
169             }
170         );
171     }
172
173     return service;
174 }])
175
176 .directive("egVolCopyEdit", function () {
177     return {
178         restrict: 'E',
179         replace: true,
180         template:
181             '<div class="row">'+
182                 '<div class="col-xs-5">'+
183                     '<input id="{{callNumber.id()}}.{{copy.id()}}"'+
184                     ' eg-enter="nextBarcode()" class="form-control"'+
185                     ' type="text" ng-model="barcode" ng-change="updateBarcode()"/>'+
186                 '</div>'+
187                 '<div class="col-xs-3"><input class="form-control" type="number" ng-model="copy_number" ng-change="updateCopyNo()"/></div>'+
188                 '<div class="col-xs-4"><eg-basic-combo-box list="parts" selected="part"></eg-basic-combo-box></div>'+
189             '</div>',
190
191         scope: { copy: "=", callNumber: "=", index: "@" },
192         controller : ['$scope','itemSvc',
193             function ( $scope , itemSvc ) {
194                 $scope.new_part_id = 0;
195
196                 $scope.nextBarcode = function (i) {
197                     $scope.$parent.focusNextBarcode($scope.copy.id());
198                 }
199
200                 $scope.updateBarcode = function () { $scope.copy.barcode($scope.barcode); $scope.copy.ischanged(1); };
201                 $scope.updateCopyNo = function () { $scope.copy.copy_number($scope.copy_number); $scope.copy.ischanged(1); };
202                 $scope.updatePart = function () {
203                     var p = $scope.part_list.filter(function (x) {
204                         return x.label() == $scope.part
205                     });
206                     if (p.length > 0) { // preexisting part
207                         $scope.copy.parts(p)
208                     } else { // create one...
209                         var part = new egCore.idl.bmp();
210                         part.id( --$scope.new_part_id );
211                         part.isnew( true );
212                         part.label( $scope.part );
213                         part.record( $scope.callNumber.owning_lib() );
214                         $scope.copy.parts([part]);
215                         $scope.copy.ischanged(1);
216                     }
217                 }
218
219                 $scope.barcode = $scope.copy.barcode();
220                 $scope.copy_number = $scope.copy.copy_number();
221
222                 if ($scope.copy.parts()) {
223                     $scope.part = $scope.copy.parts()[0];
224                     if ($scope.part) $scope.part = $scope.part.label();
225                 };
226
227                 $scope.parts = [];
228                 $scope.part_list = [];
229
230                 itemSvc.get_parts($scope.callNumber.record()).then(function(list){
231                     $scope.part_list = list;
232                     angular.forEach(list, function(p){ $scope.parts.push(p.label()) });
233                 });
234
235             }
236         ]
237
238     }
239 })
240
241 .directive("egVolRow", function () {
242     return {
243         restrict: 'E',
244         replace: true,
245         transclude: true,
246         template:
247             '<div class="row">'+
248                 '<div class="col-xs-2">'+
249                     '<select class="form-control" ng-model="classification" ng-options="cl.name() for cl in classification_list track by idTracker(cl)"/>'+
250                 '</div>'+
251                 '<div class="col-xs-1">'+
252                     '<select class="form-control" ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list track by idTracker(p)"/>'+
253                 '</div>'+
254                 '<div class="col-xs-2"><input class="form-control" type="text" ng-change="updateLabel()" ng-model="label"/></div>'+
255                 '<div class="col-xs-1">'+
256                     '<select class="form-control" ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list track by idTracker(s)"/>'+
257                 '</div>'+
258                 '<div class="col-xs-1"><input class="form-control" type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
259                 '<div class="col-xs-5">'+
260                     '<eg-vol-copy-edit ng-repeat="cp in copies track by idTracker(cp)" copy="cp" call-number="callNumber"></eg-vol-copy-edit>'+
261                 '</div>'+
262             '</div>',
263
264         scope: {allcopies: "=", copies: "=" },
265         controller : ['$scope','itemSvc','egCore',
266             function ( $scope , itemSvc , egCore ) {
267                 $scope.new_cp_id = 0;
268                 $scope.callNumber =  $scope.copies[0].call_number();
269
270                 $scope.idTracker = function (x) { if (x) return x.id() };
271
272                 // XXX $() is not working! arg
273                 $scope.focusNextBarcode = function (i) {
274                     var n;
275                     var yep = false;
276                     angular.forEach($scope.copies, function (cp) {
277                         if (n) return;
278
279                         if (cp.id() == i) {
280                             yep = true;
281                             return;
282                         }
283
284                         if (yep) n = cp.id();
285                     });
286
287                     if (n) {
288                         var next = '#' + $scope.callNumber.id() + '.' + n;
289                         var el = $(next).get(0);
290                         if (el) el.focus()
291                     }
292                 }
293
294                 $scope.suffix_list = [];
295                 itemSvc.get_suffixes($scope.callNumber.owning_lib()).then(function(list){
296                     $scope.suffix_list = list;
297                 });
298                 $scope.updateSuffix = function () {
299                     angular.forEach($scope.copies, function(cp) {
300                         cp.call_number().suffix($scope.suffix);
301                         cp.call_number().ischanged(1);
302                     });
303                 }
304
305                 $scope.prefix_list = [];
306                 itemSvc.get_prefixes($scope.callNumber.owning_lib()).then(function(list){
307                     $scope.prefix_list = list;
308                 });
309                 $scope.updatePrefix = function () {
310                     angular.forEach($scope.copies, function(cp) {
311                         cp.call_number().prefix($scope.prefix);
312                         cp.call_number().ischanged(1);
313                     });
314                 }
315
316                 $scope.classification_list = [];
317                 itemSvc.get_classifications().then(function(list){
318                     $scope.classification_list = list;
319                 });
320                 $scope.updateClassification = function () {
321                     angular.forEach($scope.copies, function(cp) {
322                         cp.call_number().label_class($scope.classification);
323                         cp.call_number().ischanged(1);
324                     });
325                 }
326
327                 $scope.updateLabel = function () {
328                     angular.forEach($scope.copies, function(cp) {
329                         cp.call_number().label($scope.label);
330                         cp.call_number().ischanged(1);
331                     });
332                 }
333
334                 $scope.$watch('callNumber.prefix()', function (v) {
335                     if (typeof v != 'object') {
336                         $scope.prefix = $scope.prefix_list.filter(function (p) {
337                             return p.id() == v;
338                         })[0];
339                         $scope.callNumber.prefix($scope.prefix);
340                     }
341                 });
342
343                 $scope.$watch('callNumber.suffix()', function (v) {
344                     if (typeof v != 'object') {
345                         $scope.suffix = $scope.suffix_list.filter( function (s) {
346                             return s.id() == v;
347                         })[0];
348                         $scope.callNumber.suffix($scope.suffix);
349                     }
350                 });
351
352                 $scope.$watch('callNumber.label_class()', function (v) {
353                     if (typeof v != 'object') {
354                         $scope.classification = $scope.classification_list.filter(function (c) {
355                             return c.id() == v;
356                         })[0];
357                         $scope.callNumber.label_class($scope.classification);
358                     }
359                 });
360
361                 $scope.$watch('callNumber.label()', function (v) {
362                     $scope.label = v;
363                 });
364
365                 $scope.prefix = $scope.callNumber.prefix();
366                 $scope.suffix = $scope.callNumber.suffix();
367                 $scope.classification = $scope.callNumber.label_class();
368                 $scope.label = $scope.callNumber.label();
369
370                 $scope.copy_count = $scope.copies.length;
371                 $scope.orig_copy_count = $scope.copy_count;
372
373                 $scope.changeCPCount = function () {
374                     while ($scope.copy_count > $scope.copies.length) {
375                         var cp = new egCore.idl.acp();
376                         cp.id( --$scope.new_cp_id );
377                         cp.isnew( true );
378                         cp.circ_lib( $scope.lib );
379                         cp.call_number( $scope.callNumber );
380                         $scope.copies.push( cp );
381                         $scope.allcopies.push( cp );
382                     }
383
384                     var how_many = $scope.copies.length - $scope.copy_count;
385                     if (how_many > 0) {
386                         var dead = $scope.copies.splice($scope.copy_count,how_many);
387                         $scope.callNumber.copies($scope.copies);
388
389                         // Trimming the global list is a bit more tricky
390                         angular.forEach( dead, function (d) {
391                             angular.forEach( $scope.allcopies, function (l, i) { 
392                                 if (l === d) $scope.allcopies.splice(i,1);
393                             });
394                         });
395                     }
396                 }
397
398             }
399         ]
400
401     }
402 })
403
404 .directive("egVolEdit", function () {
405     return {
406         restrict: 'E',
407         replace: true,
408         template:
409             '<div class="row">'+
410                 '<div class="col-xs-1"><eg-org-selector selected="owning_lib" disableTest="cant_have_vols"></eg-org-selector></div>'+
411                 '<div class="col-xs-1"><input class="form-control" type="number" min="{{orig_cn_count}}" ng-model="cn_count" ng-change="changeCNCount()"/></div>'+
412                 '<div class="col-xs-10">'+
413                     '<eg-vol-row ng-repeat="(cn,copies) in struct track by cn" copies="copies" allcopies="allcopies"></eg-vol-row>'+
414                 '</div>'+
415             '</div>',
416
417         scope: { allcopies: "=", struct: "=", lib: "@", record: "@" },
418         controller : ['$scope','itemSvc','egCore',
419             function ( $scope , itemSvc , egCore ) {
420                 $scope.new_cn_id = 0;
421                 $scope.first_cn = Object.keys($scope.struct)[0];
422                 $scope.full_cn = $scope.struct[$scope.first_cn][0].call_number();
423
424                 $scope.cn_count = Object.keys($scope.struct).length;
425                 $scope.orig_cn_count = $scope.cn_count;
426
427                 $scope.owning_lib = egCore.org.get($scope.lib);
428                 $scope.$watch('owning_lib', function (l) {
429                     angular.forEach( $scope.struct[$scope.first_cn], function (cp) {
430                         cp.call_number().owning_lib( $scope.owning_lib.id() );
431                     });
432                 });
433
434                 $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
435
436                 $scope.$watch('cn_count', function (n) {
437                     var o = Object.keys($scope.struct).length;
438                     if (n > o) { // adding
439                         for (var i = o; o < n; o++) {
440                             var cn = new egCore.idl.acn();
441                             cn.id( --$scope.new_cn_id );
442                             cn.isnew( true );
443                             cn.owning_lib( $scope.owning_lib.id() );
444                             cn.record( $scope.full_cn.record() );
445
446                             var cp = new egCore.idl.acp();
447                             cp.id( --$scope.new_cp_id );
448                             cp.isnew( true );
449                             cp.circ_lib( $scope.owning_lib.id() );
450                             cp.call_number( cn );
451
452                             $scope.struct[cn.id()] = [cp];
453                             $scope.allcopies.push(cp);
454                         }
455                     } else if (n < o) { // removing
456                         var how_many = o - n;
457                         var list = Object
458                                 .keys($scope.struct)
459                                 .sort(function(a, b){return a-b})
460                                 .reverse();
461                         for (var i = how_many; i > 0; i--) {
462                             // Trimming the global list is a bit more tricky
463                             angular.forEach($scope.struct[list[i]], function (d) {
464                                 angular.forEach( $scope.allcopies, function (l, j) { 
465                                     if (l === d) $scope.allcopies.splice(j,1);
466                                 });
467                             });
468                             delete $scope.struct[list[i]];
469                         }
470                     }
471                 });
472             }
473         ]
474
475     }
476 })
477
478 /**
479  * Edit controller!
480  */
481 .controller('EditCtrl', 
482        ['$scope','$q','$routeParams','$location','$timeout','egCore','egNet','egGridDataProvider','itemSvc',
483 function($scope , $q , $routeParams , $location , $timeout , egCore , egNet , egGridDataProvider , itemSvc) {
484
485     $scope.defaults = { // If defaults are not set at all, allow everything
486         attributes : {
487             status : true,
488             loan_duration : true,
489             fine_level : true,
490             cost : true,
491             alerts : true,
492             deposit : true,
493             deposit_amount : true,
494             opac_visible : true,
495             price : true,
496             circulate : true,
497             mint_condition : true,
498             circ_lib : true,
499             ref : true,
500             circ_modifier : true,
501             circ_as_type : true,
502             location : true,
503             holdable : true,
504             age_protect : true
505         }
506     };
507
508     $scope.saveDefaults = function () {
509         egCore.hatch.setItem('cat.copy.defaults', $scope.defaults);
510     }
511
512     $scope.fetchDefaults = function () {
513         egCore.hatch.getItem('cat.copy.defaults').then(function(t) {
514             if (t) {
515                 $scope.defaults = t;
516                 if (!$scope.batch) $scope.batch = {};
517                 $scope.batch.classification = $scope.defaults.classification;
518                 $scope.batch.prefix = $scope.defaults.prefix;
519                 $scope.batch.suffix = $scope.defaults.suffix;
520                 if ($scope.defaults.always_vols) $scope.show_vols = true;
521             }
522         });
523     }
524     $scope.fetchDefaults();
525
526     $scope.dirty = false;
527
528     $scope.show_vols = true;
529     $scope.show_copies = true;
530
531     $scope.tracker = function (x,f) { if (x) return x[f]() };
532     $scope.idTracker = function (x) { if (x) return $scope.tracker(x,'id') };
533     $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
534
535     $scope.orgById = function (id) { return egCore.org.get(id) }
536     $scope.statusById = function (id) {
537         return $scope.status_list.filter( function (s) { return s.id() == id } )[0];
538     }
539     $scope.locationById = function (id) {
540         return $scope.location_cache[''+id];
541     }
542
543     $scope.workingToComplete = function () {
544         angular.forEach( $scope.workingGridControls.selectedItems(), function (c) {
545             angular.forEach( itemSvc.copies, function (w, i) {
546                 if (c === w)
547                     $scope.completed_copies = $scope.completed_copies.concat(itemSvc.copies.splice(i,1));
548             });
549         });
550     }
551
552     $scope.completeToWorking = function () {
553         angular.forEach( $scope.completedGridControls.selectedItems(), function (c) {
554             angular.forEach( $scope.completed_copies, function (w, i) {
555                 if (c === w)
556                     itemSvc.copies = itemSvc.copies.concat($scope.completed_copies.splice(i,1));
557             });
558         });
559     }
560
561     createSimpleUpdateWatcher = function (field) {
562         $scope.$watch('working.' + field, function () {
563             var newval = $scope.working[field];
564
565             if (typeof newval != 'undefined') {
566                 if (angular.isObject(newval)) { // we'll use the pkey
567                     if (newval.id) newval = newval.id();
568                     else if (newval.code) newval = newval.code();
569                 }
570
571                 if (newval == "") {
572                     $scope.working[field] = undefined;
573                     newval = null;
574                 }
575
576                 if ($scope.workingGridControls && $scope.workingGridControls.selectedItems) {
577                     angular.forEach(
578                         $scope.workingGridControls.selectedItems(),
579                         function (cp) { cp[field](newval); cp.ischanged(1); }
580                     );
581                 }
582             }
583         });
584     }
585
586     $scope.applyTemplate = function (n) {
587         angular.forEach($scope.templates[n], function (v,k) {
588             $scope.working[k] = angular.copy(v);
589         });
590     }
591
592     var dataKey = $routeParams.dataKey;
593     console.debug('dataKey: ' + dataKey);
594
595     if (dataKey && dataKey.length > 0) {
596
597         $scope.templates = {};
598         $scope.template_name = '';
599         $scope.template_name_list = [];
600
601         $scope.fetchTemplates = function () {
602             egCore.hatch.getItem('cat.copy.templates').then(function(t) {
603                 if (t) {
604                     $scope.templates = t;
605                     $scope.template_name_list = Object.keys(t);
606                 }
607             });
608         }
609         $scope.fetchTemplates();
610  
611         $scope.working = {};
612
613         $scope.copytab = 'working';
614         $scope.tab = 'edit';
615         $scope.summaryRecord = null;
616         $scope.record_id = null;
617         $scope.data = {};
618         $scope.completed_copies = [];
619         $scope.location_orgs = [];
620         $scope.location_cache = {};
621         if (!$scope.batch) $scope.batch = {};
622
623         $scope.applyBatchCNValues = function () {
624             if ($scope.data.tree) {
625                 angular.forEach($scope.data.tree, function(cn_hash) {
626                     angular.forEach(cn_hash, function(copies) {
627                         angular.forEach(copies, function(cp) {
628                             if (typeof $scope.batch.classification != 'undefined' && $scope.batch.classification != '')
629                                 cp.call_number().label_class($scope.batch.classification);
630                             if (typeof $scope.batch.prefix != 'undefined' && $scope.batch.prefix != '')
631                                 cp.call_number().prefix($scope.batch.prefix);
632                             if (typeof $scope.batch.label != 'undefined' && $scope.batch.label != '')
633                                 cp.call_number().label($scope.batch.label);
634                             if (typeof $scope.batch.suffix != 'undefined' && $scope.batch.suffix != '')
635                                 cp.call_number().suffix($scope.batch.suffix);
636                         });
637                     });
638                 });
639             }
640         }
641
642         $scope.clearWorking = function () {
643             angular.forEach($scope.working, function (v,k,o) {
644                 if (typeof v != 'undefined')
645                     $scope.working[k] = undefined;
646             });
647         }
648
649         $scope.completedGridDataProvider = egGridDataProvider.instance({
650             get : function(offset, count) {
651                 //return provider.arrayNotifier(itemSvc.copies, offset, count);
652                 return this.arrayNotifier($scope.completed_copies, offset, count);
653             }
654         });
655
656         $scope.completedGridControls = {};
657
658         $scope.workingGridDataProvider = egGridDataProvider.instance({
659             get : function(offset, count) {
660                 //return provider.arrayNotifier(itemSvc.copies, offset, count);
661                 return this.arrayNotifier(itemSvc.copies, offset, count);
662             }
663         });
664
665         $scope.workingGridControls = {};
666
667         egNet.request(
668             'open-ils.actor',
669             'open-ils.actor.anon_cache.get_value',
670             dataKey, 'edit-these-copies'
671         ).then(function (data) {
672
673             if (data) {
674                 if (data.hide_vols && !$scope.defaults.always_vols) $scope.show_vols = false;
675                 if (data.hide_copies) $scope.show_copies = false;
676
677                 $scope.record_id = data.record_id;
678
679                 if (data.copies && data.copies.length)
680                     return itemSvc.fetchIds(data.copies);
681
682                 if (data.raw && data.raw.length) {
683
684                     /* data.raw must be an array of copies with (at least)
685                      * the call number fleshed on each.  For new copies
686                      * create from whole cloth, the id for each should
687                      * probably be negative and isnew() should return true.
688                      * Each /distinct/ call number must have a distinct id
689                      * as well, probably negative also if they're new. Clear?
690                      */
691
692                     angular.forEach(
693                         data.raw,
694                         function (cp) { itemSvc.addCopy(cp) }
695                     );
696
697                     return itemSvc.copies;
698                 }
699             }
700
701         }).then( function() {
702             $scope.data = itemSvc;
703             $scope.workingGridDataProvider.refresh();
704         });
705
706         $scope.$watch('data.copies.length', function () {
707             if ($scope.data.copies) {
708                 var base_orgs = $scope.data.copies.map(function(cp){
709                     return cp.circ_lib()
710                 }).filter(function(e,i,a){
711                     return a.lastIndexOf(e) === i;
712                 });
713
714                 var all_orgs = [];
715                 angular.forEach(base_orgs, function(o) {
716                     all_orgs = all_orgs.concat( egCore.org.fullPath(o, true) );
717                 });
718
719                 var final_orgs = all_orgs.filter(function(e,i,a){
720                     return a.lastIndexOf(e) === i;
721                 }).sort(function(a,b){return b-a});
722
723                 if ($scope.location_orgs.toString() != final_orgs.toString()) {
724                     $scope.location_orgs = final_orgs;
725                     if ($scope.location_orgs.length) {
726                         itemSvc.get_locations($scope.location_orgs).then(function(list){
727                             angular.forEach(list, function(l) {
728                                 $scope.location_cache[ ''+l.id() ] = l;
729                             });
730                             $scope.location_list = list;
731                         });
732                     }
733                 }
734             }
735
736             $scope.workingGridDataProvider.refresh();
737         });
738
739         $scope.suffix_list = [];
740         itemSvc.get_suffixes(egCore.auth.user().ws_ou()).then(function(list){
741             $scope.suffix_list = list;
742         });
743
744         $scope.prefix_list = [];
745         itemSvc.get_prefixes(egCore.auth.user().ws_ou()).then(function(list){
746             $scope.prefix_list = list;
747         });
748
749         $scope.classification_list = [];
750         itemSvc.get_classifications().then(function(list){
751             $scope.classification_list = list;
752         });
753
754         $scope.$watch('completed_copies.length', function () {
755             $scope.completedGridDataProvider.refresh();
756         });
757
758         $scope.location_list = [];
759         itemSvc.get_locations().then(function(list){
760             $scope.location_list = list;
761         });
762         createSimpleUpdateWatcher('location');
763
764         $scope.status_list = [];
765         itemSvc.get_statuses().then(function(list){
766             $scope.status_list = list;
767         });
768         createSimpleUpdateWatcher('status');
769
770         $scope.circ_modifier_list = [];
771         itemSvc.get_circ_mods().then(function(list){
772             $scope.circ_modifier_list = list;
773         });
774         createSimpleUpdateWatcher('circ_modifier');
775
776         $scope.circ_type_list = [];
777         itemSvc.get_circ_types().then(function(list){
778             $scope.circ_type_list = list;
779         });
780         createSimpleUpdateWatcher('circ_as_type');
781
782         $scope.age_protect_list = [];
783         itemSvc.get_age_protects().then(function(list){
784             $scope.age_protect_list = list;
785         });
786         createSimpleUpdateWatcher('age_protect');
787
788         createSimpleUpdateWatcher('circ_lib');
789         createSimpleUpdateWatcher('circulate');
790         createSimpleUpdateWatcher('holdable');
791         createSimpleUpdateWatcher('fine_level');
792         createSimpleUpdateWatcher('loan_duration');
793         createSimpleUpdateWatcher('cost');
794         createSimpleUpdateWatcher('deposit');
795         createSimpleUpdateWatcher('deposit_amount');
796         createSimpleUpdateWatcher('mint_condition');
797         createSimpleUpdateWatcher('opac_visible');
798         createSimpleUpdateWatcher('ref');
799
800     }
801
802 }])
803
804 .directive("egVolTemplate", function () {
805     return {
806         restrict: 'E',
807         replace: true,
808         template: '<div ng-include="'+"'/eg/staff/cat/volcopy/t_attr_edit'"+'"></div>',
809         scope: { },
810         controller : ['$scope','itemSvc','egCore',
811             function ( $scope , itemSvc , egCore ) {
812
813                 $scope.defaults = { // If defaults are not set at all, allow everything
814                     attributes : {
815                         status : true,
816                         loan_duration : true,
817                         fine_level : true,
818                         cost : true,
819                         alerts : true,
820                         deposit : true,
821                         deposit_amount : true,
822                         opac_visible : true,
823                         price : true,
824                         circulate : true,
825                         mint_condition : true,
826                         circ_lib : true,
827                         ref : true,
828                         circ_modifier : true,
829                         circ_as_type : true,
830                         location : true,
831                         holdable : true,
832                         age_protect : true
833                     }
834                 };
835
836                 $scope.fetchDefaults = function () {
837                     egCore.hatch.getItem('cat.copy.defaults').then(function(t) {
838                         if (t) {
839                             $scope.defaults = t;
840                         }
841                     });
842                 }
843                 $scope.fetchDefaults();
844
845                 $scope.dirty = false;
846                 $scope.template_controls = true;
847
848                 $scope.fetchTemplates = function () {
849                     egCore.hatch.getItem('cat.copy.templates').then(function(t) {
850                         if (t) {
851                             $scope.templates = t;
852                             $scope.template_name_list = Object.keys(t);
853                         }
854                     });
855                 }
856                 $scope.fetchTemplates();
857             
858                 $scope.applyTemplate = function (n) {
859                     angular.forEach($scope.templates[n], function (v,k) {
860                         $scope.working[k] = angular.copy(v);
861                     });
862                 }
863             
864                 $scope.deleteTemplate = function (n) {
865                     if (n) {
866                         delete $scope.templates[n]
867                         $scope.template_name_list = Object.keys($scope.templates);
868                         $scope.template_name = '';
869                         egCore.hatch.setItem('cat.copy.templates', $scope.templates);
870                         $scope.$parent.fetchTemplates();
871                     }
872                 }
873
874                 $scope.saveTemplate = function (n) {
875                     if (n) {
876                         var tmpl = {};
877             
878                         angular.forEach($scope.working, function (v,k) {
879                             if (angular.isObject(v)) { // we'll use the pkey
880                                 if (v.id) v = v.id();
881                                 else if (v.code) v = v.code();
882                             }
883             
884                             tmpl[k] = v;
885                         });
886             
887                         $scope.templates[n] = tmpl;
888                         $scope.template_name_list = Object.keys($scope.templates);
889             
890                         egCore.hatch.setItem('cat.copy.templates', $scope.templates);
891                         $scope.$parent.fetchTemplates();
892                     }
893                 }
894             
895                 $scope.templates = {};
896                 $scope.template_name = '';
897                 $scope.template_name_list = [];
898             
899                 $scope.tracker = function (x,f) { if (x) return x[f]() };
900                 $scope.idTracker = function (x) { if (x) return $scope.tracker(x,'id') };
901                 $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
902             
903                 $scope.orgById = function (id) { return egCore.org.get(id) }
904                 $scope.statusById = function (id) {
905                     return $scope.status_list.filter( function (s) { return s.id() == id } )[0];
906                 }
907                 $scope.locationById = function (id) {
908                     return $scope.location_cache[''+id];
909                 }
910             
911                 createSimpleUpdateWatcher = function (field) {
912                     $scope.$watch('working.' + field, function () {
913                         var newval = $scope.working[field];
914             
915                         if (typeof newval != 'undefined') {
916                             $scope.dirty = true;
917                             if (angular.isObject(newval)) { // we'll use the pkey
918                                 if (newval.id) $scope.working[field] = newval.id();
919                                 else if (newval.code) $scope.working[field] = newval.code();
920                             }
921             
922                             if (newval == "") {
923                                 $scope.working[field] = undefined;
924                             }
925             
926                         }
927                     });
928                 }
929             
930                 $scope.clearWorking = function () {
931                     angular.forEach($scope.working, function (v,k) {
932                         if (typeof v != 'undefined')
933                             $scope.working[k] = undefined;
934                     });
935                 }
936             
937                 $scope.working = {};
938                 $scope.location_orgs = [];
939                 $scope.location_cache = {};
940             
941                 $scope.location_list = [];
942                 itemSvc.get_locations(
943                     egCore.org.fullPath( egCore.auth.user().ws_ou(), true )
944                 ).then(function(list){
945                     $scope.location_list = list;
946                 });
947                 createSimpleUpdateWatcher('location');
948             
949                 $scope.status_list = [];
950                 itemSvc.get_statuses().then(function(list){
951                     $scope.status_list = list;
952                 });
953                 createSimpleUpdateWatcher('status');
954             
955                 $scope.circ_modifier_list = [];
956                 itemSvc.get_circ_mods().then(function(list){
957                     $scope.circ_modifier_list = list;
958                 });
959                 createSimpleUpdateWatcher('circ_modifier');
960             
961                 $scope.circ_type_list = [];
962                 itemSvc.get_circ_types().then(function(list){
963                     $scope.circ_type_list = list;
964                 });
965                 createSimpleUpdateWatcher('circ_as_type');
966             
967                 $scope.age_protect_list = [];
968                 itemSvc.get_age_protects().then(function(list){
969                     $scope.age_protect_list = list;
970                 });
971                 createSimpleUpdateWatcher('age_protect');
972             
973                 createSimpleUpdateWatcher('circ_lib');
974                 createSimpleUpdateWatcher('circulate');
975                 createSimpleUpdateWatcher('holdable');
976                 createSimpleUpdateWatcher('fine_level');
977                 createSimpleUpdateWatcher('loan_duration');
978                 createSimpleUpdateWatcher('cost');
979                 createSimpleUpdateWatcher('deposit');
980                 createSimpleUpdateWatcher('deposit_amount');
981                 createSimpleUpdateWatcher('mint_condition');
982                 createSimpleUpdateWatcher('opac_visible');
983                 createSimpleUpdateWatcher('ref');
984             }
985         ]
986     }
987 })
988
989