]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js
webstaff: more volume/copy editor work
[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         if (egCore.env.acnp)
53             return $q.when(egCore.env.acnp.list);
54
55         return egCore.pcrud.search('acnp',
56             {owning_lib : egCore.org.fullPath(org, true)},
57             null, {atomic : true}
58         ).then(function(list) {
59             egCore.env.absorbList(list, 'acnp');
60             return list;
61         });
62
63     };
64
65     service.get_suffixes = function(org) {
66         if (egCore.env.acns)
67             return $q.when(egCore.env.acns.list);
68
69         return egCore.pcrud.search('acns',
70             {owning_lib : egCore.org.fullPath(org, true)},
71             null, {atomic : true}
72         ).then(function(list) {
73             egCore.env.absorbList(list, 'acns');
74             return list;
75         });
76
77     };
78
79     service.get_statuses = function() {
80         if (egCore.env.ccs)
81             return $q.when(egCore.env.ccs.list);
82
83         return egCore.pcrud.retrieveAll('ccs', {}, {atomic : true}).then(
84             function(list) {
85                 egCore.env.absorbList(list, 'ccs');
86                 return list;
87             }
88         );
89
90     };
91
92     service.bmp_parts = {};
93     service.get_parts = function(rec) {
94         if (service.bmp_parts[rec])
95             return $q.when(service.bmp_parts[rec]);
96
97         return egCore.pcrud.search('bmp',
98             {record : rec},
99             null, {atomic : true}
100         ).then(function(list) {
101             service.bmp_parts[rec] = list;
102             return list;
103         });
104
105     };
106
107     service.flesh = {   
108         flesh : 3, 
109         flesh_fields : {
110             acp : ['call_number','parts','location'],
111             acn : ['label_class','prefix','suffix']
112         }
113     }
114
115     service.addCopy = function (cp) {
116
117         if (!cp.parts()) cp.parts([]); // just in case...
118
119         var lib = cp.call_number().owning_lib();
120         var cn = cp.call_number().id();
121
122         if (!service.tree[lib]) service.tree[lib] = {};
123         if (!service.tree[lib][cn]) service.tree[lib][cn] = [];
124
125         service.tree[lib][cn].push(cp);
126         service.copies.push(cp);
127     }
128
129     service.fetchIds = function(idList) {
130         service.tree = {}; // clear the tree on fetch
131         service.copies = []; // clear the copy list on fetch
132         return egCore.pcrud.search('acp', { 'id' : idList }, service.flesh).then(null,null,
133             function(copy) {
134                 service.addCopy(copy);
135             }
136         );
137     }
138
139     return service;
140 }])
141
142 .directive("egVolCopyEdit", function () {
143     return {
144         restrict: 'E',
145         replace: true,
146         template:
147             '<div class="row">'+
148                 '<div class="col-xs-6"><input type="text" ng-model="barcode" ng-change="updateBarcode()"/></div>'+
149                 '<div class="col-xs-2"><input type="number" ng-model="copy_number" ng-change="updateCopyNo()"/></div>'+
150                 '<div class="col-xs-4"><eg-basic-combo-box list="parts" selected="part"></eg-basic-combo-box></div>'+
151             '</div>',
152
153         scope: { copy: "=", callNumber: "=" },
154         controller : ['$scope','itemSvc',
155             function ( $scope , itemSvc ) {
156                 $scope.new_part_id = 0;
157
158                 $scope.updateBarcode = function () { $scope.copy.barcode($scope.barcode); $scope.copy.ischanged(1); };
159                 $scope.updateCopyNo = function () { $scope.copy.copy_number($scope.copy_number); $scope.copy.ischanged(1); };
160                 $scope.updatePart = function () {
161                     var p = angular.filter($scope.part_list, function (x) {
162                         return x.label() == $scope.part
163                     });
164                     if (p.length > 0) { // preexisting part
165                         $scope.copy.parts(p)
166                     } else { // create one...
167                         var part = new egCore.idl.bmp();
168                         part.id( --$scope.new_part_id );
169                         part.isnew( true );
170                         part.label( $scope.part );
171                         part.record( $scope.callNumber.owning_lib() );
172                         $scope.copy.parts([part]);
173                         $scope.copy.ischanged(1);
174                     }
175                 }
176
177                 $scope.barcode = $scope.copy.barcode();
178                 $scope.copy_number = $scope.copy.copy_number();
179
180                 if ($scope.copy.parts()) {
181                     $scope.part = $scope.copy.parts()[0];
182                     if ($scope.part) $scope.part = $scope.part.label();
183                 };
184
185                 $scope.parts = [];
186                 $scope.part_list = [];
187
188                 itemSvc.get_parts($scope.callNumber.record()).then(function(list){
189                     $scope.part_list = list;
190                     angular.forEach(list, function(p){ $scope.parts.push(p.label()) });
191                 });
192
193             }
194         ]
195
196     }
197 })
198
199 .directive("egVolRow", function () {
200     return {
201         restrict: 'E',
202         replace: true,
203         transclude: true,
204         template:
205             '<div class="row">'+
206                 '<div class="col-xs-1">'+
207                     '<select ng-model="classification" ng-options="cl.name() for cl in classification_list track by idTracker(cl)"/>'+
208                 '</div>'+
209                 '<div class="col-xs-1">'+
210                     '<select ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list track by idTracker(p)"/>'+
211                 '</div>'+
212                 '<div class="col-xs-3"><input type="text" ng-change="updateLabel()" ng-model="label"/></div>'+
213                 '<div class="col-xs-1">'+
214                     '<select ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list track by idTracker(s)"/>'+
215                 '</div>'+
216                 '<div class="col-xs-1"><input type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
217                 '<div class="col-xs-5">'+
218                     '<div class="container-fluid">'+
219                         '<eg-vol-copy-edit ng-repeat="cp in copies track by idTracker(cp)" copy="cp" call-number="callNumber"></eg-vol-copy-edit>'+
220                     '</div>'+
221                 '</div>'+
222             '</div>',
223
224         scope: {allcopies: "=", copies: "=" },
225         controller : ['$scope','itemSvc','egCore',
226             function ( $scope , itemSvc , egCore ) {
227                 $scope.new_cp_id = 0;
228                 $scope.callNumber =  $scope.copies[0].call_number();
229
230                 $scope.idTracker = function (x) { if (x) return x.id() };
231
232                 $scope.suffix_list = [];
233                 itemSvc.get_suffixes($scope.callNumber.owning_lib()).then(function(list){
234                     $scope.suffix_list = list;
235                 });
236                 $scope.updateSuffix = function () { $scope.callNumber.suffix($scope.suffix); $scope.callNumber.ischanged(1); };
237
238                 $scope.prefix_list = [];
239                 itemSvc.get_prefixes($scope.callNumber.owning_lib()).then(function(list){
240                     $scope.prefix_list = list;
241                 });
242                 $scope.updatePrefix = function () { $scope.callNumber.prefix($scope.prefix); $scope.callNumber.ischanged(1); };
243
244                 $scope.classification_list = [];
245                 itemSvc.get_classifications().then(function(list){
246                     $scope.classification_list = list;
247                 });
248                 $scope.updateClassification = function () { $scope.callNumber.label_class($scope.classification); $scope.callNumber.ischanged(1); };
249
250                 $scope.classification = $scope.callNumber.label_class();
251                 $scope.prefix = $scope.callNumber.prefix();
252                 $scope.suffix = $scope.callNumber.suffix();
253
254                 $scope.label = $scope.callNumber.label();
255                 $scope.updateLabel = function () { $scope.callNumber.label($scope.label); $scope.callNumber.ischanged(1); };
256
257                 $scope.copy_count = $scope.copies.length;
258                 $scope.orig_copy_count = $scope.copy_count;
259
260                 $scope.changeCPCount = function () {
261                     while ($scope.copy_count > $scope.copies.length) {
262                         var cp = new egCore.idl.acp();
263                         cp.id( --$scope.new_cp_id );
264                         cp.isnew( true );
265                         cp.circ_lib( $scope.lib );
266                         cp.call_number( $scope.callNumber );
267                         $scope.copies.push( cp );
268                         $scope.allcopies.push( cp );
269                     }
270
271                     var how_many = $scope.copies.length - $scope.copy_count;
272                     if (how_many > 0) {
273                         var dead = $scope.copies.splice($scope.copy_count,how_many);
274                         $scope.callNumber.copies($scope.copies);
275
276                         // Trimming the global list is a bit more tricky
277                         angular.forEach( dead, function (d) {
278                             angular.forEach( $scope.allcopies, function (l, i) { 
279                                 if (l === d) $scope.allcopies.splice(i,1);
280                             });
281                         });
282                     }
283                 }
284
285             }
286         ]
287
288     }
289 })
290
291 .directive("egVolEdit", function () {
292     return {
293         restrict: 'E',
294         replace: true,
295         template:
296             '<div class="row">'+
297                 '<div class="col-xs-1"><eg-org-selector selected="owning_lib" disableTest="cant_have_vols"></eg-org-selector></div>'+
298                 '<div class="col-xs-1"><input type="number" min="{{orig_cn_count}}" ng-model="cn_count" ng-change="changeCNCount()"/></div>'+
299                 '<div class="col-xs-10">'+
300                     '<div class="container-fluid">'+
301                         '<eg-vol-row ng-repeat="(cn,copies) in struct track by cn" copies="copies" allcopies="allcopies"></eg-vol-row>'+
302                     '</div>'+
303                 '</div>'+
304             '</div>',
305
306         scope: { allcopies: "=", struct: "=", lib: "@", record: "@" },
307         controller : ['$scope','itemSvc','egCore',
308             function ( $scope , itemSvc , egCore ) {
309                 $scope.new_cn_id = 0;
310                 $scope.first_cn = Object.keys($scope.struct)[0];
311                 $scope.full_cn = $scope.struct[$scope.first_cn][0].call_number();
312
313                 $scope.cn_count = Object.keys($scope.struct).length;
314                 $scope.orig_cn_count = $scope.cn_count;
315
316                 $scope.owning_lib = egCore.org.get($scope.lib);
317
318                 $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
319
320                 $scope.$watch('cn_count', function (n) {
321                     var o = Object.keys($scope.struct).length;
322                     if (n > o) { // adding
323                         for (var i = o; o < n; o++) {
324                             var cn = new egCore.idl.acn();
325                             cn.id( --$scope.new_cn_id );
326                             cn.isnew( true );
327                             cn.owning_lib( $scope.owning_lib );
328                             cn.record( $scope.full_cn.record() );
329
330                             var cp = new egCore.idl.acp();
331                             cp.id( --$scope.new_cp_id );
332                             cp.isnew( true );
333                             cp.circ_lib( $scope.owning_lib );
334                             cp.call_number( cn );
335
336                             $scope.struct[cn.id()] = [cp];
337                             $scope.allcopies.push(cp);
338                         }
339                     } else if (n < o) { // removing
340                         var how_many = o - n;
341                         var list = Object
342                                 .keys($scope.struct)
343                                 .sort(function(a, b){return a-b})
344                                 .reverse();
345                         for (var i = how_many; i > 0; i--) {
346                             // Trimming the global list is a bit more tricky
347                             angular.forEach($scope.struct[list[i]], function (d) {
348                                 angular.forEach( $scope.allcopies, function (l, j) { 
349                                     if (l === d) $scope.allcopies.splice(j,1);
350                                 });
351                             });
352                             delete $scope.struct[list[i]];
353                         }
354                     }
355                 });
356             }
357         ]
358
359     }
360 })
361
362 /**
363  * Edit controller!
364  */
365 .controller('EditCtrl', 
366        ['$scope','$q','$routeParams','$location','$timeout','egCore','egNet','egGridDataProvider','itemSvc',
367 function($scope , $q , $routeParams , $location , $timeout , egCore , egNet , egGridDataProvider , itemSvc) {
368
369     $scope.show_vols = true;
370     $scope.show_copies = true;
371
372     $scope.idTracker = function (x) { if (x) return x.id() };
373
374     $timeout(function(){
375
376     var dataKey = $routeParams.dataKey;
377     console.debug('dataKey: ' + dataKey);
378
379     if (dataKey && dataKey.length > 0) {
380         $scope.working = {};
381
382         $scope.tab = 'edit';
383         $scope.summaryRecord = null;
384         $scope.record_id = null;
385         $scope.data = {};
386
387         $scope.workingGridDataProvider = egGridDataProvider.instance({
388             get : function(offset, count) {
389                 //return provider.arrayNotifier(itemSvc.copies, offset, count);
390                 return this.arrayNotifier(itemSvc.copies, offset, count);
391             }
392         });
393
394         $scope.workingGridControls = {};
395
396         egNet.request(
397             'open-ils.actor',
398             'open-ils.actor.anon_cache.get_value',
399             dataKey, 'edit-these-copies'
400         ).then(function (data) {
401
402             if (data.hide_vols) $scope.show_vols = false;
403             if (data.hide_copies) $scope.show_copies = false;
404
405             $scope.record_id = data.record_id;
406
407             if (data.copies && data.copies.length)
408                 return itemSvc.fetchIds(data.copies);
409
410             if (data.raw && data.raw.length) {
411
412                 /* data.raw must be an array of copies with (at least)
413                  * the call number fleshed on each.  For new copies
414                  * create from whole cloth, the id for each should
415                  * probably be negative and isnew() should return true.
416                  * Each /distinct/ call number must have a distinct id
417                  * as well, probably negative also if they're new. Clear?
418                  */
419
420                 angular.forEach(
421                     data.raw,
422                     function (cp) { itemSvc.addCopy(cp) }
423                 );
424
425                 return itemSvc.copies;
426             }
427
428         }).then( function() {
429             $scope.data = itemSvc;
430             $scope.workingGridDataProvider.refresh();
431         });
432
433         $scope.$watch('data.copies.length', function () {
434             console.log('data.copies.length changed');
435             $scope.workingGridDataProvider.refresh();
436         });
437
438         $scope.status_list = [];
439         itemSvc.get_statuses().then(function(list){
440             $scope.status_list = list;
441         });
442         $scope.updateWorkingStatus = function () {
443             angular.forEach(
444                 $scope.workingGridControls.selectedItems(),
445                 function (cp) { cp.status($scope.working.status.id()); cp.ischanged(1); }
446             );
447         };
448     }
449
450     });
451
452 }])
453
454